在 JavaScript 中合并两个对象(NodeList)数组
Posted
技术标签:
【中文标题】在 JavaScript 中合并两个对象(NodeList)数组【英文标题】:Merging two object (NodeList) arrays in JavaScript 【发布时间】:2013-01-17 21:16:52 【问题描述】:我正在尝试合并两个对象数组,以便验证表单。在这种情况下,通常的 concat 方法似乎不起作用。 Concat 适用于普通的数值和字符串数组,但不适用于对象数组。 var allTags = allInputs.concat(allSelects);
行不行。
var allInputs = document.getElementsByTagName("input");
alert("Inputs: " + allInputs.length);
var allSelects = document.getElementsByTagName("select");
alert("Selects: " + allSelects.length);
var allTags = allInputs.concat(allSelects);
alert("allTags: " + allTags.length);
【问题讨论】:
这不是数组,它的数组像对象(NodeList) 其实就是一个NodeList,所以没有concat方法。 【参考方案1】:Concat 适用于普通数值和字符串数组,但不适用于对象数组。
实际上是这样,但是NodeList
实例没有concat
方法,并且Array#concat
没有办法识别您想要展平这些(因为它们不是数组)。
但它仍然很容易做到(不过,请参阅下面的警告)。更改此行:
var allTags = allInputs.concat(allSelects);
到
var allTags = [];
allTags.push.apply(allTags, allInputs);
allTags.push.apply(allTags, allSelects);
Live Example | Source
这通过使用一点技巧来工作:Array#push
接受可变数量的元素添加到数组中,Function#apply
使用给定的 this
值调用函数(在我们的例子中,@987654335 @) 和任何类似数组的对象作为要传递给它的参数。由于NodeList
实例是类似数组的,push
很乐意将列表的所有元素推送到数组中。
Function#apply
的这种行为(不需要第二个参数真的是一个数组)在规范中非常明确定义,并且在现代浏览器中得到很好的支持。
遗憾的是,IE6 和 7 不支持上述内容(我认为它专门使用主机对象——NodeLists
——作为Function#apply
的第二个参数),但是我们不应该支持它们,要么。 :-) IE8 也没有,这更有问题。 IE9 对此很满意。
如果您需要支持 IE8 及更早版本,可悲的是,我认为您会遇到一个无聊的旧循环:
var allInputs = document.getElementsByTagName('input');
var allSelects = document.getElementsByTagName('select');
var allTags = [];
appendAll(allTags, allInputs);
appendAll(allTags, allSelects);
function appendAll(dest, src)
var n;
for (n = 0; n < src.length; ++n)
dest.push(src[n]);
return dest;
Live Example | Source
这确实适用于 IE8 及更早版本(以及其他)。
【讨论】:
@user2035797:不用担心,我现在还添加了一个适用于 IE8 及更早版本的示例。【参考方案2】:document.get[something]
返回一个NodeList,它看起来与Array 非常相似,但有许多与众不同的特点,其中两个是:
如果您在将 NodeList 转换为实际数组时没有任何问题,您可以执行以下操作来达到您想要的效果:
var allInputs = document.getElementsByTagName("input")
, allSelects = document.getElementsByTagName("select")
;//nodeLists
var inputList = makeArray(allInputs)
, selectList = makeArray(allSelects)
;//nodeArrays
var combined = inputList.concat(selectList);
function makeArray(list)
return Array.prototype.slice.call(list);
您将失去原始 NodeList 的所有行为,包括它能够实时更新以反映对 DOM 的更改,但我的猜测是,这不是一个真正的问题。
【讨论】:
请注意,就像我在回答的第一部分中给出的类似解决方案一样,这在 IE8 或更早版本中不起作用。 (在这里试试:jsbin.com/iledok/1)sigh 至少 IE9 还不错。所以对于 IE8 及更早版本,需要一个无聊的旧循环。【参考方案3】:您正在处理的是htmlCollection
s,它们是实时集合(即,当您将节点添加到 DOM 时,它会自动添加到集合中。
遗憾的是,它没有concat
方法……这是有原因的。您需要做的是将其转换为数组,从而失去其实时行为:
var allInputsArray = [].slice.call(allInputs),
allSelectsArray = [].slice.call(allSelects),
allFields = allInputsArray.concat(allSelectsArray);
【讨论】:
【参考方案4】:我找到了一种按 dom 对象在页面或表单中出现的顺序收集它们的简单方法。 首先,在对象上创建一个虚拟类样式“reqd”,然后使用以下内容按照它们在页面上出现的顺序创建一个列表。只需将类添加到您希望收集的任何对象。
var allTags = document.querySelectorAll("input.reqd, select.reqd");
【讨论】:
【参考方案5】:查看过 underscore.js 吗?你可以这样做
var allSelectsAndInputs = _.union(_.values(document.getElementsByTagName("input")),_.values(document.getElementsByTagName("select")));
欲了解更多信息,请参阅:http://underscorejs.org/#extend
该函数适用于对象,但在此设置中有效。
【讨论】:
实际上,我正在玩它……它似乎有点不对劲。待命。 如果您喜欢,请考虑对我的回答进行投票。以上是关于在 JavaScript 中合并两个对象(NodeList)数组的主要内容,如果未能解决你的问题,请参考以下文章
在 JavaScript 中合并两个对象(NodeList)数组
如何在 JavaScript 中将两个对象合并到同一个属性中?
如何根据javascript中的键合并和替换两个数组中的对象?