js作用域链总结|青训营笔记

50 阅读2分钟

这是我参与「第四届青训营 」笔记创作活动的第13天。 本文总结了作用域与作用域链,解释了作用域链在js中是如何存在的。

作用域

执行环境中,变量或函数的作用范围。
定义了变量或函数有权访问的其他数据。
作用域都有一个变量对象。

全局作用域

  1. 全局作用域在页面打开时被创建,页面关闭时被销毁。
  2. 编写在script标签中的变量和函数,作用域为全局,在页面的任意位置可以访问到。
  3. 全局作用域可以认为是window,因为所有全局变量和函数都是作为window对象的属性和方法创建的。

局部作用域

  1. 函数调用时,函数作用域被创建,函数执行完毕,函数作用域被销毁。
  2. 每调用一次函数就会创建一个新的函数作用域,他们之间相互独立。
  3. 函数作用域可以访问上层作用域,但两个相邻函数间作用域相互独立。

es6之后的块级作用域

用let、const声明的变量,作用域在定义处的大括号内,对外不可见。 函数中的[[ Scopes ]]属性存放了它的作用域信息,Script是块级作用域,Global是全局作用域

作用域链

变量的取值首先会在创建这个变量的函数的作用域中取值,如果在当前作用域中没有找到,则会向上级作用域去查找,直到向上查找全局作用域,这个过程形成的链条就称为作用域链。

考核点

  1. 解释为什么打印函数对象时,Scope属性只能看到Global。 当函数执行时,Scope中有Global和Local,执行完毕后Local被销毁。

  2. 为什么闭包会导致内存泄漏 每一个作用域链都有变量对象,函数所包含的称为活动对象,每一个变量对象内都包含着对上一个对象的引用

        var a=10;
        function fun(){
            var b=20;
            return function fn(){
                var c=30;
                b=40;
            }
        }
        const fn = fun();
        console.dir(fun);
        // [[Scopes]]: Scopes[2]
        //             0: Script {fn: ƒ}
        //             1: Global
        console.dir(fn);
        // [[Scopes]]: Scopes[3]
        //             0: Closure (fun) {b: 20} //保存了上一层对象的变量。//若fn未引用b,则不会保存b。
        //             1: Script {fn: ƒ}
        //             2: Global

代码执行过程

在创建fn函数时,会创建一个预先包含全局变量对象的作用域链,这个作用域链被保存在内部的Scope属性中。当调用fn函数时,会为函数创建一个执行环境,然后通过复制函数的Scope属性中的对象构建起执行环境的作用域链,然后创建活动对象AO并推入执行环境的作用域链。在fn执行完成后,作用域就会被销毁。