3

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

4

5 回答 5

9

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

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

这样 nodeList 就变成了一个普通的数组,你可以使用mapreduce等等。

于 2018-04-15T16:56:05.530 回答
3

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);
}
于 2013-02-08T19:26:49.157 回答
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;
于 2013-02-08T19:43:47.320 回答
2

编写自己的“做正确的事”的函数可能是最简单的

function map() {
    var args = [].slice.call(arguments, 0);
    var ctx = args.shift();
    return [].map.apply(ctx, args);
}

然后它将适用于任何伪数组对象。

编辑此代码已更新,以确保所有参数都传递给.map,即使 ECMA 将来添加更多。

于 2013-02-08T19:44:01.263 回答
2

六年后,大多数浏览器的 NodeLists 上都可以使用mapforEach方法(IE 通常是奇怪的鸭子)。检查caniuse 上的forEachnodeList支持

如果需要旧版浏览器支持,为了简洁明了(ES6+),我选择了以下内容:

const els = Array.from(document.querySelectorAll('.selector'));

然后,您可以简单地迭代为...

els.forEach(el => doSomething)

于 2019-12-31T15:06:06.137 回答