通过一些题目来理解闭包。
涉及知识点:
1.执行上下文
2.作用域链
3.this指针
4.垃圾回收机制:标记回收
例子1:
var foo = ( function() {
var secret = 'secret'; // “闭包”内的函数可以访问 secret 变量,而 secret 变量对于外部却是隐藏的
return {
get_secret: function () { // 通过定义的接口来访问 secret
return secret;
},
new_secret: function ( new_secret ) { // 通过定义的接口来修改 secret
secret = new_secret; }
};
} () );
foo.get_secret (); // 得到 'secret'
foo.secret; // Type error,访问不能
foo.new_secret ('a new secret'); // 通过函数接口,我们访问并修改了 secret 变量
foo.get_secret (); // 得到 'a new secret'
例子2:
function foo() {
var a = 1;
function bar() {
a = a + 1;
alert(a);
}
return bar;}
var closure = foo(); // 这个时候返回的是 bar() 这个函数外加其包上的变量 a; 这里的a没有进行垃圾回收。
var closure2 = foo(); // 这里同样生成了另外一个闭包(实例)
closure(); // 2
closure2(); // 2 , 绑定了另外一份变量 a
closure(); // 3
例子3:
var a = 1;
function foo() {
function bar() {
a = a + 1;
alert(a);
}
return bar;
}
var closure = foo();
var closure2 = foo();
closure(); //2
closure2(); //3
closure(); //4
例子4:
var funcs = [];
for(var i=0; i < 5; i++) {
funcs[i] = function() { alert(i); }
}
for(var j=0; j < funcs.length; j++) {
funcsj;
}
例子5:
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;//this指针会时刻改变
};
}
};
alert(object.getNameFunc()());
例子6:
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
var that = this;
return function(){
return that.name;
};
}
};
alert(object.getNameFunc()());
闭包的作用:
它的最大用处有两个,一个是可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。
总是要通过return进行实现,因为return才能进行function作用域的延续。
因此,全局变量通过null解除引用 局部变量在离开执行环境时自动解除引用。
文字解释:
JavaScript 中的闭包实现与 JavaScript 的 Scope Chain 是密不可分的. 首先在 JavaScript 的执行中会一直存在一个 Execute Context Stack 。 Execute Context Stack 中最下面一个一定是 GlobalContext, 而在每一个函数的执行开始就会向这个 stack 中压入一个此 Function 的 Execution Context; 而一个 Execution Context 的组成分为三部分:
- Variable Object: 存储方法内的变量 vars, 方法传入的参数, 函数内定义的函数等等(函数表达式不保存), Variable Object 在任何时候是不可以被直接访问到的, 当然不同的 JS 引擎提供了访问接口就说不定了;
- Scope Chain: 这个函数执行的时候用以寻找值的 Scope Chain, 这个 Scope Chain 由 Variable Object + All Parent Scopes 组成, Variable Object 会放在这个 Scope Chain 的最前面, 这也是为什么函数内的变量会被最先找到;
-
thisValue, 函数被调用的时候的 this 对象, 存储的就是函数的调用者(caller)的引用; 对于 Variable Object 在不同的情况下会有不同的定义, 例如在全局的时候被称为 Global Object, 而在函数中则被称为 Activation Object 激活对象; 正是由于有了 Execution Context 中的 Scope Chain, JavaScript 才能够使得在方法 bar() 的内部访问到方法 foo() 中的变量 a, 才能够使方法 bar() 将变量 a 关闭在自己的作用范围内不让他随 foo() 方法的执行完毕而销毁;
作用域链:
参考文献: