起因
事情的起因是这样的,最近在阅读style-loader
源码时遇到这样一段代码:
难道我用的是假的JavaScript
吗...
如果有大佬明白这么做的原因是为什么了...那么就可以停止阅读了。
分析
关于逗号操作符,在MDN
上给出的是这样的解释:
逗号操作符 对它的每个操作数求值(从左到右),并返回最后一个操作数的值。
简单来说
代码语言:javascript复制const number = 1;
// 从左往右依次执行完毕后 返回最后一个值
number = (number , x);
console.log(number);
// expected output: 2
x = (2, 3);
console.log(x);
// expected output: 3
上述代码的number = (number , x);
其实就相当于number
而已。
可能有的同学有疑问了,这样做的效果是什么呢?
单纯为了秀而秀嘛!,别着急我们接下来往下看另外一个例子:
代码语言:javascript复制window.name = 'wang.haoyu'
const obj = {
name:'19Qingfeng',
logName() {
console.log(this.name)
}
}
obj.logName();
(0, obj.logName)();
因为用到了
window
对象,所以不要放在Node
环境下执行这段代码。最简单的方式,直接将这段代码复制丢到
chrome
控制台下去执行就ok
了!
在丢到控制台之前,大家可以自己先来尝试自己思考一下两次分别的打印结果。
我们可以看到
**obj.logName()
打印出19Qingfeng
而(0, obj.logName)()
打印出了全局对象上的window.name
的wang.haoyu
**。
两次打印结果不同的本质原因--函数调用时的this
对象指向不同,第一次不用多说指向obj
对象自然而然通过this.name
打印出的就是19Qingfeg
。
第二次(0, obj.logName)();
执行机制是这样的:
- 首先逗号操作符的原因,**它会对于左边括号内从左往右求值,最终返回最右边的值也就是返回
obj.logName
函数内容。 - 之后右侧的函数调用会调用左侧返回的
logName()
函数,但是此时相当于直接调用logName()
函数体自然而然this
就指向了window
上。
(0, obj.logName)();
// 本质上它就相当于这样
// 1. 通过逗号操作符获得函数内容
const tem = obj.logName
// 2. 外部调用修改调用者 同时改变this指向
tem()
本质上我们可以通过逗号操作符修改函数内部this
指向的改变,类似于call
方法的效果。是不是很神奇!
结尾
其实在babel
编译后的js
代码中,包括许多源码中都会出现(0,parent.fn)()
的方式。
一个小小的逗号操作符竟然能修改this
指向,不得不说js
真的是无奇不有。
希望这个知识点无论是在源码阅读中,还是面试交(吹)流(水)中都可以帮到大家脱口而出逗号操作符是可以改变函数执行时this
指向为全局对象的!。