如何将for循环变量i传入Firestore订阅函数?
如何在Firestore异步订阅中传递for循环的变量i?
你遇到的这个问题是典型的变量作用域陷阱——因为你用了var声明循环变量i,它的作用域是整个函数而非当前循环块。等异步的subscribe回调执行时,循环早就跑完了,i已经变成了maxLength的值,所以日志里的数字永远是最后那个结果。下面给你几种实用的解决办法:
方案1:把var换成let(ES6+推荐)
这是最简单的解决方案,let是块级作用域,每次循环迭代都会创建一个新的i绑定,回调里捕获的就是当前循环的那个i值,代码改动极小:
for (let i = 0; i < maxLength; i++) { let something = firebase.firestore().collection('someCollection').doc(this.someArray[i]); let something$ = Observable.create(something.onSnapshot.bind(something)); let something$Subscription = something$.subscribe ({ next: (snapshot: firebase.firestore.DocumentSnapshot) => { console.log('inserted' + i) // 现在这里的i就是当前循环的正确值了 }, error: (firestoreError: firebase.firestore.FirestoreError) => { console.log(firestoreError); } }); }
方案2:用立即执行函数(IIFE)捕获i值(兼容旧环境)
如果你的项目需要兼容不支持ES6的旧环境,可以用立即执行函数把每次循环的i封装到独立的作用域里:
for (var i = 0; i < maxLength; i++) { // 用IIFE把当前的i值传入,创建独立作用域 (function(currentI) { let something = firebase.firestore().collection('someCollection').doc(this.someArray[currentI]); let something$ = Observable.create(something.onSnapshot.bind(something)); let something$Subscription = something$.subscribe ({ next: (snapshot: firebase.firestore.DocumentSnapshot) => { console.log('inserted' + currentI) // 使用捕获到的currentI }, error: (firestoreError: firebase.firestore.FirestoreError) => { console.log(firestoreError); } }); })(i); }
方案3:提前保存当前循环的i值到闭包中
你也可以在循环内部先把当前的i赋值给一个局部变量,让回调捕获这个变量,效果和用let类似:
for (var i = 0; i < maxLength; i++) { const currentI = i; // 保存当前i的值到块级变量 let something = firebase.firestore().collection('someCollection').doc(this.someArray[currentI]); let something$ = Observable.create(something.onSnapshot.bind(something)); let something$Subscription = something$.subscribe ({ next: (snapshot: firebase.firestore.DocumentSnapshot) => { console.log('inserted' + currentI) // 使用保存的currentI }, error: (firestoreError: firebase.firestore.FirestoreError) => { console.log(firestoreError); } }); }
优先推荐方案1,因为现在ES6+已经是前端开发的标配,代码最简洁直观,也符合现代JavaScript的语法规范。
内容的提问来源于stack exchange,提问作者BOOnZ
相关产品推荐
相关产品推荐

