什么是[] .forEach.call()在JavaScript中吗?什么是[] .forEach.

2019-05-08 15:29发布

我看的代码的某些代码段,我发现多个元素调用在与施加到一个空数组一个foreach节点列表的功能。

例如,我有这样的:

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

但我不明白它是如何工作的。 任何人都可以解释我在foreach以及如何前方的空数组的行为call的作品?

Answer 1:

[]是一个数组。
该数组根本不使用。

它被放在页面上,因为使用数组,您可以访问阵列原型,像.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是一个原型,功能有(这是一个都会调用其他函数的函数)。
.call将采取的第一个参数,更换this ,不管你通过普通函数中call ,作为第一个参数( undefinednull将使用window在日常JS,或将成为任何你过去了,如果“严格模式” )。 的参数的其余部分将被传递到原来的功能。

[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>有序,您呼叫的功能提供。

编辑

逻辑结论/清除

下面,有一篇文章建议我们放弃在函数式编程尝试,并坚持手工,内嵌循环,每一次,因为该解决方案是黑客十岁上下和难看的链接。

我想说的是,虽然.forEach比它的同行,帮助较小.map(transformer).filter(predicate).reduce(combiner, initialValue) ,它仍然成为目的时,你真正想要做的就是修改外世界(不阵列),n次,同时具有访问任一arr[i]i

那么,我们如何应对的差距,作为座右铭显然是一个有才华和有知识的人,我想想象,我知道我在做什么/我要去的地方(现在,然后......其他有时它是头先学习)?

答案其实很简单,有什么东西Bob大叔和克罗克福德爵士将双方捂脸,由于监督:

它清理干净

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( ) /等辅助方法,将让生活更容易谁想要使用列表就像他们使用数组(他们应该)的人,但谁在ES6经营的豪华人民+在相对不远的将来,或在今天通天塔“transpiling”的浏览器,你都内置了语言功能,这使得这种类型的不必要的东西。

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

超级干净,而且非常有用的。
查找休息传播运营商; 尝试出来的BabelJS网站; 如果你的技术堆栈是为了在生产与巴贝尔和构建步骤中使用它们。


有没有好的理由不能够使用非阵列到阵列变换......只是不要让你的代码做什么,但粘贴同样丑陋线乱七八糟,随处可见。



Answer 2:

querySelectorAll方法返回一个NodeList ,它类似于一个数组,但它不是相当的数组。 因此,它不具有forEach方法(数组对象经由继承Array.prototype )。

由于NodeList类似于一个数组,数组的方法实际上将它利用工作,所以[].forEach.call要调用的Array.prototype.forEach方法在上下文NodeList ,就好像你已经能简单地做yourNodeList.forEach(/*...*/)

需要注意的是空数组文本仅仅是一个快捷方式扩展版本,你可能会看到往往过于:

Array.prototype.forEach.call(/*...*/);


Answer 3:

其他答案已经解释这段代码非常好,所以我就补充建议。

这是应该重构为了简化和清晰的代码一个很好的例子。 而不是使用的[].forEach.call()Array.prototype.forEach.call()每次你这样做的时候,做一个简单的功能出来的:

function forEach( list, callback ) {
    Array.prototype.forEach.call( list, callback );
}

现在,你可以调用这个函数,而不是更复杂和晦涩的代码:

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


Answer 4:

它可以通过更好的写法

Array.prototype.forEach.call( document.querySelectorAll('a'), function(el) {

});

什么是确实是document.querySelectorAll('a')返回类似阵列的对象,但它不从继承Array类型。 因此,我们调用forEach从方法Array.prototype对象与上下文返回的值document.querySelectorAll('a')



Answer 5:

空数组有一个属性forEach在其原型这是一个功能对象。 (空阵列仅仅是一个简单的方法来获得对一个参考forEach函数,所有Array的对象具有。)功能的目的,进而,有一个call属性这也是一个功能。 当你调用一个函数的call功能,它运行与给定参数的函数。 第一个参数成为this在调用的函数。

你可以找到的文档call函数在这里 。 对于文档forEach是在这里 。



Answer 6:

只需添加一行:

NodeList.prototype.forEach = HTMLCollection.prototype.forEach = Array.prototype.forEach;

瞧!

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

请享用 :-)

警告:节点列表是一个全球性的类。 如果你写的公共图书馆,请勿使用此recomendation。 但是它是提高自我效能感,当你在网站或node.js的应用工作,非常方便的方式。



Answer 7:

只是快速和肮脏的解决方案我总是最后使用。 我不会碰的原型,就像好的做法。 当然,也有很多的方式,使这更好​​的,但你的想法。

const forEach = (array, callback) => {
  if (!array || !array.length || !callback) return
  for (var i = 0; i < array.length; i++) {
    callback(array[i], i);
  }
}

forEach(document.querySelectorAll('.a-class'), (item, index) => {
  console.log(`Item: ${item}, index: ${index}`);
});


Answer 8:

[]总是返回一个新的数组,其等效于new Array()但保证返回的数组,因为Array可由用户而被覆盖[]不能。 因此,这是一种安全的方式来获得的原型Array ,然后根据描述, call用于在arraylike节点列表(此)执行的功能。

调用给定单独设置这个值和参数的函数。 MDN



Answer 9:

Norguard解释了什么是 [].forEach.call()不和詹姆斯·阿勒代斯 , 为什么我们这样做:因为querySelectorAll返回一个NodeList不具有一个foreach方法...

除非你有现代化的浏览器,如Chrome浏览器51 +,50 +的Firefox,歌剧38,Safari浏览器10。

如果没有,你可以添加填充工具 :

if (window.NodeList && !NodeList.prototype.forEach) {
    NodeList.prototype.forEach = function (callback, thisArg) {
        thisArg = thisArg || window;
        for (var i = 0; i < this.length; i++) {
            callback.call(thisArg, this[i], i, this);
        }
    };
}


Answer 10:

想在这个老问题更新:

之所以用[].foreach.call()通过元素在现代浏览器来循环主要是结束了。 我们可以使用document.querySelectorAll("a").foreach()直接。

节点列表对象是节点的集合,通常是由诸如Node.childNodes和方法如document.querySelectorAll()属性返回。

虽然节点列表不是数组, 能够遍历它用foreach()。 它也可以使用Array.from转换成实阵列()。

然而,一些老的浏览器还没有实现NodeList.forEach(),也不Array.from()。 看到本文的例子 - 这可以通过使用Array.prototype.forEach()来规避。



文章来源: What does [].forEach.call() do in JavaScript?