Los argumentos predeterminados de Javascript con el alcance de bloque falla solo en iOS

9

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

En OS X Chrome, OS X Safari, Android Chrome, Windows Chrome, Windows Firefox e incluso Windows Edge, alerta "valor correcto". En iOS Safari y iOS Chrome, alerta "No se puede encontrar la variable: val".

Los siguientes fragmentos funcionan en iOS:

No se usa el argumento predeterminado (fragmento 2):

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

Sin funciones anidadas (fragmento 3):

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

No sobrescribe la variable (fragmento 4):

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

Bloquee el alcance en lugar de la función (fragmento 5):

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

Basado en el fragmento 3, está claro que el valde arg = valdebe venir del ámbito padre, no el alcance de la función interna.

En el primer fragmento, el navegador no puede encontrar valen el ámbito actual, pero en lugar de verificar los ámbitos ancestrales, utiliza el ámbito secundario, que causa la zona muerta temporal.

¿Es esto un error de iOS o estoy malinterpretando el comportamiento correcto de JS?

Este error está ocurriendo en nuestra salida Webpack + Babel + Terser, por lo que no podemos simplemente reescribir el código para evitar este error.

Leo Jiang
fuente

Respuestas:

3

Creo que esta es una consecuencia no deseada de una implementación defectuosa de los valores predeterminados de Param y sus TDZ . Sospecho que iOS Safari cree que está intentando asignar algo que aún no ha inicializado.

Para referencia - la ubicación del error:

ingrese la descripción de la imagen aquí


Solución 1 : no inicialice un const de alcance interno con el mismo nombre que el parámetro predeterminado y el del alcance externo

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

Solución 2

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

Solución 3 No reinicialice const valen el cierre más interno:

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
fuente