【问题标题】:Why can't I use Array.forEach on a collection of Javascript elements? [duplicate]为什么我不能在 Javascript 元素集合上使用 Array.forEach? [复制]
【发布时间】:2017-02-09 08:40:23
【问题描述】:

我正在使用 Babel/ES6 构建一个应用程序。我想禁用它的仅查看版本的所有表单元素,所以我这样做了:

let form = document.getElementById('application-form')
let elements = form.elements

我希望能够做到这一点,而不是使用常规的旧 for 循环(确实有效):

elements.forEach((el) => {
    el.disabled = true
})

但我得到了TypeError: elements.forEach is not a function

奇怪的是,如果我在 Chrome 开发控制台中console.log(elements),它就像一个包含一堆 input 对象的数组。它不会以 Object 符号显示对象,并且所有键都是整数。我认为这是某种伪数组,但我什至不知道如何找出它。

编辑:简短的回答它不是一个数组,它是一个 HTMLCollection。见Why doesn't nodelist have forEach?


*更新*

每个this answernodelist 现在有forEach 方法!

【问题讨论】:

  • console.log(typeof elements)的结果
  • 花式解决方案:[...elements].forEach
  • object。但它看起来像开发控制台中的一个数组。看起来它实际上是一个 HTMLCollection
  • 总是检查类型...不要使用duck testing(如果它看起来像鸭子,像鸭子一样游泳,像鸭子一样叫声,那么它可能是鸭子)
  • @squint: "...当我的发动机处于高速运转状态时..." ROFL!我确定我知道那是什么样的。

标签: javascript arrays ecmascript-6 babeljs


【解决方案1】:

你可以。你不能那样使用它,因为HTMLFormControlsCollection 上没有form.elements 给你的forEach 属性(这不是一个数组)。

以下是您无论如何都可以使用它的方法:

Array.prototype.forEach.call(form.elements, (element) => {
    // ...
});

或者在现代浏览器上,您可以利用底层 HTMLCollectioniterable 的事实,即使它没有 forEach

// `for-of`:
for (const element of elements) {
    // ...do something with `element`...
}

// Spreading into an array:
[...elements].forEach((element) => {
    // ...do something with `element`...
});

这在 IE11 等过时的浏览器上不起作用。

还有Array.from(需要一个用于过时浏览器的polyfill):

Array.from(elements).forEach((element) => {
    // ...
});

详情见my answer here"array-like"部分。

【讨论】:

  • ES6 转换:[...elements].forEach(el => el.disabled = true);
  • @SterlingArcher:确实!嗯,我不确定我上面链接的答案是否提到......编辑:啊,是的,确实如此。但它错误地将其称为运算符。编辑2:不再。 :-)
  • 随意编辑成解决方案,因为 ES6 确实被标记了。 Array.from也不错。
  • @SterlingArcher:这和.from() 解决方案都很好,但它们不必要地创建了一个新数组并在节点中复制。太糟糕了 Firefox 的 Array 泛型方法没有标准化。做得更好Array.forEach(elements, function(el) {...})
  • @T.J.Crowder 实际上这对我不起作用。 [...elements].forEach WebPack 给了我一个 Unexpected Token 错误。但是let elements = [...form.elements]; elements.forEach 确实有效。
【解决方案2】:

不能HMTLCollection 上使用forEachforEach 只能用于 `array。

替代方案是,使用lodash 并执行_.toArray(),这会将 HTMLColelction 转换为数组。在此之后,您可以对其进行正常的数组操作。或者,使用 ES6 spread 并使用 forEach()

这样,

var a = document.getElementsByTagName('div')
[...a].forEach()

【讨论】:

    【解决方案3】:

    form.elementsdocument.getElementsByTagNamedocument.getElementsByClassNamedocument.querySelectorAll 返回一个节点列表。

    节点列表本质上是一个对象,没有像数组这样的任何方法。

    如果您希望将节点列表用作数组,您可以使用Array.from(NodeList)Array.prototype.slice.call(NodeList) 的老派方式

    // es6
    const thingsNodeList = document.querySelectorAll('.thing')
    const thingsArray = Array.from(thingsNodeList)
    thingsArray.forEach(thing => console.log(thing.innerHTML))
    
    // es5
    var oldThingsNodeList = document.getElementsByClassName('thing')
    var oldThingsArray = Array.prototype.slice.call(oldThingsNodeList)
    thingsArray.forEach(function(thing){ 
      console.log(thing.innerHTML) 
    })
    <div class="thing">one</div>
    <div class="thing">two</div>
    <div class="thing">three</div>
    <div class="thing">four</div>

    【讨论】:

      猜你喜欢
      • 2015-01-22
      • 2018-11-07
      • 1970-01-01
      • 2022-10-14
      • 1970-01-01
      • 1970-01-01
      • 2017-10-04
      • 2021-05-17
      • 2020-04-03
      相关资源
      最近更新 更多