Javascript 闭包问题

标签 javascript for-loop closures for-in-loop

所以,我仍在阅读 Apress Pro Javascript 技术,但我在闭包方面遇到了麻烦。

正如 John Resig 所说:

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.

然后他在 list 2-16 中展示了一个使用匿名函数来引入作用域的示例。

/**
 * 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);
        };
    })();               
}

这个例子按预期工作,主要对象的行为是正确的。

在下文中,它在迭代期间使用另一次自执行函数来引入范围。

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

/**
 * 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);

相反,在将 i 参数作为参数传递给自执行函数后,它起作用了。

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

我的问题是:

  • 为什么第一种情况(for循环),不需要传递i参数,而
    在第二个(对于 in)中,需要它才能正常工作吗?

最佳答案

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

var item = items[i];

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

在第二个示例中,除了将 i 作为参数传递之外,您还可以这样做:

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

这使得两个示例更加相似。

同样,您也可以更改第一个示例,将 i 作为参数传递,而不是在变量中冗长地声明它。

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

关于您是使用 var 语句声明变量的本地副本,还是将其作为参数传递给您的自执行函数,这是任意的。

编辑:

@Zecc 在评论中提出了一个很好的观点,我想解释一下:

(function (i) {

    // using `i` works as expected. 

}(i));

作为:

(function () {

    var i = i;

    // using `i` doesn't work... i = undefined.

}());

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

(function () {

    var i;

    i = i;

}());    

并且 var 关键字始终为其后的变量分配值 undefined

关于Javascript 闭包问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7066576/

相关文章:

swift - 有没有一种方法可以在不测试的情况下运行闭包?

javascript - bootstrap datepicker无法设置minDate

javascript - 一个范围到另一个范围的非线性插值

javascript - 数据未显示在下拉列表中

c# - 代码困惑 - 为什么一个有效,而另一个无效?

javascript - 如何在 JavaScript(或 CSS)中平均对齐使用循环、数组和附加子项创建的两个垂直列?

javascript - AngularJS - Textarea 在 ng-click 后不想清除

Bash 脚本通过删除最后访问的文件来限制目录大小

javascript - 杂耍异步 - LearnYouNode - 立即调用函数表达式

Javascript 用表达式和闭包进行封装