ABSTRACT: Grasp the array method by code.
- Original text: Understanding and efficient use of array methods by implementing 25 array methods (long text, recommended collection)
- Translator: Front-end wisdom
Fundebug Copyright shall be owned by the original author upon authorization to reproduce.
To use methods on a given array, you just need to pass []. Method names, which are defined on the Array.prototype object. Here, let's not use these phases first. Instead, we'll start with a simple way to define our own versions and build on them.
There is no better way to learn than to take things apart and reassemble them. Note that when we implement our own methods, don't override existing methods, because some libraries need them, and it's also convenient to compare our own methods with the original ones.
So don't name our custom method like this:
Array.prototype.map = function map() { // implementation };
It's better to name it this way:
function map(array) { // implementation }
We can also implement our approach by using class keywords and extending the Array constructor, as follows:
class OwnArray extends Array { public constructor(...args) { super(...args); } public map() { // implementation return this; } }
The only difference is that instead of using array parameters, we use this keyword.
But I think the class approach brings unnecessary confusion, so let's take the first approach.
With this in mind, let's start with the simplest way to implement forEach!
Collection class
.forEach
The Array.prototype.forEach method performs the provided function once for each element of the array without changing the original array.
[1, 2, 3, 4, 5].forEach(value => console.log(value));
Realization
function forEach(array, callback) { const { length } = array; for (let index = 0; index < length; index += 1) { const value = array[index]; callback(value, index, array) } }
Let's traverse the array and perform callbacks for each element. One thing to note here is that this method returns nothing, so undefined is returned by default.
Method ripple
The advantage of using array methods is that operations can be linked together. Consider the following code:
function getTodosWithCategory(todos, category) { return todos .filter(todo => todo.category === category) .map(todo => normalizeTodo(todo)); }
In this way, we don't have to save the results of map execution into variables, and the code will be more concise.
Unfortunately, forEach did not return to the original array, which means that we can't do the following things
// Unable to work function getTodosWithCategory(todos, category) { return todos .filter(todo => todo.category === category) .forEach((value) => console.log(value)) .map(todo => normalizeTodo(todo)); }
Help function (print information)
Then we implement a simple function that better explains the function of each method: what to accept as input, what to return, and whether it modifies the array.
function logOperation(operationName, array, callback) { const input = [...array]; const result = callback(array); console.log({ operation: operationName, arrayBefore: input, arrayAfter: array, mutates: mutatesArray(input, array), // shallow check result, }); }
The mutatesArray method is used to determine whether the original array has been changed or not. If a change has just returned true, it will return false. Of course, everyone has good ideas to put forward in the comments.
function mutatesArray(firstArray, secondArray) { if (firstArray.length !== secondArray.length) { return true; } for (let index = 0; index < firstArray.length; index += 1) { if (firstArray[index] !== secondArray[index]) { return true; } } return false; }
Then we use logOperation to test the forEach method we implemented earlier.
logOperation('forEach', [1, 2, 3, 4, 5], array => forEach(array, value => console.log(value)));
Print results:
{ operation: 'forEach', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 1, 2, 3, 4, 5 ], mutates: false, result: undefined }
.map
The map method calls the callback function once for each element in the original array in sequence. The callback returns (including undefined) after each execution are combined to form a new array.
Realization
function map(array, callback) { const result = []; const { length } = array; for (let index = 0; index < length; index +=1) { const value = array[index]; result[index] = callback(value, index, array); } return result; }
The callback function provided to the method accepts the old value as a parameter, returns a new value, and then saves it under the same index in the new array, which is represented by the variable result.
It should be noted here that we have returned a new array without modifying the old one.
test
logOperation('map', [1, 2, 3, 4, 5], array => map(array, value => value + 5));
Print results:
{ operation: 'map', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 1, 2, 3, 4, 5 ], mutates: false, result: [ 6, 7, 8, 9, 10 ] }
.filter
The filter callback of Array.prototype.filter returns the value of false, each of which is stored in a new array and returned.
[1, 2, 3, 4, 5].filter(number => number >= 3); // -> [3, 4, 5]
Realization
function push(array, ...values) { const { length: arrayLength } = array; const { length: valuesLength } = values; for (let index = 0; index < valuesLength; index += 1) { array[arrayLength + index] = values[index]; } return array.length; } -------------------------------------------------- function filter(array, callback) { const result = []; const { length } = array; for (let index = 0; index < length; index += 1) { const value = array[index]; if (callback(value, index, array)) { push(result, value); } } return result; }
Get each value and check whether the provided callback function returns true or false, then add the value to the newly created array or discard it appropriately.
Note that instead of storing values in the same index placed in the incoming array, the push method is used here for the result array. In this way, result does not have an empty slot because of the discarded value.
test
logOperation('filter', [1, 2, 3, 4, 5], array => filter(array, value => value >= 2));
Function:
{ operation: 'filter', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 1, 2, 3, 4, 5 ], mutates: false, result: [ 2, 3, 4, 5 ] }
The BUGs that may exist after code deployment can not be known in real time. In order to solve these BUGs afterwards, it takes a lot of time to debug the log s. By the way, we recommend a useful BUG monitoring tool [Fundebug].[ https://www.fundebug.com/?utm_source=xiaozhi].
.reduce
The reduce() method receives a function as an accumulator, and each value in the array (from left to right) begins to shrink and is eventually computed as a value. The reduce() method takes four parameters: the initial value (or the return value of the previous callback function), the current element value, the current index, and an array that calls reduce().
Specifically, how to calculate this value needs to be specified in the callback. Let's look at a simple example of reducing: summing up a set of numbers:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].reduce((sum, number) => { return sum + number; }, 0) // -> 55
Note that the callback here accepts two parameters: sum and number. The first parameter is always the result of the previous iteration, and the second parameter is the current array element in the traversal.
Here, when we iterate over an array, sum contains the sum of all the numbers in the current index of the loop, because each iteration we add the current value of the array to sum.
Realization
function reduce(array, callback, initValue) { const { length } = array; let acc = initValue; let startAtIndex = 0; if (initValue === undefined) { acc = array[0]; startAtIndex = 0; } for (let index = startAtIndex; index < length; index += 1) { const value = array[index]; acc = callback(acc, value, index, array) } return acc; }
We created two variables acc and startAtIndex and initialized them with their default values, initValue and 0, respectively.
Then, check whether initValue is undefined. If so, the first value of the array must be set to the initial value, and the startAtIndex must be set to 1 in order not to repeat the calculation of the initial element.
Each iteration, reduce saves the results of callbacks in an accumulator (acc) and then uses them in the next iteration. For the first iteration, ACC is set to initValue or array[0].
test
logOperation('reduce', [1, 2, 3, 4, 5], array => reduce(array, (sum, number) => sum + number, 0));
Function:
{ operation: 'reduce', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 1, 2, 3, 4, 5 ], mutates: false, result: 15 }
Search class
What operations are more common than searching for specific values? Here are some ways to help us.
.findIndex
findIndex helps us find the index of a given value in an array.
[1, 2, 3, 4, 5, 6, 7].findIndex(value => value === 5); // 4
The findIndex method performs a callback function once for each array index of 0. length-1 (including) until a callback function is found to return the true value (forced to be true). If such an element is found, findIndex immediately returns the index of that element. FindIndex returns - 1 if the callback never returns the true value, or if the length of the array is 0.
Realization
function findIndex(array, callback) { const { length } = array; for (let index = 0; index < length; index += 1) { const value = array[index]; if (callback(value, index, array)) { return index; } } return -1; }
test
logOperation('findIndex', [1, 2, 3, 4, 5], array => findIndex(array, number => number === 3));
Function:
{ operation: 'findIndex', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 1, 2, 3, 4, 5 ], mutates: false, result: 2 }
.find
The only difference between find and find index is that it returns the actual value, not the index. In practice, we can reuse the realized findIndex.
[1, 2, 3, 4, 5, 6, 7].find(value => value === 5); // 5
Realization
function find(array, callback) { const index = findIndex(array, callback); if (index === -1) { return undefined; } return array[index]; }
test
logOperation('find', [1, 2, 3, 4, 5], array => find(array, number => number === 3));
Function
{ operation: 'find', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 1, 2, 3, 4, 5 ], mutates: false, result: 3 }
.indexOf
indexOf is another way to get an index of a given value. However, this time, let's pass the actual value as a parameter rather than a function. Similarly, to simplify the implementation, you can use the findIndex implemented earlier
[3, 2, 3].indexOf(3); // -> 0
Realization
function indexOf(array, searchedValue) { return findIndex(array, value => value === searchedValue) }
test
logOperation('indexOf', [1, 2, 3, 4, 5], array => indexOf(array, 3));
results of enforcement
{ operation: 'indexOf', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 1, 2, 3, 4, 5 ], mutates: false, result: 2 }
.lastIndexOf
LastIndexOf works the same way as indexOf. The lastIndexOf() method returns the last index of the specified element in the array, and - 1 if it does not exist.
[3, 2, 3].lastIndexOf(3); // -> 2
Realization
function lastIndexOf(array, searchedValue) { for (let index = array.length - 1; index > -1; index -= 1 ){ const value = array[index]; if (value === searchedValue) { return index; } } return -1; }
The code is basically similar to findIndex, but instead of performing callbacks, it compares value with searchedValue. If the comparison result is true, the index is returned, and - 1 is returned if the value is not found.
test
logOperation('lastIndexOf', [1, 2, 3, 4, 5, 3], array => lastIndexOf(array, 3));
results of enforcement
{ operation: 'lastIndexOf', arrayBefore: [ 1, 2, 3, 4, 5, 3 ], arrayAfter: [ 1, 2, 3, 4, 5, 3 ], mutates: false, result: 5 }
.every
every() method tests whether all elements in an array can pass the test of a specified function, which returns a Boolean value.
[1, 2, 3].every(value => Number.isInteger(value)); // -> true
Let's think of every method as an array equivalent to logic and sum.
Realization
function every(array, callback){ const { length } = array; for (let index = 0; index < length; index += 1) { const value = array[index]; if (!callback(value, index, array)) { return false; } } return true; }
Let's call back for each value. If false is returned at any time, the loop exits and the entire method returns false. The method returns true if the loop terminates without entering the if statement (indicating that all conditions are valid).
test
logOperation('every', [1, 2, 3, 4, 5], array => every(array, number => Number.isInteger(number)));
results of enforcement
{ operation: 'every', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 1, 2, 3, 4, 5 ], mutates: false, result: true }
.some
The some method is just the opposite of everywhere, that is, if one of them is true, it will return true. Similar to the every method, we can think of some method as an equivalent to logic or array.
[1, 2, 3, 4, 5].some(number => number === 5); // -> true
Realization
function some(array, callback) { const { length } = array; for (let index = 0; index < length; index += 1) { const value = array[index]; if (callback(value, index, array)) { return true; } } return false; }
Let's perform callbacks for each value. If true is returned at any time, the loop exits and the entire method returns true. The method returns false if the loop terminates without entering the if statement (indicating that none of the conditions are valid).
test
logOperation('some', [1, 2, 3, 4, 5], array => some(array, number => number === 5));
results of enforcement
{ operation: 'some', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 1, 2, 3, 4, 5 ], mutates: false, result: true }
.includes
The includes method works like some method, but includes does not need callbacks, but provides a parameter value to compare elements.
[1, 2, 3].includes(3); // -> true
Realization
function includes(array, searchedValue){ return some(array, value => value === searchedValue) }
test
logOperation('includes', [1, 2, 3, 4, 5], array => includes(array, 5));
results of enforcement
{ operation: 'includes', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 1, 2, 3, 4, 5 ], mutates: false, result: true }
Stitching, attaching and inverting arrays
.concat
The concat() method is used to merge two or more arrays. Instead of changing an existing array, this method returns a new array.
[1, 2, 3].concat([4, 5], 6, [7, 8]) // -> [1, 2, 3, 4, 5, 6, 7, 8]
Realization
function concat(array, ...values) { const result = [...array]; const { length } = values; for (let index = 0; index < length; index += 1) { const value = values[index]; if (Array.isArray(value)) { push(result, ...value); } else { push(result, value); } } return result; }
concat takes arrays as the first parameter and takes unspecified values as the second parameter. These values can be arrays or other types of values.
First, create a result array by copying the incoming array. Then, iterate through values to check if the value is an array. If so, use the push function to append its value to the result array.
push(result, value) adds only one element to the array. Instead, by using the expansion operator push(result,... Value) Appends all the values of the array to the result array. To some extent, let's flatten the array.
test
logOperation('concat', [1, 2, 3, 4, 5], array => concat(array, 1, 2, [3, 4]));
results of enforcement
{ operation: 'concat', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 1, 2, 3, 4, 5 ], mutates: false, result: [ 1, 2, 3, 4, 5, 1, 2, 3, 4 ] }
.join
The join() method is used to put all elements in an array into a string, which is separated by a specified delimiter.
['Brian', 'Matt', 'Kate'].join(', ') // -> Brian, Matt, Kate
Realization
function join(array, joinWith) { return reduce( array, (result, current, index) => { if (index === 0) { return current; } return `${result}${joinWith}${current}`; }, '' ) }
Reduc's callback is magical: reduce traverses the provided array and splices the result strings together, placing the required separators between the values of the array (passed as join With).
The array[0] value requires some special processing, because result is an empty string at this point, and we don't want the joinWith to precede the first element.
test
logOperation('join', [1, 2, 3, 4, 5], array => join(array, ', '));
results of enforcement
{ operation: 'join', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 1, 2, 3, 4, 5 ], mutates: false, result: '1, 2, 3, 4, 5' }
.reverse
The reverse() method reverses the position of the elements in the array and returns the array, which changes the original array.
Realization
function reverse(array) { const result = [] const lastIndex = array.length - 1; for (let index = lastIndex; index > -1; index -= 1) { const value = array[index]; result[lastIndex - index ] = value } return result; }
The idea is simple: First, define an empty array and save the last index of the array as a variable. Then traverse the array, save each value in the last index - index position of the result result result, and return to the result array.
test
logOperation('reverse', [1, 2, 3, 4, 5], array => reverse(array));
results of enforcement
{ operation: 'reverse', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 1, 2, 3, 4, 5 ], mutates: false, result: [ 5, 4, 3, 2, 1 ] }
Add, delete, and add values
.shift
The shift() method deletes the first element from the array and returns the value of that element. This method changes the length of the array.
[1, 2, 3].shift(); // -> 1
Realization
function shift(array) { const { length } = array; const firstValue = array[0]; for (let index = 1; index > length; index += 1) { const value = array[index]; array[index - 1] = value; } array.length = length - 1; return firstValue; }
First, the original length of the array and its initial values are saved, then the array is traversed and each value is moved down an index. Upon completion of the traversal, the length of the array is updated and the initial value is returned.
test
logOperation('shift', [1, 2, 3, 4, 5], array => shift(array));
results of enforcement
{ operation: 'shift', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 2, 3, 4, 5 ], mutates: true, result: 1 }
.unshift
unshift() method adds one or more elements to the beginning of an array and returns the new length of the array (this method modifies the original array).
[2, 3, 4].unshift(1); // -> [1, 2, 3, 4]
Realization
function unshift(array, ...values) { const mergedArrays = concat(values, ...array); const { length: mergedArraysLength } = mergedArrays; for (let index = 0; index < mergedArraysLength; index += 1) { const value = mergedArrays[index]; array[index] = value; } return array.length; }
First, you need to join the array values (as a single value passed as a parameter) together with the array. It should be noted here that values are placed first, that is, in front of the original array.
Then save the length of the new array and traverse it, save its value in the original array, and override the value at the beginning.
test
logOperation('unshift', [1, 2, 3, 4, 5], array => unshift(array, 0));
results of enforcement
{ operation: 'unshift', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 0, 1, 2, 3, 4, 5 ], mutates: true, result: 6 }
.slice
slice()
Method returns a new array object, which is a shallow copy of the original array determined by begin and end (including start, excluding end) and the original array will not be changed.
slice extracts all elements in the original array that index from start to end (including start, but not end).
[1, 2, 3, 4, 5, 6, 7].slice(3, 6); // -> [4, 5, 6]
Implementation (simple implementation)
function slice(array, startIndex = 0, endIndex = array.length) { const result = []; for (let index = startIndex; index < endIndex; index += 1) { const value = array[index]; if (index < array.length) { push(result, value); } } return result; }
Let's traverse the array from startIndex to endIndex and put each value into result. The default parameter here is used so that when no parameter is passed, the slice method creates only a copy of the array.
Note: The if statement ensures that only values under a given index are added to the result in the original array.
test
logOperation('slice', [1, 2, 3, 4, 5], array => slice(array, 1, 3));
results of enforcement
{ operation: 'slice', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 1, 2, 3, 4, 5 ], mutates: false, result: [ 2, 3 ] }
.splice
The splice() method modifies the array by deleting or replacing existing elements or adding new elements in place, and returns the modified content as an array. This method changes the original array.
First, specify the starting index, then specify how many values to delete, and the remaining parameters are the values to insert.
const arr = [1, 2, 3, 4, 5]; // Starting at position 0, delete two elements and insert 3, 4, 5 arr.splice(0, 2, 3, 4, 5); arr // -> [3, 4, 5, 3, 4, 5]
Realization
function splice( array, insertAtIndex, removeNumberOfElements, ...values) { const firstPart = slice(array, 0, insertAtIndex); const secondPart = slice(array, insertAtIndex + removeNumberOfElements); const removedElements = slice( array, insertAtIndex, insertAtIndex + removeNumberOfElements ); const joinedParts = firstPart.concat(values, secondPart); const { length: joinedPartsLength } = joinedParts; for (let index = 0; index < joinedPartsLength; index += 1) { array[index] = joinedParts[index]; } array.length = joinedPartsLength; return removedElements; }
The idea is to cut insertAtIndex and insertAtIndex + removeNumberOfElements twice. In this way, the original array is cut into three segments. The first part and the third part add an inserted element to form the content of the last array.
test
logOperation('splice', [1, 2, 3, 4, 5], array => splice(array, 1, 3));
results of enforcement
{ operation: 'splice', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 1, 5 ], mutates: true, result: [ 2, 3, 4 ] }
.pop
The pop() method deletes the last element from the array and returns the value of that element. This method changes the length of the array.
Realization
function pop(array) { const value = array[array.length - 1]; array.length = array.length - 1; return value; }
First, save the last value of the array in a variable. Then you just need to reduce the length of the array by 1 to delete the last value.
test
logOperation('pop', [1, 2, 3, 4, 5], array => pop(array));
results of enforcement
{ operation: 'pop', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 1, 2, 3, 4 ], mutates: true, result: 5 }
.push
push() adds one or more elements to the end of an array and returns the new length of the array.
[1, 2, 3, 4].push(5); // -> [1, 2, 3, 4, 5]
Realization
function push(array, ...values) { const { length: arrayLength } = array; const { length: valuesLength } = values; for (let index = 0; index < valuesLength; index += 1) { array[arrayLength + index] = values[index]; } return array.length; }
First, we save the length of the original array and the values to be added to their respective variables. Then, iterate over the supplied values and add them to the original array.
test
logOperation('push', [1, 2, 3, 4, 5], array => push(array, 6, 7));
results of enforcement
{ operation: 'push', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 1, 2, 3, 4,5, 6, 7 ], mutates: true, result: 7 }
.fill
When we want to fill an empty array with a placeholder value, we can use the fill method. If you want to create an array of null elements of a specified number, you can do this:
[...Array(5)].fill(null) // -> [null, null, null, null, null]
Realization
function fill(array, value, startIndex = 0, endIndex = array.length) { for (let index = startIndex; index < endIndex; index += 1) { array[index] = value; } return array; }
What the fill method really does is replace the values of arrays within the specified index range. If no scope is provided, the method replaces the values of all arrays.
test
logOperation("fill", [...new Array(5)], array => fill(array, 0));
results of enforcement
{ operation: 'fill', arrayBefore: [ undefined, undefined, undefined, undefined, undefined ], arrayAfter: [ 0, 0, 0, 0, 0 ], mutates: true, result: [ 0, 0, 0, 0, 0 ] }
Flat class
Sometimes our arrays are nested in two or three layers. We want to flatten them, that is, to reduce the degree of nesting. For example, you want to put all values at the top level. There are two new features to help us: flat and flatMap methods.
.flat
The flat method reduces the depth of nesting by specifying depth values.
[1, 2, 3, [4, 5, [6, 7, [8]]]].flat(1); // -> [1, 2, 3, 4, 5, [6, 7, [8]]]
Because the depth of expansion is 1, only the first series array is flattened and the rest remains unchanged.
[1, 2, 3, [4, 5]].flat(1) // -> [1, 2, 3, 4, 5]
Realization
function flat(array, depth = 0) { if (depth < 1 || !Array.isArray(array)) { return array; } return reduce( array, (result, current) => { return concat(result, flat(current, depth - 1)); }, [], ); }
First, we check whether the depth parameter is less than 1. If so, that means nothing to be flat. We should simply return to the array.
Secondly, let's check whether the array parameter belongs to the array type, because if it's not, then flattening is meaningless, so we only return this parameter.
Let's use the reduce function we implemented earlier. Start with an empty array, then take each value of the array and flatten it.
Notice that we call the flat function with (depth - 1). Each call decreases the depth parameter to avoid creating an infinite loop. When flattening is completed, the return value is added back and forth to the result array.
test
logOperation('flat', [1, 2, 3, [4, 5, [6]]], array => flat(array, 2));
results of enforcement
{ operation: 'flat', arrayBefore: [ 1, 2, 3, [ 4, 5, [Array] ] ], arrayAfter: [ 1, 2, 3, [ 4, 5, [Array] ] ], mutates: false, result: [ 1, 2, 3, 4, 5, 6 ] }
.flatMap
The flatMap() method first maps each element using a mapping function, and then compresses the result into a new array. It's almost the same as map and flat with a depth value of 1, but flatMap is usually slightly more efficient in merging into one method.
In the map method above, only one value is returned for each value. Thus, an array containing three elements still has three elements after mapping. Using flatMap, you can return an array in the provided callback function, which will be flattened later.
[1, 2, 3].flatMap(value => [value, value, value]); // [1, 1, 1, 2, 2, 2, 3, 3, 3]
Each returned array is flat. Instead of an array with three arrays nested, we get an array with nine elements.
Realization
function flatMap(array, callback) { return flat(map(array, callback), 1); }
First, map is used, and then the result array of the array is flattened one layer.
test
logOperation('flatMap', [1, 2, 3], array => flatMap(array, number => [number, number]));
results of enforcement
{ operation: 'flatMap', arrayBefore: [ 1, 2, 3 ], arrayAfter: [ 1, 2, 3 ], mutates: false, result: [ 1, 1, 2, 2, 3, 3 ] }
generator class
The last three methods are special in the way they return to the generator. If you are not familiar with generators, skip them, because you may not use them very quickly.
.values
The values method returns a generator that generates the values of the array.
const valuesGenerator = values([1, 2, 3, 4, 5]); valuesGenerator.next(); // { value: 1, done: false }
Realization
function values(array) { const { length } = array; function* createGenerator() { for (let index = 0; index < length; index += 1) { const value = array[index]; yield value; } } return createGenerator(); }
First, let's define the createGenerator function. In it, we traverse the array and generate each value.
.keys
The keys method returns a generator that generates an index of the array.
const keysGenerator = keys([1, 2, 3, 4, 5]); keysGenerator.next(); // { value: 0, done: false }
Realization
function keys(array) { function* createGenerator() { const { length } = array; for (let index = 0; index < length; index += 1) { yield index; } } return createGenerator(); }
The implementation is exactly the same, but this time, the index is generated, not the value.
.entries
The entry method returns the generator that generates the key-value pair.
const entriesGenerator = entries([1, 2, 3, 4, 5]); entriesGenerator.next(); // { value: [0, 1], done: false }
Realization
function entries(array) { const { length } = array; function* createGenerator() { for (let index = 0; index < length; index += 1) { const value = array[index]; yield [index, value]; } } return createGenerator(); }
The same implementation, but now let's combine indexes and values and generate them in arrays.
summary
The efficient use of arrays is the basis for becoming a good developer. Understanding the complexity of their internal work is the best way I know.
The BUGs that may exist after code deployment can not be known in real time. In order to solve these BUGs afterwards, it takes a lot of time to debug the log s. By the way, we recommend a useful BUG monitoring tool [Fundebug].[ https://www.fundebug.com/?utm_source=xiaozhi].
Original text: https://dev.to/bnevilleoneill/understand-array-methods-by-implementing-them-all-of-them-iha
On Fundebug
Fundebug Focus on JavaScript, Wechat applets, Wechat games, Alipay applets, React Native, Node.js and Java online application real-time BUG monitoring. Since 2016, Fundebug has handled a total of 2 billion + errors. Payment customers include Sunshine Insurance, Walnut Programming, Lychee FM, Palm 1-to-1, Weimai, Youth League and many other brand enterprises. Welcome! Free trial!