zoukankan      html  css  js  c++  java
  • 理解作用域链

    先来看两个例子

    var x = 10;
    
    bar();   //10
    function foo(){
      console.log(x);
    }
    
    function bar(){
      var x = 30;
      foo();
    }
    

    解析

        执行bar,相当于执行foo(),foo里面要输出x,我们首先要从foo自己的作用域下面去找
        foo里边是没有声明x的,然后我们会到foo的词法作用域去找,也就是声明foo的作用域去找。
        在这里foo的词法作用域就是全局作用域,全局作用域里声明的x=10,所以输出10
    
     var x = 10;
        bar();  //30
    
        function bar(){
           var x = 30;
           function foo(){
               console.log(x); 
          }
           foo();
       }
    

    解析

        执行bar(),就会执行foo().foo里输出x,我们首先找foo的作用域里,发现没有声明x
        那就接着找foo的词法作用域。也就是声明foo的作用域,发现有x=30,于是输出了30
    

    几个相关的概念

    一 、execution context (执行上下文,也叫执行环境):

    • 执行上下文定义了变量和函数有权访问的其他数据。

    • 每个执行环境,都有一个与之关联的变量对象(variable object).环境中定义的所有变量和函数都保存在这个对象中。(我们编写的代码无法访问这个对象,但是解析器可以)

    • 全局执行环境,是最外围的一个执行环境,在WEB浏览器中,全局执行环境被认为是 window对象,因此所有的全局变量和函数都是作为window对象的属性和方法创建的。

    • 某个执行环境中的所有代码都执行完毕之后,该环境被销毁,保存在其中的所有变量和函数定义,也随之销毁。(全局执行环境,直到应用程序退出——例如关闭管业或浏览器时才会被销毁)

    • 每个函数都有自己的执行环境

    二 、scope chain(作用域链),activation object(活动对象)

    • 当代码在一个环境中执行时,会创建变量对象的一个作用域链。

    • 作用域链的前端,始终都是当前执行的代码所在环境的变量对象。如果这个环境是函数,则将其活动对象作为变量对象。活动对象在最开始只包含一个arguments对象(这个对象在全局执行环境中是不存在的)

    • 作用域链中的下一个变量对象来自包含(外部)环境,以此类推,一致延续到全局执行环境。

    • 全局执行环境的变量对象,始终都是作用域链中的最后一个对象。

    三 、[[Scope]]属性

    • 函数是特殊的可执行对象。
    • 既然是对象,就可以拥有属性。
    • 函数中存在着一个内部属性[[Scope]](我们不能使用,供JS引擎使用)
    • 函数被创建时,这个内部属性就会包含函数被创建的作用域中对象的集合。
    • 这个集合呈链式连接,被称为函数的作用域链
    • 作用域链上的每一个对象被称为变量对象(variable object)
    • 每一个变量对象都以键值对形式存在

    执行顺序

            //范例1
            var x = 10;
    
            bar();  //10
            function foo() {
                console.log(x);
            }
    
            function bar() {
                var x = 30;
                foo();
    

    首先

          1.代码在一开始会有声明前置,
          var x ;
          funciton bar();
          funciton foo();
          之后再去执行 x=10;
    
          在一开始的时候,这个执行环境叫全局执行环境(global Context),也就是全局作用域。
    
          全局执行环境里包含了两个对象,一个是活动对象(AO),一个是Scope属性
          global Context = {
              AO : {
                  x : 10;
                  bar : function;
                  foo : function;
               },
              Scope:null
           }
    
        声明bar时  得到下面:
        bar().[[Scope]]  = global Context.AO
        声明foo时  得到下面:
        foo().[[Scope]]  = global Context.AO
        
        执行代码的时候,当我们需要一个值,会首先从它的活动对象里去找,如果找不到就要到它的[[Scope]] 里去找。
    
       2.当调用bar()时,进入bar的执行上下文
        因为bar里值声明了一个x,所以bar的活动对象里只有一个x
        barContext = {
          AO : {
              X : 30
          },
          Scope :bar.[[Scope]]   //global Context.AO
        }
        
       3. 当调用foo()的时候,进入foo的执行上下文
        fooContext = {
        //foo里没有声明变量,foo也没有参数,所以foo的活动对象是空的
        AO:{}
        Scope:foo.[[Scope]]    //global Context.AO
      }


     

  • 相关阅读:
    【BZOJ 4581】【Usaco2016 Open】Field Reduction
    【BZOJ 4582】【Usaco2016 Open】Diamond Collector
    【BZOJ 4580】【Usaco2016 Open】248
    【BZOJ 3754】Tree之最小方差树
    【51Nod 1501】【算法马拉松 19D】石头剪刀布威力加强版
    【51Nod 1622】【算法马拉松 19C】集合对
    【51Nod 1616】【算法马拉松 19B】最小集合
    【51Nod 1674】【算法马拉松 19A】区间的价值 V2
    【BZOJ 2541】【Vijos 1366】【CTSC 2000】冰原探险
    【BZOJ 1065】【Vijos 1826】【NOI 2008】奥运物流
  • 原文地址:https://www.cnblogs.com/wjlbk/p/11783851.html
Copyright © 2011-2022 走看看