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值。