閉包是指可以引用外部函數中的局部變量的函數,並致使外部函數調用後函數對象與局部變量沒法及時銷燬。函數是JavaScript中惟一擁有自身做用域的結構,所以閉包的建立依賴於函數。緩存
var Foo = function() { var name = 'staven'; this.getName = function() { return name; }; }; var foo = new Foo(); console.log(foo.name); //undefined console.log(foo.getName()); //staven
做用域鏈的這種配置機制引出了一個值得注意的反作用,即閉包只能取得包含函數中任何變量的最後一個值。閉包
for(var i = 0; i < 10; i++) { setTimeout(function() { console.log(i); //10次輸出10 }, 1000); }
爲了正確的得到循環序號,最好使用自執行匿名函數。app
for(var i = 0; i < 10; i++) { (function(e) { setTimeout(function() { console.log(e); }, 1000); })(i); }
匿名函數的執行環境具備全局性,所以其 this 對象一般指向 window(在經過 call()或 apply()改變函數執行環境的狀況下, this 就會指向其餘對象)。函數
var name = '全局'; var obj = { name: '局部', getName: function(){ var that = this; return function(){ return that.name; } } }; console.log(obj.getName()()); //局部
把外部做用域中的 this 對象保存在一個閉包可以訪問到的變量裏,就可讓閉包訪問該對象了。this
var name = "全局"; var obj = { name: "局部", getName: function() { var that = this; return function() { return that.name; }; } }; console.log(obj.getName()()); //"局部"
只要咱們臨時須要一些變量,均可以使用塊級做用域(私有做用域)。當匿名函數執行完畢,其做用域鏈當即銷燬,從而能夠減小閉包占用資源問題。prototype
(function($, window, document, undefined){ var name = "staven"; $.fn.getName = function(){ }; })(jQuery, window, document);
緩存數據、柯里化code
//利用閉包實現 var Book = (function(){ //靜態私有變量 var bookNum = 0; //靜態私有方法 function checkBook(name){ console.log("checking Book……"); } //建立類 function _book(newId, newName, newPrice){ if(this instanceof _book){ //私有變量 var name, price; //私有方法 function checkID(id){ console.log("checking id……"); } //特權方法 this.getName = function(){}; this.getPrice = function(){}; this.setName = function(){}; this.setPrice = function(){}; //公有屬性 this.id = newId; //公有方法 this.copy = function() { console.log("copying……") }; bookNum++; if(bookNum > 100){ throw new Error('咱們僅出版100本書'); } //構造器 this.setName(name); this.setPrice(price); }else{ return new _book(newId, newName, newPrice); } } //構建原型 _book.prototype = { //靜態共有屬性 isJSBook:false, //靜態共有方法 show:function(){ console.log("showing……"); } }; //返回類 return _book; })(); Book(21,'staven',23).show(); //showing…… Book(21,'staven',23).copy(); //copy…… var book = new Book(21,'staven',23); book.show(); //showing…… book.copy(); //copying……
因爲閉包會攜帶包含它的函數的做用域,所以會比其餘函數佔用更多的內存。過分使用閉包可能會致使內存佔用過多,建議只在絕對必要時再考慮使用閉包。對象