《JavaScript高级程序设计》读书笔记7.2闭包

闭包是指有权访问另一个函数作用域中的变量的函数。

  • 如何创建作用域链(粗略
    1. 函数被调用,会创建一个执行环境和作用域链
    2. arguments和其他命名参数的值来初始化函数的活动对象(活动对象作为变量对象)
    3. 作用链中外部函数依次往外排
  • 作用域链的作用
    • 函数执行过程中,为读取和写入变量的值,需要在作用域链中逐级查找变量。
1
2
3
4
5
6
7
8
9
10
例子
function compare(value1,value2){
if(value1<value2){
return -1;
}else if{
return 1;
}else{
return 0;
}
}

例子如图
clipboard.png

  • 如何创建作用域链(详细
    • 全局环境的变量对象始终存在,而函数的局部环境的变量对象,则只在函数执行的过程中存在。
      1. 在创建函数时,会创建一个预先包含全局变量对象的作用域链,并保存在函数内部的[[Scope]]属性中。
      2. 在调用函数时,会为函数创建一个执行环境,然后通过复制函数的[[Scope]]属性中的对象构建起执行环境的作用域链。
      3. 函数的活动对象(在这被当作变量对象)被创建并被推入执行环境作用域的前端。
    • 作用域链本质上是一个指向变量对象的指针列表,它只引用但不实际包含对象
  • 常见的闭包方式:在一个函数内部创建另一个函数,如下
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function createComparisonFunction(propertyName){
    return function(object1,object2){
    var value1=object1[propertyName];
    var value2=object2[propertyName];
    if.....
    }
    }

    var compare=createComparsionFunction("name");
    var result=compare({name:"Nicholas"},{name:"Greg"});
    即使内部的匿名函数被返回了,且在其他地方被调用,仍可以访问变量propertyName.

作用域链的关系如图
clipboard.png

1.闭包与变量

闭包的问题:闭包只能取得包含函数中任何变量的最后一个值。

1
2
3
4
5
6
7
8
9
10
11
function createFunctions(){
var result=new Array();
for(var i=0;i<10;i++){
result[i]=function(){
return i;
}
}
return result;
}
表面上,每个函数返回自己的索引值
实际上,每个函数返回10
  • 解释
    • 每个函数作用域链中保存着包含函数的活动对象,则都是引用同一个变量i;
    • 包含函数返回后,变量i值是10,此时每个函数都引用着保存着变量i的包含函数活动对象
    • 每个函数内部i的值都是10。
1
2
3
4
5
6
7
8
9
10
11
12
13
改进后的闭包
function createFunctions(){
var result=new Array();
for(var i=0;i<10;i++){
result[i]=function(num){
return function(){
return num;
};
}(i);
}
return result;
}
每个函数返回自己的索引值。
  • 解释
    • 没有直接把闭包赋值给数组,而是定义了一个匿名函数,并将立即执行该匿名函数的结果赋值给数组。
    • 在匿名函数内部,创建并返回一个访问num的闭包。
    • 闭包只能取得包含函数任何变量的最后一个值。

2.this对象

  • this对象是在运行时基于函数的执行环境绑定的:在全局函数中,this等于window,而当函数被作为对象的方法调用时,this等于那个对象。(非闭包,匿名函数情况下)

  • 匿名函数的执行环境具有全局性,因此其this对象通常指向window(除call()apply()改变执行环境外)。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var name="The window";
    var object={
    name:"My object",
    getNameFunc:function(){
    return function(){
    return this.name;
    };
    }
    };

    alert(object.getNameFunc()()); //"The window"(非严格模式下)
  • 解释

    • 每个函数在被调用时都会自动取得两个特殊变量(对象):thisarguments
    • 内部函数在搜索这两个变量时,只会搜索到其活动对象为止,永远不会直接访问外部函数中的这两个变量。所以当搜不到时就等于window。
    • but可以间接访问.把外部作用域中的this对象保存在一个闭包能够访问的变量中,就可以让闭包访问对象了。
1
2
3
4
5
6
7
8
9
10
11
12
var name="The window";
var object={
name:"My object",
getNameFunc:function(){
var that=this;
return function(){
return that.name;
};
}
};

alert(object.getNameFunc()()); //"My object"
  • 几种特殊的情况
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var name="The window";
    var object={
    name:"My object",
    getName:function(){
    return this.name;
    }
    };

    object.getName(); //"My object"
    (object.getName)() //"My object"
    (object.getName=object.getName)() //"The window" 在非严格模式下。赋值的是函数本身,this的值不能得到维持,相当于在全局环境下调用,所以指向"window"。

3.内存泄漏

IE早些版本的问题

liborn wechat
欢迎您扫一扫上面的微信二维码,订阅我的公众号!