JavaScript闭包中this关键字的行为问题咨询
为什么在Node.js中使用
this.n的setTimeout回调会输出undefined? 你遇到的问题核心在于函数执行时this的指向差异,以及闭包的工作方式不同,咱们一步步拆解来看:
先看正常工作的g(i)函数
function g(i){ return function() { console.log(i); } } for(i=0;i<4;i++) { setTimeout(g(i),3000); }
这里g(i)返回的是一个闭包函数,它直接捕获了外部函数g的参数i。每次循环调用g(i)时,都会创建一个全新的函数作用域,把当前循环的i值单独保存下来。3秒后每个回调执行时,都能拿到各自对应循环的i值,所以会输出0 1 2 3,这是闭包的典型正确用法。
再看出问题的f(i)函数
function f(i){ this.n = i; return function() { console.log(this.n); } } for(i=0;i<4;i++) { setTimeout(f(i),3000); }
这里有两个关键的问题点:
调用
f(i)时this的指向:
你直接调用f(i)(没有用new关键字作为构造函数),在Node.js的非严格模式下,this会指向全局对象global;如果是严格模式,this会是undefined。不管哪种情况,this.n = i其实是在给全局对象赋值(如果是严格模式这里会直接报错),而且循环四次后,global.n会被最后一次的3覆盖。setTimeout回调执行时
this的指向:
在Node.js中,setTimeout的回调函数是在严格模式环境下运行的,此时this的默认指向是undefined。所以当回调函数function() { console.log(this.n); }执行时,this是undefined,访问undefined.n自然就得到undefined了。
如何修复f(i)函数?
如果你想让f(i)实现和g(i)一样的效果,可以试试下面几种方法:
- 用变量保存当前
this(闭包捕获):function f(i){ this.n = i; const self = this; // 保存当前作用域的this return function() { console.log(self.n); } } - 用箭头函数继承外部
this:
箭头函数不会绑定自己的this,它会继承外部函数作用域的this:function f(i){ this.n = i; return () => { console.log(this.n); } } - 用
bind强制绑定this:
通过bind方法把回调函数的this固定为f函数执行时的this:function f(i){ this.n = i; return function() { console.log(this.n); }.bind(this); }
修改后,回调函数就能正确访问到对应的n值,输出预期的0 1 2 3了。
内容的提问来源于stack exchange,提问作者Sanchit Anand
相关产品推荐
相关产品推荐

