Les arguments par défaut de Javascript avec la portée des blocs échouent sur iOS uniquement

9

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

Sous OS X Chrome, OS X Safari, Android Chrome, Windows Chrome, Windows Firefox et même Windows Edge, il alerte «valeur correcte». Sur iOS Safari et iOS Chrome, il signale "Impossible de trouver la variable: val".

Les extraits suivants fonctionnent tous sur iOS:

Ne pas utiliser d'argument par défaut (extrait 2):

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

Aucune fonction imbriquée (extrait 3):

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

Variable non prioritaire (extrait 4):

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

Bloquer la portée au lieu de la fonction (extrait 5):

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

Sur la base de l'extrait 3, il est clair que l' valen arg = valdevrait provenir de la portée des parents, pas la portée de la fonction intérieure.

Dans le premier extrait, le navigateur ne peut pas trouver valdans la portée actuelle, mais au lieu de vérifier les portées d'ancêtre, il utilise la portée enfant, ce qui provoque la zone morte temporelle.

Est-ce un bug iOS ou est-ce que je comprends mal le bon comportement JS?

Ce bogue se produit dans notre sortie Webpack + Babel + Terser, nous ne pouvons donc pas simplement réécrire le code pour éviter ce bogue.

Leo Jiang
la source

Réponses:

3

Je pense que c'est une conséquence indésirable d'une implémentation boguée des valeurs par défaut de Param et de leurs TDZ . Je soupçonne qu'iOS Safari pense que vous essayez d'assigner à quelque chose que vous n'avez pas encore initialisé.

Pour référence - l'emplacement de l'erreur:

entrez la description de l'image ici


Solution de contournement 1 Ne pas initialiser une constante de portée interne avec le même nom que le paramètre par défaut et celui de la portée externe

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

Solution de contournement 2

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

Solution de contournement 3 Ne réinitialisez pas du tout const valdans la fermeture la plus intérieure:

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
la source