javascript 函数初探 (六)--- 闭包初探#4

时间:2023-03-09 07:38:20
javascript 函数初探 (六)--- 闭包初探#4

环中的闭包:

让我们来看一下一个会循环三次的操作,她在每次迭代中都会创建一个返回当前序列号的新函数,该函数会被添加到一个数组中,并最终返回:

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(); 

下面一些章节我们来探讨一下对象,敬请期待。。。

javascript 函数初探 (六)--- 闭包初探#4