Javascript 如何在Javascript中将DOM节点列表转换为数组?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2735067/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 01:42:36  来源:igfitidea点击:

How to convert a DOM node list to an array in Javascript?

javascripthtmldom

提问by Guss

I have a Javascript function that accepts a list of HTML nodes, but it expects a Javascript array (it runs some Array methods on that) and I want to feed it the output of Document.getElementsByTagNamethat returns a DOM node list.

我有一个 Javascript 函数,它接受一个 HTML 节点列表,但它需要一个 Javascript 数组(它在上面运行一些 Array 方法),我想向它提供Document.getElementsByTagName返回 DOM 节点列表的输出。

Initially I thought of using something simple like:

最初我想使用一些简单的东西,比如:

Array.prototype.slice.call(list,0)

And that works fine in all browsers, except of course Internet Explorer which returns the error "JScript object expected", as apparently the DOM node list returned by Document.getElement*methods is not a JScript object enough to be the target of a function call.

这在所有浏览器中都可以正常工作,当然 Internet Explorer 除外,它返回错误“预期的 JScript 对象”,因为Document.getElement*方法返回的 DOM 节点列表显然不是 JScript 对象,不足以成为函数调用的目标。

Caveats: I don't mind writing Internet Explorer specific code, but I'm not allowed to use any Javascript libraries such as JQuery because I'm writing a widget to be embedded into 3rd party web site, and I cannot load external libraries that will create conflict for the clients.

警告:我不介意编写 Internet Explorer 特定的代码,但我不允许使用任何 Javascript 库,例如 JQuery,因为我正在编写一个嵌入到 3rd 方网站的小部件,并且我无法加载外部库会给客户造成冲突。

My last ditch effort is to iterate over the DOM node list and create an array myself, but is there a nicer way to do that?

我最后的努力是遍历 DOM 节点列表并自己创建一个数组,但有没有更好的方法来做到这一点?

采纳答案by CMS

NodeLists are host objects, using the Array.prototype.slicemethod on host objects is not guaranteed to work, the ECMAScript Specification states:

NodeLists 是宿主对象Array.prototype.slice不能保证在宿主对象上使用该方法,ECMAScript 规范指出:

Whether the slice function can be applied successfully to a host object is implementation-dependent.

切片功能是否可以成功应用于宿主对象取决于实现。

I would recommend you to make a simple function to iterate over the NodeListand add each existing element to an array:

我建议您创建一个简单的函数来迭代NodeList并将每个现有元素添加到数组中:

function toArray(obj) {
  var array = [];
  // iterate backwards ensuring that length is an UInt32
  for (var i = obj.length >>> 0; i--;) { 
    array[i] = obj[i];
  }
  return array;
}

UPDATE:

更新:

As other answers suggest, you can now can use in modern environments the spread syntax or the Array.frommethod:

正如其他答案所暗示的那样,您现在可以在现代环境中使用传播语法或Array.from方法:

const array = [ ...nodeList ] // or Array.from(nodeList)

But thinking about it, I guess the most common use case to convert a NodeList to an Array is to iterate over it, and now the NodeList.prototypeobject has the forEachmethod natively, so if you are on a modern environment you can use it directly, or have a pollyfill.

但是仔细想想,我想将 NodeList 转换为 Array 的最常见用例是对其进行迭代,现在NodeList.prototype对象forEach本身就有方法,所以如果您在现代环境中,您可以直接使用它,或者有一个pollyfill。

回答by camiloazula

In es6you can just use as follows:

es6 中你可以使用如下:

  • Spread operator

     var elements = [... nodelist]
    
  • Using Array.from

     var elements = Array.from(nodelist)
    
  • 展开运算符

     var elements = [... nodelist]
    
  • 使用 Array.from

     var elements = Array.from(nodelist)
    

more reference at https://developer.mozilla.org/en-US/docs/Web/API/NodeList

更多参考https://developer.mozilla.org/en-US/docs/Web/API/NodeList

回答by vsync

Using spread (ES2015), it's as easy as: [...document.querySelectorAll('p')]

使用spread (ES2015),就像:[...document.querySelectorAll('p')]

(optional: use Babelto transpile the above ES6 code to ES5 syntax)

(可选:使用Babel将上述 ES6 代码转译为 ES5 语法)



Try it in your browser's console and see the magic:

在浏览器的控制台中尝试一下,看看它的神奇之处:

for( links of [...document.links] )
  console.log(links);

回答by Gena Shumilkin

Use this simple trick

使用这个简单的技巧

<Your array> = [].map.call(<Your dom array>, function(el) {
    return el;
})

回答by Brett Zamir

While it is not really a proper shim, since there is no spec requiring working with DOM elements, I've made one to allow you to use slice()in this manner: https://gist.github.com/brettz9/6093105

虽然它不是一个真正合适的 shim,因为没有要求使用 DOM 元素的规范,我已经制作了一个允许您以slice()这种方式使用:https: //gist.github.com/brettz9/6093105

