资讯专栏INFORMATION COLUMN

js经典面试题--变量提升、执行环境、作用域链

EscapedDog / 2855人阅读

摘要:经典面试题变量提升执行环境作用域链今天记录一个的经典面试题,该编程题涉及到了的变量提升执行环境作用域链问题。这样,一致延续到全局执行环境全局执行环境的变量对象始终都是作用域链中的最后一个对象。

js经典面试题--变量提升、执行环境、作用域链

今天记录一个js的经典面试题,该编程题涉及到了js的变量提升、执行环境、作用域链问题。

1、变量提升
js没有块级作用域,使用var声明的变量会自动添加到最接近的环境中。在函数内部,最接近的环境就是函数的局部环境。如果初始化变量时没有使用var变量,该变量会自动被添加到全局环境。下面两幅图是等价的,结果都是控制台打印出1 2 3 4 5

2、 执行环境
每个函数都有自己的执行环境。当执行流进入一个函数时(即调用该函数),函数的环境就会被推入一个环境栈中。而在函数执行之后,将其环境弹出栈,把控制权返回给之前的执行环境。全局执行环境是最外围的一个执行环境。全局执行环境被认为是window对象,全局执行环境直到应用程序退出--例如关闭网页或浏览器---时才会被销毁。

function a(){
    //执行a功能代码
  }
  a();       //函数a的环境被推入一个环境栈中。
  
  function b(){
    //执行b功能代码
    var c=function(){
      //执行c功能代码
      function d(){
        //执行d功能代码
      }
      retrun d();
    }
    return c();
  }
  b();     //函数b、c、d依次被推入一个环境栈中,当调用b()函数时,其依次被弹出

其执行的具体流程如下图所示:

3、作用域链
当代码在一个环境中执行时,会创建变量对象的一个作用域链。作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。作用域链的前端,始终都是当前执行的代码所在环境的变量对象。作用域链中的下一个变量对象来自包含(外部)环境,而再下一个变量对象则来自下一个包含环境。这样,一致延续到全局执行环境;全局执行环境的变量对象始终都是作用域链中的最后一个对象。

var a=1;
function b(){
    //执行b功能代码
    var bVar=1;
    var c=function(){
      //执行c功能代码
      var cVar=2;
      function d(){
        //执行d功能代码
        var dVar=3;
        cVar=3;
      }
      retrun d();
    }
    return c();
 }
 b();  

以上代码共涉及4个执行环境:全局环境,b()的局部环境、c()的局部环境、d()的局部环境。全局环境有一个变量a和一个函数b()。b()的局部环境中有一个变量bVar和一个函数c.....依次。位于最里边的函数可以访问外部环境的所有变量和函数,因为外部环境是它的父执行环境。总结:内部环境可以通过作用域链访问所有的外部环境,但外部环境无法访问到内部环境中的任何变量和函数。这些环境之间的联系是线性、有次序的。每个环境都可以向上搜索作用域链,以查询变量和函数名(服从就近原则);但任何环境都不能通过向下搜索作用域而进入另一个执行环境。

通过上面介绍执行环境与作用域的两幅图可以看出,浏览器在执行js时,首先会将window对象(全局执行环境)压入环境栈,每次执行一个函数时,被调用的函数(按照调用的先后顺序)依次压入环境栈中。而压入栈中的环境类似于容器,往栈底方向的容器包含了上面的容器。容器中存放的是自己的变量和函数以及上面的容器。我们可以把容器的玻璃的材质想象为车窗户(可以从里边看到外面,但是无法从外面看到里边),当在某个环境(容器)中执行代码块时,就好比我们站在当前容器里,此时我们可以看到外部容器(父级环境)的变量和函数,但却看不到内部容器的任何东西,这就是作用域链。

下面进入正题,说下我对该面试题的理解

1    var foo = {n:1};
2    (function (foo) {
3        console.log(foo.n);
4        foo.n=3;
5        var foo = {n:2};
6        console.log(foo.n);
7    })(foo);
8    console.log(foo.n); 

上面的代码其实可以写成这样:

1    var foo = {n:1};
2    (function (foo) {
3         var foo;
4        console.log(foo.n);
5        foo.n=3;
6        var foo = {n:2};
7        console.log(foo.n);
8    })(foo);
9    console.log(foo.n); 

1、声明一个变量,为引用类型
2和8、声明一个匿名函数,并立即执行,传递的参数是第1行中的foo。将一个对象类型赋值给一个新的变量,由于对象是引用类型,实质上是指将对象的地址赋值给该变量(也就是说这两个变量指向同一个地址空间),因此改变新的变量中的属性值或方法,对应的原来对象的值也会改变。
3、原题中的第5行,由于存在变量提升,因此会在函数开始就声明,此时为undefined;然而由于一个变量的声明优先级低于形参,所以这行没有任何效果
4、打印形参的foo.n,打印1
5、改变第1行变量foo的属性n的值为3;
6、重新声明并定义了一个变量,开辟了新的内存空间,n为2
7、由于js中的代码是自上而下执行,所以此时输出2
9、上面的函数调用结束后,局部变量被销毁,而之前的内存空间值已经变为3,所以输出3
所以最终的结果为:1 2 3

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/94349.html

相关文章

  • Web前端经典面试(一)

    摘要:本篇收录了一些面试中经常会遇到的经典面试题,并且都给出了我在网上收集的答案。网页的行为层负责回答内容应该如何对事件做出反应这一问题。 本篇收录了一些面试中经常会遇到的经典面试题,并且都给出了我在网上收集的答案。眼看新的一年马上就要开始了,相信很多的前端开发者会有一些跳槽的悸动,通过对本篇知识的整理以及经验的总结,希望能帮到更多的前端面试者。(如有错误或更好的答案,欢迎指正,水平有限,望...

    princekin 评论0 收藏0
  • Web前端经典面试(一)

    摘要:本篇收录了一些面试中经常会遇到的经典面试题,并且都给出了我在网上收集的答案。网页的行为层负责回答内容应该如何对事件做出反应这一问题。 本篇收录了一些面试中经常会遇到的经典面试题,并且都给出了我在网上收集的答案。眼看新的一年马上就要开始了,相信很多的前端开发者会有一些跳槽的悸动,通过对本篇知识的整理以及经验的总结,希望能帮到更多的前端面试者。(如有错误或更好的答案,欢迎指正,水平有限,望...

    Batkid 评论0 收藏0
  • Web前端经典面试(一)

    摘要:本篇收录了一些面试中经常会遇到的经典面试题,并且都给出了我在网上收集的答案。网页的行为层负责回答内容应该如何对事件做出反应这一问题。 本篇收录了一些面试中经常会遇到的经典面试题,并且都给出了我在网上收集的答案。眼看新的一年马上就要开始了,相信很多的前端开发者会有一些跳槽的悸动,通过对本篇知识的整理以及经验的总结,希望能帮到更多的前端面试者。(如有错误或更好的答案,欢迎指正,水平有限,望...

    chanthuang 评论0 收藏0
  • JS核心知识点梳理——上下文、作用域、闭包、this(上)

    摘要:引言满满的干货,面试必系列,参考大量资料,并集合自己的理解以及相关的面试题,对核心知识点中的作用域闭包上下文进行了梳理。如果在小区这个作用域找到了张老师,我就会在张老师的辅导下学钢琴我张老师房间钢琴构成了学琴的上下文环境。 showImg(https://segmentfault.com/img/bVbo4hv?w=1800&h=1000); 引言 满满的干货,面试必bei系列,参考大...

    Andrman 评论0 收藏0

发表评论

0条评论

EscapedDog

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<