编程go之Javascript

JavaScript:闭包学习

2017-04-07  本文已影响56人  勇往直前888

基本概念

var a = 10;
var b = 200;

function fn() {
    var b = 20;

    function bar() {
        console.log("a + b = " + (a + b));
        console.log("this.b = " + this.b);
    }

    return bar;
}

var foo = fn();
foo();  
// a + b = 30
// this.b = 200
  • 闭包foo()的创建环境是作用域链bar() => fn() => 全局
    abar()fn()中都没有,所以取了全局的a = 10
    bbar()中没有,取了fn()b = 20;;全局中的 b = 200;被屏蔽了。

使用场景

闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。

实现getset

function Person(){  
    var name = "default";     
     
    return {  
       getName : function(){  
           return name;  
       },  
       setName : function(newName){  
           name = newName;  
       }  
    }  
};  
   
var john = Person();  
john.getName();          // "default"
john.setName("john");  
john.getName();          // "john"
console.log(john.name);  // undefined
   
var jack = Person();  
jack.getName();          // "default"
jack.setName("jack");    
jack.getName();          // "jack"
console.log(jack.name);  // undefined 

这个看上去就很面向对象了。封装了数据name,同时提供了getName()setName(newName)两个闭包(返回的内部函数)来作为这个变量的访问接口。

缓存

var CachedSearchBox = (function(){  
    var cache = {},  
       count = [];  
    return {  
       attachSearchBox : function(dsid){  
           if(dsid in cache){//如果结果在缓存中  
              return cache[dsid];//直接返回缓存中的对象  
           }  
           var fsb = new uikit.webctrl.SearchBox(dsid);//新建  
           cache[dsid] = fsb;//更新缓存  
           if(count.length > 100){//保正缓存的大小<=100  
              delete cache[count.shift()];  
           }  
           return fsb;        
       },  
   
       clearSearchBox : function(dsid){  
           if(dsid in cache){  
              cache[dsid].clearSelection();    
           }  
       }  
    };  
})();  
   
CachedSearchBox.attachSearchBox("input1"); 

解决this问题

var name = "The Window";
var object = {
    name : "My Object",
   getNameFunc : function(){
       return function(){
        return this.name;
     };
   }
};
object.getNameFunc()();  // "The Window"

that大法:

var name = "The Window";
var object = {
  name : "My Object",
  getNameFunc : function(){
    var that = this;
    return function(){
      return that.name;
    };
  }
};
object.getNameFunc()(); // "My Object"

匿名包装器

其实就是我们通常说的自执行匿名函数
匿名函数的作用是减少临时的中间变量,解决取名困难问题。
自执行就是定义后马上执行,并且只执行一次。如果没有闭包,函数马上就垃圾回收了,如果有闭包引用变量,那么作用域会继续替闭包保存变量,相当于一个缓存。

for(var i = 0; i < 10; i++) {
    setTimeout(function() {
        console.log(i);  
    }, 1000);
} // 输出10个10,与预期有差距
  • 函数setTimeout(fn, time);的参数fn是一个函数;这里的fn是一个匿名函数,并且使用了外部的变量i,所以这个匿名函数是一个闭包。
for(var i = 0; i < 10; i++) {
    (function(e) {
        setTimeout(function() {
            console.log(e);  
        }, 1000);
    })(i);
}
  • (funtion(e))(i)是一个自执行匿名函数,定义完后马上执行。变量i属于for循环所在的作用域,通过参数e传递给函数setTimeout(fn, time);

参考文章

深入理解javascript原型和闭包(14)——从【自由变量】到【作用域链】
深入理解javascript原型和闭包(15)——闭包
作用域的图画得不错

学习Javascript闭包(Closure)
两个作用总结得不错
最后的例子给的挺好,thisthat(或者self)大法

详解js中的闭包
这里的图画得挺不错的

js闭包的用途
使用的例子不错

闭包和引用
循环的例子给得不错

Javascript闭包——懂不懂由你,反正我是懂了
既然是翻译stackflow的文章,可以看看

上一篇 下一篇

猜你喜欢

热点阅读