为什么这段代码表现得像一个闭包?

时间:2016-10-03 06:12:30

标签: javascript

据我所知,javascript中的for循环不会创建单独的闭包。那么有人可以向我解释为什么在下面的代码中数组dogs没有填充两个对相同对象的引用?即{name: 'lunski', species: 'dog'}

var animals = [
    {name: 'fluffy', species: 'dog'},
    {name: 'miauw', species: 'cat'}, 
    {name: 'lunski', species: 'dog'}
];

var dogs = [];

for(var i = 0, e = animals.length; i<e; i++){
    if ( animals[i].species === 'dog' ){
        dogs.push(animals[i]);
    }
};

我认为dogs[]中的数组元素都会保存对animals[2]的引用,但实际上数组dogs将同时包含蓬松对象和lunski对象。

编辑: 所以,它几乎看起来好像正在创建一个闭包(尽管我明白并非如此)。但问题仍然存在,为什么dogs[]充满了独特的对象?

1 个答案:

答案 0 :(得分:2)

你正在混淆概念。将闭包从这个中解脱出来(完全是另一回事),让我们看一下你问的问题。

  

为什么在下面的代码中数组狗没有填充两个相同   对象{name:'lunski',种类:'dog'}

您正在将两个不同的对象(animals[0]animals[2))推送到dogs数组中 - 它们不是对animals对象本身的引用(数组是对象)但是到单个animals元素中包含的对象。

因为这不是闭包变量i没有固定到它设置的最后一个值。

<强>更新

我相信我终于理解了你想要的问题 - 这里是一个答案,展示了一个带闭包的匿名函数和一个没有闭包的匿名函数如何与你的数组一起工作(参见this fiddle来测试)。

代码/小提琴创建4个输入。第一个和第三个没有关闭,第二个和第四个是关闭。输入意味着被点击(他们有一个click监听器)并且他们每个都将animals[i]记录到控制台。请参阅下面示例中的注释,以解释记录的值。

var animals = [
    {name: 'fluffy', species: 'dog'}, 
  {name: 'miauw', species: 'cat'},
  {name: 'lunski', species: 'dog'}
  ];

var dogs = [];
for (var i = 0; i < animals.length; i++) {
  if (animals[i].species === 'dog') {
    // the first and third elements created in the loop have no closure
    // the variable i will be set to 2 because it has reached the end of its loop - it's value was not bound with function
    // therefore when you click on the input labeled "fluffy (no closure)" or lunski (no closure) they will log "undefined" to the console since animals[2] is undefined.
        e = document.createElement("input");
        e.value = animals[i].name + " (no closure)" ;
        e.addEventListener('click', function() {
          console.log(animals[i])}
        )
    document.body.appendChild(e);


    // the second and fourth elements created in the loop have closure
    // because the function is enclosed within a function
    // the variable i will be valid and set to what it is when the funtion runs 
    // Note: The exclamation point causes the outer function to be executed immediately - creating the event listener
    // therefore when you click on the input labeled "fluffy (closure)" or lunski (closure)
    // you will see the whole object in the console
    e = document.createElement("input");
    e.value = animals[i].name + " (with closure)" ;;
    !function(animals, i){
        e.addEventListener('click', function() {
          console.log(animals[i])}
        )
     }(animals, i)
    document.body.appendChild(e);
  }
};

我希望这会有所帮助。如果您有兴趣查看更多闭包示例,请查看此SO post