ES6闭包与this绑定问题:为何dessert.scoops输出为0而非1?
为什么
dessert.scoops输出0而不是预期的1? 先贴出你的代码(我补全了构造函数缺失的function关键字,否则会触发语法错误):
// constructor function function IceCream() { this.scoops = 0; } // adds scoop to ice cream IceCream.prototype.addScoop = function() { const cone = this; // 保存当前this指向 setTimeout(function() { cone.scoops++; // 修改scoops值 console.log('scoop added!'); }, 0.5); }; const dessert = new IceCream(); dessert.addScoop(); console.log(dessert.scoops);
这个问题的核心是JavaScript事件循环的异步执行机制,简单来说就是:同步代码会优先执行完毕,异步任务要等同步代码全部跑完才会被处理。
具体到你的代码执行流程:
- 调用
dessert.addScoop()时,里面的setTimeout会被JS引擎放入宏任务队列——哪怕你设置的延迟只有0.5毫秒(提醒:setTimeout的第二个参数单位是毫秒,0.5实际是0.0005秒,而且浏览器有最小延迟限制,一般是4ms左右,实际等待时间会更长),这个回调函数不会立刻执行。 - 紧接着的
console.log(dessert.scoops)是同步代码,JS引擎会优先执行它——此时setTimeout的回调还没机会运行,cone.scoops++根本没执行,所以dessert.scoops还是初始值0,输出自然是0。 - 等所有同步代码执行完毕,事件循环才会从宏任务队列里取出
setTimeout的回调函数执行,这时候才会把scoops加1,同时打印scoop added!。
如果想让console.log(dessert.scoops)输出1,你需要把它放到异步上下文里,或者用Promise/async await来处理异步逻辑,举几个可行方案:
方案1:把日志放到setTimeout回调内
IceCream.prototype.addScoop = function() { const cone = this; setTimeout(function() { cone.scoops++; console.log('scoop added!'); console.log(cone.scoops); // 这里会输出1 }, 500); // 改成500毫秒更直观,能清晰看到先后顺序 }; const dessert = new IceCream(); dessert.addScoop();
方案2:用Promise+then处理异步
IceCream.prototype.addScoop = function() { const cone = this; return new Promise((resolve) => { setTimeout(function() { cone.scoops++; console.log('scoop added!'); resolve(); }, 500); }); }; const dessert = new IceCream(); dessert.addScoop().then(() => { console.log(dessert.scoops); // 这里输出1 });
方案3:用async/await简化异步流程
function IceCream() { this.scoops = 0; } IceCream.prototype.addScoop = function() { const cone = this; return new Promise((resolve) => { setTimeout(() => { cone.scoops++; console.log('scoop added!'); resolve(); }, 500); }); }; async function getIceCreamScoops() { const dessert = new IceCream(); await dessert.addScoop(); console.log(dessert.scoops); // 输出1 } getIceCreamScoops();
内容的提问来源于stack exchange,提问作者praveen-me
相关产品推荐
相关产品推荐

