【问题标题】:Using a Function with a Parameter inside a forEach Loop在 forEach 循环中使用带有参数的函数
【发布时间】:2018-03-14 20:15:30
【问题描述】:

为了使我的代码更简洁,我决定采用我经常使用的 if/else 语句并将其转换为函数。我尝试将此函数应用于 forEach 循环,但是,我收到一个错误,即函数的参数未定义。

代码如下:

var addClass = (className) => {
    (this.classList.contains(className) === true)
        ? this.classList.remove('active') & this.classList.add(className)
        : this.classList.add(className);
}

exploreStory_buttons.forEach(el => el.addEventListener('mouseover'), addClass(active));

任何对我做错了什么的见解将不胜感激。像往常一样,我觉得解决方案可能很简单:我只是没有看到它。

【问题讨论】:

  • addClass(active) : active 是一个未定义的变量,因此您传递给函数的参数是未定义的。应该是"active"
  • @JeremyThille 我实际上曾尝试在参数括号中的 active 周围加上引号,但没有成功。
  • BTW & 是一个按位运算符,您可能指的是 && 用于短路操作。此外,如果它已经存在,为什么还要添加相同的类..?

标签: javascript function foreach


【解决方案1】:

您想在适当的上下文中调用该函数。为此目的有Function#call。您还需要使用普通函数,因为“胖箭头”函数处理 this 的方式不同。

var addClass = function (className) {
    if (this.classList.contains(className)) {
        this.classList.remove('active');
        this.classList.add(className);
    } else {
        this.classList.add(className);
    }
}

exploreStory_buttons.forEach(el => {
    el.addEventListener('mouseover'); // where is the event listener??
    addClass.call(this, active);   // N.B. active is undefined here. Do you mean "active"?
});

您也不想滥用语言功能来编写“智能”代码。对多个语句使用 if/else 和多行,你不是代码混淆器。


假设您要添加“悬停”行为,代码将如下所示:

function addClass(className) {
    return function () {
        this.classList.add(className);
    }
}
function removeClass(className) {
    return function () {
        this.classList.remove(className);
    }
}

var activate = addClass('active');
var deactivate = removeClass('active');

exploreStory_buttons.forEach(el => {
    el.addEventListener('mouseenter', activate);
    el.addEventListener('mouseleave', deactivate);
});

注意addClassremoveClass 如何返回可用作事件处理程序的函数。将它们存储到 activatedeactivate 变量中意味着您不会在循环内创建函数的多个等效副本,而是实际上将相同的函数分配给所有元素。


通过实现hover() 函数可以避免activate/deactivate 变量和函数返回函数(jQuery 有一个similar feature):

function hover(elements, onenter, onleave) {
    elements.forEach(el => {
        el.addEventListener('mouseenter', onenter);
        el.addEventListener('mouseleave', onleave);
    });
}

hover(exploreStory_buttons, function () {
    this.addClass('active');
}, function () {
    this.removeClass('active');
});

这里的事件处理函数只在需要的地方直接创建一次。比将它们存储在辅助变量中要好得多。

【讨论】:

  • 感谢您的建议和推荐。 '代码混淆器'是相当讽刺的大声笑。但是,我尝试实现您的解决方案,并且收到 addEventListener 未能在事件目标上执行的错误消息:需要 2 个参数,但只存在一个。到目前为止,我对这意味着什么感到非常困惑
  • 这就是我的评论 // where is the event listener?? 的意思。也请阅读我的其余答案。
  • 哇,这有点绕我的头,但我肯定会尽我所能将我对此的理解实现到我的代码中。这些绝对是我以前没有遇到过的一些概念。我想问一下:您在提供的示例中从函数中删除了 if 语句。这仅仅是因为在您的实现中不需要它们吗?或者您只是因为不需要分享您的观点而没有添加它们?
  • 不需要它们。我相信classList.addclassList.remove 足够聪明,可以自己进行classList.contains 检查。自己做检查意味着它最终会被做两次。
  • 我实现了您的第三个代码 sn-p 示例并且它有效:尽管我确实必须将这些逗号换成分号。再次感谢您的代码和解释。我觉得如果我能够牢牢掌握你分享的概念,我一定会成为一个更好的开发者。再次感谢!
【解决方案2】:

您的代码有几个问题:

  1. 我假设您想在mouseover 上将元素的类更改为活动。在这种情况下,addClass 函数必须返回另一个函数,但是是常规函数,而不是粗箭头,因此可以正确绑定。
  2. 你真的想要在这一行上按位与吗:

    this.classList.remove('active') & this.classList.add(className)

还是逻辑与?

exploreStory_buttons = document.getElementsByClassName('explore-story');
var addClass = (className) => function() {
    this.classList.contains(className)
        ? (this.classList.remove('active') && this.classList.add(className))
        : this.classList.add(className);
}


Array.prototype.forEach.call(exploreStory_buttons, (el) => el.addEventListener('mouseover', addClass.call(el, 'active')));
.active {
  color: red
}
<button class="explore-story active">Story 1</button>
<button class="explore-story">Story 2</button>

【讨论】:

  • 哦,哇,我肯定打算使用函数式并且肯定:如果你没有向我指出,我永远不会发现这个错误。非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-15
  • 2019-02-12
相关资源
最近更新 更多