闭包与let

什么是闭包❓

闭包(closure)是指有权访问其他函数作用域中变量的函数—— JavaScript 高级程序设计

  首先,闭包是一个函数,其次,它能够访问其他函数作用域中的变量。

来看下面的例子
var data = []
for (var i = 0; i < 3; i++) {
  data[i] = function () {
    console.log(i)
  }
}
// 期望输出 0 1 2,实际是 3 3 3
data[0]()
data[1]()
data[2]()

  上面的代码之所以没有产生预期的效果,是因为 i 是一个全局变量,当程序执行到 data[0]() data[1]() data[2]() 时他们引用的都是同一个变量 i,此时循环已经结束,i 最终的值为3。

为了使程序产生预期的效果,我们可以这么做
var data = []
for (var i = 0; i < 3; i++) {
  (function (i) { // ❗注意,这个 i 是形参,是这个立即执行函数的内部变量,实际上可以任意命名
    data[i] = function () { // 变量的查找同样遵循就近原则,里面的 i 指的是形参 i
      console.log(i)
    }
  }(i)) // ❗注意,这个 i 是实参,是 for 循环中的 i
}
data[0]() // 0
data[1]() // 1
data[2]() // 2

  上面的代码中,我们将每次循环的 i 以参数形式传递给立即执行函数,然后在立即执行函数内部定义 data[i]函数。

  按照之前对闭包的定义,data[0] data[1] data[2] 都是闭包,他们能够访问立即执行函数内部的形参 i。在其他一些程序设计语言中,上面的代码看起来是不正常的,因为函数执行完毕后,这个函数作用域内的变量就会被释放,这些变量应该只在函数运行时有效才对。但是在 JavaScript 中,函数会形成闭包,当有其他函数引用了这个函数作用域内的变量时,在这个函数执行完毕后,被引用的变量不会被释放。

在这个例子中,要达到预期的效果还有一种更优雅的方式?
var data = []
for (let i = 0; i < 3; i++) { // 仅仅将 var 替换为了 let
  data[i] = function () {
    console.log(i)
  }
}
data[0]() // 0
data[1]() // 1
data[2]() // 2
详解

  MDN 对闭包的定义是

闭包是函数和声明该函数的词法环境的组合。这个环境包含了这个闭包创建时所能访问的所有局部变量

  在 ES6 之前,JavaScript 并没有块级作用域的概念,只有 全局作用域函数作用域。任何不是定义在函数内部的变量,都是一个全局变量,可以在全局内访问。

  ES6 提出了块级作用域的概念,if{} 内,for 循环内等都是一个块级作用域,但是❗注意,函数内部不是块级作用域,它依然叫函数作用域。因为块级作用域对 var 关键字声明的变量不起作用,而函数作用域对 var 变量有约束作用,配合块级作用域使用的是 ES6 提出的新的关键字 letconst

   let 关键字声明的变量只在当前作用域(既包含块级作用域也包含函数作用域)内有效,所以在 for 循环内定义的 let 变量就有了和函数内部的变量类似的特性。

  在浏览器的调试工具中可以证实上面的说法

使用闭包实现预期效果

使用 let 块级作用域实现预期效果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值