2014-09-04 72 views
1

我知道在javascript中通过引用复制对象,但这很奇怪。代码运行后字符串发生变化

var project = projects[projectIndex]; 

var projectName = project[0]["repository"]["name"]; 
console.log("type" + " of name " + projectName + " in " + ownerFolderName); 

projectTasks.push(function(callback){ 
    omnifocus.create_folder_if_possible_in_group(projectName, ownerFolderName, function() { 
     callback(); 
    }); 
}); 

在这个片段中循环运行多次。使用console.log登录时,projectName正确无误。但是,当用于匿名函数(在projectTasks中)时,值为总是与最后一项的值相同。

例如:如果它循环三次,它将记录“1”,“2”,“3”(这是正确的)。但是,在匿名函数中,它将以“3”值运行三次。

的完整代码可以在这里:https://github.com/gcamp/github-omnifocus-sync/blob/master/index.js

+2

因为它是一个异步操作,你的PROJECTNAME是已经由时间“3”它输入你的匿名功能。 – 2014-09-04 03:25:27

回答

3

这是标准的关闭问题。你有一个变量叫projectName。您在访问此变量的循环中定义函数。但是这些函数并没有在定义点使用变量的值 - 它们将在调用点使用变量的值。由于您正在循环项目并在该过程中更改projectName,因此在调用该函数时,该值是循环中的最后一个值。

解决这个的标准方法是使用一个IIFE来限制在每循环基础的变量:

for (var projectIndex in projects) { 
    var project = projects[projectIndex]; 

    var projectName = project[0]["repository"]["name"]; 
    console.log("type" + " of name " + projectName + " in " + ownerFolderName); 

    (function(projectName) { 
     projectTasks.push(function (callback) { 
      omnifocus.create_folder_if_possible_in_group(projectName, ownerFolderName, function() { 
       callback(); 
      }); 
     }); 
    })(projectName); 
} 
1

“新用户”正确地指出,你push功能可能是异步的,因此你完成for循环调用回调函数之前。

记住,不像其他C/Java相关的语言,在JavaScript变量由功能而不是大括号{}范围的。所以为了确保你的闭合变量在你的循环中没有改变,你需要将它的值传递给一个函数。有很多方法去了解这一点,但这里有一个不需要太大的变化对你的代码:

function makeCallback(projectName) 
{ 
    return function(callback){ 
     omnifocus.create_folder_if_possible_in_group(
      projectName, ownerFolderName, 
      function() { 
       callback(); 
      }); 
    }; 
} 

...

var project = projects[projectIndex]; 

var projectName = project[0]["repository"]["name"]; 
console.log("type" + " of name " + projectName + " in " + ownerFolderName); 

projectTasks.push(makeCallback(projectName)); 

另一种选择是使用Array.prototype.forEach(),而不是你的for循环。

相关问题