回答

收藏

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

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

    4 O$ K$ i( e8 l; T5 @4 j6 C; s
  • var funcs = ;// let's create 3 functionsfor (var i = 0; i 输出此:9 E% l/ n0 _5 P- x
  • My value: 3
      W2 O: q0 T$ b5 v1 R, K& I
  • My value: 3
    # ]; W. Z2 M( v( a3 e
  • My value: 3
    8 `7 \- m8 c8 S( H
  • 而且我希望它输出:
      u, i# j& `5 D$ d& \* D, P+ r, R
  • My value: 0
    " w. Y* S( {: J. F/ p! H' n6 \
  • My value: 1
    5 o# I4 o8 F- a4 V
  • My value: 2# m# @0 b4 W, r8 P9 P  Z: |
  • 当使用事件监听器导致函数运行延迟时,也会出现同样的问题:
    & Q9 I+ Z' [0 Q3 }* U4 D. i* v
  • [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));}$ }- k4 y0 |8 G: F6 {
在for in和for of循环也很明显:) U/ Y3 m, U1 [5 Q0 J; I
[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]这个基本问题的解决方案是什么?
- W. i* D) ?8 q; F9 u                                                               
1 ?# k7 Y, P) n2 j! p! A# F' E    解决方案:                                                               
+ n, b; S! d$ B                                                                问题是i每个匿名函数中的变量都与函数外的相同变量绑定。
6 \1 \# r  X" c( `( w' ~ES解决方案: letECMAScript 6 (ES6) 引入了不同于基于变量的新关键词let和const关键字var。例如,在有let在基于索引的循环中,循环中的每个迭代都会有一个i具有循环范围的新变量,因此您的代码将按预期工作。: @8 w4 N& @5 H, q- y) q' z$ F
[code]for (let i = 0; i 但请注意,Edge 14 前的 IE9-IE11 和 Edge 支持let但是会出现上述错误(他们不会i每次创建一个新的函数,所以上述所有函数都会像我们使用的 一样记录 3 var)。Edge 14 终于做到了。7 R1 L# K" m: p) v0 k& W7 I
ES5.1 解决方案:forEach随着该Array.prototype.forEach函数的可用性相对较广(2015 年),值得注意的是,在主要涉及值数组迭代的情况下,.forEach()为每次迭代获得不同的封闭包提供了一种干净自然的方法。也就是说,假设你有一定的包含值(DOM 引用、对象等。)数组,并且设置在每个元素中,您可以这样做:
* Y. E/ }3 o8 ?[code]var someArray = [ /* whatever */ ...someArray.forEach(function(arrayElement) {  / ... code code code for this one element  someAsynchronousFunction(arrayElement,function()      arrayElement.doSomething(); );code]这个想法是和的.forEach循环回调函数的每次调用都将是其自身的封闭包。传递给处理程序的参数是特定于迭代特定步骤的数组元素。如果在异步回调中使用,则不会与迭代其他步骤中建立的任何其他回调发生冲突。
1 D9 N. P+ y5 ^' y+ _- x1 k若碰巧使用 jQuery,该$.each()函数为您提供类似的功能。
; e3 S& U7 W% T. L经典解决方案:闭包您要做的是将每个函数中的变量绑定到函数外的一个单独的、不变的值:
7 k' I/ L$ j/ \& v  l% M7 B[code]var funcs = [];function createfunc(i) {  return function()      console.log("My value: "   i);  };}for (var i = 0; i Run code snippetHide results
& p& @9 y. j2 c% o7 c" w6 QFull page8 S1 S' `, ]" L& ]
由于 JavaScript 中没有块作用域-只有函数作用域-通过在新函数中创建和包装函数,您可以确保i如你所愿。
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则