Domyślne argumenty JavaScript z określaniem zakresu bloków nie działają tylko w systemie iOS

9

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

W OS X Chrome, OS X Safari, Android Chrome, Windows Chrome, Windows Firefox, a nawet Windows Edge ostrzega o „poprawnej wartości”. W iOS Safari i iOS Chrome wyświetla ostrzeżenie „Nie można znaleźć zmiennej: val”.

Wszystkie poniższe fragmenty działają w systemie iOS:

Nieużywanie domyślnego argumentu (fragment 2):

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

Brak funkcji zagnieżdżonych (fragment 3):

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

Nie zastępuje zmiennej (fragment 4):

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

Blokuj zakres zamiast funkcji (fragment 5):

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

Na podstawie fragmentu 3 jasne jest, że parametr valin arg = valpowinien pochodzić z zakresu nadrzędnego, a nie z zakresu funkcji wewnętrznej.

W pierwszym fragmencie przeglądarka nie może znaleźć valw bieżącym zakresie, ale zamiast sprawdzać zakresy przodka, używa zakresu potomnego, co powoduje czasową martwą strefę.

Czy to błąd w systemie iOS, czy nie rozumiem właściwego zachowania JS?

Ten błąd występuje w naszym wyjściu Webpack + Babel + Terser, więc nie możemy po prostu przepisać kodu, aby uniknąć tego błędu.

Leo Jiang
źródło

Odpowiedzi:

3

Myślę, że jest to niepożądana konsekwencja błędnej implementacji domyślnych wartości Param i ich TDZ . Podejrzewam, że iOS Safari myśli, że próbujesz przypisać coś, czego jeszcze nie zainicjowałeś.

Dla odniesienia - lokalizacja błędu:

wprowadź opis zdjęcia tutaj


Obejście 1 Nie inicjuj stałej zakresu wewnętrznego o takiej samej nazwie jak parametr domyślny i parametr zakresu zewnętrznego

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

Obejście 2

Siła constdo 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');
}

Obejście 3 W ogóle nie inicjuj ponownie const valw najbardziej wewnętrznym zamknięciu:

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');
}
Joe
źródło