我经常想用forEach或map遍历NodeList。我的简化代码就像这样:
var nodeListMap = Array.prototype.map;
var els = document.querySelectorAll('.classname');
nodeListMap.call(els, function(el){...});
这很好用。但是,我不想map.call
,但如果我这样做......
var nodeListMap = Array.prototype.map.call;
var els = document.querySelectorAll('.classname');
nodeListMap(els, function(el){...});
然后返回
TypeError: object is not a function
如何修改代码,以便我只执行nodeListMap(array, fn)
?
答案 0 :(得分:4)
我遇到了同样的问题,我对ES6的超级简单解决方案是:
const els = [...document.querySelectorAll('.classname')]
这样的方式nodeList成为常规数组,你可以使用map
,reduce
等等。
答案 1 :(得分:2)
Array.prototype.map.call
只是获取call
函数(Function.prototype.call
),没有上下文。您需要将其绑定到map
函数:
var nodeListMap = Function.prototype.call.bind(Array.prototype.map);
如果您不想使用bind
,也可以写
function nodeListMap(_list /* … */) {
return Function.prototype.call.apply(Array.prototype.map, arguments);
}
答案 2 :(得分:2)
另一种选择是将此功能添加到原型NodeList:
NodeList.prototype.map = function(step){
return Array.prototype.map.call(this, step);
};
NodeList.prototype.forEach = function(step){
return Array.prototype.forEach.call(this, step);
};
有了这个,你可以打电话:
els.map(function(el){...});
应该注意的是,有些人可能会以这种方式修改NodeList的原型,但我个人并没有真正看到它的问题。
或者,如果您需要设置this
对象:
NodeList.prototype.map = function(step){
return Array.prototype.map.call(this, step, Array.prototype.slice.call(arguments, 1));
};
NodeList.prototype.forEach = function(step){
return Array.prototype.forEach.call(this, step, Array.prototype.slice.call(arguments, 1));
};
注意:以上会产生副作用,当您未传递第二个参数时,this
将变为空数组,而不是window
。
或
NodeList.prototype.map = Array.prototype.map;
NodeList.prototype.forEach = Array.prototype.forEach;
答案 3 :(得分:2)
编写自己的“做正确的事”
的功能可能是最简单的function map() {
var args = [].slice.call(arguments, 0);
var ctx = args.shift();
return [].map.apply(ctx, args);
}
然后将用于任何伪数组对象。
编辑此代码已更新,以确保将所有参数传递给.map
,即使ECMA将来添加更多。
答案 4 :(得分:1)
六年后,为了简洁明了(ES6 +),我来解决以下问题:
const els = Array.from(document.querySelectorAll('.selector'));