Javascript аргументы по умолчанию с блочной областью видимости не работают только на iOS - PullRequest
9 голосов
/ 06 апреля 2020

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 Край, он предупреждает "правильное значение". В 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, ясно, что val в arg = val должно исходить из родительской области, а не области внутренней функции.

В первом фрагменте браузер не может найти val в текущей области, но вместо проверки областей предка он использует дочернюю область, которая вызывает временную мертвую зону.

Is это ошибка iOS или я неправильно понимаю правильное поведение JS?

Эта ошибка возникает в нашем выводе Webpack + Babel + Terser, поэтому мы не можем просто переписать код, чтобы избежать этой ошибки.

1 Ответ

3 голосов
/ 13 апреля 2020

Я думаю, что это нежелательное следствие ошибочной реализации значений по умолчанию Param и их TDZ . Я подозреваю, что iOS Safari считает, что вы пытаетесь присвоить то, что еще не инициализировано.

Для справки - местоположение ошибки:

enter image description here


Обходной путь 1 Не инициализируйте внутреннюю область видимости с тем же именем, что и у параметра по умолчанию, и у внешней области видимости

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

Сила const до let:

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');
}

Обходное решение 3 Не инициализировать const 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');
}
...