Answers:
[]
是一个数组。
根本不使用此数组。
之所以放在页面上,是因为使用数组使您可以访问数组原型,例如.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>
顺序,都在调用提供的函数。
在下面,有一个指向文章的链接,该文章建议我们每次都放弃对函数式编程的尝试,并坚持每次手动,内联循环,因为这种解决方案有些hacker且难看。
我想说的是,虽然.forEach
比其同行少乐于助人,.map(transformer)
,.filter(predicate)
,.reduce(combiner, initialValue)
,它仍然成为目的时,你真正想要做的是改变外界(不是数组),n次,虽然能获得两种arr[i]
或i
。
那么,我们如何处理差距,因为Motto显然是一个有才华和知识渊博的人,我想想象一下,我知道我在做什么/我要去哪里(时不时…………其他)是最先学习的时间?
答案实际上很简单,由于疏忽,鲍伯叔叔和克罗克福德爵士都将面临困境:
清理它。
function toArray (arrLike) { // or asArray(), or array(), or *whatever*
return [].slice.call(arrLike);
}
var checked = toArray(checkboxes).filter(isChecked);
checked.forEach(listValues);
现在,如果您自己问自己是否需要执行此操作,答案很可能不是……
这确实是通过... ... 如今这些具有高级功能的Every(?)库完成的。
如果您使用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( )
/ 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 ];
超级干净,非常有用。
查找剩余和价差运算符;在BabelJS网站上试用它们;如果您的技术堆栈正常,请在Babel的生产环境中使用它们并进行构建。
有没有好的理由不能够使用非数组转换成阵列......只是不要让你的代码乱七八糟的什么都不做,但粘贴同样丑陋线,无处不在。
.call
确实会更改的值this
,这就是为什么要call
与forEach一起使用的原因。如果forEach看起来像,forEach (fn) { var i = 0; var len = this.length; for (; i < length; i += 1) { fn( this[i], i, this ); }
则通过this
说出forEach.call( newArrLike )
意思进行更改,它将使用该新对象作为this
。
.call
不会改变的价值this
的传递给里面有什么forEach
,.call
改变的值this
的foreach内。如果您对为什么this
不将其传递给forEach
想要调用的函数感到困惑,则应查找this
JavaScript中的行为。作为附录,只适用在这里(和地图/过滤/减少),有一个第二个参数forEach
,这组this
函数内arr.forEach(fn, thisInFn)
或[].forEach.call(arrLike, fn, thisInFn);
或刚使用.bind
; arr.forEach(fn.bind(thisInFn));
[]
只是作为数组存在,因此您可以使用.call
该.forEach
方法,并将其更改为this
要使用的集合。.call
看起来是这样的:function (thisArg, a, b, c) { var method = this; method(a, b, c); }
除了有内部黑魔法设置this
里面method
等于你为通过thisArg
。
该querySelectorAll
方法返回NodeList
,类似于数组,但它不是一个数组。因此,它没有forEach
方法(哪个数组对象通过继承Array.prototype
)。
由于a NodeList
与数组相似,因此数组方法实际上可以在其上工作,因此通过使用,[].forEach.call
您可以Array.prototype.forEach
在的上下文中调用该方法NodeList
,就好像您可以简单地做到yourNodeList.forEach(/*...*/)
。
请注意,空数组文字只是扩展版本的快捷方式,您可能还会经常看到它:
Array.prototype.forEach.call(/*...*/);
[].forEach.call(['a','b'], cb)
over 就没有优势了吗?那是对的吗?['a','b'].forEach(cb)
forEach
[].forEach()
:)
var section = document.querySelectorAll(".section"); section.forEach((item)=>{ console.log(item.offsetTop) })
效果很好
forEach
阵列,但不支持NodeList对象)
其他答案已经很好地解释了此代码,因此我只添加一个建议。
这是一个很好的示例代码,为了简单和清楚起见,应对其进行重构。与其使用[].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
});
想更新这个老问题:
[].foreach.call()
在现代浏览器中使用循环浏览元素的原因已基本结束。我们可以document.querySelectorAll("a").foreach()
直接使用。
NodeList对象是节点的集合,通常由诸如Node.childNodes之类的属性以及诸如document.querySelectorAll()之类的方法返回。
尽管NodeList不是数组,但可以使用forEach()对其进行迭代。也可以使用Array.from()将其转换为实际的Array。
但是,某些较旧的浏览器尚未实现NodeList.forEach()或Array.from()。可以使用Array.prototype.forEach()来规避此问题-请参阅本文档的示例。
我总是最终使用的只是一个快速而肮脏的解决方案。我不会碰原型,只是一个好习惯。当然,有很多方法可以使它变得更好,但是您知道了。
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
用于在类似数组的节点列表(this)上执行功能。
调用具有给定值和单独提供的参数的函数。dn
[]
实际上将始终返回一个数组,同时window.Array
可以和任何被覆盖(在所有的旧版浏览器),所以也可以window.Array.prototype.forEach
被覆盖任何东西。在不支持getter / setter或对象密封/冻结(冻结会导致其自身的可扩展性问题)的浏览器中,两种情况均不能保证安全。
prototype
或方法的可能性的额外信息:forEach
。
Norguard解释什么 [].forEach.call()
不和詹姆斯·阿勒代斯 为什么我们这样做:因为querySelectorAll返回一个NodeList
不具有一个foreach方法...
除非您拥有现代浏览器,例如Chrome 51 +,Firefox 50 +,Opera 38,Safari 10。
如果没有,您可以添加一个Polyfill:
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);
}
};
}
此页面上有很多很好的信息(请参阅答案 + 答案 + 评论),但是我最近遇到了与OP相同的问题,并且花了一些时间才能了解整个情况。所以,这是一个简短的版本:
目标是Array
在类似数组的方法上使用NodeList
本身没有这些方法的方法。
较旧的模式通过Function.call()
,选择了Array的方法,并使用了数组常量([]
),而不是Array.prototype
因为它的类型更短:
[].forEach.call(document.querySelectorAll('a'), a => {})
使用更新的模式(在ECMAScript 2015之后)Array.from()
:
Array.from(document.querySelectorAll('a')).forEach(a => {})