为什么我得到的数组值为“undefined”

时间:2018-03-13 11:17:22

标签: javascript node.js

我是node.js的新手,所以如果我的问题不成熟,我会道歉。基本上我正在尝试迭代一系列值来执行某些操作,但我不知道为什么我会得到这些值为undefined

代码:

for (var i = 0; i < array.length; ++i) {
    console.log(array[i]); //At this point I'm getting values without any problem
    var sQ = {
        _tag: array[i],
        _pid: data.change_caption_post_mail,
        time: data.change_caption_post_time,
    };

    db.collection('tags')
        .find(sQ)
        .count({}, function(error, numOfDocs) {
            if (error) throw err;
            console.log(array[i]);
            //But here I'm getting values as **undefined**
        });
}

3 个答案:

答案 0 :(得分:6)

替换

var i = 0; i < array.length; ++i

通过

let i = 0; i < array.length; i++

你已经完成了。

for (let i = 0; i < array.length; i++) {
    console.log(array[i]); //At this point I'm getting values without any problem
    var sQ = {
        _tag: array[i],
        _pid: data.change_caption_post_mail,
        time: data.change_caption_post_time,
    };

    db.collection('tags')
        .find(sQ)
        .count({}, function(error, numOfDocs) {
            if (error) throw err;
            console.log(array[i]);
            // i will be array.length here in all your callbacks
        });
}

问题的原因:缺乏理解scope

选中此示例以了解问题:

var创建function scope

&#13;
&#13;
var funcs = []

for (var i = 0; i < 10; i++) {
  funcs.push(function() {
    console.log(i)
  })
}

funcs.forEach(function(func) {
  func()
})
&#13;
&#13;
&#13;

虽然您可能希望此forEach循环导致正在打印09,但您会获得10次10。造成这种情况的原因是使用i关键字声明变量var,这会创建function scope,导致function中的每个funcs持有引用相同的 i变量。在执行forEach循环时,先前的for - 循环已结束且i保持10(从上次迭代开始的9 ++)。

比较创建let而不是block scope的ES6&#39; function scope在这方面的行为:

let(ES6或正式 ES2015 )创建block scope

&#13;
&#13;
var funcs = []

for (let i = 0; i < 10; i++) {
  funcs.push(function() {
    console.log(i)
  })
}

funcs.forEach(function(func) {
  func()
})
&#13;
&#13;
&#13;

由于let创建block scopefor循环的每次迭代都有其自己的&#34;变量i

使用IIFE包装器

的ES5解决方案

如果你需要一个ES5解决方案,一个IIFE( i 立即 i nvoked f unction e xpression)包装将是要走的路:

&#13;
&#13;
var funcs = []

for (var i = 0; i < 10; i++) {
  funcs.push((function(value) {
    return function() {
      console.log(value)
    }
  }(i)))
}

funcs.forEach(function(func) {
  func()
})
&#13;
&#13;
&#13;

此处,i作为参数传递给存储其自己的副本value的每个函数。

for..in循环也是如此:

&#13;
&#13;
var funcs = [],
  obj = {
    first: "first",
    last: "last",
    always: "always"
  }
  
for (var key in obj) {
  funcs.push(function() {
    console.log(key)
  })
}

funcs.forEach(function(func) { // outputs: "always", "always", "always"
  func()
})
&#13;
&#13;
&#13;

同样,funcs中的所有函数都将reference保持为相同的key,因为var key创建了一个位于for..in循环之外的函数作用域。同样,let会产生您可能更期待的结果:

&#13;
&#13;
var funcs = [],
  obj = {
    first: "first",
    last: "last",
    always: "always"
  }
  
for (let key in obj) {
  funcs.push(function() {
    console.log(key)
  })
}

funcs.forEach(function(func) {
  func()
})
&#13;
&#13;
&#13;

还要比较优秀的(!)书

  

Nicholas C. Zakas: "Understanding ES6",没有淀粉压榨,p。 8-9。

从中获取了这些例子。

答案 1 :(得分:2)

var i = 0更改为let i = 0

for (let i = 0; i < array.length; ++i) {
console.log(array[i]); //At this point I'm getting values without any problem
var sQ = {
    _tag: array[i],
    _pid: data.change_caption_post_mail,
    time: data.change_caption_post_time,
};

db.collection('tags')
    .find(sQ)
    .count({}, function (error, numOfDocs) {
        if (error) throw err;
        console.log(array[i]);
    });

}

N.B。当回调函数(function (error, numOfDocs) {...})正在执行时,for循环结束。如果我们在执行回调时声明var i然后i等于array.length,那么array [array.length]将返回undefined。其中一个解决方案是使用ES6 let,它将为每次迭代创建回调的块范围i

答案 2 :(得分:0)

问题是,在你的回调函数中, i 的引用仍然只是在调用回调时已经改变的引用。

您可以将代码更改为

for (var i = 0; i < array.length; ++i) {
    (function(){
    var index = i;
    console.log(array[index]); //At this point I'm getting values without any problem
    var sQ = {
        _tag: array[index],
        _pid: data.change_caption_post_mail,
        time: data.change_caption_post_time,
    };

    db.collection('tags')
        .find(sQ)
        .count({}, function(error, numOfDocs) {
            if (error) throw err;
            console.log(array[index]);
            //But here I'm getting values as **undefined**
        });
    })();
}

这个调整应该可以正常工作