1. 什么是闭包?
参考MDN。
2. 闭包的使用示例
2.1 示例1
<div>1</div>
<div>2</div>
<div>3</div>
<script>
var nodes = document.getElementsByTagName('div');
for (var i = 0, len = nodes.length; i < len; i++) {
/* 注意这里 */
(function (i) { nodes[i].onclick = function () {
console.log(i + 1);
}; })(i); };
</script>
2.2 延伸
var Type = {};
for (var i = 0, type; type = ['Number', 'String', 'Boolean', 'Array', 'Function',
'RegExp', 'Date', 'Undefined', 'Null','Error'][i++];) {
(function (type) {
Type['is' + type] = function (obj) {
return Object.prototype.toString.call(obj) === '[object ' + type + ']';
}
})(type);
};
说明:对于本例来说仅能判断类型,并不能保证类型的合法性,如判断Date如下所示:
function isValidDate(d) {
if (Object.prototype.toString.call(d) !== "[object Date]") {
return false;
}
return !isNaN(d.getTime());
}
3. 闭包的更多作用及示例
3.1 封装变量
在闭包块中实现“私有变量”
var mult = (function () {
var cache = {}, // “制表法”缓存结果集,避免重复的运算
// 封闭calculate 函数
calculate = function () {
var a = 1;
for (var i = 0, l = arguments.length; i < l; i++) {
a = a * arguments[i];
} return a;
}; return function () {
var args = Array.prototype.join.call(arguments, ',');
if (args in cache) {
return cache[args];
} return cache[args] = calculate.apply(null, arguments);
};
})();
MDN的例子用闭包模拟私有方法,也是模块模式的基础。
3.2 延续局部变量的寿命
var report = function( src ){
var img = new Image();
img.src = src;
};
report( 'www.xxx.com/stat' );
有问题的代码
为了解决函数局部变量在函数执行后立即被销毁的问题,可以用闭包来保存对局部变量的引用以达到延续局部变量生命周期。
var report = (function () {
var imgs = []; return function (src) {
var img = new Image();
imgs.push(img);
img.src = src;
}
})(); report('www.xxx.com/stat');
3.3 闭包和面向对象设计
// 闭包写法
var extent = function () {
var value = 0;
return {
call: function () {
value++;
console.log(value);
}
};
};
var extent1 = extent(),
extent2 = extent();
extent1.call(); // 输出:1
extent1.call(); // 输出:2
extent1.call(); // 输出:3 extent2.call(); // 输出:1 var Extent = function () {
this.value = 0;
}; // 面向对象的写法
Extent.prototype.call = function () {
this.value++;
console.info(this.value);
};
var myExtent1 = new Extent();
myExtent1.call();
myExtent1.call();
myExtent1.call(); var myExtent2 = new Extent();
myExtent2.call();
说明:本文代码来自《JavaScript设计模式与开发实践》和网络。