Why does babel rewrite imported function call to (0, fn)(...)?

给定一个输入文件,如

import { a } from 'b';


function x () {
a()
}

babel will compile it to

'use strict';


var _b = require('b');


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

但在松散模式下编译时,函数调用的输出为 _b.a();

我已经做了一些研究,在哪里逗号运算符添加,希望有一个注释来解释它。 负责添加它的代码是 给你

6640 次浏览

(0, _b.a)()确保在 this设置为全局对象的情况下调用函数 _b.a(如果启用了严格模式,则设置为 undefined)。如果您要直接调用 _b.a(),那么 _b.a将在 this设置为 _b的情况下被调用。

(0, _b.a)();等于

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

(,是逗号运算符,请参阅 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator)。

逗号运算符计算它的每个操作数(从左到右) 并返回最后一个操作数的值。

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

那么,让我们看一个例子:

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


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

现在,在 foo方法中,this等于 a(因为 foo附着在 a上)。因此,如果您直接调用 a.foo() ,它将在控制台中记录 false

但是,如果你调用 (0, a.foo)()。表达式 (0, a.foo)将计算它的每个操作数(从左到右)并返回最后一个操作数的值。换句话说,(0, a.foo)相当于

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

因为这个函数不再附加到任何东西上,所以它的 this是全局对象 window。这就是为什么当调用 (0, a.foo)()时它会在控制台中记录 true

以这种迂回的方式调用函数:

(throwAwayValueHere, fn)(args);

工作原理是这样的:

  • 计算逗号表达式 throwAwayValueHere, fn: 逗号运算符计算它的第一个操作数,抛弃该值,然后计算它的第二个操作数,并将该值作为计算结果。
  • That value is then called as a function, passing in the arguments.

以这种方式打电话会在两种情况下产生效果:

1. 如果函数位于对象属性上,例如:

(throwAwayValueHere, obj.fn)(args);

它在函数调用期间调用函数 没有,将 this设置为 obj; 相反,它被设置为默认值,要么是全局 this值(浏览器上的 window) ,要么是严格模式下的 undefined

例如:

"use strict";
const obj = {
value: 42,
fn: function() {
console.log(`typeof this = ${typeof this}`);
if (typeof this === "object") {
console.log(`this.value = ${this.value}`);
}
}
};


// Normal call:
console.log(`obj.fn():`);
obj.fn();


// Indirect call:
console.log(`(0, obj.fn)():`);
(0, obj.fn)();

这就是 Babel 在这里调用的原因: 在原始代码中,调用只是 a(),它使用默认的 this值调用 a。即使 a_b的一个属性,执行 (0, _b.a)()也会做同样的事情。

2. If the function is eval, it makes it an indirect eval which means it's evaluated as though at global scope, rather than eval's default behavior of running arbitrary code from a string in 本地 scope, giving it access to all in-scope variables.

Example:

"use strict";


let a = "global a";


function directEval() {
let a = "local a";
eval("console.log(`a = ${a}`);");
}


function indirectEval() {
let a = "local a";
(0,eval)("console.log(`a = ${a}`);");
}


console.log("direct:");
directEval();
console.log("indirect:");
indirectEval();