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

Wil*_*ith 93 javascript ecmascript-6 babeljs

给定一个输入文件

import { a } from 'b';

function x () {
  a()
}
Run Code Online (Sandbox Code Playgroud)

babel会把它编译成

'use strict';

var _b = require('b');

function x() {
  (0, _b.a)();
}
Run Code Online (Sandbox Code Playgroud)

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

我已经对添加逗号运算符的位置进行了一些研究,希望有一个解释它的注释.负责添加它的代码在这里.

Rob*_*b W 130

(0, _b.a)()确保_b.a通过this设置为全局对象来调用函数(或者如果启用了严格模式,则调用该函数undefined).如果你要_b.a()直接调用,则_b.a调用thisset to _b.

(0, _b.a)(); 相当于

0; // Ignore result
var tmp = _b.a;
tmp();
Run Code Online (Sandbox Code Playgroud)

(该,是逗号操作符,见https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator).

  • 谢谢你的链接.经过这么多次,最后决定找出发生了什么. (3认同)

Huo*_*yen 20

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

console.log((1, 2)); // Returns 2 in console
console.log((a = b = 3, c = 4)); // Returns 4 in console
Run Code Online (Sandbox Code Playgroud)

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

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

a.foo(); // Returns 'false' in console
(0, a.foo)(); // Returns 'true' in console
Run Code Online (Sandbox Code Playgroud)

现在,在foo方法中,this等于a(因为foo附加a).所以,如果你a.foo(直接打电话,它将登录false控制台.

但是,如果你打电话(0, a.foo)().表达式(0, a.foo)将评估其每个操作数(从左到右)并返回最后一个操作数的值.换句话说,(0, a.foo)相当于

function() {
  console.log(this === window);
}
Run Code Online (Sandbox Code Playgroud)

由于此函数不再附加到任何内容,因此它this是全局对象window.这就是它true在通话时登录控制台的原因(0, a.foo)().

  • 这让我大吃一惊。这里的关键是逗号运算符“返回最后一个操作数的值”——这里的“值”是函数本身,没有包含它的父对象——所以 foo 不再存在于 a 中。 (4认同)

T.J*_*der 7

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

(throwAwayValueHere, fn)(args);
Run Code Online (Sandbox Code Playgroud)

工作原理如下:

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

以这种方式进行调用在两种情况下会产生影响:

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

(throwAwayValueHere, obj.fn)(args);
Run Code Online (Sandbox Code Playgroud)

它调用该函数而不在函数调用期间设置this为;obj相反,它被设置为默认值,即全局this值(window在浏览器上)或undefined严格模式。

例子:

(throwAwayValueHere, fn)(args);
Run Code Online (Sandbox Code Playgroud)

这就是 Babel 在那里这样做的原因:在原始代码中,调用很简单a(),它a使用默认this值进行调用。(0, _b.a)()即使a是 的属性,“做”也会做同样的事情_b

2. 如果函数是eval,则它会使其成为间接函数eval,这意味着它会像在全局范围内一样进行计算,而不是从本地eval范围内的字符串运行任意代码的默认行为,从而使其能够访问所有范围内的变量。

例子:

(throwAwayValueHere, obj.fn)(args);
Run Code Online (Sandbox Code Playgroud)