深究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……

  因为闭包会携带包含它的函数的做用域,所以会比其余函数占用更多的内存。过分使用闭包可能会致使内存占用过多,建议只在绝对必要时再考虑使用闭包。对象

相关文章
相关标签/搜索