JavaScript中的'in'运算符用于处理数组中未定义元素的情况。

18

请考虑以下代码片段:

> a = [1, undefined, undefined, undefined, 3]
  [1, undefined, undefined, undefined, 3]
> b = [1,,,,3]
  [1, undefined × 3, 3]
> 1 in a
  true
> 1 in b
  false

我是否遗漏了什么?看起来,根据我如何定义数组中的 undefined 元素,in 运算符的行为会有所不同。


3个回答

32

数组其实就是普通的 JavaScript 对象,只不过有一些专门的特性。引用自 ECMA 5.1 规范中的 Array Objects 部分

数组对象对某种类型的属性名给予了特殊处理。当且仅当 ToString(ToUint32(P)) 等于 P 且 ToUint32(P) 不等于 232−1 时,属性名 P(以字符串形式表示)就是一个 数组下标

所以说,数组下标就是数组对象的属性。现在,让我们来看一下数组中缺失元素的情况。

引用自 ECMA 5.1 标准规范

数组元素可以省略在元素列表的开始、中间或结尾。每当元素列表中的逗号未被赋值表达式(即在另一个逗号之前或在开头的逗号)所跟随时,省略的数组元素将会增加数组长度并增加后续元素的下标。被省略的数组元素没有定义。如果数组末尾省略了元素,则该元素不会增加数组长度。

所以,当你说:

b = [1,,,,3];
除了元素1和3之外,其余元素都被视为数组中的缺失元素。现在,元素1和3对应于属性0和4(JavaScript中的数组索引从0开始)。
您可以像这样检查:
console.log(Object.getOwnPropertyNames(b));
# [ '0', '4', 'length' ]
console.log(Object.getOwnPropertyNames(a));
# [ '0', '1', '2', '3', '4', 'length' ]
只有索引 04b 中。你可能会想知道为什么 a 从索引 04 都有属性,但值是 undefined。因为在索引 1、2 和 3 处的元素被定义为 undefined,而在 b 中,我们不知道这些值是什么。这就是为什么它们没有被分配到属性(索引)上。

现在,您正在使用 in 运算符检查 1 是否在 b 中。引用自 in 运算符 MDN Doc

如果指定的属性存在于指定的对象中,则 in 运算符返回 true。

所以,您基本上在检查 1 是否是 b 的一个属性,但它不是。这就是为什么 '1' in b 返回 false

注意:

如果您想知道 1 是否在数组中,您应该使用 Array.prototype.indexOf,像这样:

console.log(a.indexOf(1));
# 0
console.log(b.indexOf(1));
# 0
console.log(b.indexOf(5));
# -1

Array.prototype.indexOf 如果要查找的元素不在数组中,则返回-1。因此,您可能希望执行以下操作

console.log(a.indexOf(1) !== -1);
# true
console.log(b.indexOf(1) !== -1);
# true
console.log(a.indexOf(5) !== -1);
# false

6
我认为你的“注释”是最重要的部分。原帖似乎在寻找“值”,但实际上是在使用错误的方法(in运算符而不是[].indexOf)寻找“键”...也许并非如此。 - Ian
5
对我来说最重要的部分似乎是“定义为undefined”的概念——许多人似乎会忽略这种区别。 - Niet the Dark Absol
就像@NiettheDarkAbsol所说的,在我的话中——定义、未定义和未声明之间的区别。在,,,的情况下,位置1处的元素被视为未声明。没有该名称的属性。 - Benjamin Gruenbaum

1
在您的例子中,a[1]被定义,但被设置为undefined,因此1 in a == true。相比之下,b[1]根本没有被设置,因此1 in b == false。这就是为什么有些人说undefined很奇怪的原因。
要检查数组a是否具有值1,请使用a.indexOf(1) != -1。
要检查a[1]是否已定义,请使用a.hasOwnProperty("1")(1 in a略有不同,可能实际上并不是你想要的,因为它可以在a的原型中定义1,但在a本身中未定义)。
要将a[1]设置为undefined,请使用a[1] = undefined。
要使a[1]不再被定义,请使用delete a[1]。

-3
//-1 means not in the list
//['a','b','c'].indexOf('a') is return index if not find in the list then it give -1.

if(['a','b','c'].indexOf('d') == -1)
{
    console.log('yes it -1')
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接