[].forEach.call() 在 JavaScript 中有什么作用? [英] What does [].forEach.call() do in JavaScript?

查看:23
本文介绍了[].forEach.call() 在 JavaScript 中有什么作用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在查看一些代码片段,我发现多个元素在节点列表上调用一个函数,并将 forEach 应用于一个空数组.

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.

例如我有类似的东西:

[].forEach.call( document.querySelectorAll('a'), function(el) {
   // whatever with the current node
});

但我无法理解它是如何工作的.谁能解释一下 forEach 前面的空数组的行为以及 call 是如何工作的?

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.

它被放在页面上,因为使用数组可以让你访问数组原型,比如 .forEach.

It's being put on the page, because using an array gives you access to array prototypes, like .forEach.

这只是比输入Array.prototype.forEach.call(...);

接下来,forEach 是一个将函数作为输入的函数...

Next, forEach is a function which takes a function as an input...

[1,2,3].forEach(function (num) { console.log(num); });

...并且对于 this 中的每个元素(其中 this 类似于数组,因为它有一个 length,你可以访问它的部分,如 this[1]) 它将传递三件事:

...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:

  1. 数组中的元素
  2. 元素的索引(第三个元素将通过 2)
  3. 对数组的引用

最后,.call 是函数具有的原型(它是在其他函数上调用的函数).
.call 将采用它的第一个参数并将常规函数内部的 this 替换为您传递的任何 call,作为第一个参数 (undefinednull 将在日常 JS 中使用 window ,或者将是您传递的任何内容,如果在严格模式"下).其余参数将传递给原始函数.

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"

因此,您正在创建一种快速调用 forEach 函数的方法,并将 this 从空数组更改为所有 的列表<a> 标签,并且对于每个 顺序,您正在调用提供的函数.

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.

下面有一篇文章的链接,建议我们放弃函数式编程的尝试,并每次都坚持手动、内联循环,因为这个解决方案是黑客式的且难看的.

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.

我想说虽然 .forEach 不如它的对应物有用,.map(transformer), .filter(predicate), .reduce(combiner, initialValue),当您真正想要做的只是修改外部世界(不是数组)n 次,同时可以访问任一 时,它仍然有用arr[i]i.

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.

那么我们如何处理这种差异,因为 Motto 显然是一个才华横溢、知识渊博的人,我想想象我知道我在做什么/我要去哪里(不时........其他时候是头先学习)?

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:

清理.

function toArray (arrLike) { // or asArray(), or array(), or *whatever*
  return [].slice.call(arrLike);
}

var checked = toArray(checkboxes).filter(isChecked);
checked.forEach(listValues);

现在,如果您质疑自己是否需要这样做,答案很可能是否定的...
这确切的事情是由......完成的......这些天每个(?)具有高阶功能的库.
如果您使用 lodash 或下划线甚至 jQuery,它们都会有一种方法来获取一组元素并执行 n 次操作.
如果你不使用这样的东西,那么一定要自己写.

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);
};

针对 ES6(ES2015) 及更高版本的更新

不仅 slice( )/array( )/etc 辅助方法将使那些想要像使用数组一样使用列表的人的生活更轻松(正如他们应该的那样),但是对于那些在相对不久的将来可以在 ES6+ 浏览器中操作或在今天在 Babel 中转译"的人来说,你有内置的语言功能,这使得这种类型的事情变得不必要.

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 ];

超级干净,非常有用.
查找 RestSpread 运算符;在 BabelJS 站点上试用它们;如果您的技术栈井井有条,请在生产环境中使用 Babel 和构建步骤.

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 中有什么作用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