执行环境和变量对象

还是一个代码题(不得不说代码题真的很考研基础),先放代码

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对象里

var关键字

可以看出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();
image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容