我看的代码的某些代码段,我发现多个元素调用在与施加到一个空数组一个foreach节点列表的功能。
例如,我有这样的:
[].forEach.call( document.querySelectorAll('a'), function(el) {
// whatever with the current node
});
但我不明白它是如何工作的。 任何人都可以解释我在foreach以及如何前方的空数组的行为call
的作品?
我看的代码的某些代码段,我发现多个元素调用在与施加到一个空数组一个foreach节点列表的功能。
例如,我有这样的:
[].forEach.call( document.querySelectorAll('a'), function(el) {
// whatever with the current node
});
但我不明白它是如何工作的。 任何人都可以解释我在foreach以及如何前方的空数组的行为call
的作品?
[]
是一个数组。
该数组根本不使用。
它被放在页面上,因为使用数组,您可以访问阵列原型,像.forEach
。
这仅仅是比打字快Array.prototype.forEach.call(...);
接着, forEach
是取一个函数作为输入的功能...
[1,2,3].forEach(function (num) { console.log(num); });
...以及在各元素this
(其中, this
是阵列状,在于其具有一个length
,并且可以访问它的部件,如this[1]
它会通过三两件事:
2
) 最后, .call
是一个原型,功能有(这是一个都会调用其他函数的函数)。
.call
将采取的第一个参数,更换this
,不管你通过普通函数中call
,作为第一个参数( undefined
或null
将使用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);
};
这不仅是一个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网站; 如果你的技术堆栈是为了在生产与巴贝尔和构建步骤中使用它们。
有没有好的理由不能够使用非阵列到阵列变换......只是不要让你的代码做什么,但粘贴同样丑陋线乱七八糟,随处可见。
该querySelectorAll
方法返回一个NodeList
,它类似于一个数组,但它不是相当的数组。 因此,它不具有forEach
方法(数组对象经由继承Array.prototype
)。
由于NodeList
类似于一个数组,数组的方法实际上将它利用工作,所以[].forEach.call
要调用的Array.prototype.forEach
方法在上下文NodeList
,就好像你已经能简单地做yourNodeList.forEach(/*...*/)
需要注意的是空数组文本仅仅是一个快捷方式扩展版本,你可能会看到往往过于:
Array.prototype.forEach.call(/*...*/);
其他答案已经解释这段代码非常好,所以我就补充建议。
这是应该重构为了简化和清晰的代码一个很好的例子。 而不是使用的[].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
});
它可以通过更好的写法
Array.prototype.forEach.call( document.querySelectorAll('a'), function(el) {
});
什么是确实是document.querySelectorAll('a')
返回类似阵列的对象,但它不从继承Array
类型。 因此,我们调用forEach
从方法Array.prototype
对象与上下文返回的值document.querySelectorAll('a')
空数组有一个属性forEach
在其原型这是一个功能对象。 (空阵列仅仅是一个简单的方法来获得对一个参考forEach
函数,所有Array
的对象具有。)功能的目的,进而,有一个call
属性这也是一个功能。 当你调用一个函数的call
功能,它运行与给定参数的函数。 第一个参数成为this
在调用的函数。
你可以找到的文档call
函数在这里 。 对于文档forEach
是在这里 。
只需添加一行:
NodeList.prototype.forEach = HTMLCollection.prototype.forEach = Array.prototype.forEach;
瞧!
document.querySelectorAll('a').forEach(function(el) {
// whatever with the current node
});
请享用 :-)
警告:节点列表是一个全球性的类。 如果你写的公共图书馆,请勿使用此recomendation。 但是它是提高自我效能感,当你在网站或node.js的应用工作,非常方便的方式。
只是快速和肮脏的解决方案我总是最后使用。 我不会碰的原型,就像好的做法。 当然,也有很多的方式,使这更好的,但你的想法。
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}`);
});
[]
总是返回一个新的数组,其等效于new Array()
但保证返回的数组,因为Array
可由用户而被覆盖[]
不能。 因此,这是一种安全的方式来获得的原型Array
,然后根据描述, call
用于在arraylike节点列表(此)执行的功能。
调用给定单独设置这个值和参数的函数。 MDN
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);
}
};
}
想在这个老问题更新:
之所以用[].foreach.call()
通过元素在现代浏览器来循环主要是结束了。 我们可以使用document.querySelectorAll("a").foreach()
直接。
节点列表对象是节点的集合,通常是由诸如Node.childNodes和方法如document.querySelectorAll()属性返回。
虽然节点列表不是数组, 能够遍历它用foreach()。 它也可以使用Array.from转换成实阵列()。
然而,一些老的浏览器还没有实现NodeList.forEach(),也不Array.from()。 看到本文的例子 - 这可以通过使用Array.prototype.forEach()来规避。