英文:
How to properly use and understand the call() method while using forEach() method
问题
Four months into javascript, and I ran into the following code that I can't put in terms of the techniques that I understand. I was hoping that someone could refactor this code not in order to satisfy what its purpose is, but to put it in terms that I would understand. Perhaps just explaining how the forEach() works with call(). I understand them separately but not combined.
我学习 JavaScript 四个月了,遇到了下面的代码,我无法用我理解的技术术语来解释它。我希望有人能重构这段代码,不是为了满足它的目的,而是为了用我能理解的方式来表达它。也许只是解释 forEach() 如何与 call() 结合使用。我单独理解它们,但结合起来理解起来有困难。
I have tried to rewrite it without the forEach and call but that defeats my purpose. I can implement this functionality without these two, but it sure makes the code succinct with them.
我尝试过不使用 forEach 和 call 来重写它,但这违背了我的目的。我可以在没有这两个的情况下实现这个功能,但使用它们可以使代码更简洁。
let parentElement = document.getElementById("node1");
let array = [];
parentElement.addEventListener("click", (e) => {
var elems = document.querySelectorAll(".active"); // make them all active
array.forEach.call(elems, function(el) {
el.classList.remove("active"); // remove active
});
e.target.className = "active"; // set clicked element to active
});
.active,
.btn:hover {
background-color: #666;
color: white;
}
<div id="node1">
<button class="btn">1</button>
<button class="btn">2</button>
</div>
英文:
Four months into javascript, and I ran into the following code that I can't put in terms of the techniques that I understand. I was hoping that someone could refactor this code not in order to satisfy what its purpose is, but to put it in terms that I would understand. Perhaps just explaining how the forEach() works with call(). I understand them separately but not combined.
I have tried to rewrite it without the forEach and call but that defeats my purpose. I can implement this functionality without these two, but it sure makes the code succinct with them.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
let parentElement = document.getElementById("node1");
let array = [];
parentElement.addEventListener("click", (e) => {
var elems = document.querySelectorAll(".active"); // make them all active
array.forEach.call(elems, function(el) {
el.classList.remove("active"); // remove active
});
e.target.className = "active"; // set clicked element to active
});
<!-- language: lang-css -->
.active,
.btn:hover {
background-color: #666;
color: white;
}
<!-- language: lang-html -->
<div id="node1">
<button class="btn">1</button>
<button class="btn">2</button>
</div>
<!-- end snippet -->
答案1
得分: 2
这段代码模式有点过时。我会解释它的工作原理,然后展示给你一种现代的方法。
var elems = document.querySelectorAll(".active"); // 让它们都处于活动状态
此时elems
的值是一个NodeList,而不是数组。
在过去,无法在NodeList上使用.forEach()
方法。因此,您需要从数组中借用该方法(尽管后来添加了这个方法,但在这个示例中,让我们假设它还不存在)。
Array.forEach.call(elems, function (el) {…});
这行允许您在elems
NodeList上使用Array.forEach()
。您正在执行/调用array.forEach
函数,将elems
作为上下文的“this
”对象。
现代方式
如今,您可以使用for … of
,它允许您遍历可迭代对象,如NodeList、数组和许多其他对象。
for (const el of document.querySelectorAll('.active')) {
el.classList.remove('active');
}
我认为您会发现这种语法更容易阅读和理解。
(顺便说一下,您考虑过在这种情况下使用单选按钮输入是否更合适?您可以将它们样式化,使其看起来像按钮。)
英文:
This code pattern is a bit dated. I'll explain how it works, and then show you a modern method.
var elems = document.querySelectorAll(".active"); // make them all active
The value of elems
at this point is a NodeList. It is not an Array.
Back in the day, you couldn't use .forEach()
on a NodeList. Therefore, you needed to borrow that method from Array. (It was added later, but for this example let's assume it doesn't exist yet.)
array.forEach.call(elems, function (el) {…});
This line allows you to use Array.forEach()
over the elems
NodeList. You're executing/calling the array.forEach
function, with elems
as the "this
" object for context.
The Modern Way
These days, you can use for … of
, which allows you to iterate over iterables like NodeList, Arrays, and many others.
for (const el of document.querySelectorAll('.active')) {
el.classList.remove('active');
}
I think you'll find this syntax easier to read and understand.
(By the way, have you considered that radio button inputs might fit better for your use in this case? You can style them to look like buttons.)
答案2
得分: 1
我们不再需要 Array.call。
另外,var elems = document.querySelectorAll(".active"); // make them all active
并不会使它们全部变为活动状态,而只是选择已激活的元素。
所有现代浏览器都可以在从 querySelectorAll 返回的静态(非动态)NodeList 上使用 .forEach(你需要使用 spread 来使用 map 和 filter,像这样:[...elems].map(el => something(el))
)
以下是更简洁的现代方法来实现你想要的效果 - 注意使用了 classList.toggle 并传递了一个布尔值来在为真时强制添加类:
document.getElementById("node1").addEventListener("click", (e) => {
const tgt = e.target;
document.querySelectorAll(".btn")
.forEach(el => el.classList.toggle("active", el === tgt));
});
.active,
.btn:hover {
background-color: #666;
color: white;
}
<div id="node1">
<button class="btn">1</button>
<button class="btn">2</button>
</div>
英文:
We no longer need Array.call.
Also var elems = document.querySelectorAll(".active"); // make them all active
does not make all active, but just selects the active ones
All modern browsers can do .forEach on the static (not live) NodeList returned from querySelectorAll (you need to spread to use map and filter line this: [...elems].map(el => something(el))
)
Here is the more concise modern way to do want you want - note the classList.toggle with the boolean to force
the class when true
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
document.getElementById("node1").addEventListener("click", (e) => {
const tgt = e.target;
document.querySelectorAll(".btn")
.forEach(el => el.classList.toggle("active",el === tgt));
});
<!-- language: lang-css -->
.active,
.btn:hover {
background-color: #666;
color: white;
}
<!-- language: lang-html -->
<div id="node1">
<button class="btn">1</button>
<button class="btn">2</button>
</div>
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论