Javascript闭包问题 [英] Javascript closures issues

查看:100
本文介绍了Javascript闭包问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



正如John Resig所说:


闭包允许引用父函数中存在的变量。
然而,它不提供变量创建时的值;它提供了带父函数的变量的最后一个值。在for循环中,你会看到这种情况的最常见的问题。有一个变量用作interaor(例如,i)。在for循环中,正在创建使用闭包再次引用迭代器的新函数。 rpoblem是新的闭包函数被调用的时间,它们将引用迭代器的最后一个值(即数组中的最后一个位置),而不是你期望的值taht。


然后他在列表2-16中提供了一个使用匿名函数来引用范围的示例。

  / ** 
*清单2-16。使用匿名函数来诱导
*示例需要创建多个Closure使用函数的示例
* /
//具有ID为main的元素
var obj = document的示例。 getElementById(main);

//绑定到
的项目数组var items = [click,keypress];

for(var i = 0; i< items.length; i ++){
//使用自执行的匿名函数来引用范围
(function(){
//记住这个范围内的值
var item = items [i];

//将一个函数绑定到元素
obj [on+ item ] = function(){
// item指的是已成功的父变量
//在此循环的上下文中作用域
alert(thanks for your+ item);
};
})();
}

此示例按预期工作,主要对象的行为是正确的。



在下面,它使用另一个时间自我执行的函数来诱使范围,在迭代期间。



函数的目的是创建一个对象,为其所有属性定义getter和setter。在这种情况下,示例不起作用。

  / ** 
*创建的动态生成方法的示例
*实例化新对象时
* /
//创建接受属性对象的新用户对象
function User(properties ){
//迭代该对象的属性,并确保
//正确的作用域(如前所述)
var that = this;

for(var i in properties){
(function(){
console.log(property:+ i);
//创建一个nwe getter for the property
that [get+ i] = function(){
return properties [i];
};

//创建一个新的setter for the property
that [set+ i] = function(val){
properties [i] = val;
};
})
}
}

//创建一个新的用户对象实例,并传入
//属性的对象以使用
种子。var user =新用户({
name:Bob,
age:44
});

//注意,name属性不存在,因为它在
//属性对象中是私有的
alert(user.name == null);

//但是,我们可以使用动态生成的新的getnaem()
//方法访问它的值
console.log(name:+ user.getname()); // name:44 :(
alert(user.getname()==Bob);

//最后,我们可以看到可以设置和
//新生成的函数

user.setage(22);
alert(user.getage()== 22);

相反,将i参数作为参数传递给自执行函数后,它会工作。

  for(var i in properties){
(function(prop){
console.log(property:+ i);
//为属性
创建一个nwe getter,[get+ prop] = function(){
return property [prop];
};
$ b b //为属性
创建一个新的setter [set+ prop] = function(val){
property [prop] = val;
};
} )(i);
}

