What does [].forEach.call() do in JavaScript?([].forEach.call() 在 JavaScript 中做了什么?)
问题描述
I was looking at some snippets of code, and I found multiple elements calling a function over a node list with a forEach applied to an empty array.
For example I have something like:
[].forEach.call( document.querySelectorAll('a'), function(el) {
// whatever with the current node
});
but I can't understand how it works. Can anyone explain me the behaviour of the empty array in front of the forEach and how the call
works?
[]
is an array.
This array isn't used at all.
It's being put on the page, because using an array gives you access to array prototypes, like .forEach
.
This is just faster than typing Array.prototype.forEach.call(...);
Next, forEach
is a function which takes a function as an input...
[1,2,3].forEach(function (num) { console.log(num); });
...and for each element in this
(where this
is array-like, in that it has a length
and you can access its parts like this[1]
) it will pass three things:
- the element in the array
- the index of the element (third element would pass
2
) - a reference to the array
Lastly, .call
is a prototype which functions have (it's a function which gets called on other functions).
.call
will take its first argument and replace this
inside of the regular function with whatever you passed call
, as the first argument (undefined
or null
will use window
in everyday JS, or will be whatever you passed, if in "strict-mode"). The rest of the arguments will be passed to the original function.
[1, 2, 3].forEach.call(["a", "b", "c"], function (item, i, arr) {
console.log(i + ": " + item);
});
// 0: "a"
// 1: "b"
// 2: "c"
Therefore, you're creating a quick way to call the forEach
function, and you're changing this
from the empty array to a list of all <a>
tags, and for each <a>
in-order, you are calling the function provided.
EDIT
Logical Conclusion / Cleanup
Below, there's a link to an article suggesting that we scrap attempts at functional programming, and stick to manual, inline looping, every time, because this solution is hack-ish and unsightly.
I'd say that while .forEach
is less helpful than its counterparts, .map(transformer)
, .filter(predicate)
, .reduce(combiner, initialValue)
, it still serves purposes when all you really want to do is modify the outside world (not the array), n-times, while having access to either arr[i]
or i
.
So how do we deal with the disparity, as Motto is clearly a talented and knowledgeable guy, and I would like to imagine that I know what I'm doing/where I'm going (now and then... ...other times it's head-first learning)?
The answer is actually quite simple, and something Uncle Bob and Sir Crockford would both facepalm, due to the oversight:
clean it up.
function toArray (arrLike) { // or asArray(), or array(), or *whatever*
return [].slice.call(arrLike);
}
var checked = toArray(checkboxes).filter(isChecked);
checked.forEach(listValues);
Now, if you're questioning whether you need to do this, yourself, the answer may well be no...
This exact thing is done by... ...every(?) library with higher-order features these days.
If you're using lodash or underscore or even jQuery, they're all going to have a way of taking a set of elements, and performing an action n-times.
If you aren't using such a thing, then by all means, write your own.
lib.array = (arrLike, start, end) => [].slice.call(arrLike, start, end);
lib.extend = function (subject) {
var others = lib.array(arguments, 1);
return others.reduce(appendKeys, subject);
};
Update for ES6(ES2015) and Beyond
Not only is a slice( )
/array( )
/etc helper method going to make life easier for people who want to use lists just like they use arrays (as they should), but for the people who have the luxury of operating in ES6+ browsers of the relatively-near future, or of "transpiling" in Babel today, you have language features built in, which make this type of thing unnecessary.
function countArgs (...allArgs) {
return allArgs.length;
}
function logArgs (...allArgs) {
return allArgs.forEach(arg => console.log(arg));
}
function extend (subject, ...others) { /* return ... */ }
var nodeArray = [ ...nodeList1, ...nodeList2 ];
Super-clean, and very useful.
Look up the Rest and Spread operators; try them out at the BabelJS site; if your tech stack is in order, use them in production with Babel and a build step.
There's no good reason not to be able to use the transform from non-array into array... ...just don't make a mess of your code doing nothing but pasting that same ugly line, everywhere.
这篇关于[].forEach.call() 在 JavaScript 中做了什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:[].forEach.call() 在 JavaScript 中做了什么?
- 如何显示带有换行符的文本标签? 2022-01-01
- 使用 iframe URL 的 jQuery UI 对话框 2022-01-01
- 如何向 ipc 渲染器发送添加回调 2022-01-01
- 如何调试 CSS/Javascript 悬停问题 2022-01-01
- 我不能使用 json 使用 react 向我的 web api 发出 Post 请求 2022-01-01
- 从原点悬停时触发 translateY() 2022-01-01
- 为什么我的页面无法在 Github 上加载? 2022-01-01
- 是否可以将标志传递给 Gulp 以使其以不同的方式 2022-01-01
- 为什么悬停在委托事件处理程序中不起作用? 2022-01-01
- 在不使用循环的情况下查找数字数组中的一项 2022-01-01