为什么是FileReader ?带有自执行函数的Onload处理程序集

Why is FileReader.onload handler set with a self executing function

本文关键字:函数 Onload 处理 程序集 执行 FileReader 为什么      更新时间:2023-09-26

使用web应用程序中的文件遵循代码MDN:

function handleFiles(files) {
  for (var i = 0; i < files.length; i++) {
    var file = files[i];
    var imageType = /image.*/;
    if (!file.type.match(imageType)) {
      continue;
    }
    var img = document.createElement("img");
    img.classList.add("obj");
    img.file = file;
    preview.appendChild(img); // Assuming that "preview" is a the div output where the content will be displayed.
    var reader = new FileReader();
    reader.onload = (function(aImg) { return function(e) { aImg.src = e.target.result; }; })(img);
    reader.readAsDataURL(file);
  }
}

聚焦这一行:

reader.onload = (function(aImg) { return function(e) { aImg.src = e.target.result; }; })(img);

自执行函数背后的原因是什么?我理解img被传递给函数并在返回函数的方法中使用,但是为什么他们不像这样引用它:

reader.onload = function(e) { img.src = e.target.result; };

for循环中没有特殊的作用域,因此在循环中声明变量将在每次迭代时覆盖变量,因此

for (var i = 0; i < 10; i++) {
    var img = document.createElement("img");
    setTimeout(function() {
        console.log(img);
    }, 100);
}

将只记录最后一个映像,记录10次。

同样的setTimeout是异步的,reader.onload也是异步的,它在稍后的时间执行回调,所以因为img变量在循环中定义不正确,需要一个闭包来创建一个新的作用域来锁定img的值,它也可以被写为

(function(aImg) {
    reader.onload = function() {
        aImg.src = e.target.result;
    }
})(img);

有人决定聪明一点,写一个IIFE,在每次迭代中锁定img的值,并返回一个函数。

换句话说,如果它们只是在没有IIFE的情况下引用它,它们最终只会得到最后一个img,因为for循环会在每次迭代中完成并覆盖img变量,并且onload函数稍后执行,当循环完成并且img只保存最后一个值集时。