一般情况下,当函数执行完毕后,局部活动对象就会被销毁,内存中仅保留全局作用域(全局执行环境的变量对象)。但是,闭包是不同的。
当函数执行完毕后,其活动对象不会被销毁,因为匿名函数仍然在引用这个活动对象。
function makeFunc() {
var name = "Mozilla";
function displayName() {
alert(name);
}
return displayName;
}
var myFunc = makeFunc();
myFunc();
运行这段代码和之前的 init() 示例的效果完全一样。其中的不同 — 也是有意思的地方 — 在于内部函数 displayName() 在执行前,被外部函数返回。
在一些编程语言中,函数中的局部变量仅在函数的执行期间可用。一旦 makeFunc() 执行完毕,我们会认为 name 变量将不能被访问。然而,因为代码运行得没问题,所以很显然在 JavaScript 中并不是这样的。
这个谜题的答案是,JavaScript中的函数会形成闭包。 闭包是由函数以及创建该函数的词法环境组合而成。这个环境包含了这个闭包创建时所能访问的所有局部变量。在我们的例子中,myFunc 是执行 makeFunc 时创建的 displayName 函数实例的引用,而 displayName 实例仍可访问其词法作用域中的变量,即可以访问到 name 。由此,当 myFunc 被调用时,name 仍可被访问。
下面是一个更有意思的示例 — makeAdder 函数:
function makeAdder(x) {
return function(y) {
return x + y;
};
}
var add5 = makeAdder(5);
var add10 = makeAdder(10);
console.log(add5(2));
console.log(add10(2));
var name="window";
var object = {
name: "object",
getNameFunc : function () {
return function () {
return this.name;
}
}
};
console.log(object.getNameFunc()()); // window 严格模式下
因为在闭包中return的function,其实不属于任何对象,所以返回了全局的window。
每个函数在被调用时,都会自动取得两个特殊变量:this和arguments。内部函数在搜索这两个变量时,只会搜索到其活动对象为止。
var name = 'window';
var object = {
name: "object",
getNameFunc:function () {
var that = this;
return function () {
return that.name;
}
}
};
console.log(object.getNameFunc()()); // object
闭包可以访问that。 即使在函数返回之后,that也仍然引用着object,所以最终返回object
var name = "window";
var object = {
name : "object",
getName:function () {
console.log(this.name);
}
};
object.getName(); // object
(object.getName)(); // object
(object.getName = object.getName)(); //window
第一句,this.name就是object.name
第二句,this的值得到了维持,因为object.getName和 (object.getName)定义相同
第三句,因为赋值表达式的值是函数本身,所以this不能得到维持,返回window