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[0] = "a";
arr[1] = "b";
arr[2] = "c";

Any type of data can be put into an array.

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

arr[0]; // Object {a: 1}
arr[1]; // [1, 2, 3]
arr[2]; // 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[0][1]; // 2
a[1][1]; // 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[0]; //'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[1]; // 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[0] (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[2] = "c";
arr.length; // 3

arr[9] = "d";
arr.length; // 10

arr[1000] = "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[1]; // 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[4294967296]; // "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[100] = "a";

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

In the above code, the array arr has only one member arr[100], 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[1]; // 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[1];

a[1]; // 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[0]; //'a'
obj[1]; //'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[3] = "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[0]; //'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"[1]; //'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