javascript - [].forEach.call() 在 JavaScript 中做什么?

标签 javascript arrays foreach ecmascript-5 nodelist

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

例如我有这样的东西:

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

但我不明白它是如何工作的。任何人都可以向我解释 forEach 前面的空数组的行为以及 call 的工作原理吗?

最佳答案

[]是一个数组。
这个数组根本没有被使用。

它被放在页面上,因为使用数组可以让您访问数组原型(prototype),例如 .forEach .

这比输入 Array.prototype.forEach.call(...); 快多了

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

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

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

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

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

[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> 的列表标签,以及每个 <a>按顺序,您正在调用提供的函数。

编辑

逻辑结论/清理

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

我会说 .forEach不如其同行有用,.map(transformer) , .filter(predicate) , .reduce(combiner, initialValue) ,当您真正想做的只是修改外部世界(而不是数组)n 次,同时可以访问 arr[i] 时,它仍然有用。或 i .

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

答案其实很简单,由于疏忽,Bob 叔叔和 Crockford 爵士都会脸红:

清理干净

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 次操作的方法。
如果您不使用这样的东西,那么一定要自己编写。

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 中编译”,你有内置的语言特性,这使得这种类型的事情变得不必要了。

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 干净,非常有用。
查看 RestSpread 运算符;在 BabelJS 站点上试用它们;如果您的技术堆栈是有序的,请在生产中使用它们与 Babel 和构建步骤。


没有充分的理由不能使用从非数组到数组的转换......只是不要让你的代码变得一团糟但是粘贴相同的丑陋的线条,无处不在。

关于javascript - [].forEach.call() 在 JavaScript 中做什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16053357/

相关文章:

javascript - 倒计时仅适用于第一个按钮,但不适用于其他按钮

java - 通过选择排序按字母顺序对字符串数组进行排序?

javascript - 将多个按键绑定(bind)到按键事件

javascript - 第一行中的“ Uncaught SyntaxError :意外的 token <”

javascript - jquery 延迟加载和其他 Jquery/javascript 函数在附加后不起作用

Java List forEach Lambda 表达式 - 第一个元素并遍历所有元素

C# - For vs Foreach - 巨大的性能差异

java - 用叠瓦式 for 循环填充数组

python - 将低维 numpy 数组的部分提取到高维数组的最终轴中

jquery - 在 Jquery 模式弹出窗口中呈现局部 View