# Array

## Definition

An array is a set of values ​​arranged in order. The position of each value is numbered (starting from 0), and the entire array is indicated by square brackets.

``````var arr = ["a", "b", "c"];
``````

The `a`, `b`, and `c` in the above code constitute an array, and the square brackets at both ends are the signs of the array. `a` is position 0, `b` is position 1, and `c` is position 2.

In addition to assigning values ​​at the time of definition, arrays can also be assigned after being defined.

``````var arr = [];

arr = "a";
arr = "b";
arr = "c";
``````

Any type of data can be put into an array.

``````var arr = [
{ a: 1 },
[1, 2, 3],
function () {
return true;
},
];

arr; // Object {a: 1}
arr; // [1, 2, 3]
arr; // function (){return true;}
``````

The three members of the above array `arr` are objects, arrays, and functions in sequence.

If the elements of the array are still arrays, a multidimensional array is formed.

``````var a = [
[1, 2],
[3, 4],
];
a; // 2
a; // 4
``````

## The essence of array

In essence, arrays belong to a special kind of object. The `typeof` operator will return the type of the array is `object`.

``````typeof [1, 2, 3]; // "object"
``````

The above code shows that the `typeof` operator considers the type of an array to be an object.

The particularity of the array is that its key name is a set of integers (0, 1, 2...) arranged in order.

``````var arr = ["a", "b", "c"];

Object.keys(arr);
// ["0", "1", "2"]
``````

In the above code, the `Object.keys` method returns all the keys of the array. You can see that the keys of the array are integers 0, 1, 2.

Because the key names of the array members are fixed (the default is always 0, 1, 2...), the array does not need to specify a key name for each element, and each member of the object must specify a key name. JavaScript language stipulates that the key names of objects are always strings, so the key names of arrays are actually strings. The reason why it can be read as a numeric value is because the non-string key name will be converted to a string.

``````var arr = ["a", "b", "c"];

arr["0"]; //'a'
arr; //'a'
``````

The above code uses numeric value and string as the key name respectively, and the result can read the array. The reason is that the numeric key name is automatically converted to a string.

Note that this is also true during assignment. A value is always first converted into a string, and then assigned as a key name.

``````var a = [];

a[1.0] = 6;
a; // 6
``````

In the above code, since the conversion of `1.00` into a string is `1`, the value can be read by the number key `1`.

As mentioned in the previous chapter, objects have two methods to read members: dot structure (`object.key`) and square bracket structure (`object[key]`). However, for numeric key names, the dot structure cannot be used.

``````var arr = [1, 2, 3];
arr.0 // SyntaxError
``````

In the above code, the writing of `arr.0` is illegal, because a single value cannot be used as an identifier. Therefore, array members can only be represented by square brackets `arr` (square brackets are operators and can accept values).

## length property

The `length` property of the array returns the number of members of the array.

``````["a", "b", "c"].length; // 3
``````

JavaScript uses a 32-bit integer to store the number of elements in the array. This means that the maximum number of array members is 4294967295 (232-1), which means that the maximum value of the `length` property is 4294967295.

As long as it is an array, there must be a `length` property. This attribute is a dynamic value, equal to the largest integer in the key name plus `1`.

``````var arr = ["a", "b"];
arr.length; // 2

arr = "c";
arr.length; // 3

arr = "d";
arr.length; // 10

arr = "e";
arr.length; // 1001
``````

The above code indicates that the numeric keys of the array do not need to be consecutive, and the value of the `length` property is always greater than the largest integer key by `1`. In addition, this also shows that the array is a dynamic data structure, and the members of the array can be added or removed at any time.

The `length` property is writable. If you manually set a value smaller than the current number of members, the number of members in the array will automatically be reduced to the value set by `length`.

``````var arr = ["a", "b", "c"];
arr.length; // 3

arr.length = 2;
arr; // ["a", "b"]
``````

The above code indicates that when the `length` property of the array is set to 2 (that is, the largest integer key can only be 1), then the integer key 2 (the value is `c`) is no longer in the array and is automatically deleted.

An effective way to empty the array is to set the `length` property to 0.

``````var arr = ["a", "b", "c"];

arr.length = 0;
arr; // []
``````

