从[[scope]]说闭包

闭包

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

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

  • 创建(引擎准备并填充三个变量)
    + vo:函数参数,内部变量, 函数内部声明
    + scope chain: 作用域链
    + 确定this的值并填充
  • 执行
  • 词法作用域
    代码创建时定义的静态作用域
  • 上下文
    代码运行时,this的指向

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

每个函数在定义的时候都有一个[[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
 ```
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容