UPDATE: When I raised this with the editor of the DOM4 spec (asking whether they might add their own restrictions to host objects (so that the spec would require implementers to properly convert these objects when used with array methods) beyond the ECMAScript spec which had allowed for implementation-independence), he replied that "Host objects are more or less obsolete per ES6 / IDL." I see per http://www.w3.org/TR/WebIDL/#es-arraythat specs can use this IDL to define "platform array objects" but http://www.w3.org/TR/domcore/doesn't seem to be using the new IDL for HTMLCollection(though it looks like it might be doing so for Element.attributesthough it only explicitly states it is using WebIDL for DOMString and DOMTimeStamp). I do see [ArrayClass](which inherits from Array.prototype) is used for NodeList(and NamedNodeMapis now deprecated in favor of the only item that would still be using it, Element.attributes). In any case, it looks like it is to become standard. The ES6 Array.frommight also be more convenient for such conversions than having to specify Array.prototype.sliceand more semantically clear than [].slice()(and the shorter form, Array.slice()(an "array generic"), has, as far as I know, not become standard behavior).

更新:当我用 DOM4 规范的编辑器提出这个问题时(询问他们是否可以向宿主对象添加自己的限制(以便规范要求实现者在与数组方法一起使用时正确转换这些对象)超出 ECMAScript 规范允许实现独立),他回答说“根据 ES6 / IDL,主机对象或多或少已经过时了。” 我看到每个http://www.w3.org/TR/WebIDL/#es-array规范可以使用这个 IDL 来定义“平台数组对象”,但http://www.w3.org/TR/domcore/没有似乎没有将新的 IDL 用于HTMLCollection(尽管它看起来可能会这样做,Element.attributes尽管它只是明确声明它正在将 WebIDL 用于 DOMString 和 DOMTimeStamp)。我确实看到[ArrayClass](继承自 Array.prototype)用于NodeListNamedNodeMap现在已弃用,取而代之的是唯一仍在使用它的项目,Element.attributes)。无论如何,看起来它是要成为标准的。ES6Array.from也可能比必须指定更方便,Array.prototype.slice并且在语义上更清晰[].slice()Array.slice()据我所知,更短的形式(“数组泛型​​”)尚未成为标准行为)。

回答by Bharata

Today, in 2018, we could use the ECMAScript 2015 (6th Edition) or ES6, but not all browsers can understand it (for ex. IE does not understand all of it). If you want you could use ES6 as follows: var array = [... NodeList];(as spread operator) or var array = Array.from(NodeList);.

今天,在 2018 年,我们可以使用 ECMAScript 2015(第 6 版)或 ES6,但并非所有浏览器都能理解它(例如,IE 无法理解所有内容)。如果你愿意,你可以使用ES6如下: var array = [... NodeList];为传播运营商)或var array = Array.from(NodeList);

In other case (if you can not use ES6) you can use the shortest way to convert a NodeListto an Array:

在其他情况下(如果您不能使用 ES6),您可以使用最短的方法将 a 转换NodeList为 an Array

var array = [].slice.call(NodeList, 0);.

var array = [].slice.call(NodeList, 0);.

For example:

例如:

var nodeList = document.querySelectorAll('input');
//we use "{}.toString.call(Object).slice(8, -1)" to find the class name of object
console.log({}.toString.call(nodeList).slice(8, -1)); //NodeList

var array = [].slice.call(nodeList, 0);
console.log({}.toString.call(array).slice(8, -1)); //Array

var result = array.filter(function(item){return item.value.length > 5});

for(var i in result)
  console.log(result[i].value); //credit, confidence
<input type="text" value="trust"><br><br>
<input type="text" value="credit"><br><br>
<input type="text" value="confidence">

But if you want to iterate over the DOMnode list easy only, then you do not need to convert a NodeListto an Array. It's possible to loop over the items in a NodeListusing:

但是如果你只想简单地迭代DOM节点列表,那么你不需要将 a 转换NodeList为 an Array。可以在NodeListusing 中循环项目:

var nodeList = document.querySelectorAll('input');
// Calling nodeList.item(i) isn't necessary in JavaScript
for(var i = 0; i < nodeList.length; i++)
    console.log(nodeList[i].value); //trust, credit, confidence
<input type="text" value="trust"><br><br>
<input type="text" value="credit"><br><br>
<input type="text" value="confidence">

Don't be tempted to use for...inor for each...into enumerate the items in the list, since that will also enumerate the length and item properties of the NodeListand cause errors if your script assumes it only has to deal with element objects. Also, for..inis not guaranteed to visit the properties in any particular order. for...ofloops will loop over NodeList objects correctly.

不要试图使用for...infor each...in枚举列表中的项目,因为NodeList如果您的脚本假定它只需要处理元素对象,那么这也会枚举 的长度和项目属性并导致错误。此外,for..in不保证以任何特定顺序访问属性。for...ofloops 将正确循环 NodeList 对象。

See too:

另见:

回答by Strelok

var arr = new Array();
var x= ... get your nodes;

for (i=0;i<x.length;i++)
{
  if (x.item(i).nodeType==1)
  {
    arr.push(x.item(i));
  }
}

This should work, cross browser and get you all the "element" nodes.

这应该有效,跨浏览器并为您提供所有“元素”节点。