【问题标题】:ForEach function with event listener带有事件监听器的 ForEach 函数
【发布时间】:2016-02-05 18:29:39
【问题描述】:

我试图在我的代码中减少重复次数。在我的一些包含许多元素的代码中,我觉得我做的太多了。是时候学习如何减少代码并遵循 DRY 技术了。

下面的代码是我当前如何将 eventListeners 附加到我的元素。

var at1, at2 ,at3 ,at4 ,at5 ,at6 , at7, at8,

at1 = UI.byId("at1");
at1.addEventListener("click", UI.at1Func, false);

at2 = UI.byId("at2");
at2.addEventListener("click", UI.at2Func, false);

at3 = UI.byId("at3");
at3.addEventListener("click", UI.at3Func, false);

at4 = UI.byId("at4");
at4.addEventListener("click", UI.at4Func, false);

at5 = UI.byId("at5");
at5.addEventListener("click", UI.at5Func, false);

at6 = UI.byId("at6");
at6.addEventListener("click", UI.at6Func, false);

at7 = UI.byId("at7");
at7.addEventListener("click", UI.at7Func, false);

at8 = UI.byId("at8");
at8.addEventListener("click", UI.at8Func, false);

我一直在尝试使用 forEach 循环。但我遇到了功能问题。对于初学者来说,该功能似乎被抢先触发。而且因为我希望我的主要负载能够反映任何变化,所以它会创建无限循环并崩溃。我正在使用 VS2015,我尝试使用没有任何库的普通 JS 编写...请不要使用 jquery。

这是我在 forEach 循环中的尝试:请参阅底部的编辑。

var ats = ['at1', 'at2', 'at3', 'at4', 'at5', 'at6', 'at7', 'at8'];
        ats.forEach(function (key) {
            var ele = UI.byId(key);
            ele.addEventListener("click", UI.atFunc(key), false);
        });

该函数在我的“UI.myLoad”代码块中。这是 UI.atFunc(key)...

atFunc: function (key) {
    var value = localStorage.getItem(key);
        localStorage.setItem(key, value++);
        console.log(key);
        //UI.myLoad(); //commented out to prevent crashing for now.
    },

预期的行为是,当单击任何键时,应将 1 个整数的值添加到其在本地存储中的透视项目中,并且 UI.myLoad 仅加载应用程序上的主要主题、值和超时。但是因为我的 forLoop 在那个代码块中,所以它会导致崩溃。我将它移到 UI.myLoad 的范围之外,但它根本不起作用。代码有问题吗?还是我以错误的方式解决这个问题,应该尝试只使用 for 循环?我见过 forEach 正常工作的例子,但我自己做不到。

[编辑:下面的代码是使用公认答案的解决方案,但发现了另一个问题。现在确定了完整的解决方案。]

(function () {
var UI;
UI = {
byId: function (id) {
        return document.getElementById(id);
},
loadBtns: function () {
    var ats = ['at1', 'at2', 'at3', 'at4', 'at5', 'at6', 'at7', 'at8'];
    ats.forEach(function (key) {
        var ele = UI.byId(key);
        ele.addEventListener("click", UI.atFunc(key), false);
    });
},
myLoad: function () {
    //load and refresh elements
    /*
    var at1 = localStorage.getItem("at1");
        if (!at1) {
            spn1.innerText = 0;               
        }
        if (at1) {
            spn1.innerText = at1;
        }
    ....
    */
},
atFunc: function (key) {
        return function() {
            var value = localStorage.getItem(key);
            localStorage.setItem(key, +value + +1);
            UI.myLoad();
            };
    }
}
window.onload = function () {
    UI.myLoad();
    UI.loadBtns();
}
}())

【问题讨论】:

  • 你想给它附加一个函数,而不是立即运行它。从atFunc 返回一个新函数。
  • 我进行了编辑,但函数以指数方式返回

标签: javascript foreach


【解决方案1】:

您的问题源于atFunc。它“被抢先触发”的原因是因为您正在立即调用该函数。

ele.addEventListener("click", UI.atFunc(key), false);

它的作用是运行函数UI.atFunc,然后返回undefined 的值。这基本上将您的上述行转换为:

UI.atFunc(key);
ele.addEventListener("click", undefined, false);

相反,您想要返回一个捕获正确键的函数。由于函数就像 JS 中的任何其他值一样,您可以像这样返回一个:

atFunc: function(key) {
  return function() {
    var value = localStorage.getItem(key);
    ...
  };
}

这样您返回一个新的函数值而不是undefined,并且该函数绑定到点击事件。

【讨论】:

  • 我一定是做错了什么,它仍然会触发多次。我将在上面进行编辑。
  • 我标记了这个答案,因为这是解决最初问题的方法。然而,当我在我的代码中使用这个解决方案(以及另一个答案)时,该函数被以指数方式调用。我通过将事件侦听器移到 myLoad 函数之外并将其单独加载到我的对象中解决了这个问题。
【解决方案2】:

问题在于addEventListener中添加函数的方式。

在第一个代码中,您正确引用了函数

at1.addEventListener("click", UI.at1Func, false);

但是在第二个代码中,你添加了括号,括号立即调用函数并返回结果,即undefined

有很多方法可以解决这个问题,但可能最简单的方法是使用闭包修改 atFunc 函数并返回一个函数

atFunc: function (key) {
    return function() {
        localStorage[key]++;
    }
},

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-15
    • 2020-09-20
    • 1970-01-01
    • 2013-12-20
    • 1970-01-01
    相关资源
    最近更新 更多