闭包 作用域 作用域链

178 阅读2分钟

作用域链

当代码在一个环境中执行时,会创建变量对象的一个作用域链。作用域链的用途,是保证对执行坏境有权访问的所有变量和函数的有序访问。作用域链的前端,始终都是当前执行的代码所在环境的变量对象。(当声明一个函数时,局部作用域一级一级向上包起来,就是作用域链)

作用域

作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期。js的作用域靠函数形成,即一个函数的变量在函数外不可以访问。

全局作用域

1、任何地方都能访问到的对象拥有全局作用域。
2、函数外面定义的变量拥有全局作用域。
3、未定义直接赋值的变量自动声明为拥有全局作用域。
4、window对象的属性拥有全局作用。

局部作用域

局部作用域一般只在固定的代码片段内可访问到,最常见的例如函数内部。

闭包

闭包的本质就是在一个函数内部创建另一个函数。
闭包是由函数以及创建该函数的词法环境组合而成。这个环境包含了这个闭包创建时所能访问的所有局部变量。
在创建函数的时候,产生相应的执行环境,在执行环境里生成活动对象、作用域链。先利用作用域进行变量提升,然后顺序执行的时候,对变量进行赋值操作,执行完毕把执行环境从执行环境栈中弹出。当某个函数的作用域链还引用着其他函数的活动对象时,就会形成闭包。

分析

function foo() {
    let a = 1;
    function bar() {
        let a = 2;
        function baz() {
            let a = 3;
            console.log(a);
        }
        baz();
    }
    bar();
}
foo();

作用域链:
全局作用域调用了foo()函数;
foo()函数调用了bar()函数;
bar()函数调用了baz()函数; window->foo-OA->bar-OA->baz-OA

let a = 1;
function foo(){
  let a = 2;
  function baz(){            
    console.log(a);     
  }
  bar(baz);
}
function bar(fn){
  let a = 3;    
  fn();
}
foo();

作用域链:
全局作用域调用foo();
foo()调用baz();
baz()形成闭包作为bar()的参数;

闭包的销毁

一般来说,在函数内创建的局部变量,在函数运行结束后,是会被自动销毁的. 每运行一次函数,就会创建一次数据,如果没有引用上层作用域的变量,数据在 函数运行结束后,便会被销毁。函数运行结束后,也会被销毁。