JavaScript闭包底层解析

1. 闭包是一个函数,这个函数有权访问另一个函数作用域中的变量,创建闭包最常见的方式,就是在函数内部创建函数。要想彻底搞清其中细节,必须从函数从创建到调用的时候都发生了什么入手

2. 函数第一次被调用,创建一个执行环境,和相应的作用域链

3. 作用域链赋值给一个特殊的内部属性Scope

4. 使用this,arguments和其他命名参数的值初始化函数的变量对象

5. 在作用域链中,内部函数的活动对象处于第一位,外部函数的活动对象始终处于第二位……直至全局执行环境

6. 执行函数时,为读取写入变量的值,需要在作用域链中查找变量

function compare(a  ,b){
if(a<b){
return -1;
}else if(a>b){
return 1;
}else{
return 0;
}
}
var result = compare(5,10); // -1 1. 第一次调用compare()函数时,会创建一个活动对象,包括{this,arguments ,a,b}
2. 全局执行环境的变量对象{compare , result, this},在compare()的作用域链中处于第二位的

7. 每一个执行环境都有一个用来存放变量的对象——变量对象

  1.  全局环境中的变量对象始终存在

  2.  compare函数的局部环境的变量对象,只在函数执行过程中存在

8.  在创建compare函数时,先创建一个作用域链,这个作用域链预先就包含了全局变量对象

9. 作用域链保存在compare函数内部的Scope属性中

10. 调用compare函数时,会为函数创建一个执行环境,compare函数的局部变量对象被创建并放到作用域链的前端。

11. 所以,作用域链本质上是一个指向变量对象的指针列表,只引用但不实际包含变量对象

  1. Scope[{this,arguments ,a,b} , {compare , result, this}]

  2. compare函数在访问一个变量时,先从scope中第一个元素开始搜索,一个一个往后找

  3. 函数执行完毕后,局部变量对象被销毁,内存中仅存全局变量对象


1. 存在闭包就不一样了

2. 在函数内部定义的函数(子函数)会将外部函数(父函数)的变量对象添加到它(子函数)的作用域链中

function createCompareFunction(propName){
return function(obj1 , obj2){
var a = obj1[propName];
var b = obj2[propName]; if(a<b){
return -1;
}else if(a>b){
return 1;
}else{
return 0;
}
}
} var compare = createCompareFunction('name');
var result = compare({name:"Nico"} , {name:"Greg"});//true 1. 在内部的匿名函数的作用域链中,实际上包含外部函数的变量对象
2. 这个内部的匿名函数被return到外部后,这个匿名函数它的作用域链被初始化了
3. 包含createCompareFunction函数的变量对象以及全局变量对象
4. 所以,匿名函数可以访问createCompareFunction函数中所有的变量
5. 更为重要的是,createCompareFunction函数执行完毕被销毁后,其变量对象还有一份保存在匿名函数中,所以仍可以访问其内部的变量
上一篇:BZOJ P1188 HNOI2007 分裂游戏——solution


下一篇:MVC思想