为什么 babel 将导入的函数调用重写为 (0, fn)(...)?
Why does babel rewrite imported function call to (0, fn)(...)?
给定一个输入文件,如
import { a } from 'b';
function x () {
a()
}
babel 会将其编译为
'use strict';
var _b = require('b');
function x() {
(0, _b.a)();
}
但是在松散模式下编译时,函数调用输出为 _b.a();
我对逗号运算符的添加位置做了一些研究,希望有评论可以解释它。
负责添加它的代码是here.
(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)。
The comma operator evaluates each of its operands (from left to right)
and returns the value of the last operand.
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)
将评估它的每个操作数(从左到右)和 returns 最后一个操作数的值。换句话说,(0, a.foo)
等同于
function() {
console.log(this === window);
}
由于这个函数不再附加到任何东西,它的 this
是全局对象 window
。这就是为什么它在调用 (0, a.foo)()
.
时在控制台中记录 true
以这种迂回方式调用函数:
(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()
,它使用默认值 this
调用 a
。即使 a
是 _b
的 属性,执行 (0, _b.a)()
也会做同样的事情。
2。如果函数是 eval
,它使它成为一个 间接 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();
给定一个输入文件,如
import { a } from 'b';
function x () {
a()
}
babel 会将其编译为
'use strict';
var _b = require('b');
function x() {
(0, _b.a)();
}
但是在松散模式下编译时,函数调用输出为 _b.a();
我对逗号运算符的添加位置做了一些研究,希望有评论可以解释它。 负责添加它的代码是here.
(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)。
The comma operator evaluates each of its operands (from left to right) and returns the value of the last operand.
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)
将评估它的每个操作数(从左到右)和 returns 最后一个操作数的值。换句话说,(0, a.foo)
等同于
function() {
console.log(this === window);
}
由于这个函数不再附加到任何东西,它的 this
是全局对象 window
。这就是为什么它在调用 (0, a.foo)()
.
true
以这种迂回方式调用函数:
(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()
,它使用默认值 this
调用 a
。即使 a
是 _b
的 属性,执行 (0, _b.a)()
也会做同样的事情。
2。如果函数是 eval
,它使它成为一个 间接 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();