ブロックスコープを指定したJavascriptのデフォルト引数がiOSでのみ失敗する


9

try {
  const val = 'correct value';
  (() => {
    ((arg = val) => {
      const val = 'ignored value';
      alert(arg);
    })();
  })();
} catch (err) {
  alert(err.message || 'Unknown error');
}

OS X Chrome、OS X Safari、Android Chrome、Windows Chrome、Windows Firefox、さらには Windows Edgeでは、「正しい値」を警告します。iOS SafariおよびiOS Chromeでは、「変数が見つかりません:val」という警告が表示されます。

次のスニペットはすべてiOSで機能します。

デフォルトの引数を使用しない(抜粋2):

try {
  const val = 'correct value';
  (() => {
    alert(val);
    (() => {
      const val = 'wrong value';
    })();
  })();
} catch (err) {
  alert(err.message || 'Unknown error');
}

ネストされた関数はありません(スニペット3):

try {
  const val = 'correct value';
  ((arg = val) => {
    const val = 'ignored value';
    alert(val || 'wrong value');
  })();
} catch (err) {
  alert(err.message || 'Unknown error');
}

変数を上書きしない(スニペット4):

try {
  const val = 'correct value';
  (() => {
    ((arg = val) => {
      alert(arg);
    })();
  })();
} catch (err) {
  alert(err.message || 'Unknown error');
}

関数の代わりにブロックスコープ(スニペット5):

try {
  const val = 'correct value';
  {
    ((arg = val) => {
      const val = 'ignored value';
      alert(arg);
    })();
  }
} catch (err) {
  alert(err.message || 'Unknown error');
}

スニペット3に基づいて、valin arg = valは内部関数のスコープではなく、親スコープから取得する必要があることは明らかです。

最初のスニペットでは、ブラウザーvalは現在のスコープを見つけることができませんが、祖先スコープをチェックする代わりに、一時的なデッドゾーンを引き起こす子スコープを使用します。

これはiOSのバグですか、それともJSの正しい動作を誤解していますか?

このバグはWebpack + Babel + Terserの出力で発生しているため、コードを書き換えてこのバグを回避することはできません。

回答:


3

これは、Paramのデフォルト値とそのTDZのバグのある実装の望ましくない結果だと思います。iOS Safariが、まだ初期化していないものに割り当てようとしていると思っているのではないかと思います。

参考のために-エラーの場所:

ここに画像の説明を入力してください


回避策1 デフォルトのパラメーターと同じ名前と外側のスコープのものと同じ名前で内側のスコープconstを初期化しないでください

try {
    const val = 'correct value';
    (() => {
        ((arg = val) => {
            const val_ = 'ignored value';       // <----
            alert(arg);
        })();
    })();
} catch (err) {
    console.error(err);
    console.error('msg', err.message || 'Unknown error');
}

回避策2

強制的constlet

try {
    let val = 'correct value';                 // <----
    (() => {
        ((arg = val) => {
            const val = 'ignored value';
            alert(arg);
        })();
    })();
} catch (err) {
    console.error(err);
    console.error('msg', err.message || 'Unknown error');
}

回避策3const val最も内側のクロージャーで 再初期化しないでください。

try {
    const val = 'correct value';
    (() => {
        ((arg = val) => {
            // const val = 'ignored value';      // <--
            alert(arg);
        })();
    })();
} catch (err) {
    console.error(err);
    console.error('msg', err.message || 'Unknown error');
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.