ES6
Extension of arrays
Extended operator
The spread operator (spread) is three points (…) . It is like the inverse of the REST argument, turning an array into a comma-separated sequence of arguments.
console.log(... [1, 2, 3]) // 1 2 3 console.log(1, ... [2, 3, 4], 5) // 1 2 3 4 5 [...document.querySelectorAll('div')] // [<div>, <div>, <div>]Copy the code
This operator is used primarily for function calls.
function push(array, ... items) { array.push(... items); } function add(x, y) { return x + y; } const numbers = [4, 38]; add(... numbers) // 42Copy the code
In the code above, array.push(… The items) and add (… Numbers), both function calls that use extension operators. This operator turns an array into a sequence of arguments.
Extended operators can be used in conjunction with normal function parameters, making them very flexible.
function f(v, w, x, y, z) { } const args = [0, 1]; f(-1, ... args, 2, ... [3]);Copy the code
Extended operators can also be followed by expressions.
const arr = [
...(x > 0 ? ['a'] : []),
'b',
];
Copy the code
If the extension operator is followed by an empty array, nothing happens.
/ [... [], 1] / [1]Copy the code
Note: Extension operators can only be placed in parentheses when a function is called, otherwise an error will be reported.
(... [1, 2]) // Uncaught SyntaxError: Unexpected number console.log((... [1, 2])) // Uncaught SyntaxError: Unexpected number console.log(... [1, 2]) // 1 2Copy the code
In all three cases, the extension operator is inside parentheses, but in the first two cases an error is reported because the parentheses inside the extension operator are not function calls.
The apply method replaces the function
Because the extension operator can expand an array, the apply method is no longer needed to convert the array to a function parameter.
Function f(x, y, z) {//... } var args = [0, 1, 2]; f.apply(null, args); Function f(x, y, z) {//... } let args = [0, 1, 2]; f(... args);Copy the code
Here is a practical example of the extension operator replacing apply to simplify writing the largest element of an array using math.max.
Math.max. Apply (null, [14, 3, 77]) math.max (... [14, 3, 77]) // equivalent to math.max (14, 3, 77);Copy the code
In the above code, because JavaScript does not provide a function for finding the largest element of an array, you can only use the math.max function, which turns the array into a sequence of parameters and then evaluates the maximum. Now that you have the extension operator, you can use math.max directly.
Another example is adding an array to the end of another array using the push function.
Var arr1 = [0, 1, 2]; var arr2 = [3, 4, 5]; Array.prototype.push.apply(arr1, arr2); // let arr1 = [0, 1, 2]; let arr2 = [3, 4, 5]; arr1.push(... arr2);Copy the code
In the ES5 version of the code above, the arguments to the push method cannot be arrays, so we have to use the apply method to work around the push method. With the extension operator, you can pass an array directly to the push method.
Extend the application of operators
(1) Copy array
Arrays are composite data types, so copying directly copies Pointers to the underlying data structure rather than cloning an entirely new array.
const a1 = [1, 2];
const a2 = a1;
a2[0] = 2;
a1 // [2, 2]
Copy the code
In the code above, A2 is not a clone of A1, but another pointer to the same data. Modifying A2 will directly change A1.
ES5 can only copy arrays using workarounds.
const a1 = [1, 2];
const a2 = a1.concat();
a2[0] = 2;
a1 // [1, 2]
Copy the code
In the above code, A1 returns a clone of the original array, and modification of A2 has no effect on A1.
const a1 = [1, 2]; // const a2 = [...a1]; // const [...a2] = a1;Copy the code
In both cases, a2 is a clone of A1.
(2) Merge arrays
The extension operator provides a new way of writing array merges.
const arr1 = ['a', 'b']; const arr2 = ['c']; const arr3 = ['d', 'e']; // ES5 merge array arr1.concat(arr2, arr3); / / / 'a', 'b', 'c', 'd', 'e'] / / ES6 merger array [arr1,... arr2... arr3] / [' a ', 'b', 'c', 'd', 'e']Copy the code
However, both methods are shallow copies and should be used with caution.
const a1 = [{ foo: 1 }];
const a2 = [{ bar: 2 }];
const a3 = a1.concat(a2);
const a4 = [...a1, ...a2];
a3[0] === a1[0] // true
a4[0] === a1[0] // true
Copy the code
In the above code, A3 and A4 are new arrays combined in two different ways, but their members are references to the original array members, which is a shallow copy. If you change the value pointed to by a reference, it is synchronized to the new array.
(3) Combine with deconstruction assignment
Extension operators can be used in conjunction with destructuring assignments to generate arrays.
// ES5
a = list[0], rest = list.slice(1)
// ES6
[a, ...rest] = list
Copy the code
const [first, ...rest] = [1, 2, 3, 4, 5];
first // 1
rest // [2, 3, 4, 5]
const [first, ...rest] = [];
first // undefined
rest // []
const [first, ...rest] = ["foo"];
first // "foo"
rest // []
Copy the code
If an extension operator is used for array assignment, it must be placed in the last bit of the argument, otherwise an error will be reported.
const [...butLast, last] = [1, 2, 3, 4, 5]; / / error const [first,... the middle, and last] = [1, 2, 3, 4, 5]. / / an errorCopy the code
(4) String
Extension operators can also turn strings into true arrays.
[...'hello']
// [ "h", "e", "l", "l", "o" ]
Copy the code
(5) Objects that implement the Iterator interface
Any object that defines an Iterator interface (see the Chapter on Iterator) can be converted to a true array using the extension operator.
let nodeList = document.querySelectorAll('div');
let array = [...nodeList];
Copy the code
In the above code, the querySelectorAll method returns a NodeList object. It’s not an array, it’s an array-like object. In this case, the extension operator can turn it into a true array because the NodeList object implements Iterator.
For array-like objects that do not have an Iterator interface deployed, the extension operator cannot turn them into true arrays.
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
// TypeError: Cannot spread non-iterable object.
let arr = [...arrayLike];
Copy the code
In the above code, arrayLike is an array-like object, but without the Iterator interface deployed, the extension operator will report an error. At this point, you can turn an arrayLike into a real Array using the array. from method instead.
(6) Map and Set structures, Generator functions
An extension operator internally calls the Iterator interface of a data structure, so any object that has an Iterator interface can use an extension operator, such as a Map structure.
let map = new Map([ [1, 'one'], [2, 'two'], [3, 'three'], ]); let arr = [...map.keys()]; / / [1, 2, 3]Copy the code
When the Generator function runs, it returns an traverser object, so extension operators can also be used.
const go = function*(){
yield 1;
yield 2;
yield 3;
};
[...go()] // [1, 2, 3]
Copy the code
In the above code, the variable go is a Generator function that returns an traverser object. Executing the extension operator on this traverser object converts the values of the internal traversal into an array.
An error is reported if you use the extension operator on an object that does not have an Iterator interface.
const obj = {a: 1, b: 2};
let arr = [...obj]; // TypeError: Cannot spread non-iterable object
Copy the code
Array.from()
The array. from method is used to convert two types of objects into true arrays: array-like objects and iterable objects (including the new ES6 data structures Set and Map).
Here is an array-like object, array. from turns it into a real Array.
let arrayLike = { '0': 'a', '1': 'b', '2': 'c', length: 3 }; Var arr1 = [].slice.call(arrayLike); / / / 'a', 'b', 'c'] / / written ES6 let arr2 = Array. The from (arrayLike); // ['a', 'b', 'c']Copy the code
In practice, common array-like objects are the NodeList collection returned by DOM operations, and arguments objects inside functions. Array.from can turn them into real arrays.
/ / the NodeList object let ps = document. QuerySelectorAll (" p "); Array.from(ps).filter(p => { return p.textContent.length > 100; }); Function foo() {var args = array. from(arguments); / /... }Copy the code
Array.of()
The array.of () method converts a set of values to an Array.
Array of (3, 11, 8) / /,11,8 [3] Array of (3) / / [3] Array) of (3). The length / / 1Copy the code
The array.of () method can be simulated using the following code.
function ArrayOf(){
return [].slice.call(arguments);
}
Copy the code
Array instance copyWithin()
The copyWithin() method of an array instance, inside the current array, copies the specified member to another location (overwriting the original member) and returns the current array. That is, using this method, you modify the current array.
It takes three arguments.
- Target (required) : Replace data from this location. If it is negative, it is the reciprocal.
- Start (Optional) : reads data from this position. The default value is 0. If the value is negative, it is calculated from the end.
- End (Optional) : Stops reading data until this position, which is equal to the array length by default. If the value is negative, it is calculated from the end.
All three arguments should be numeric; if not, they are automatically converted to numeric values.
[1, 2, 3, 4, 5].copyWithin(0, 3)
// [4, 5, 3, 4, 5]
Copy the code
The code above shows that the members from bit 3 to the end of the array (4 and 5) are copied to the position starting at bit 0, overwriting the original 1 and 2.
Here are some more examples.
[1, 2, 3, 4, 5]. CopyWithin (0, 3, 4) // [4, 2, 3, 4, 5] 1 of 4 [1, 2, 3, 4, 5]. CopyWithin (0, 2, 1) / / [4, 2, 3, 4, 5] / / copies the 3 to 0 bit []. CopyWithin. Call ({length: 5, 3: Let i32A = new Int32Array([1, 2, 3, 4, 5]); i32a.copyWithin(0, 2); // Int32Array [3, 4, 5, 4, CopyWithin. Call (new Int32Array([1, 2, 3, 4, 5]), 0, 3, 4); // Int32Array [4, 2, 3, 4, 5]Copy the code
Find () and findIndex() of array instances
The find method of an array instance, used to find the first array member that matches the criteria. Its argument is a callback function that is executed by all array members until the first member that returns true is found, and then returned. If there is no qualified member, undefined is returned.
[1, 4, -5, 10].find((n) => n < 0)
// -5
Copy the code
The above code finds the first member of the array that is less than 0.
[1, 5, 10, 15].find(function(value, index, arr) { return value > 9; }) / / 10Copy the code
In the code above, the find callback can take three arguments: the current value, the current position, and the original array.
The findIndex method on an array instance is used much like the find method, returning the location of the first qualified array member, or -1 if all members fail.
[1, 5, 10, 15].findIndex(function(value, index, arr) { return value > 9; / / 2})Copy the code
Fill () for array instances
The fill method fills an array with the given value.
['a', 'b', 'c'].fill(7)
// [7, 7, 7]
new Array(3).fill(7)
// [7, 7, 7]
Copy the code
As the code above shows, the fill method is handy for initializing an empty array. Any existing elements in the array will be erased.
The fill method can also accept a second and third parameters that specify where the fill starts and ends.
['a', 'b', 'c'].fill(7, 1, 2)
// ['a', 7, 'c']
Copy the code
The code above shows that the fill method starts at bit 1, fills the original array with 7, and ends just before bit 2.
Array instance entries(), keys() and values()
ES6 provides three new methods — entries(), keys() and values() — for traversing groups of numbers. They both return an Iterator object (see the Chapter on Iterator), which can be used as a for… The of loop is traversed, the only differences being that keys() is traversal of key names, values() is traversal of key values, and entries() is traversal of key value pairs.
Includes () of array instances
The array.prototype. includes method returns a Boolean value indicating whether an Array contains a given value, similar to the includes method of strings. ES2016(ES7) introduced this approach.
[1, 2, 3].includes(2) // true
[1, 2, 3].includes(4) // false
[1, 2, NaN].includes(NaN) // true
Copy the code
The second argument to this method represents the starting position of the search, which defaults to 0. If the second argument is negative, it represents the reciprocal position, and if it is greater than the array length (for example, if the second argument is -4, but the array length is 3), it is reset to start at 0.
[1, 2, 3].includes(3, 3); // false
[1, 2, 3].includes(3, -1); // true
[NaN].indexOf(NaN)
// -1
[NaN].includes(NaN)
// true
Copy the code
Array instance flat(), flatMap()
The members of arrays are sometimes still arrays, array.prototype.flat () is used to “flatten” nested arrays into one-dimensional arrays. This method returns a new array with no effect on the original data.
[1, 2, [3, 4]].flat()
// [1, 2, 3, 4]
Copy the code
Flat () “flattens” only one layer by default. If you want to “flatten” a nested array of multiple layers, you can write the argument to the flat() method as an integer representing the number of layers you want to flatten, which defaults to 1.
[1, 2, [3, [4, 5]]].flat()
// [1, 2, 3, [4, 5]]
[1, 2, [3, [4, 5]]].flat(2)
// [1, 2, 3, 4, 5]
Copy the code
In the code above, flat() takes 2 to “flatten” the two layers of nested arrays.
If you want to convert to a one-dimensional array regardless of the number of nesting levels, you can use the Infinity keyword as an argument.
[1, [2, [3]]].flat(Infinity)
// [1, 2, 3]
Copy the code
If the array is empty, the flat() method skips the empty.
[1, 2, , 4, 5].flat()
// [1, 2, 4, 5]
Copy the code
The flatMap() method performs a function on each member of the original Array (equivalent to array.prototype.map ()), and then flat() on the Array of returned values. This method returns a new array, leaving the original array unchanged.
/ / equivalent to the [[2, 4], [3, 6], [4, 8]]. Flat () [2, 3, 4] flatMap ((x) = > [x, x * 2]) / / [2, 4, 3, 6, 4, 8]Copy the code
FlatMap () can expand only one layer array.
/ / equivalent to the [[[2]], [[4]], [[6]], [[8]]]. Flat () [1, 2, 3, 4]. FlatMap (x = > [* 2] [x]) / / [[2], [4], [6], [8]]Copy the code
Object extension
The super keyword
We know that the this keyword always refers to the current object of the function, but ES6 has added another similar keyword super to refer to the prototype object of the current object.
const proto = { foo: 'hello' }; const obj = { foo: 'world', find() { return super.foo; }}; Object.setPrototypeOf(obj, proto); obj.find() // "hello"Copy the code
In the code above, the object obj.find() method references the foo property of the prototype object proto via super.foo.
Note that when the super keyword represents a prototype object, it can only be used in the object’s methods, and will return an error if used elsewhere.
Const obj = {foo: super.foo} const obj = {foo: super.foo} const obj = {foo: () => super.foo} function () { return super.foo } }Copy the code
Deconstruction assignment
Destructible assignment of an object is used to take values from an object, which is equivalent to assigning all of the target object’s Enumerable properties that have not yet been read to the specified object. All the keys and their values are copied to the new object.
let { x, y, ... z } = { x: 1, y: 2, a: 3, b: 4 }; x // 1 y // 2 z // { a: 3, b: 4 }Copy the code
Extended operator
Object extension operator (…) Retrieves all traversable properties of the parameter object and copies them to the current object.
let z = { a: 3, b: 4 }; let n = { ... z }; n // { a: 3, b: 4 }Copy the code
Since arrays are special objects, the extension operators for objects can also be used for arrays.
let foo = { ... ['a', 'b', 'c'] }; foo // {0: "a", 1: "b", 2: "c"}Copy the code
If the extension operator is followed by an empty object, it has no effect.
{... {}, a: 1} // { a: 1 }Copy the code
Chain judgment operator
To read the message. The body. The user firstName, the security method is as follows.
/ / error writing const firstName = message. The body. The user. The firstName; / / the correct writing const firstName = (message && message. The body & message. The body. The user && message. The body. The user. The firstName) | | 'default';Copy the code
In the example above, the firstName attribute is at the fourth level of the object, so you need to check four times to see if each level has a value.
Ternary operators? : is also used to determine whether an object exists.
const fooInput = myForm.querySelector('input[name=foo]')
const fooValue = fooInput ? fooInput.value : undefined
Copy the code
In the example above, you must check whether fooInput exists before reading fooinput. value.
Such layers of determination are troublesome, so ES2020(ES11) introduces the optional chaining operator? To simplify the above.
const firstName = message? .body? .user? .firstName || 'default'; const fooValue = myForm.querySelector('input[name=foo]')? .valueCopy the code
Does the above code use? The. Operator directly determines whether the object on the left is null or undefined during the chain call. If so, it does not proceed further and returns undefined.
Here is an example of determining whether an object method exists and executing it immediately if it does.
iterator.return? . ()Copy the code
Iterator. return is called if it has a definition, otherwise iterator.return returns undefined. .The latter part.
Most of this article comes from the following ES6 tutorial:
Getting started with ECMAScript 6
ECMAScript 6 profile