函数作用域

2020-07-19  本文已影响0人  any_5637

我们先来了解几个概念:
执行期上下文:当函数执行时,会创建一个称为执行期上下文的内部对象。一个执行期上下文定义了一个函数执行时的环境,函数每次执行时对应的执行上下文都是独一无二的,所以多次调用一个函数会导致创建多个执行上下文,当函数执行完毕,它所产生的执行上下文被销毁。

  <pre>解析1:执行期上下文指的就是函数执行前一刻所产生的AO对象</pre>
  <pre>解析2:函数执行环境就是指变量提升函数提升得到的那些AO对象属性</pre>
  <pre>解析3:
  function test() { }

  函数多次调用,产生不同的AO对象:
  test();           ---->AO{}
  test();           ---->AO{}
  函数执行完毕之后对应的AO对象销毁。
  </pre>

[[scope]]:每个js函数都是一个对象,对象中有些属性我们可以访问,但有些不可以,这些属性仅供js引擎存取,[[scope]]就是其中一个。

  function test() { }

  我们可以访问的函数属性(如:test.length/test.prototype);
  我们不能访问但着实存在的函数属性(如:test.[[scope]])

作用域链:[[scope]]中所存储的执行期上下文对象的集合,这个集合呈链式连接,我们把这种链式连接叫做作用域链。
结合着例子来理解一下:

  function a() {
    function b() {
        var b=234;
    }
  }
  var glob = 100;
  a();

a函数被定义时发生如下过程:


作用域链1.jpg

先不要细琢磨上面GO里放置的各个属性。上面a.[[scope]]还没有构成一个链,只有GO对象的存在,下面继续。

a函数被执行时,发生如下过程:


作用域链2.jpg

a函数执行前一刻所产生的AO对象放到了a函数作用域a.[[scope]]的顶端;现在a.[[scope]]上已构成一个链.
查找变量:从作用域链的顶端依次向下查找(再补充:在哪个函数里查找变量,就去哪个函数的作用域顶端去查找),最标准的说法。

再继续研究刚刚的例子:

  function a() {
    function b() {
        var b=234;
    }
}
var glob = 100;
a();

b函数被创建时,发生如下过程:


作用域链3.jpg

也就是说b函数刚刚出生时所在的环境是a执行的结果,直接给b函数的出生创造好了环境。

b函数被执行时,发生如下过程:


作用域链4.jpg

b函数执行前一刻产生的AO对象放置在b.[[scope]]的最顶端。现在透彻地理解一下,在函数b中去访问变量时,是在b函数的作用域[[scope]]最顶端去查找变量。

再深入剖析看看,检查自己是否理解清楚了:

首先,a作用域中的顶端AO与b作用域的第二个AO是同一个AO的引用么?还是两个不同的AO?

答案:是同一个AO的引用,下面代码来验证一下

    function a() {
        function b() {
        var b=234;
            aa=0;
        }
    var aa=123;
        b( );
        console.log(aa);//输出0,代表变量aa在语句b()执行完之后,值被改变了。
}
var glob = 100;
a();

GO{
    glob:100,
    a:~~~~~
}

    AO(a){
        aa:0,
         b:~~~~~~   
    }
         

再来,在上面的例子中,第7行b函数执行完之后,概念上是执行期上下文被销毁,而实际函数a和函数b的作用域变化应该是什么样的呢?
答案:

  function a() {
    function b(){
        function c() {
        
        }
        c();
    }
    b();
}
a();

具体过程如下

a 定义:  a.[[scope]]    -->   0:GO

a 执行:  a.[[scope]]    -->   0:AO(a)
                             1:GO
                             
b 定义:  b.[[scope]]    -->   0:AO(a)
                             1:GO
注意b执行了才会产生c的定义哈!!
b 执行:  b.[[scope]]    -->   0:AO(b)
                             1:AO(a)
                             2:GO
                             
c 定义:  c.[[scope]]    -->   0:AO(b)
                             1:AO(a)
                             2:GO
                             
c 执行: c.[[scope]]    -->   0:AO(c)
                             1:AO(b)
                             2:AO(a)
                             3:GO

现在再来看这句话,函数里边能访问函数外边的变量,但函数外边不能访问呢函数里边的变量;从上边的过程来看,在b中访问c中的局部变量,是不可能的,因为b.[[scope]]中不存在函数c的执行期上下文AO(c)。

上一篇 下一篇

猜你喜欢

热点阅读