回答

收藏

循环内的 JavaScript 闭包——简单实用的示例

技术问答 技术问答 328 人阅读 | 0 人回复 | 2023-09-12


    / M# c4 N# W% J7 }
  • var funcs = ;// let's create 3 functionsfor (var i = 0; i 输出此:. x2 E" P+ P6 k& s* d9 E
  • My value: 3
    8 q* N+ i$ N9 L! x0 D) m
  • My value: 3
    . |! F  J9 `4 e5 C
  • My value: 3
    ( w2 t3 l; i. i
  • 而且我希望它输出:0 u' p0 e, ?' O; d+ s5 F8 ?
  • My value: 09 k7 G# ?) q; G' d( l
  • My value: 1. O9 k0 P/ I/ F; V) X+ w' u
  • My value: 2; H. `9 ^7 ]" Y3 g  \
  • 当函数运行延迟是由使用事件监听器引起时,也会出现同样的问题:
    # s! I+ \! ]6 d. i+ [
  • [code]var buttons = document.getElementsByTagName("button");// let's create 3 functionsfor (var i = 0; i … 或异步代码,如使用 Promises:[code]// Some async wait functionconst wait = (ms) => new Promise((resolve,reject) => setTimeout(resolve,ms));for (var i = 0; i  console.log(i));}
    : ]2 a! r  A$ W" A' r
在for in和for of循环也很明显:% g0 j9 W6 j* p" G" _3 K
[code]const arr = [1,2,3];const fns = [];for(var i in arr){  fns.push(() => console.log(`index: ${i}`));}for(var v of arr){  fns.push(() => console.log(`value: ${v}`));}for(var f of fns){  f()code]这个基本问题的解决方案是什么?
; [& g$ A: |" N                                                               
) Y. W- a* I# [( \4 X    解决方案:                                                                ( S" Y  U8 M+ x* j  f- D: i
                                                                问题是i每个匿名函数中的变量都与函数外的相同变量绑定。1 G: n: r: m  M& C; A: L* S: i/ L
ES解决方案: letECMAScript 6 (ES6) 引入新的let和const关键字,它们的作用域和var基于 - 的变量不同。例如,在有let-based 在索引循环中,每次迭代都会有一个具有循环范围的新变量i,因此,您的代码将按预期工作。有很多资源,但我建议2ality 块范围帖作为良好的信息来源。- @! y" x6 P1 ?6 R$ h- c4 o* J
[code]for (let i = 0; i 但请注意,IE9-IE11 和 Edge 14 前的 Edge 支持let但是会出现上述错误(他们不会i每次都会创建新函数,所以上述所有函数都会像我们用 3 一样记录 3 var)。Edge 14 终于做对了。
3 y( |. X9 D% z9 Q" |' e2 o+ C3 {ES5.1 解决方案:forEach随着Array.prototype.forEach函数相对广泛的可用性(2015年 ),值得注意的是,在主要涉及迭代一组值的情况下,.forEach()它为每次迭代提供了一种干净自然的方式来获得不同的封闭包。也就是说,假设你有一定的包含值(DOM 引用、对象等)的数组,并且出现了为每个元素设置特定回调的问题,您可以这样做:0 X3 F) r; x* ]5 A+ {
[code]var someArray = [ /* whatever */ ...someArray.forEach(function(arrayElement) {  / ... code code code for this one element  someAsynchronousFunction(arrayElement,function()      arrayElement.doSomething(); );code]这个想法是每次调用回调函数与循环一起使用的回调函数.forEach将是它自己的封闭包。传递给处理程序的参数是特定于迭代特定步骤的数组元素。如果在异步回调中使用,则不会与迭代其他步骤中建立的任何其他回调发生冲突。# }& w2 b% r2 |0 l; U3 _0 [. A
若碰巧在 jQuery 工作,这个$.each()函数会给你类似的能力。! e7 C) X1 o+ @% l/ g! g; O1 M
经典解决方案:闭包您要做的是将每个函数中的变量绑定到函数外的一个单独的、不变的值:
$ j: E% y; P, s% _: b' L8 Z[code]var funcs = [];function createfunc(i) {  return function()      console.log("My value: "   i);  };}for (var i = 0; i 由于 JavaScript 中没有块作用域-只有函数作用域-通过在新函数中创建和包装函数,您可以确保 “i” 保持你的期望。
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则