美文网首页
函数作用域

函数作用域

作者: any_5637 | 来源:发表于2020-07-19 11:31 被阅读0次

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

  <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的作用域变化应该是什么样的呢?
答案:

  • b函数执行完之后,自己的执行期上下文AO被干掉(销毁),即b.[[scope]]回到b被定义的状态。
  • 往下进行到第9行,a函数执行完后,b函数作用域b.[[scope]]直接被销毁;同时,a函数的执行期上下文AO被销毁,a.[[scope]]回到被定义的状态,a函数等待下一次被调用执行。
    思考一下,下面函数执行的作用域链:
  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)。

相关文章

  • JavaScript 作用域和闭包理解

    作用域: 分为函数作用域,和块级作用域; 函数作用域 函数作用域外面的无法访问函数作用域内部的变量和函数,这样就可...

  • JS的作用域

    JS的作用域: 全局作用域、函数作用域、eval 作用域、块级作用域 全局作用域: 函数作用域: 结果截屏: 说...

  • 详解Kotlin中的作用域函数

    Kotlin作用域函数 作用域函数,Kotlin在语法层面支持拓展函数,作用域函数,作用域函数是指对数据做一些变换...

  • 1. let , const 块级作用域

    作用域全局作用域 => global函数作用域 => 因函数执行而产生的作用域 块级作用域形式 : { }特点 :...

  • js 变量作用域问题 以及 let

    JavaScript中有以下两种作用域 全局作用域函数作用域全局作用域是函数之外(最外层代码)的作用域。在函数之外...

  • 第九天,函数作用域和声明提前

    函数作用域和函数声明提前。 函数作用域,分为全局作用域和部分作用域,在系统执行函数时会自动创建一个作用域,在执行完...

  • C - 作用域

    C - 作用域 一个 C 变量的作用域可以是: 块作用域 函数作用域 函数原型作用域 或 文件作用域 作用域描述程...

  • 作用域

    标识符的作用域有函数原型作用域、局部作用域(块作用域)、类作用域和 命名空间(namespace) 作用域 函数原...

  • 变量声明、声明提前和作用域

    一. 作用域 分为全局作用域和函数作用域 函数作用域简言之就是:变量在声明他们的函数体以及这个函数体嵌套的任意函数...

  • 前端JS基础三(作用域 闭包)

    作用域 作用域链 注意:函数的父级作用域是函数定义时候的作用域,不是函数执行时候的作用域,也就是说那个作用域定义了...

网友评论

      本文标题:函数作用域

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