Node.js与Node.js REPL的区别及《You Don't Know JS》代码运行疑问
解析《You Don't Know JS》中this绑定的代码行为
嘿,我最近正在钻研《You Don't Know JS》系列,刚看到第三本书第2章“'this' All make sense now”里的这段代码,立刻动手用Node.js v8.11.1跑了一遍,发现里面的this绑定逻辑挺值得琢磨的:
function foo() { console.log( this.a ); } function doFoo(fn) { // `fn` is just another reference to `foo` fn(); // <-- 这里是关键的调用位置! } var obj = { a: 2, foo: foo }; var a = "oops, global"; // 全局作用域下的a doFoo( obj.foo ); // 输出 "oops, global"
我把这段代码存成了foo.js,执行node foo.js命令时,结果和书中描述的一致(如果是在全局环境下运行的话)。这里的核心点在于函数调用位置(call-site)决定了this的绑定对象:
- 当我们把
obj.foo作为参数传给doFoo时,本质上是把foo函数的引用单独抽离了出来——相当于在doFoo内部调用的是一个“独立”的函数,而不是obj的方法。 - 在非严格模式下,这种独立调用的函数,this会默认绑定到全局对象:
- 浏览器环境中,全局对象是
window,var a会自动挂载到window上,所以this.a就是"oops, global"; - 如果是在Node.js的模块文件中运行,情况会有点不一样:模块顶层的
var a属于模块作用域,不会挂载到global对象上,此时fn()调用时this绑定到module.exports(空对象),所以会输出undefined;但如果是在Node.js的REPL全局环境下运行,var a会挂载到global上,结果就和书中一致了。
- 浏览器环境中,全局对象是
简单来说,只要函数不是作为对象方法、不是用call/apply/bind指定this、不是作为构造函数调用,非严格模式下this就会绑定到全局对象——这就是为什么这段代码会输出"oops, global"而不是我们预想的2。
内容的提问来源于stack exchange,提问作者Daniele Paolini
相关产品推荐
相关产品推荐

