18

Please consider the following snippet of code:

> 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

Am I missing something? It seems to be that, depending on how I define undefined elements in an array, the in operator behaves differently.

thefourtheye
  • 206,604
  • 43
  • 412
  • 459
fcracker79
  • 902
  • 6
  • 21
  • See also [What is “`[undefined x 1]`” in JavaScript?](https://stackoverflow.com/q/10683773/1048572) – Bergi Jul 04 '17 at 17:51

3 Answers3

32

Arrays are nothing but normal JavaScript objects, with some specialization. Quoting from Array Objects section of ECMA 5.1 Specification

Array objects give special treatment to a certain class of property names. A property name P (in the form of a String value) is an array index if and only if ToString(ToUint32(P)) is equal to P and ToUint32(P) is not equal to 232−1.

So, array indices are nothing but properties of array objects. Now, lets see about missing elements in an Array.

Quoting from the ECMA 5.1 Standard Specification,

Array elements may be elided at the beginning, middle or end of the element list. Whenever a comma in the element list is not preceded by an AssignmentExpression (i.e., a comma at the beginning or after another comma), the missing array element contributes to the length of the Array and increases the index of subsequent elements. Elided array elements are not defined. If an element is elided at the end of an array, that element does not contribute to the length of the Array.

So, when you say

b = [1,,,,3];

except the elements 1 and 3, all others are treated as missing elements in the array. Now elements 1 and 3 correspond to the properties 0 and 4 (Array indices start with 0 in JavaScript).

You can check that like this

console.log(Object.getOwnPropertyNames(b));
# [ '0', '4', 'length' ]
console.log(Object.getOwnPropertyNames(a));
# [ '0', '1', '2', '3', '4', 'length' ]

Only the indices 0 and 4 are in b. You might be wondering why a has the properties from 0 to 4, though the values are undefined. Because, the elements at indices 1, 2 and 3 are defined to be undefined, where as in b, we don't know what those values are. That is why they are not allocated to a property (index).

Now, you are checking if 1 is in b, with in operator. Quoting from in operator MDN Doc,

The in operator returns true if the specified property is in the specified object.

So, you are basically checking if 1 is one of the properties of b, which is not. That is why '1' in b returns false.

Note:

If you wanted to know if 1 is in the Array or not, you should use Array.prototype.indexOf, like this

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

Array.prototype.indexOf returns -1 if the element being searched is not there in the Array. So, you might want to do something like this

console.log(a.indexOf(1) !== -1);
# true
console.log(b.indexOf(1) !== -1);
# true
console.log(a.indexOf(5) !== -1);
# false
thefourtheye
  • 206,604
  • 43
  • 412
  • 459
  • 6
    I think your **Note** is the most important part. The OP seems to be looking for **values**, but is actually searching for **keys**, by using the wrong thing (`in` operator, not `[].indexOf`)...maybe not though – Ian Mar 17 '14 at 07:00
  • 5
    Most important part to me seems to be the concept of "defined to be `undefined`" - a lot of people seem to miss this distinction. – Niet the Dark Absol Mar 17 '14 at 08:46
  • What @NiettheDarkAbsol said, and in my words - the difference between defined, undefined and undeclared. In the `,,,` case the element at position 1 is treated as if it is not declared. There is no property with that name. – Benjamin Gruenbaum Mar 17 '14 at 14:08
1

In your example, a[1] is defined, but is set to undefined, therefore 1 in a == true. By contrast, b[1] is not set at all, therefore 1 in b == false. This is why some people say that undefined is weird.

To check whether an array a has the value 1, use a.indexOf(1) != -1.

To check whether the a[1] is defined, use a.hasOwnProperty("1") (1 in a is subtly different, and is probably not actually what you want, because it can be true if 1 is defined in a's prototype but not in a itself).

To set a[1] to undefined, use a[1] = undefined.

To make a a[1] stop being defined, use delete a[1].

The Spooniest
  • 2,713
  • 12
  • 14
-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')
}
Anders
  • 7,431
  • 6
  • 42
  • 76