js闭包问题

首先想要理解闭包,必须先要理解js中的作用域问题。

作用域不过就是两种,一种是全局变量一种是局部变量。

例如:

var n = 66;
function fn(){
   alert(n);
}
fn();

这段代码中的n就是定义的全局变量。

function fn(){
   var n = 66;
   alert(n);
}
fn();

而这段代码中的n就是局部变量,而内部变量在函数外部是不能访问的。注意:定义局部变量的时候必须要写var,不然n就会变成你定义的全局变量。

那么如何从外部函数来取内部函数的变量呢?

   function fn1(){
    n=66;
    function fn2(){
      alert(n);
    }
    return fn2;
  }
  var result=fn1();
  result(); 

运行这段代码,浏览器会弹出66.我们用过return的方式在fn1中吧fn2 return到全局变量中,我们把fn2作为返回值的这种方式来实现f1外部读取它的内部变量。这样整个内部和外部形成了一个作用域链,只要fn1调用不清楚,整个作用域链中的所有变量都保留在内存不消失。这个性质也造成了js代码严重的性能问题,闭包是一把双刃剑,他能实现很多的高级应用,但是如果处理不好就会造成全局污染,让代码的运行速度大打折扣。

什么是闭包呢?

我个人的理解,知道是关于外部函数访问内部的局部变量,那么这个函数就形成闭包。闭包也就是能够读取其他函数内部变量的函数。

闭包在实际工作中的用途是什么呢?下面我们来看一段这样的代码:

var s=[];
function foo(){for (var i=0;i<3;i++){
        s[i]=function(){
            alert(i)
        }
    }
};
foo();
s[0](); // 3
s[1](); // 3
s[2](); // 3

这段代码会连续跳出三个3.如果我们有一个需求就是每次弹出的数字是出现的次数,那么这段代码就有问题了,因为我们都知道代码是按顺序加载的,当我们执行s[0]的时候我们上面的循环代码已经执行完了,也就是说输出所有的i都只能是3,因为代码已经执行完了。如果我们想来实现上述需求就必须要把所有循环的i存起来,这时候闭包就有用了,我们可以形成一个作用域链把所有的i都存到作用域链中,这样只要执行所有的i都没有释放也就能取到所有的i的值的,下面来看代码。

var s=[];
    function foo(){
        for (var i=0;i<3;i++){
            (function(index){
                s[i]=function(){
                    alert(index);
                }
            })(i);
        }
    };
    foo();
s[0](); // 0
s[1](); // 1
s[2](); // 2

这种写法有一个好处,仔细的同学能看到我在内部写了一个匿名函数。我们创建了一个匿名的函数,并立即执行它,由于外部无法引用他的内部变量,因此在函数执行完之后会立即释放资源,关键是不污染全局变量。

最后再说闭包最后的一个用途:

var person = function(){    
    //变量作用域为函数内部,外部无法访问    
    var name = "default";       
    return {    
       getName : function(){    
           return name;    
       },    
       setName : function(newName){    
           name = newName;    
       }    
    }    
}();    
     
alert(person.name);//直接访问,结果为undefined    
alert(person.getName()); //结果为default    
person.setName("abruzzi");  
alert(person.getName());//结果为abruzzi

如上述代码,我们可以利用闭包进行函数封装,我们通过return方式来形成作用域链,在我们调用person方法时候才能访问,而直接访问是不能访问的,因为var定义的局部变量,所以我们取不到name的值而我们定义的函数getName里面return name;这个方法把name返回,在person方法里面也是一个return,所以我们可以通过getName的方法来访问person里面的name值。

posted @ 2016-07-03 20:34  JcScript  阅读(1167)  评论(0编辑  收藏  举报