Gli argomenti predefiniti di Javascript con ambito scoping non funzionano solo su iOS


9

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

Su OS X Chrome, OS X Safari, Android Chrome, Windows Chrome, Windows Firefox e persino Windows Edge, avvisa "valore corretto". Su iOS Safari e iOS Chrome, avvisa "Impossibile trovare la variabile: val".

I seguenti frammenti funzionano tutti su iOS:

Non utilizzare l'argomento predefinito (snippet 2):

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

Nessuna funzione nidificata (snippet 3):

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

Variabile non prioritaria (snippet 4):

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

Blocca l'ambito invece della funzione (snippet 5):

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

Basato sullo snippet 3, è chiaro che valin arg = valdovrebbe provenire dall'ambito padre, non dall'ambito della funzione interna.

Nel primo frammento, il browser non riesce a trovare vall'ambito corrente, ma invece di verificare gli ambiti dell'antenato, utilizza l'ambito figlio, che causa la zona morta temporale.

È un bug di iOS o sto fraintendendo il comportamento corretto di JS?

Questo errore si verifica nel nostro output Webpack + Babel + Terser, quindi non possiamo semplicemente riscrivere il codice per evitare questo errore.

Risposte:


3

Penso che questa sia una conseguenza indesiderata di un'implementazione errata dei valori di default di Param e dei loro TDZ . Sospetto che iOS Safari pensi che tu stia cercando di assegnare a qualcosa che non hai ancora inizializzato.

Per riferimento - la posizione dell'errore:

inserisci qui la descrizione dell'immagine


Soluzione 1 Non inizializzare una const di ambito interno con lo stesso nome del parametro predefinito e di quello dell'ambito esterno

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

Soluzione alternativa 2

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

Soluzione 3 Non reinizializzare affatto const valnella chiusura più interna:

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');
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.