gpt4 book ai didi

javascript - 当为循环中的每个元素分配不同的事件监听器时,它们都运行相同的函数,尽管使用了 .bind() 和闭包

转载 作者:行者123 更新时间:2023-11-28 07:01:16 25 4
gpt4 key购买 nike

问题

该项目使用 CreateJS,构建后您可以通过添加 JSON 数据在 Canvas 中创建各种游戏和练习。为了演示这个问题,我将使用“字母板”的示例,您可以单击每个字母的图片来听到它被大声朗读。问题是它们都播放最后一个字母的声音。

创建练习时,将从数据库加载 JSON 数据。它添加了用户指定的所有内容,但是在添加区域时出现了问题。这些是用户定义的坐标、大小以及单击时要执行的操作。它通过循环检查要添加的区域类型(圆形、矩形、隐藏矩形等)、通过 CreateJS 添加它,然后分配一个事件监听器来执行预定义的操作来完成此操作。然而,最终,所有事件监听器都执行相同的操作,即最后一个。但是,我正在使用 .bind() ,并且还尝试在匿名函数中创建闭包,结果相同。

示例

这是一个区域的数据的样子(以字母 A 为例):

{"coords":"25,30,67,55","type":"rectangleHidden","actions":[{"do":"playSound","data":{"asset":{"id":"a","src":"a.mp3"}}}]}

您可以使用 JSON Editor Online 更好地查看这里: Data for A to C

所有资源均已预加载且可访问。加载所有资源后,将构建场景并运行此函数:

p.addAreas = function (areas, event) {
var i = 0,
length = (typeof areas != 'undefined') ? areas.length : 0;

for (; i < length; i++) {
var x = i;
switch (areas[i].type) {
case 'rectangleHidden':
var rectangleHidden = new ui.Rectangle(areas[i].coords, this.STRIKE, this.FILL, this.STROKE_STYLE, false);
rectangleHidden.alpha = 0.01;
this.addChild(rectangleHidden);
rectangleHidden.addEventListener('click', this.doActions.bind(event, areas[i].actions, this));
break;
default :
break;
}
}
}

我省略了开关的不同情况,因为此示例仅使用矩形隐藏。下一个也是如此,我只包含了 playSound。所以addEventListener分配的函数就是这个:

p.doActions = function (actions, scene) {
"use strict";
var i = 0,
length = actions.length;


// cleans up scene
p.cleanUp(scene);

// adds actions in sequence order
for (; i < length; i++) {
var action = actions[i],
data = action.data;

// switch over action
switch (action.do) {
case 'playSound':
var delayTime = Number(data.delay || 0);
var looper = Number(data.loop || 0);
new createjs.Sound.play(data.asset.id, { delay: delayTime, loop: looper });
break;
default:
break;
}
}
}

即使使用了.bind(),在这种情况下,所有字母都会播放声音“c.mp3”,而不是它们各自的声音。我这哪里出错了? eventListener 是否在某处被覆盖?

我尝试过的

我尝试修改添加事件监听器的代码,如下所示:

rectangleHidden.on('click', function (scene, action) {
return scene.doActions.bind(event, action, scene);
}(this, areas[i].actions));

但它仍然产生相同的结果。

我还尝试在另一个项目中创建一个经典的闭包,其中事件监听器使用循环中的 i 值调用此函数:

function saveNumber(value) {
return function () { console.log(value); };
}

在另一个项目中,正如预期的那样,每个列表项在单击时从控制台的数组中写入自己的自己的编号。当我尝试将此函数添加到当前项目中的事件监听器时,它仍然每次都会写出循环的最后一个值,在本例中为 2rectangleHidden.addEventListener('click', saveNumber(i));

它们之间有什么区别?(该函数是在循环外部和 addAreas 表达式外部定义的。)

其他信息

我可以补充一点,this指的是Canvas阶段本身,我最初并没有编写这段代码,我只是想解决这个问题。在我从 createjs-2013.12.12 更新到 createjs-2015.05.21 之前,相同的代码似乎一直在工作,但切换回它并没有任何区别。如果您需要的话请向我询问更多详情!

我已阅读JavaScript closure inside loops – simple practical example ,虽然乍一看似乎可以帮助我,但它并不能完全解决我的问题。在答案中解释了如何使用闭包和 .bind() 来解决问题,但是,我的问题是尽管使用了这些,但还是发生了这种情况。

最佳答案

问题确实出在 CreateJS 和更新到最新版本上。以前的类是通过使用初始化方法来扩展的,后来改为使用 SuperClass_constructor,如解释的 here.

由于旧代码,按钮未正确创建,并导致 .on() 和 .addEventListener() 方法出现问题。该循环一直有效!

关于javascript - 当为循环中的每个元素分配不同的事件监听器时,它们都运行相同的函数,尽管使用了 .bind() 和闭包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32116079/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com