¿Por qué babel reescribe la llamada de función importada en (0, fn) (…)?

100

Dado un archivo de entrada como

import { a } from 'b';

function x () {
  a()
}

babel lo compilará para

'use strict';

var _b = require('b');

function x() {
  (0, _b.a)();
}

pero cuando se compila en modo suelto, la llamada a la función se emite como _b.a();

He investigado un poco dónde se agrega el operador de coma con la esperanza de que haya un comentario que lo explique. El código responsable de agregarlo está aquí .

Will Smith
fuente
4
Deberían haberlo hecho _b.a.call()para dejar clara la intención.
Bergi
@Bergi Estoy seguro de que la razón por la que usan (0,) es para ahorrar espacio en el código transpilado.
Andy
consulte también la sintaxis de JavaScript (0, fn) (args)
Bergi

Respuestas:

138

(0, _b.a)()asegura que la función _b.ase llame con thisel objeto global establecido (o si el modo estricto está habilitado, en undefined). Si tuviera que llamar _b.a()directamente, entonces _b.ase llama con thisconfigurado en _b.

(0, _b.a)(); es equivalente a

0; // Ignore result
var tmp = _b.a;
tmp();

( ,es el operador de coma, consulte https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator ).

Rob W
fuente
3
Gracias por el enlace. pasó por alto esto tantas veces y finalmente decidió averiguar qué estaba pasando.
theflowersoftime
@RobW Creo que agregar var _a = (0, _b.a)en la parte superior del archivo y luego llamar _aahorraría más espacio en muchos casos, ¿alguna idea de que no hicieron eso?
Andy
1
@Andy Tu sugerencia puede tener efectos secundarios, por ejemplo, cuándo _b.aes un captador (dinámico).
Rob W
@RobW Ya veo, entonces estás diciendo que la idea es evitar posibles efectos secundarios hasta que sea necesario llamar a la función.
Andy
Tenga en cuenta que los módulos siempre son código estricto, por lo que siempre lo es this === undefinedy ni siquiera necesita mencionar el objeto global
Bergi
22

El operador de coma evalúa cada uno de sus operandos (de izquierda a derecha) y devuelve el valor del último operando.

console.log((1, 2)); // Returns 2 in console
console.log((a = b = 3, c = 4)); // Returns 4 in console

Entonces, veamos un ejemplo:

var a = {
  foo: function() {
    console.log(this === window);
  }
};

a.foo(); // Returns 'false' in console
(0, a.foo)(); // Returns 'true' in console

Ahora, en foométodo, thises igual a a(porque foose adjunta a a). Entonces, si llama a.foo() directamente, iniciará sesión falseen la consola.

Pero, si te llamaras (0, a.foo)(). La expresión (0, a.foo)evaluará cada uno de sus operandos (de izquierda a derecha) y devolverá el valor del último operando. En otras palabras, (0, a.foo)es equivalente a

function() {
  console.log(this === window);
}

Dado que esta función ya no está asociada a nada, thises el objeto global window. Es por eso que inicia sesión trueen la consola cuando llama (0, a.foo)().

Huong Nguyen
fuente
la ejecución console.log(this === window);en la consola de desarrollo ya no registra la impresión.
kushdilip
2
Esto me estaba volviendo loco. La clave aquí es que el operador Comma "devuelve el valor del último operando" - el "valor" aquí es la función en sí misma sin su padre contenedor - por lo que foo ya no vive dentro de a.
martinp999