循环处理媒体数组时仅能获取首个媒体资源宽高的问题求助
循环处理媒体数组时仅能获取首个媒体资源宽高的问题求助
看起来你碰到了老JavaScript环境里异步回调结合作用域的经典坑!先帮你捋清楚问题根源,再给你适配旧环境的解决办法。
问题原因分析
你写的for循环里,i和每次创建的img变量都属于外层共享的作用域。而img.onload是异步触发的,当它执行的时候,循环早就跑完了——这时候i已经变成了数组的长度,img变量也只会指向最后一次循环创建的图片实例。再加上你两个媒体的src完全相同,浏览器会缓存资源,第二个图片的onload会直接触发,但因为作用域绑定的问题,你没法区分每个回调对应的是哪一次循环的图片,最终就出现了只拿到第一个资源数据的错觉。
适配旧JS环境的解决方案
你可以用**立即执行函数(IIFE)**给每次循环创建独立的作用域,把当前迭代的索引和媒体数据传进去,让每个onload回调都能绑定到自己对应的图片实例上。修改后的代码如下:
var imgSrc = 'fallBack.png'; var imgType = 'photo'; var screenW = document.body.clientWidth; var screenH = document.body.clientHeight; var images = [ {media: { type: "photo", media: "image1.png" }}, {media: { type: "photo", media: "image1.png" }} ]; for (var i = 0; i < images.length; i++) { // 用IIFE创建独立作用域,保存当前迭代的索引和媒体项 (function(currentIndex, currentMedia) { var img = new Image(); img.onload = function() { console.log(this); // 现在每个图片的onload都会打印对应的实例 // 你的业务逻辑可以在这里正常执行 if(this.width < this.height && screenW < screenH) { imgSrc = this.src; imgType = "photo"; // 建议:如果要给每个媒体项单独存储宽高,直接给对象加属性更合理 // currentMedia.media.width = this.width; // currentMedia.media.height = this.height; } }; // 必须设置src才能触发onload,别漏了这一步 img.src = currentMedia.media.media; })(i, images[i]); }
额外说明
- 立即执行函数的作用是每次循环都生成一个独立作用域,把当前的
i和currentMedia“固定”下来,避免后续循环覆盖变量导致回调拿错数据。 - 如果你想保留每个媒体的宽高信息,不要只覆盖全局的
imgSrc和imgType,直接给数组里的媒体对象添加width/height属性会更实用,这样每个资源的信息都能单独存储。
备注:内容来源于stack exchange,提问作者Joe
相关产品推荐
相关产品推荐