If the artificial setting of `length` is greater than the current number of elements, the number of members of the array will increase to this value, and the new positions will be empty.

``````var a = ["a"];

a.length = 3;
a; // undefined
``````

The above code indicates that when the `length` property is set to be greater than the number of arrays, reading the newly added position will return `undefined`.

If you manually set `length` to an illegal value, JavaScript will report an error.

``````// set a negative value
[].length = -1
// RangeError: Invalid array length

// The number of array elements is greater than or equal to 2 to the 32nd power
[].length = Math.pow(2, 32)
// RangeError: Invalid array length

// set string
[].length ='abc'
// RangeError: Invalid array length
``````

It is worth noting that since the array is essentially an object, you can add attributes to the array, but this does not affect the value of the `length` property.

``````var a = [];

a["p"] = "abc";
a.length; // 0

a[2.1] = "abc";
a.length; // 0
``````

The above code sets the keys of the array to string and decimal respectively, and the result does not affect the `length` property. Because the value of the `length` property is equal to the largest numeric key plus 1, and this array does not have an integer key, the `length` property remains at `0`.

If the key name of the array is to add an out-of-range value, the key name will be automatically converted to a string.

``````var arr = [];
arr[-1] = "a";
arr[Math.pow(2, 32)] = "b";

arr.length; // 0
arr[-1]; // "a"
arr; // "b"
``````

In the above code, we added two illegal numeric keys to the array `arr`, but the `length` property did not change as a result. These number keys have become string key names. The reason why the last two lines get the value is because when you get the key value, the numeric key name will be converted to a string by default.

## in operator

The operator `in`, which checks whether a key name exists, applies to objects as well as arrays.

``````var arr = ["a", "b", "c"];
2 in arr; // true
"2" in arr; // true
4 in arr; // false
``````

The above code shows that there is a key named `2` in the array. Since the key names are all strings, the value `2` will be automatically converted into a string.

Note that if a position in the array is empty, the `in` operator returns `false`.

``````var arr = [];
arr = "a";

100 in arr; // true
1 in arr; // false
``````

In the above code, the array `arr` has only one member `arr`, and the key names in other positions will all return `false`.

## for...in loop and array traversal

The `for...in` loop can traverse not only objects, but also arrays. After all, arrays are just a special kind of object.

``````var a = [1, 2, 3];

for (var i in a) {
console.log(a[i]);
}
// 1
// 2
// 3
``````

However, `for...in` not only traverses all numeric keys in the array, but also traverses non-numeric keys.

``````var a = [1, 2, 3];
a.foo = true;

for (var key in a) {
console.log(key);
}
// 0
// 1
// 2
// foo
``````

When the above code traverses the array, it also traverses the non-integer key `foo`. Therefore, it is not recommended to use `for...in` to traverse the array.

For array traversal, consider using `for` loop or `while` loop.

``````var a = [1, 2, 3];

// for loop
for (var i = 0; i < a.length; i++) {
console.log(a[i]);
}

// while loop
var i = 0;
while (i < a.length) {
console.log(a[i]);
i++;
}

var l = a.length;
while (l--) {
console.log(a[l]);
}
``````

The above code is three ways to traverse the array. The last way of writing is reverse traversal, that is, traversing from the last element to the first element.

The `forEach` method of arrays can also be used to traverse arrays. For details, see the chapter on Array objects in the Standard Library.

``````var colors = ["red", "green", "blue"];
colors.forEach(function (color) {
console.log(color);
});
// red
// green
// blue
``````

## Array space

When a certain position of the array is an empty element, that is, there is no value between the two commas, we say that the array has a hole (hole).

``````var a = [1, , 1];
a.length; // 3
``````

The above code shows that the space of the array does not affect the `length` property.

It should be noted that if there is a comma after the last element, no space will be generated. In other words, with or without this comma, the result is the same.

``````var a = [1, 2, 3];

a.length; // 3
a; // [1, 2, 3]
``````

In the above code, there is a comma after the last member of the array, which does not affect the value of the `length` property, and the effect is the same as without this comma.

The space of the array is readable, and `undefined` is returned.

``````var a = [, , ,];
a; // undefined
``````

Using the `delete` command to delete an array member will form a gap and will not affect the `length` property.

``````var a = [1, 2, 3];
delete a;

