还是一个代码题(不得不说代码题真的很考研基础),先放代码
var foo = 1;
function main () {
console.log(foo);
var foo = 2;
console.log(this.foo);
this.foo = 3;
}
main();
new main();
其实这个题就是一个很经典的var的变量提升和this指向的问题。先上运行结果
-
node运行的结果
node.png -
浏览器运行的结果
浏览器.png
当时我看到这个运行结果都惊呆了,我认为输出的应该是undefined,1,undefined,2。所以又去查阅了资料,大概说下我的看法,暂时抛开在node环境和window环境运行的区别不说,先说下node环境下运行的结果。第一个和第三个undefined用var关键字的变量提示就可以解释。我们都知道通过mian()这种方式调用函数的时候this应该是指向全局变量,但是不是很奇怪明明第一行声明了foo为1但this.foo还是undefined呢?这个主要是因为foo是明明声明的并不是global声明的(明明:关我啥事)。我们在node环境下最外层调用函数时的this(如果没有.运算符的话)指向的是global,而我们通过var foo = 1的方式声明的变量却不在global对象里

可以看出global对象里并没有foo这个变量,所以也就解释了第二哥undefined的原因。但在浏览器里面的最外层this就指向window对象,所以在浏览器环境下第二个输出的是1。对于第四个undefined的原因,就要说到本文的主题了:执行环境和变量对象。
执行环境
每一个函数都有一个自己的执行环境,这个执行环境是一个栈,也正是因为有了执行环境,才有了闭包的概念变量对象
每一个执行环境都有自己的变量对象,这个变量对象里存放着改执行环境内的函数和变量,但我们无法通过代码访问到这个变量对象
除了这个两个概念呢,我们还要知道new操作符做的4件事情新建一个对象
把this指向这个对象
执行函数
返回这个对象
在理解了这几个概念后,我们再返回头来看看第四个undefined的原因。为了区分main()和new main()的作用域,我们把main()的作用域称为mian1,new main()的作用域称为main2。我们在执行new main()的时候,会先在main2里创建一个对象(假设加obj),然后再mian2里声明一个foo,我们这时通过this.foo访问的其实是obj上的foo。但我们是在mian2里声明的foo,自然访问obj上的foo就是undefined了。下面是几个时刻对应的作用域和变量对象-
第一个undefined(变量提升)
第一个undefined -
第二个1(最外层函数的this指向)
第二个1 -
第三个undefined(变量提升)
第三个undefined -
第四个undefined(new 操作符)
函数执行完毕
tip: 如果不使用直接给一个未声明变量赋值的话,这个变量会默认添加到global对象中去。
foo = 1;
function main () {
console.log(foo);
var foo = 2;
console.log(this.foo);
this.foo = 3;
}
main();
new main();






