数组超出界限:与未定义或长度检查的比较?

时间:2011-07-18 03:38:32

标签: javascript arrays

这似乎是一个常见的javascript惯用语:

function foo (array, index) {
    if (typeof array[index] == 'undefined')
        alert ('out of bounds baby');
}

而不是更普遍(在其他语言中)和概念上更简单:

function foo (array, index) {
    if (index >= array.length)
        alert ('boo');
}

据我所知,第一种情况也适用于其中有“缺口”的数组,但这是一个足以保证成语的常见情况吗?

可以看到提示此问题的代码示例here。在这种情况下,当在函数内部使用'argument'变量时,假设它是一个连续的数组是不是很明智?

6 个答案:

答案 0 :(得分:26)

唯一正确的方法是检查索引与长度。

可以为元素分配值undefined。在这里使用它作为哨兵只是愚蠢。 (可能存在检查未定义的其他有效且可能重叠的原因,但不是“对于超出限制的检查” - 当给定arg的值为真的 undefined。)

快乐的编码。

答案 1 :(得分:15)

你也可以写:

if ( index in array ) {

即使array[index]设置为undefined,也会返回true。

答案 2 :(得分:1)

不要测试undefined。您应该使用数组的长度。有些情况下,它根本无法测试未定义,因为undefined是合法数组条目的合法值。这是一个合法的JS数组:

var legalArray = [4, undefined, "foo"];

你可以像这样访问它:

var legalArray = [4, undefined, "foo"];

var result = "";
for (var i = 0; i < legalArray.length; i++) {
    result += legalArray[i] + "<br>";
}

$("#result").html(result);

生成此输出:

4
undefined
foo

如本jsFiddle所示:http://jsfiddle.net/jfriend00/J5PPe/

答案 3 :(得分:0)

据我所知,这并不常见,更常见的是:

for (var i=0, iLen=array.length; i<iLen; i++) {
  // do stuff
}

您不应该与undefined进行比较,因为数组的成员可能已被赋值为undefined,或者可能未分配任何值。

e.g。

var a = [0,,,,];

alert(a.length); // 4 (or 5 in buggy IE);

a[1] === undefined; // true but not out of bounds

使用for循环的主要原因是,如果使用for..in循环,则数组属性可能不会以数字顺序返回。

for..in循环在稀疏数组中效率要高得多,但是如果重要的话必须处理可能的无序访问(如果应该避免,则必须继承和非数字可枚举属性)。 / p>

答案 4 :(得分:0)

在 JavaScript 中数组可以是稀疏的——它们可以包含“洞”。例如

const array = new Array(3);

导致 array 三个“洞” - 不是值。所以同时

const isInBounds = 0 <= index && index < array.length;

正确识别 index 是否在 array 的边界内,但不指示 array[index] 处是否有值。

Object.prototype.hasOwnProperty() 可用于确定值是否存在于 index。还需要注意的是,在存在“漏洞”的情况下,语言的不同部分可能表现得非常不同。

// ESLint: no-prototype-builtins)
const hasOwnProperty = Object.prototype.hasOwnProperty;

function show(array, index) {
  const msg =
    0 > index || index >= array.length
      ? `index ${index} is out of bounds`
      : !hasOwnProperty.call(array, index)
      ? `index ${index} is a hole`
      : `index ${index} holds ${array[index]}`;

  console.log(msg);
}

const subject = [undefined, , 1];

show(subject, -1);
// "index -1 is out of bounds"

for (let i = 0; i < subject.length; i += 1) show(subject, i);
// "index 0 holds undefined"
// "index 1 is a hole"
// "index 2 holds 1"

show(subject, 3);
// "index 3 is out of bounds"

const toString = (value) =>
  value !== undefined ? value.toString() : 'undefined';

// for..of doesn't skip holes
const byForOf = [];
for (const value of subject) byForOf.push(toString(value));
console.log(`Values found by for..of: ${byForOf.join(', ')}`);
// "Values found by for..of: undefined, undefined, 1"

// .forEach skips holes
const byForEach = [];
subject.forEach((value) => byForEach.push(toString(value)));
console.log(`Values found by .forEach: ${byForEach.join(', ')}`);
// "Values found by .forEach: undefined, 1"

// .reduce skips holes
const reducer = (acc, value) => {
  acc.push(toString(value));
  return acc;
};
const byReduce = subject.reduce(reducer, []);
console.log(`Values found by .reduce: ${byReduce.join(', ')}`);
// "Values found by .reduce: undefined, 1"

// .map preserves holes
const byMap = subject.map(toString);
console.log(`Values found by .map: ${byMap.join(', ')}`);
// "Values found by .map: undefined, , 1"

答案 5 :(得分:-1)

在这种情况下,测试它以确保它不会意外地将字符串“undefined”添加到调用String。在下面的例子中,它实际上会这样做:

var undefd;
"{0} is dead, but {1} is alive! {0} {2}".format("ASP", undefd, "ASP.NET")
// output as "ASP is dead, but {1} is alive! ASP ASP.NET"

就个人而言,我可能只是缓存长度,然后进行数字比较。

修改

旁注:他的方法也避免了NaN检查,但强制严格并行:

// this will fail unless 0001 is cast to a number, which means the method
// provided will fail. 
"{0} is dead, but {1} is alive! {0001} {2}".format("ASP", "ASP.NET")