循环中的闭包:
让我们来看一下一个会循环三次的操作,她在每次迭代中都会创建一个返回当前序列号的新函数,该函数会被添加到一个数组中,并最终返回:
function F(){ var arr = [], i; for(i=0; i<3; i++){ arr[i] = function(){ return i; } } return arr; } var arr = F(); arr[0](); arr[1](); arr[2]();
显然这不是我们想要的结果。为啥呢?
原来我们在三次循环中创建了三个闭包,而他们最终都指向了一个共同的局部变量i。但是闭包不会记录她们的值(上文说过),她们有的只不过是相关域在创建时的一个链接(引用)。
在这个例子中,变量i恰巧存在于定义这三个函数作用域中。对于这三个函数而言,当她们要获取某个变量时,她会从其所在的域开始逐级向上找那个距离最近的i,由于循环结束时i值为3,所以这三个值同时指向了这一个i值。
如何纠正这种行为呢?答案是换一种闭包形式:
function F(){ var arr = [], i; for(i=0; i<3; i++){ arr[i] = (function(x){ return function(){ return x; } })(i); } return arr; } var arr = F(); arr[0](); arr[1](); arr[2]();
这里我们不再直接创建一个返回i的函数了,而是将i传递给了另一个即时函数,在即使函数中i就被赋值给了局部变量x,这样一来每次循环都会有不同作用域的局部变量x,那么以来每个函数中的x值都会不同了。
或者我们可以来个正常点的:
function F(){ fucntion her(x){ return function(){ return x; }; }; var arr = [], i; for(i=0; i<3; i++){ arr[i] = her(i); }; return arr; }
目的是为了使中间函数将i值本地化。
假如我们不想把一个变量暴露到全局作用域中,因为这样的话,其他代码就会有修改她们的可能,所以我们会把这个变量保护到相关函数内部,然后提供两个额外的函数, getter(),setter()。一个用来获取变量,另一个用来对变量赋值。
var gets, sets; (function(){ var a = 0; getValue = function(){ return a; } setValue = function(v){ if(typeof v === 'number'){ a = v } } })(); setValue(1); getValue();
下面一些章节我们来探讨一下对象,敬请期待。。。