为什么含new关键字的JavaScript代码在Chrome DevTools与JSFiddle输出不同
问题分析
相关测试代码如下:
function foo() { this.baz = "baz" console.log(this.bar + " " + baz); } var bar = "bar"; var baz = new foo(); console.log(baz.baz)
核心差异根源
两个执行环境的作用域隔离规则不同,导致foo函数内对baz变量的查找结果不一致:
JSFiddle的执行逻辑
JSFiddle默认会把用户编写的JS代码包裹在
window.onload(或DOMContentLoaded)的回调函数中执行,你声明的var bar、var baz都不是全局变量,而是这个回调函数的局部变量:- 变量提升阶段:回调作用域内先声明
foo函数、bar、baz变量,三者初始值均为undefined - 执行
bar = "bar"完成赋值 - 执行
var baz = new foo()时,先运行构造函数foo:this指向新创建的实例,实例自身没有bar属性,所以this.bar是undefined- 查找
baz变量时,向上追溯到回调作用域的baz,此时new foo()还没有执行完成,返回值还没赋值给baz,所以baz是undefined
- 最终输出
undefined undefined,和你看到的结果一致。
- 变量提升阶段:回调作用域内先声明
Chrome Sources面板的执行逻辑
Sources面板运行的代码默认直接暴露在全局作用域下,你用
var声明的bar、baz都会挂载到window对象上成为全局属性。
你看到baz是{baz:"baz"}对象的原因是当前页面全局作用域下已经存在一个提前声明的baz对象(可能是页面内置变量、你之前运行代码遗留的变量),构造函数foo执行时找到的就是这个已存在的对象,转成字符串输出就是[object Object]。
如果你打开无痕模式的新标签页运行这段代码,得到的结果会和JSFiddle一致。
补充说明
你代码里的核心易错点:var baz = new foo()的执行顺序是先运行new foo(),再把返回值赋值给baz,构造函数运行过程中baz还没完成赋值,所以正常情况下读取到的永远是提升后的初始值undefined。
内容的提问来源于stack exchange,提问作者ArunM
相关产品推荐
相关产品推荐

