var fs=require('fs');
var path=['c:/', 'd:/', ''];
for (var i = 0; i < path.length; i++) {
  if (path[i].length > 0) {
    // 可以得到值
    console.info(path[i]);
    fs.exists(path[i], function(exists) {
      if (exists) {
        // 为何得到的是undefined?如何将下面的变量正确输出呢?
        console.info('get path inside', path[i]);
      } else {
        console.error('path not exists');
      }
    })
  }
}
输出怎么是undefined?
      14 回复
    
    bind 进去就好了
fs.exists(path[i], function(exists) {
  if (exists) {
    console.info('get path inside’, this.path);
  } else {
    console.error(‘path not exists’);
  }
}.bind({ path:path[i] }) );
JavaSript可以使用调用这个闭包函数时的Context中的变量。否则,闭包中引用了path[i],如果path === undefined,会报错的。
你的示例代码中出现的这种现象,归根结底是因为把循环和异步调用函数结合在一起使用。由于fs.exists()是一个异步函数,所以它只会在真正被调用时再去查看Context中的变量取值。此时,循环已经执行完毕,变量的取值分别是i = 3; path[3] = undefined;。因此,返回一个path not existed就是理所当然。
- 验证i = 3
// 验证循环与异步函数一起使用时的context
var fs = require('fs');
var paths=['c:/', 'd:/', ''];
for (var i = 0; i < paths.length; i++) {
    if (paths[i].length > 0) {
                
        fs.exists(paths[i], function(exists) {
            if (exists) {
                console.info('get path inside', paths[i], i);
                
            } else {
                console.error('path not exists', i);
            }
        });
    }
}
- 解决方法:使用Array.map()取代for循环
var fs = require('fs');
var paths=['c:/', 'd:/', ''];
paths.map(function(dest) {
    fs.exists(dest, function(exists) {
        console.log(dest, exists);
    });
});
- 如果目标对象不是一个数组,没法使用Array.map(),可以用Async等模块控制调用异步函数的流程。
很明显这里形成了一个闭包,由于回调函数是异步的,在执行回调函数时其所在的上层作用域已经执行完退出了,但是由于闭包的原因,回调函数仍然引用了上层作用域 的变量对象,但此时变量的值已经改变,在这里就是i=3,所以输出undefined,此时我们可以在循环内部开辟一个执行作用域,把包含回调函数的方法放入这个作用域中,,这样就进行了作用域隔离,可以避免这个问题,因此可以这样修改:
var fs=require('fs');
var path=['c:/', 'd:/', ''];
for (var i = 0; i < path.length; i++) {
    if (path[i].length > 0) {
        // 可以得到值
        console.info(path[i]);
        (function(i){
            fs.exists(path[i], function(exists) {
                if (exists) {
                console.info('get path inside', path[i]);
                } else {
                console.error('path not exists');
                }
            });
        })(i);
    }
} 
       
       
       
       
       
    