ECMAScript 最易让人误解的一点是,它支持闭包(closure)。闭包
闭包,指的是词法表示包括不被计算的变量的函数,也就是说,函数可使用函数以外定义的变量。函数
在 ECMAScript 中使用全局变量是一个简单的闭包实例。请思考下面这段代码:spa
var sMessage = "hello world"; function sayHelloWorld() { alert(sMessage); } sayHelloWorld();
在上面这段代码中,脚本被载入内存后,并无为函数 sayHelloWorld() 计算变量 sMessage 的值。该函数捕获 sMessage 的值只是为了之后的使用,也就是说,解释程序知道在调用该函数时要检查 sMessage 的值。sMessage 将在函数调用 sayHelloWorld() 时(最后一行)被赋值,显示消息 "hello world"。ip
在一个函数中定义另外一个会使闭包变得更加复杂。例如:内存
var iBaseNum = 10; function addNum(iNum1, iNum2) { function doAdd() { return iNum1 + iNum2 + iBaseNum; } return doAdd(); }
这里,函数 addNum() 包括函数 doAdd() (闭包)。内部函数是一个闭包,由于它将获取外部函数的参数 iNum1 和 iNum2 以及全局变量 iBaseNum 的值。 addNum() 的最后一步调用了 doAdd(),把两个参数和全局变量相加,并返回它们的和。get
这里要掌握的重要概念是,doAdd() 函数根本不接受参数,它使用的值是从执行环境中获取的。io
能够看到,闭包是 ECMAScript 中很是强大多用的一部分,可用于执行复杂的计算。function
提示:就像使用任何高级函数同样,使用闭包要当心,由于它们可能会变得很是复杂。class
在来两个例子:变量
function foo(x) {
var tmp = 3;
return function (y) {
alert(x + y + tmp);
x.memb = x.memb ? x.memb + 1 : 1;
alert(x.memb);
}
}
var age = new Number(2);
var bar = foo(age); // bar 如今是一个引用了age的闭包
bar(10);
不出咱们意料,每次运行bar(10),x.memb都会自加1。但须要注意的是x每次都指向同一个object变量——age,运行两次bar(10)后,age.memb会变成2.
var db = (function() {
// 建立一个隐藏的object, 这个object持有一些数据
// 从外部是不能访问这个object的
var data = {};
// 建立一个函数, 这个函数提供一些访问data的数据的方法
return function(key, val) {
if (val === undefined) { return data[key] } // get
else { return data[key] = val } // set
}
// 咱们能够调用这个匿名方法
// 返回这个内部函数,它是一个闭包
})();
db('x'); // 返回 undefined
db('x', 1); // 设置data['x']为1
db('x'); // 返回 1
// 咱们不可能访问data这个object自己
// 可是咱们能够设置它的成员
闭包常常用于建立含有隐藏数据的函数(但并不老是这样)。