闭包,在函数内部定义了一个函数,然后这个函数调用到了父函数内的相关临时变量,这些相关的临时变量就会存入闭包作用域里面。
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
延迟执行(懒函数)
由于闭包可以调用父函数相关临时变量存入闭包作用域内,这个特性可以实现懒函数,可以用来优化程序性能。
function lazySum(arr) {
return function () {
return arr.reduce(function (x, y) {
return x + y;
});
};
}
var sum = lazySum([1,3,5,7,9]);
// 只有在调用sum 函数时,才会执行加法运算。
var result = sum();
console.log(result);
由于相关变量保留在闭包作用域内的特性,如果父函数的变量时循环变量,这样就有可能在执行懒函数时出现意料之外的问题。下面的代码预期的结果是4,实际的结果却是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
可以通过立即执行函数(指定义完了立即调用的匿名函数,往往用它来开辟一个独立的作用域),对方法体进行修改,从而达到预期的效果。
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 具有特殊的作用域链,外部函数很难访问到局部变量。详细介绍请转到Javascript 基础之作用域
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"
模块化
闭包有益于模块化编程。它能以简单方式开发较小的模块,从而提高开发速度和程序的可复用性。与没有使用闭包的程序相比,使用闭包可将模块划分得更小。
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);
});