为什么我得到的数组值为"undefined"

ano*_*ous 0 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**
        });
}
Run Code Online (Sandbox Code Playgroud)

con*_*exo 6

更换

var i = 0; i < array.length; ++i
Run Code Online (Sandbox Code Playgroud)

通过

let i = 0; i < array.length; i++
Run Code Online (Sandbox Code Playgroud)

你完成了

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
        });
}
Run Code Online (Sandbox Code Playgroud)

问题原因:缺乏了解 scope

检查此示例以了解问题:

var 创建 function scope

var funcs = []

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

funcs.forEach(function(func) {
  func()
})
Run Code Online (Sandbox Code Playgroud)

虽然你可能会想到这forEach导致数字回路09正在打印,而不是你的十倍10.这样做的原因是变量i使用被宣布var关键字,它创建了一个function scope导致每次functionfuncs保持一个参考相同的 i变量.在forEach执行循环时,前一个for-loop已经结束并i保持10(从最后一次迭代开始9 ++).

比较ES6的let创建方式,block scope而不是function scope在这方面的行为:

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

var funcs = []

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

funcs.forEach(function(func) {
  func()
})
Run Code Online (Sandbox Code Playgroud)

因为let创建block scope,循环的每次迭代for都有其"自己的"变量i.

使用IIFE包装器的ES5解决方案

如果你需要一个ES5液,IIFE( mmediately nvoked ˚FË上的表达)的包装将是要走的路:

var funcs = []

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

funcs.forEach(function(func) {
  func()
})
Run Code Online (Sandbox Code Playgroud)

这里,i作为参数传递给存储其自己的副本的每个函数value.

for..in循环也是如此:

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()
})
Run Code Online (Sandbox Code Playgroud)

同样,所有函数都funcs保持reference相同,key因为var key创建一个存在于for..in循环之外的函数作用域.再次,let产生您可能更期望的结果:

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()
})
Run Code Online (Sandbox Code Playgroud)

还要比较优秀的(!)书

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

从中抽取了例子.