我的问题是:




  • 为什么在第一种情况下(for循环),没有必要传递i参数,而

    在第二种情况

  • 解决方案

    在第一个示例中,您声明了一个本地变量中的数组元素的内容的副本:

      var item = items [i ]; 

    内联注释说,这里我们记住闭包范围内的值。



    在第二个示例中,您不必将 i 作为参数,也可以这样做:

     (function(){

    var prop = i; //见这里!

    控制台.log(property:+ i);
    //为属性
    创建一个nwe getter [get+ prop] = function(){
    return properties [prop] ;
    };

    //为属性
    创建一个新的setter [set+ prop] = function(val){
    properties [prop] = val;
    };
    })();

    这两个例子更类似。



    同样,你也可以改变第一个例子来传递 i 作为参数,而不是在变量中详细地声明它。

     (function(item){
    //将一个函数绑定到元素
    obj [on+ items [item] = function
    // item是指已成功的父变量
    //在此循环的上下文中作用域
    alert(感谢您的+ items [item]);
    };
    })(i);

    对于是否使用声明变量的本地副本是任意的, var 语句,或将其作为参数传递到自执行函数中。



    编辑:


    $ b b

    @Zecc在评论中买了一个好点,我想解释一下:

      i){

    //使用`i'按预期工作

    }(i));

    其中:

     (function(){

    var i = i;

    //使用`i'不起作用... i = undefined。

    }());

    这是因为 var variable = value 语句实际上是:

     (function(){

    var i;

    i = i;

    }());

    var 关键字始终分配变量 undefined


    So, I'm still reading Apress Pro Javascript Techniques and i'm having troubles with closures.

    As John Resig states:

    Closures allow you to reference variables that exist within the parent function. However it does not provide the value of the variable at the time it is created; It provides the last value of the variable withing the parent function. The most common issue under which you'll see this occurr during a for loop. There is one variable being used as an interaor (e.g., i). Inside of the for loop, new functions are being created that utilize the closure to reference the iterator again. The rpoblem is tat the time the new closured functions are called, they will reference the last value of the iterator (i.e., the last position in an array), not the value taht you woul expect.

    Then he presents, in listing 2-16 an example using anonymous functions to induce scope.

    /**
     * Listing 2-16. Example of Using Anonymous Functions to induce the 
     * Scope Needed to Create Multiple Closure-Using Functions 
     */
    // An element with an ID of main
    var obj = document.getElementById("main");
    
    // An array of items to bind to
    var items = ["click", "keypress"];
    
    for (var i = 0; i < items.length; i++) {
        // Use a self executed anonymous function to induce scope
        (function() {
            // Remembre the value within this scope
            var item = items[i];
    
            // Bind a function to the element
            obj["on" + item] = function() {
                // item refers to a parent variable that has been successfully
                // scoped within the context of this loop
                alert("thanks for your " + item);
            };
        })();               
    }
    

    This example works as expected, and the behavious of the main object is correct.

    The in the following, it uses another time a self-executing function to induce scope, during an iteration.

    The purpose of the function is to create an object, defining getters and setters for all its properties. In this case, the example does not work.

    /**
     * Listing 2-25. Example of Dynamicaaly Generated Methods That Are Created 
     * When a New Object is instantiated
     */          
    // Create a new user object that accepts an object of properties
    function User(properties) {
        // Iterate thorugh the properties of the object, and make sure
        // that it's properly scoped (sas discussed previously)
        var that = this;
    
        for (var i in properties) { 
           (function() {
               console.log("property: " + i);
               // Create a nwe getter for the property
               that["get" + i] = function() {
                   return properties[i];
                };
    
                // Create a new setter  for the property
               that["set" + i] = function(val) {
                   properties[i] = val;
               };
           })();                    
        }
    }
    
    // Create a new user object instance and pass in an object of
    // properties to seed it with
    var user = new User({
        name: "Bob",
        age: 44
    });
    
    // Just note that the name property does not exists, as it's private within the  
    // properties object
    alert(user.name == null);
    
    // However, we're able to access its value using the new getnaem()
    // method that was dynamically generated
    console.log("name: " + user.getname());  // name: 44 :(
    alert(user.getname() == "Bob");
    
    // Finally, we can see that it's possible to set and gt the age using
    // the newly generated functions
    
    user.setage(22);
    alert(user.getage() == 22);
    

    Instead, after passing the i parameter as argument to the self-executing function,it works.

    for (var i in properties) { 
           (function(prop) {
               console.log("property: " + i);
               // Create a nwe getter for the property
               that["get" + prop] = function() {
                   return properties[prop];
                };
    
                // Create a new setter  for the property
               that["set" + prop] = function(val) {
                   properties[prop] = val;
               };
           })(i);                   
        }
    

    My question is:

    • Why in the first case (for loop), it is not necessary to pass the i parameter, while
      in the second (for in) it is needed in order to work properly?

    解决方案

    In the first example you are declaring a copy of the contents of the array element in a local variable:

    var item = items[i];
    

    As the inline comment says, here we're remembering the value within the closure scope.

    In the 2nd example, instead of passing i as a parameter, you could also have done:

       (function() {
    
           var prop = i; // See here!
    
           console.log("property: " + i);
           // Create a nwe getter for the property
           that["get" + prop] = function() {
               return properties[prop];
            };
    
            // Create a new setter  for the property
           that["set" + prop] = function(val) {
               properties[prop] = val;
           };
       })(); 
    

    Which makes both examples more similar.

    Similarly, you could also alter the first example to pass i as a parameter, rather than declaring it verbosely in a variable.

    (function(item) {
        // Bind a function to the element
        obj["on" + items[item] = function() {
            // item refers to a parent variable that has been successfully
            // scoped within the context of this loop
            alert("thanks for your " + items[item]);
        };
    })(i);     
    

    It's arbitrary as to whether you declare a local copy of the variable using a var statement, or pass it as a parameter into your self executing function.

    Edit:

    @Zecc bought up a good point in the comments, which I'd like to explain:

    (function (i) {
    
        // using `i` works as expected. 
    
    }(i));
    

    Where as:

    (function () {
    
        var i = i;
    
        // using `i` doesn't work... i = undefined.
    
    }());
    

    This is because the var variable = value statement is effectively:

    (function () {
    
        var i;
    
        i = i;
    
    }());    
    

    and the var keyword always assigns the variable(s) following it with the value undefined.

    这篇关于Javascript闭包问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