javascript - 如何在纯 Javascript 中连接 getElementsByClassName 的结果?

标签 javascript concatenation element

我正在尝试编写一个可在两个不同页面上使用的书签。一旦掌握了元素,我就可以成功地迭代和处理它们,但为了适应两个不同的页面,我想通过两个不同的类名编译 DIV 列表。我从这个开始:

traces=
  [].concat.apply(document.getElementsByClassName('fullStacktrace'),
                  document.getElementsByClassName('msg'))

但在第一页上结果是这样的:

> traces=[].concat.apply(document.getElementsByClassName('fullStacktrace'),
                         document.getElementsByClassName('msg'))
[HTMLCollection[2]]
> traces[0]
[div.fullStacktrace, div.fullStacktrace]
> traces[1]
undefined
> traces[0][0]
<div class=​"fullStacktrace" style=​"height:​ auto;​">​…​</div>​

而在另一页

> traces=[].concat.apply(document.getElementsByClassName('fullStacktrace'),
                         document.getElementsByClassName('msg'))
[HTMLCollection[0], div#msg_2.msg.l1,  ... div#msg_6460.msg.l1]
> traces[0]
[]
> traces[1]
<div class=​"msg l1" id=​"msg_2">​…​</div>​

所以 getElementsByClassName 对两个页面都有效,但看起来 concat.apply 不会迭代其第一个参数,但会迭代其第二个参数?!

所以我尝试使用 concat 两次并全力以赴使用括号:

traces=(
  (
    [].concat.apply(document.getElementsByClassName('fullStacktrace'))
  )
  .concat.apply(document.getElementsByClassName('msg'))
)

但它变得更奇怪:第一页说:

Array[1]
> 0: HTMLCollection[0]
  length: 0
  > __proto__: HTMLCollection
length: 1
> __proto__: Array[0]

另一个:

Array[1]
> 0: HTMLCollection[283]  // Lots of div#msg_3.msg.l1 sort of things in here
  length: 1
>__proto__: Array[0]

获取其完整的 div 补集。

由于两组元素仅在一个或另一个页面上,因此我可以在特定情况下使用条件,但上面的行为对我来说非常令人惊讶,所以我想理解它。有什么想法吗?

仅供引用,这是 Mac Chrome 版本 56.0.2924.87(64 位)

最佳答案

要使用 concat,集合需要是数组参数。任何其他争论都不会平息。您可以使用 .slice() 来实现:

traces= [].concat([].slice.call(document.getElementsByClassName('fullStacktrace')),
                  [].slice.call(document.getElementsByClassName('msg')))

现代语法会让它变得更好一些。这使用“spread”语法创建一个新数组,并将两个集合的内容分布到其中:

traces = [...document.getElementsByClassName('fullStacktrace'),
          ...document.getElementsByClassName('msg')]

或者使用更容易填充的东西,您可以使用 Array.from() 来转换集合:

traces = Array.from(document.getElementsByClassName('fullStacktrace'))
              .concat(Array.from(document.getElementsByClassName('msg'))))

总的来说,我一开始就不会使用getElementsByClassName。我会使用.querySelectorAll。您将获得更好的浏览器支持和更强大的选择功能:

traces = document.querySelectorAll('.fullStacktrace, .msg')

这使用了与CSS相同的选择器,因此上面的选择器实际上传递了一组两个选择器,每个选择器选择具有各自类的元素。


详细说明

第一个示例:

我对上述问题的解释太简洁了。这是您的第一次尝试:

traces = [].concat.apply(document.getElementsByClassName('fullStacktrace'),
              document.getElementsByClassName('msg'))

.concat() 的工作方式是采用任何给定的值作为其 this 值及其参数,并将它们组合成一个数组。但是,当 this 值或任何参数是实际的 Array 时,它会将其内容平铺到结果中。因为 HTMLCollection 不是数组,所以它被视为只是要添加的任何其他值,而不是被展平。

.apply() 允许您设置被调用方法的 this 值,然后将其第二个参数的成员作为单独的参数传播给该方法。因此,在上面的示例中,作为第一个参数传递给 .apply()HTMLCollection 不会被展平到结果中,但作为第二个参数传递给 .apply() 会这样做,因为是 .apply() 进行传播,而不是 .concat()。从 .concat() 的 Angular 来看,第二个 DOM 选择从未存在过;它只看到具有 msg 类的单个 DOM 元素。


第二个示例:

traces=(
  (
    [].concat.apply(document.getElementsByClassName('fullStacktrace'))
  )
  .concat.apply(document.getElementsByClassName('msg'))
)

这有点不同。这部分 [].concat.apply(document.getElementsByClassName('fullStacktrace')) 遇到与第一个示例相同的问题,但您注意到 HTMLCollection 没有t 最终得到结果。原因是当您将 .apply.concat(... 链接到末尾时,您实际上放弃了该调用的结果。

举一个更简单的例子。当你这样做时:

[].concat.apply(["bar"], ["baz", "buz"])

...[]实际上是一个浪费的数组。这只是访问 .concat() 方法的一个简短方法。在 .concat() 内,["bar"] 将是 this 值,"baz""buz" 将作为单独的参数传递,因为 .apply() 再次将其第二个参数作为单独的参数传递给方法。

如果将简单的示例更改为这样,您可以更清楚地看到这一点:

["foo"].concat.apply(["bar"], ["baz", "buz"])

...请注意,"foo" 不在结果中。那是因为 .concat() 对此一无所知;它只知道 ["bar"]"baz""buz"

所以当你这样做时:

[].concat.apply(collection).concat.apply(collection)

你也做了同样的事情。第二个 .concat.apply 基本上会丢弃第一个集合,并仅继续处理提供给 .apply() 的数据,因此第一个集合不会出现。如果您没有在第二次调用中使用 .apply,那么您最终会得到一个包含两个未展平 HTMLCollection 的数组。

[].concat.apply(collection).concat(collection)
// [HTMLCollection, HTMLCollection]

关于javascript - 如何在纯 Javascript 中连接 getElementsByClassName 的结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42856863/

相关文章:

javascript - django:提交 POST 创建对象不起作用

javascript - 使用node.js和socket.io在Heroku上发布应用程序

php - 如何获取与mysql中的concat值字段相关的COUNT和INNER JOIN

jquery - 如何确定哪个元素在 .keyup jquery 方法调用上触发?

ruby - 将数组的元素移动到 Ruby 中的另一个数组

javascript - 在你的 ember.js 网络应用程序中,伪持久状态应该存在于何处?

c - 有没有办法在C中打印字符串,如下: puts ("this is a string" + variable);?

python - 将多索引数据帧与数据帧连接起来

javascript - 如何获取元素节点列表

javascript - 为什么 javascript 将我的日期转换为数字类型