您的位置:首页 > Web前端 > JavaScript

从两个函数来学习js闭包的概念

2017-09-19 16:31 218 查看
从两个函数来学习js闭包的概念

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

如下面f1()函数,通过return将自己内部的函数f2()返回,使得在f1()的外部,可以通过return的f2()函数来访问f1()函数内部变量n

function f1() {
var n = 999;
nAdd = function() {
n += 1;
};
function f2() {
return n;
}
return f2;
}
var result1 = f1();
var result2 = f1();
alert(result1()); // 999
nAdd();
alert(result1()); // 1000
alert(result2()); // 999


在继续闭包的理解之前,需要了解下函数执行过程中发生的一些事情:

当某个函数被调用时,会创建一个执行环境(execution context)及相应的作用域链。

然后,使用 arguments 和其他命名参数的值来初始化函数的活动对象(activation object)。但在作用域链中,外部函数的活动对象始终处于第二位,外部函数的外部函数的活动对象处于第三位,……直至作为作用域链终点的全局执行环境。

也就是说:函数在执行之前,都会创建一个新的执行环境,从result2()的返回值999可以看出来,他并不受nAdd()操作的影响。

无论什么时候在函数中访问一个变量时,就会从作用域链中搜索具有相应名字的变量。一般来讲,

当函数执行完毕后,局部活动对象就会被销毁,内存中仅保存全局作用域(全局执行环境的变量对象)。

但是,闭包的情况又有所不同。因为f1()return的函数f2包含了对f1函数内部定义的变量n的引用,所以变量n不会立即被回收。

下面这段函数执行结果为The Window

var name = "The Window";
var object = {
name: "My Object",
getNameFunc: function() {
return function() {
return this.name;
};
}
};
alert(object.getNameFunc()()); //The Window


按照对闭包的初步了解,可能会认为执行object.getNameFunc()(),实际是在执行

function() {
return this.name;
}


那么再从作用域链逐层向上寻找变量时,会找到object中的name

但是却找到了全局变量var name = “The Window”;

那么理解的误区在哪呢?就是对作用域链中具体保存的内容理解有误。

作用域链中保存的内容为:

对于每一个执行环境,都会创建一个与之关联的作用域链。每个执行环境的作用域链的前端,始终都是该执行环境的变量对象,对于全局执行环境就相当于window对象,对于函数执行环境就相当于该函数的活动对象;对于全局执行环境,已经是根部,没有后续,对于函数执行环境,其作用域链的后续是该函数对象的[[scope]]属性里的作用域链。

上面描述简单来说,就是函数执行过程中对于变量的查找是沿着作用域链逐层向上寻找,作用域链内存放是该作用域的活动变量,那么活动变量又包含哪些呢?

在一个函数对象被调用的时候,会创建一个活动对象,首先将该函数的每个形参和实参,都添加为该活动对象的属性和值;将该函数体内显示声明的变量和函数,也添加为该活动的的属性。

也就是说保存了形参和实参,函数体内显示声明的变量和函数。从上面可以看出并不包含this对象,所以并不会逐层向上寻找到object的this对象。

那么为什么又会把this指向window呢,其实执行的最终形式是:

object.getNameFunc()() --> getNameFunc() --> window.getNameFunc()


所以this指向函数的调用者window,最终this.name就指向了全局变量

var name = "The Window";


如有不正确的地方,欢迎交流指正。

相关参考:

http://www.cnblogs.com/amy-fox/p/5856771.html

http://www.cnblogs.com/pssp/p/5216085.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  javascript 闭包