前言
使用 webpack 工具打包 React 项目编译后的代码,经常会出现以下片段:
v=rt((0,r.useState)(void 0),2),
为什么 r.useState
方法,要用 (0,r.useState)(void 0)
的方式去执行呢?r.useState(void 0)
的调用方式也是可运行的,为什么不这么写?
带着这个问题,下文将重点探讨 (0, function)(param)
的应用。
逗号操作符
对它的每个操数求值(从左到右),并返回最后一个操作数的值。
let x = 1;
x = (x++, x);
console.log(x);
// expected output: 2
x = (2, 3);
console.log(x);
// expected output: 3
熟悉 逗号操作符
这个知识点后,对 (0,r.useState)(void 0)
的前半部分,也就能认识了。(0,r.useState)
也即 r.userState
对应的方法实例。
举个例子:
r.userState = function(){
console.log('leon');
};
则 (0,r.useState)
对应的方法实例为:
function(){
console.log('leon');
}
this
的指向
在浏览器控制台运行以下代码:
(function() {
(0,eval)("var leon = 123"); // 通过 eval 创建全局变量 leon
})();
console.log(leon); // 输出 123
eval
执行的代码环境上下文,通常是局部上下文。
但是,我们发现 eval
执行的代码 var leon = 123
在全局上下文中起效。
以下为 MDN 文档中,对 eval
作用域的说明:
function test() {
var x = 2, y = 4;
console.log(eval('x + y')); // 直接调用,使用本地作用域,结果是 6
var geval = eval; // 等价于在全局作用域调用
console.log(geval('x + y')); // 间接调用,使用全局作用域,throws ReferenceError 因为`x`未定义
}
可以得出:(0,eval)
属于间接调用,使用的是 全局作用域,this
指向的是全局上下文。
使用以下代码验证下:
(function() {
(0,eval)("console.log(this)");
})();
发现输出 this
指向的是 Window
。
小结
通过 (0, function)(param)
方式调用 function
,function
的 this
指向的是 Window
(全局上下文)。
为什么不用 call / apply 指定全局上下文 window ?
比如:
function sayName(){
console.log(this.name);
}
sayName.apply({
name: "leon"
}, [])
apply
是可以指定 this
的。
但是,原型链上的 apply
方法,是可以修改的。
比如:
Function.prototype.apply = function(){
console.log('new apply');
};
function sayName(){
console.log(this.name);
}
sayName.apply({
name: "leon"
}, [])
则 apply
方法,被重写后,失去了指定 this
的能力。
所以,为什么不用 call / apply 指定全局上下文 window ?
就是为预防 call / apply
被篡改后,导致程序运行异常。
为什么逗号操作符用 0 ?
其实,用其他数字或者字符串也是没问题的。
至于为什么用 (0, function)
? 可以说是业界的默认规则。
如果硬要说个为什么,可能是 0
在二进制的物理存储方式上,占用的空间较小。
总结
相信读者阅读到这里,对 (0,r.useState)(void 0)
应该不再感到陌生。
(0, function)(param)
的使用提炼如下:
- 运用逗号操作符,获取到
function
实例的地址 - 改变
this
指向全局上下文