为什么babel重写导入的函数调用(0,fn)(...)?

时间:2015-08-28 15:56:26

标签: javascript ecmascript-6 babeljs

给出像

这样的输入文件
import { a } from 'b';

function x () {
  a()
}

babel将其编译为

'use strict';

var _b = require('b');

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

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

我已经对添加逗号运算符的位置进行了一些研究,希望有一条评论解释它。 负责添加它的代码是here

3 个答案:

答案 0 :(得分:125)

(0, _b.a)()确保调用函数_b.a并将this设置为全局对象(或者如果启用了严格模式,则调用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)。

答案 1 :(得分:17)

  

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

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。这就是为什么它在调用true时在控制台中记录(0, a.foo)()

答案 2 :(得分:0)

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

(throwAwayValueHere, fn)(args);

工作方式如下:

  • 计算逗号表达式 throwAwayValueHere, fn:逗号运算符计算其第一个操作数,丢弃该值,然后计算其第二个操作数并将该值作为其结果。
  • 然后将该值作为函数调用,并传入参数。

以这种方式调用会在两种情况下产生效果:

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(),它使用默认的 a 值调用 this。即使 (0, _b.a)()a 的属性,执行 _b 也会做同样的事情。

2.如果函数是 eval,它使它成为 indirect eval 这意味着它被评估为好像在全局范围内,而不是 eval 的默认运行行为local 范围内的字符串中的任意代码,使其可以访问所有范围内的变量。

示例:

"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();