带有对象数组的 IE11 问题(适用于 Firefox 和 Chrome)

IE11 probelm with array of objects (it works on Firefox and Chrome)

我正在动态创建一个对象数组,如下所示:

let span = document.createElement('span')

span.classList.add('animated')
span.classList.add('char')

span.textContent = (char.match(/'|\.|\!|\?| |\,|\.|\;|\:|\./)) ? char  : '\ '

chars.push({
    char: char,
    span: span,
    solved: span.textContent === '\ ' ? false : true
 })

稍后当我尝试遍历数组并像这样访问元素时:

chars[i].span.classList.add('high-light')

我收到以下错误:

Unable to get property 'span' of undefined or null reference

为什么?

完整代码可在此处获得:https://github.com/sickdyd/secret-sentence

问题出在这里:

for (let i = 0; i < chars.length; i++) {
  // ...
  setTimeout(function() {
    chars[i].span.classList.add('high-light')

这是 IE11 中的一个错误。用let语法声明的变量在ES2015正式引入,2013年IE11发布——虽然遇到let不会抛出语法错误,但不符合规范。具体来说,在 IE11 中使用 let 声明的变量不会 获得块作用域 - 相反,它们具有函数作用域,就像 var 一样,所以在循环结束时,i 等于 chars.length,而 chars[chars.length] 等于 undefined,因此尝试引用 chars[i].span 将引发错误。

我建议避免 for 循环并使用 forEach 来代替,这将解决问题并让您避免跟踪索引:

chars.forEach(function(char) {
  // ...
  setTimeout(function() {
    char.span.classList.add('high-light')
    // ...
    // instead of referencing chars[i], reference char

您也可以使用主要的 closure inside loops 示例,尽管它很丑陋:

for (let i = 0; i < chars.length; i++) {
  (function(i) {
    // now, there will be a separate `i` argument for every iteration
    // ...
    setTimeout(function() {
      chars[i].span.classList.add('high-light')
      // ...
  })(i);
}

您还可以考虑自动转译您的代码以兼容 ES5 Babel