美文网首页
深入理解JS之Scope链

深入理解JS之Scope链

作者: Doter | 来源:发表于2020-03-21 18:40 被阅读0次

    作用域的创建

    作用域的创建时机

    解析器在解析的过程中在生成AST的时候,同时构建其作用域。

    查看其作用域链

    如下代码:在控制台直接执行

    var testSelf = {};
    function A(){
      var a = "1";
      var b = testSelf;
      var c = "3";
      function B(){//闭包1
        var c = "1"
        function C(){//闭包2
          var d = "1"
          console.log(a,b,c,d)
        }
        debugger;
        C()
      }
      debugger;
      return B
    }
    debugger
    var B = A()
    B()
    testSelf.a="aaa";
    B()
    
    A的scope链 B的scope链 C的scope链g

    根据上图即代码我们可以得到一下结论:

    1. 方法的Scope链在该方法创建后以及生成了[[scopes]],而这个scopes是数组形式的链式。
    2. 当个方法的内部使用的变量未在该方法中声明。则会在其创建的时所在的scope中查找,如果找到了,就将该scope加入[[scopes]],并值将该变量加入scope。
    3. 当上层scope没有找到,则依次向上查找并重复步骤2。
    4. 子scopes共享父的scopes

    123比较容易理解,关于4.
    我们观察B:
    在B中并没有使用到变量ab,
    如同C中没有使用变量e,
    但是C中使用了a和b,根据123,将会在C的scopes中加入A的作用域里的a和b。
    但是我们发现B的scopes中也有A的作用域里的a和b。
    所以我觉得可以理解为,B的scopes是C的父scopes,当在解析C的时候,发现a和b变量不存在,则将会在scopes中添加Closure(闭包)A。从而B也会有Closure(闭包)A。

    小结:
    scope链生成是在代码解析的时候生成的,解析器通过识别到使用的变量未在该方法中声明,则会在该方法的声明创建的地方的作用域查找,依次向上直到全局scope。

    同时scope中存储的数据是可修改的,具体参考demojs打印结果。

    附加题

    var x = 10
    function fn() {
      console.log(x)
    }
    function show(f) {
      var x = 20;
      (function() {
        f() 
      })()
    }
    show(fn)
    

    我们尝试解答这个题:
    首先回顾,闭包是在js解析的时候生成的。

    1. 当解析器解析fn的时候,发现console.log(x)里面的x没有在fn中定义。
    2. 那么将会在fn声明所在的scope(即全局scope)中查找x,当找到x后,将添加到的scopes里面,且x的值为10。
    3. 接下来show将fn作为参数传递进去了。
    4. 尽管show内部声明了x,并且有个闭包的匿名函数,但是f执行时,这个f在解析过程中已经形成了闭包,即第2步。那么执行时,直接在Scopes中找到了x的值为10。随即打印了10

    延深思考:如果我删除var x = 10。执行会出现什么结果?

    推荐scope的文章

    相关文章

      网友评论

          本文标题:深入理解JS之Scope链

          本文链接:https://www.haomeiwen.com/subject/dqzyyhtx.html