JS 中一个理解闭包的很好的例子

前言

今天刷红宝书看到了闭包,凭着再掘金摸爬滚打几个月的经历,一路踏过正则,原型,对象继承,终于还是在这里卡壳了。

注:

本文参考自Javascript高级编程及思否提问死否文章

例子

关于闭包有个很典型的例子:

function createFunctions() {
  var result = new Array();
  for (var i = 0; i < 10; i++) {
    result[i] = function() {
      return i;
    };
  }
  return result;
}

let a = createFunctions();
console.log(a[0]());

这要按照我们所想,肯定打印的是0,然而答案是不管打印第几个,这个函数数组的结果都是10。

解释

上面贴的第一个链接,回答中有这么精彩的一段:

函数1作用域
for(var i = 0; i < 10; i++) { 函数1作用域
        我在函数1作用域中
        result[i] = function() { 函数2作用域
          我在函数2作用域中
          return i;
        };
}
函数1作用域
console.log(i); 毫无疑问,执行到这里的时候,i是10,既然这里是10
                那么在函数2作用域中访问i也是10也就不足为奇了
                因为函数2作用域中没有,向上去函数1作用域中找
                

因此,可以看出,这个闭包主要有两个作用域,作用域2因为没有i的存在,自然只能去1中寻找,自然只能是10了,因为闭包运行时i在作用域1中即为10.

引申

这里主要提到了两种帮助我们加深理解的方式:

1作用域
for(let i = 0; i < 10; i++) {2作用域
    我在块2作用域中
    console.log(i); // 毫无疑问,这里的i从0依次增加到10  
    result[i] = function() {3作用域
      我在块3作用域中
      return i;
    };
}1作用域

为什么把var换成let,得到的函数数组的索引就不都是10了呢?我们都知道let可以创建块级作用域,因此每次for循环,都是一个新的块级作用域,而这个作用域与全局的作用域并不是同一个,自然就可以打印出1-10了。

同时我们可以创建另一个匿名函数强制让闭包的行为符合预期:

function createFunctions() {
  var result = new Array();
  for (var i = 0; i < 10; i++) {
    result[i] = (function(num) {
      return function() {
        return num;
      };
    })(i);
  }
  return result;
}

let a = createFunctions();
console.log(a[0]());

这里我们没有把闭包赋值给数组,而是定义了一个匿名函数,讲立即执行该匿名函数的结果赋给数组,同时这个匿名函数有个参数num,即最后要返回的值,在调用每个匿名函数时,我们传入了i,使得每个函数都有自己的i的copy。

当然还有别的方式:

function createFunctions() {
  var result = new Array();
  for (var i = 0; i < 10; i++) {
    result[i] = (function(num) {
      return i;
    })();
  }
  return result;
}

let a = createFunctions();
console.log(a);

多省心。

手动狗头~

发布了346 篇原创文章 · 获赞 330 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_43870742/article/details/103941743