从[[scope]]说闭包

2019-08-28  本文已影响0人  静_summer

闭包

词法作用域是在定义时确定的: [[scope]]
上下文是函数执行时的变量环境: vo + [[scope]]
所以闭包执行的时候是通过[[scope]]来访问作用域链上的变量。

函数的从声明到执行的过程:

作用域链(函数定义的时候确定):

每个函数在定义的时候都有一个[[scopes]]属性,指向的是它的作用域链。直到函数销毁。其中closure是闭包,script指向自身变量,global指向全局变量

[[Scopes]]: Scopes[3]
         0: Closure (foo) {y: 20}
         1: Script {bar: ƒ}
         2: Global {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, 
     function foo() {
         alert(x);
     }
     
     (function () {
         var x = 20;
         foo(); // 10, but not 20
     })();
     var x = 10;
     // 通过Function构造的函数,不能访问闭包变量,只能访问全局变量,[[scope]]作用域链没有closure
     function foo() {
     
     var y = 20;
     
     function barFD() { // 函数声明
         alert(x);
         alert(y);
     }
     
     var barFE = function () { // 函数表达式
         alert(x);
         alert(y);
     };
     
     var barFn = Function('alert(x); alert(y);');
     
     barFD(); // 10, 20
     barFE(); // 10, 20
     barFn(); // 10, "y" is not defined
     
     }
     
     foo();
     // 变量查找= 作用域链查找(直到global没有找到) + 原型链查找
     function foo() {
     // var x = 20;
     
     function bar() {
         alert(x);
     }
     
     bar();
     }
     
     Object.prototype.x = 10;
     
     foo(); // 20

 ```
* 在代码执行阶段有两个声明能够修改作用域链:
     * with
     * catch
 ``` javascript
 // 普通的闭包的作用域链在定义的时候确定,不能修改参数的调用值
     var x = 10;
     function foo() {
         alert(x);
     }
     (function () {
         var x = 20;
         foo(); // 10, but not 20
     })();
 // 使用with之后,with绑定的对象推到作用域链的最前端,同时再进行变量赋值,能够改变参数的调用值
     var x = 10, y = 10;

     with ({x: 20}) {
     
     var x = 30, y = 30;
     
         alert(x); // 30
         alert(y); // 30
     }
     
     alert(x); // 10
     alert(y); // 30
 ```
上一篇 下一篇

猜你喜欢

热点阅读