a; // undefined
a.length; // 3
``````

The above code uses the `delete` command to delete the second element of the array. This position forms a space, but it has no effect on the `length` property. In other words, the `length` property does not filter gaps. Therefore, you must be very careful when using the `length` property for array traversal.

A certain position of the array is empty, and a certain position is `undefined`, which is different. If it is a space, use the `forEach` method of the array, the `for...in` structure, and the `Object.keys` method to traverse, and the space will be skipped.

``````var a = [, , ,];

a.forEach(function (x, i) {
console.log(i + ". " + x);
});
// does not produce any output

for (var i in a) {
console.log(i);
}
// does not produce any output

Object.keys(a);
// []
``````

If a certain position is `undefined`, it will not be skipped when traversing.

``````var a = [undefined, undefined, undefined];

a.forEach(function (x, i) {
console.log(i + ". " + x);
});
// 0. undefined
// 1. undefined
// 2. undefined

for (var i in a) {
console.log(i);
}
// 0
// 1
// 2

Object.keys(a);
// ['0', '1', '2']
``````

That is to say, the empty space means that the array does not have this element, so it will not be traversed, and `undefined` means that the array has this element, and the value is `undefined`, so the traversal will not skip.

## Array-like objects

If all the keys of an object are positive integers or zeros, and have the `length` property, then the object is very similar to an array, and is syntactically called an "array-like object".

``````var obj = {
0: "a",
1: "b",
2: "c",
length: 3,
};

obj; //'a'
obj; //'b'
obj.length; // 3
obj.push("d"); // TypeError: obj.push is not a function
``````

In the above code, the object `obj` is an array-like object. However, "array-like objects" are not arrays, because they do not have methods specific to arrays. The object `obj` has no `push` method for an array, and an error will be reported if this method is used.

The fundamental characteristic of "array-like objects" is the `length` property. As long as there is a `length` property, this object can be considered similar to an array. But there is a problem. This `length` property is not a dynamic value and will not change with changes in members.

``````var obj = {
length: 0,
};
obj = "d";
obj.length; // 0
``````

The above code adds a numeric key to the object `obj`, but the `length` property has not changed. This shows that `obj` is not an array.

Typical "array-like objects" are the `arguments` objects of functions, and most sets of DOM elements, as well as strings.

``````// arguments object
function args() {
return arguments;
}
var arrayLike = args("a", "b");

arrayLike; //'a'
arrayLike.length; // 2
arrayLike instanceof Array; // false

// DOM element set
var elts = document.getElementsByTagName("h3");
elts.length; // 3
elts instanceof Array; // false

// string
"abc"; //'b'
"abc".length; // 3
"abc" instanceof Array; // false
``````

The above code contains three examples, none of them are arrays (the `instanceof` operator returns `false`), but they all look very much like arrays.

The slice method of the array can turn the "array-like object" into a real array.

``````var arr = Array.prototype.slice.call(arrayLike);
``````

In addition to turning it into a real array, there is another way for "array-like objects" to use arrays, which is to put the array methods on the object through `call()`.

``````function print(value, index) {
console.log(index + ":" + value);
}

Array.prototype.forEach.call(arrayLike, print);
``````

In the above code, `arrayLike` represents an array-like object. You cannot use the `forEach()` method of an array, but you can graft `forEach()` to `arrayLike` through `call()` transfer.

The following example uses this method to call the `forEach` method on the `arguments` object.

``````// forEach method
function logArgs() {
Array.prototype.forEach.call(arguments, function (elem, i) {
console.log(i + ". " + elem);
});
}

// equivalent to for loop
function logArgs() {
for (var i = 0; i < arguments.length; i++) {
console.log(i + ". " + arguments[i]);
}
}
``````

Strings are also array-like objects, so you can also use `Array.prototype.forEach.call` to traverse.

``````Array.prototype.forEach.call("abc", function (chr) {
console.log(chr);
});
// a
// b
// c
``````

Note that this method is slower than using the original `forEach` of the array directly, so it is better to first convert the "array-like object" into a real array, and then directly call the `forEach` method of the array.

``````var arr = Array.prototype.slice.call("abc");
arr.forEach(function (chr) {
console.log(chr);
});
// a
// b
// c
``````