如何在subscribe()作用域内获取代码片段中的counter变量值?
关于在subscribe作用域内获取变量值的解决方案
嘿,我来帮你搞定这两个问题!
问题1:如何在subscribe的作用域内获取变量值?
核心要解决的是闭包作用域陷阱——因为subscribe的回调通常是异步触发的(比如用户点击事件、异步请求完成),如果直接引用外部循环或全局的变量,很可能拿到的是变量被修改后的最终值,而非触发时的当前值。常用的解决思路有这些:
- 用ES6的
let/const创建块级作用域,捕获变量的当前值 - 改用
forEach这类自带回调作用域的迭代方式 - 用立即执行函数(IIFE)为每个回调创建独立的作用域
问题2:你的代码片段中如何在subscribe()里获取正确的counter值?
先分析你代码里的问题:你的counter在循环中持续递增,但subscribe是在用户点击标记时才会执行。当点击发生时,循环早已经跑完了,counter已经变成了this.pois的总长度,所以此时调用that.goToSlide(counter)传的肯定不是你想要的对应标记的索引值。
给你几个简单有效的修改方案:
方案1:用let捕获当前counter值
在addMarker的then回调外部,先把当前的counter值存到一个块级变量里,这样subscribe的回调就能捕获到这个固定值:
let counter: number = 0; for(let poi of this.pois) { let coord = poi.LocationCoordinates.replace(' ', '').split(','); let that = this; // 捕获当前循环的counter值 let currentCounter = counter; this.map.addMarker({ icon: 'marker.png', animation: 'DROP', position: { lat: coord[0], lng: coord[1] } }).then(marker => { console.log(currentCounter); marker.on(GoogleMapsEvent.MARKER_CLICK).subscribe(() => { that.goToSlide(currentCounter); }); counter++; }); }
方案2:改用forEach循环(更简洁)
forEach的回调函数自带独立作用域,第二个参数就是当前元素的索引,完美避开闭包陷阱:
this.pois.forEach((poi, counter) => { let coord = poi.LocationCoordinates.replace(' ', '').split(','); let that = this; this.map.addMarker({ icon: 'marker.png', animation: 'DROP', position: { lat: coord[0], lng: coord[1] } }).then(marker => { console.log(counter); marker.on(GoogleMapsEvent.MARKER_CLICK).subscribe(() => { that.goToSlide(counter); }); }); });
这个方案不需要额外维护counter变量,代码更清爽,推荐用这个!
方案3:立即执行函数(ES5兼容写法)
如果需要兼容ES5环境,可以用立即执行函数创建独立作用域,把当前的counter值传进去:
let counter: number = 0; for(let poi of this.pois) { let coord = poi.LocationCoordinates.replace(' ', '').split(','); let that = this; this.map.addMarker({ icon: 'marker.png', animation: 'DROP', position: { lat: coord[0], lng: coord[1] } }).then((function(currentCounter) { return function(marker) { console.log(currentCounter); marker.on(GoogleMapsEvent.MARKER_CLICK).subscribe(() => { that.goToSlide(currentCounter); }); counter++; } })(counter)); }
不过这个写法相对繁琐,现在ES6普及后,前两种方案更合适。
内容的提问来源于stack exchange,提问作者Ruben Miquelino
相关产品推荐
相关产品推荐

