开发者问题收集

未捕获的类型错误:无法读取属性 - 尽管属性存在

2013-03-07
839
var sorted = DocumentListData.Documents.sort(function (a, b) {
    var nameA = a.Document.toLowerCase(),
        nameB = b.Document.toLowerCase();

    return nameA.localeCompare(nameB);
});

for (var i = 0, len = sorted.length; i < len; i++) {

    if (sorted[i].Document=== 'abc') {
        sorted.splice(i, 1);
    }

    if (sorted[i].Document=== 'xyz') {
        sorted.splice(i, 1);
    }
}

我花了一个小时思考这里到底出了什么错误。它抛出“Document is undefined”,尽管 Document 属性存在。

Uncaught TypeError: Cannot read property 'Document' of undefined 。当我删除 sorted.splice(i,1) 时,它可以正常工作并且没有错误。

2个回答

您正在修改正在迭代的数组。 splice(i,1) 删除第 i 个元素。当您拼接排序后的数组时,您将删除元素,因此最终会超出数组的长度,因为循环会转到数组的原始长度。 sorted[i] 然后未定义,并且您会收到您所描述的错误。

通常,以这种方式修改当前正在迭代的数组从来都不是一个好主意。如果您必须以这种方式执行此操作,请确保包含 if 检查以查看 i 是否不为 >= 到数组的当前长度。但使用 while 循环可能更适合这里。

var counter =0;
while(counter < sorted.length) {
var doc = sorted[counter].Document;
  if (doc === 'abc' ||doc === 'xyz') {
    sorted.splice(counter, 1);
  }
  else{
   counter++;
  }
}

更多想法

  1. document 是 javascript 浏览器环境中的预定义变量,通常 JS 有一个约定,即大写变量仅适用于构造函数。因此 Document 可能不是一个很好的属性名称选择。

  2. 如果您不需要支持旧版本的 IE,您还可以查看 Array.Prototype.filter ,这是一种更简洁的方式来做您想做的事情

Ben McCormick
2013-03-07

如果最后一个元素的 Documentabc ,它将在第一个 if 条件中被删除。

sorted[i] 将变为 undefined (因为您已经删除了最后一个元素),并且当第二个 if 运行时,您将收到所描述的错误。

您可以使用 else if 来修复此问题:

if (sorted[i].Document=== 'abc') {
    sorted.splice(i, 1);
} else if (sorted[i].Document=== 'xyz') {
    sorted.splice(i, 1);
}
Matt
2013-03-07