深究JavaScript——閉包

概念

  閉包是指可以引用外部函數中的局部變量的函數,並致使外部函數調用後函數對象與局部變量沒法及時銷燬。函數是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

  匿名函數的執行環境具備全局性,所以其 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……

  因爲閉包會攜帶包含它的函數的做用域,所以會比其餘函數佔用更多的內存。過分使用閉包可能會致使內存佔用過多,建議只在絕對必要時再考慮使用閉包。對象

相關文章
相關標籤/搜索