如何遍历nodeList功能样式

时间:2013-02-08 19:23:50

标签: javascript prototype

我经常想用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)

5 个答案:

答案 0 :(得分:4)

我遇到了同样的问题,我对ES6的超级简单解决方案是:

const els = [...document.querySelectorAll('.classname')]

这样的方式nodeList成为常规数组,你可以使用mapreduce等等。

答案 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'));