閉包,在函數(shù)內(nèi)部定義了一個函數(shù)饱溢,然后這個函數(shù)調(diào)用到了父函數(shù)內(nèi)的相關(guān)臨時變量酪捡,這些相關(guān)的臨時變量就會存入閉包作用域里面法挨。
function Count(param) {
var x = param || 0;
return {
addValue: function () {
x = x + 1;
return x;
}
}
}
var count = new Count();
console.log(count.addValue()); // 1
console.log(count.addValue()); // 2
console.log(count.addValue()); // 3
console.log(count.addValue()); // 4
閉包示意圖
延遲執(zhí)行(懶函數(shù))
由于閉包可以調(diào)用父函數(shù)相關(guān)臨時變量存入閉包作用域內(nèi),這個特性可以實現(xiàn)懶函數(shù)兄旬,可以用來優(yōu)化程序性能狼犯。
function lazySum(arr) {
return function () {
return arr.reduce(function (x, y) {
return x + y;
});
};
}
var sum = lazySum([1,3,5,7,9]);
// 只有在調(diào)用sum 函數(shù)時,才會執(zhí)行加法運算。
var result = sum();
console.log(result);
由于相關(guān)變量保留在閉包作用域內(nèi)的特性悯森,如果父函數(shù)的變量時循環(huán)變量宋舷,這樣就有可能在執(zhí)行懶函數(shù)時出現(xiàn)意料之外的問題。下面的代碼預(yù)期的結(jié)果是4瓢姻,實際的結(jié)果卻是25肥缔。
function Count(param) {
var arr = [];
for(var i = 0; i < param; i ++) {
arr.push(function() {
return i * i;
});
}
return arr
}
var count = new Count(5);
var f = count[2];
console.log(f()) // 25
可以通過立即執(zhí)行函數(shù)(指定義完了立即調(diào)用的匿名函數(shù),往往用它來開辟一個獨立的作用域)汹来,對方法體進行修改续膳,從而達到預(yù)期的效果。
function Count(param) {
var arr = [];
for(var i = 0; i < param; i ++) {
arr.push((function(n) {
return n * n;
}) (i));
}
return arr
}
var count = new Count(5);
var f = count;
console.log(f) // [0, 1, 4, 9, 16]
外部讀取局部變量
由于Javascript 具有特殊的作用域鏈收班,外部函數(shù)很難訪問到局部變量坟岔。詳細介紹請轉(zhuǎn)到Javascript 基礎(chǔ)之作用域
function Student() {
var name = "Spursyy";
return function() {
return name;
};
}
var student = new Student();
var name = student();
console.log(name); // "Spursyy"
模擬私有成員變量
保護私有成員變量,隱藏私有成員的方法
function Student() {
var name;
return {
set: function(name) {
this.name = name;
},
get: function() {
return this.name;
}
}
}
var student = new Student();
student.set("Spursy");
var name = student.get();
console.log(name); // "Spursy"
模塊化
閉包有益于模塊化編程摔桦。它能以簡單方式開發(fā)較小的模塊社付,從而提高開發(fā)速度和程序的可復(fù)用性。與沒有使用閉包的程序相比邻耕,使用閉包可將模塊劃分得更小鸥咖。
var each = function (object, callback, args) {
var name;
var i = 0;
var length = object.length;
var isObj = length === undefined || typeof (object) == "function";
if (args) {
if (isObj) {
for (name in object) {
if (callback.apply(object[name], args) === false) {
break;
}
}
}
else {
for (; i < length; ) {
if (callback.apply(object[i++], args) === false) {
break;
}
}
}
}
else {
if (isObj) {
for (name in object) {
if (callback.call(object[name], name, object[name]) === false) {
break;
}
}
}
else {
for (var value = object[0]; i < length && callback.call(value, i, value) !== false; value = object[++i]) {
}
}
}
return object;
}
var arr = [1, 2, 3, 4, 5];
each(arr, function (index, value) {
console.log(index + ':' + value);
});