两个的函数的区别谁能说下
发布于 10 年前 作者 lianxuan 3643 次浏览 最后一次编辑是 8 年前
var fs = require('fs');
var files = ['a.txt', 'b.txt', 'c.txt'];
for (var i = 0; i < files.length; i++) {
  fs.readFile(files[i], 'utf-8', function(err, contents) {
    console.log(files);
    console.log(i);
    console.log(files[i]);
  });
}

var fs = require('fs');
var files = ['a.txt', 'b.txt', 'c.txt'];
for (var i = 0; i < files.length; i++) {
  (function(i) {
    fs.readFile(files[i], 'utf-8', function(err, contents) {
      console.log(files[i] + ': ' + contents);
    });
  })(i);
}```
书上说第一个是模块的的 `readFile` 中的回调函数一直是一个实例,第二个则是用了闭包,就创建三个实例,感觉不是很明白,麻烦解答下
7 回复

楼主代码没标记没格式化… 帮楼主做了. 两个回调函数区别在对作用域外部的变量的引用上边… 第一个函数里 i 使用了同一个外部的 i, 第二个回调里每次拷贝一个 i 到函数里. 运行的结果不同… 但不明白为什么这东西被叫做"实例"…

两段代码的运行结果是不一致的,这个在js中是很常见的代码。运用闭包保证当前运行环境,个人是这么理解的,这是解释性语言的原因?代码执行不进行预编译。需要通过闭包来确定当前内部状态? 求大神指教- -

谢谢楼上的解答,关于实例的问题我也是从书上看到的

用面向对象来解释: for (var i = 0; i < files.length; i++) { fs.readFile(…, function(err, contents) { console.log(i); }); } 相当于,在执行环境中,this.i = 0; for 运行了3次循环, this.i = 0; this.i = 1; this.i=2; 当最后异步回调的时候会去取用this.i === 2;

for (var i = 0; i < files.length; i++) { (function(i) { fs.readFile(…, function(err, contents) { console.log(files[i] + ': ’ + contents); }); })(i); } 相当于,在执行环境中,this.i = 0; for 运行了3次循环, this.i = 0; this.i = 1; this.i=2; 但是, 在每次循环, 使用function () {} () 创建一个匿名的“对象”, 并使匿名对象的属性i 赋值为外部的i. 每个匿名“对象”的异步回调函数在匿名“对象”内的执行环境中,访问匿名“对象”的i.

关键是内存占用. for 中的i只是一个内存位置. 当function () {} () 会在内部启动一个内存占用. (每个循环会生成一个内存占用)

关于内存占用的回收: 当所处的函数环境不再对变量有引用的时候, 内存会被回收.

第一种情况你console的都是循环后的结果,因为是异步的,里面的i是无法同步访问的,所以你每次打印的i的值都是最后一次i的值。 第二种情况就是为了解决第一种情况用了function闭包,把i的值保存下来了没有被gc回收,所以可以打印每次i不同的值

提一个另外的话题,建议写法:

var fs = require('fs');
var files = ['a.txt', 'b.txt', 'c.txt'];

files.forEach(read);
function read(filename) {
  fs.readFile(filename, 'utf8', function (err, content) {
    if (err) return console.errror(err.stack);
    console.log(content);
  });
}

很多 callback hell 是可以通过提取函数来解决的。另外,array 的 forEach, map, reduce, filter 这些方法也还是挺好用的。

其实写一句 var item = files[i],再把item传到异步的函数里就行了。

回到顶部