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自己
// 可是咱們能夠設置它的成員
閉包常常用於建立含有隱藏數據的函數(但並不老是這樣)。