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