1. 什麼是閉包?node
參考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以下所示:app
1 function isValidDate(d) { 2 if (Object.prototype.toString.call(d) !== "[object Date]") { 3 return false; 4 } 5 return !isNaN(d.getTime()); 6 }
3. 閉包的更多做用及示例ide
3.1 封裝變量函數
在閉包塊中實現「私有變量」this
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的例子用閉包模擬私有方法,也是模塊模式的基礎。spa
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設計模式與開發實踐》和網絡。