Аргументы 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, то ясно , что valв arg = valдолжно исходить от родительской области, а не объем внутренней функции.

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

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

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

Лео Цзян
источник

Ответы:

3

Я думаю, что это является нежелательным следствием ошибочной реализации значений параметров по умолчанию и их 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

Силы 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');
}
jzzfs
источник