Cet article vous présente 25 méthodes de tableau, et vous pouvez comprendre et utiliser ces méthodes de tableau efficacement en implémentant 25 méthodes de tableau. Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer. J'espère qu'il sera utile à tout le monde.
Pour utiliser des méthodes sur un tableau donné, passez simplement [].方法名
Ces méthodes sont définies sur l'objet Array.prototype
. Ici, nous n'utiliserons pas ces phases, nous commencerons plutôt par une méthode simple pour définir nos propres versions et construire sur ces versions.
Il n’y a pas de meilleure façon d’apprendre que de démonter les choses et de les remonter. Notez que lorsque nous implémentons nos propres méthodes, n'écrasez pas les méthodes existantes, car certaines bibliothèques en ont besoin, et il est également pratique de comparer les différences entre nos propres méthodes et les méthodes d'origine.
Alors ne nommez pas notre méthode personnalisée comme ceci :
Array.prototype.map = function map() { // implementation };
Il est préférable de la nommer comme ceci :
function map(array) { // implementation }
Nous pouvons également utiliser le mot-clé class
et étendre Array
Le constructeur pour implémenter notre méthode ressemble à ceci :
class OwnArray extends Array { public constructor(...args) { super(...args); } public map() { // implementation return this; } }
La seule différence est qu'au lieu d'utiliser un paramètre de tableau, nous utilisons le mot-clé this
.
Cependant, je pense que la méthode class apporte une confusion inutile, nous adoptons donc la première méthode.
Avec cela, commençons par mettre en œuvre la méthode la plus simple forEach
!
.forEach
Array.prototype.forEach
pour chaque élément du tableau Exécutez la fonction fournie une fois sans modifier le tableau d'origine.
[1, 2, 3, 4, 5].forEach(value => console.log(value));
Implémentation
function forEach(array, callback) { const { length } = array; for (let index = 0; index < length; index += 1) { const value = array[index]; callback(value, index, array) } }
Nous parcourons le tableau et exécutons le rappel pour chaque élément. Une chose à noter ici est que cette méthode ne renvoie rien, elle renvoie donc undefined
par défaut.
Ondulation de méthode
L'avantage de l'utilisation des méthodes de tableau est que les opérations peuvent être enchaînées entre elles. Considérons le code suivant :
function getTodosWithCategory(todos, category) { return todos .filter(todo => todo.category === category) .map(todo => normalizeTodo(todo)); }
De cette façon, nous n'avons pas besoin de sauvegarder les résultats d'exécution de map
dans des variables, et le code sera plus concis.
Malheureusement, forEach
ne renvoie pas le tableau d'origine, ce qui signifie que nous ne pouvons pas faire les choses suivantes
// 无法工作 function getTodosWithCategory(todos, category) { return todos .filter(todo => todo.category === category) .forEach((value) => console.log(value)) .map(todo => normalizeTodo(todo)); }
Implémentez ensuite une fonction simple qui explique mieux ce que fait chaque méthode : ce qu'elle accepte en entrée, ce qu'elle renvoie et si elle modifie le tableau.
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, }); }
La méthode mutatesArray est utilisée pour déterminer si le tableau d'origine a été modifié. S'il y a une modification, retournez simplement true
, sinon retournez false
. Bien entendu, si vous avez de bonnes idées, vous pouvez les proposer dans les commentaires.
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; }
Utilisez ensuite logOperation
pour tester la méthode forEach
que nous avons implémentée plus tôt.
logOperation('forEach', [1, 2, 3, 4, 5], array => forEach(array, value => console.log(value)));
Résultat d'impression :
{ operation: 'forEach', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 1, 2, 3, 4, 5 ], mutates: false, result: undefined }
.map
map
donnera à chaque élément du tableau d'origine le La fonction callback
est appelée une fois dans l'ordre. callback
Les valeurs de retour après chaque exécution (y compris undefined
) sont combinées pour former un nouveau tableau.
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; }
La fonction de rappel fournie à la méthode accepte l'ancienne valeur comme paramètre et renvoie une nouvelle valeur, qui est ensuite enregistrée dans le nouveau tableau sous le même index, ici en utilisant le variable result
signifie.
Ce qu'il faut noter ici, c'est que nous avons renvoyé un nouveau tableau et n'avons pas modifié l'ancien.
logOperation('map', [1, 2, 3, 4, 5], array => map(array, value => value + 5));
Imprimer les résultats :
{ operation: 'map', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 1, 2, 3, 4, 5 ], mutates: false, result: [ 6, 7, 8, 9, 10 ] }
.filter
Array.prototype.filter
Filtrer les retours de rappel Pour les valeurs de false
, chaque valeur est enregistrée dans un nouveau tableau puis renvoyée.
[1, 2, 3, 4, 5].filter(number => number >= 3); // -> [3, 4, 5]
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; }
pour obtenir chaque valeur et vérifier si la fonction de rappel fournie renvoie true
ou false
, puis ajouter la valeur au tableau nouvellement créé, ou, le cas échéant, la supprimer .
Notez que la méthode result
est utilisée ici sur le tableau push
au lieu de sauvegarder les valeurs au même index où elles ont été placées dans le tableau transmis. De cette façon, result
n'aura pas d'emplacements vides en raison de valeurs rejetées.
logOperation('filter', [1, 2, 3, 4, 5], array => filter(array, value => value >= 2));
s'exécute :
{ operation: 'filter', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 1, 2, 3, 4, 5 ], mutates: false, result: [ 2, 3, 4, 5 ] }
.reduce
reduce()
la méthode reçoit une fonction En tant qu'accumulateur, chaque valeur du tableau commence à rétrécir (de gauche à droite), calculant finalement une valeur . La méthode reduce()
accepte quatre paramètres : valeur initiale (ou la valeur de retour de la dernière fonction de rappel), la valeur actuelle de l'élément, l'index actuel et le tableau sur lequel réduire() est appelé.
La manière exacte dont cette valeur est calculée doit être spécifiée dans le rappel. Regardons un exemple simple utilisant reduce
: additionner un ensemble de nombres :
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].reduce((sum, number) => { return sum + number; }, 0) // -> 55
注意这里的回调接受两个参数:sum
和number
。第一个参数总是前一个迭代返回的结果,第二个参数在遍历中的当前数组元素。
这里,当咱们对数组进行迭代时,sum
包含到循环当前索引的所有数字的和因为每次迭代咱们都将数组的当前值添加到sum
中。
实现
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; }
咱们创建了两个变量acc
和startAtIndex
,并用它们的默认值初始化它们,分别是参数initValue
和0
。
然后,检查initValue
是否是undefined
。如果是,则必须将数组的第一个值设置为初值,为了不重复计算初始元素,将startAtIndex
设置为1
。
每次迭代,reduce
方法都将回调的结果保存在累加器(acc
)中,然后在下一个迭代中使用。对于第一次迭代,acc
被设置为initValue
或array[0]
。
测试
logOperation('reduce', [1, 2, 3, 4, 5], array => reduce(array, (sum, number) => sum + number, 0));
运行:
{ operation: 'reduce', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 1, 2, 3, 4, 5 ], mutates: false, result: 15 }
有什么操作比搜索特定值更常见?这里有一些方法可以帮助我们。
.findIndex
findIndex
帮助咱们找到数组中给定值的索引。
[1, 2, 3, 4, 5, 6, 7].findIndex(value => value === 5); // 4
findIndex
方法对数组中的每个数组索引0..length-1
(包括)执行一次callback
函数,直到找到一个callback
函数返回真实值(强制为true
)的值。如果找到这样的元素,findIndex
会立即返回该元素的索引。如果回调从不返回真值,或者数组的length
为0
,则findIndex
返回-1
。
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; }
logOperation('findIndex', [1, 2, 3, 4, 5], array => findIndex(array, number => number === 3));
运行:
{ operation: 'findIndex', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 1, 2, 3, 4, 5 ], mutates: false, result: 2 }
.find
find
与findIndex
的唯一区别在于,它返回的是实际值,而不是索引。实际工作中,咱们可以重用已经实现的findIndex
。
[1, 2, 3, 4, 5, 6, 7].find(value => value === 5); // 5
function find(array, callback) { const index = findIndex(array, callback); if (index === -1) { return undefined; } return array[index]; }
logOperation('find', [1, 2, 3, 4, 5], array => find(array, number => number === 3));
{ operation: 'find', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 1, 2, 3, 4, 5 ], mutates: false, result: 3 }
.indexOf
indexOf
是获取给定值索引的另一种方法。然而,这一次,咱们将实际值作为参数而不是函数传递。同样,为了简化实现,可以使用前面实现的findIndex
[3, 2, 3].indexOf(3); // -> 0
function indexOf(array, searchedValue) { return findIndex(array, value => value === searchedValue) }
logOperation('indexOf', [1, 2, 3, 4, 5], array => indexOf(array, 3));
{ operation: 'indexOf', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 1, 2, 3, 4, 5 ], mutates: false, result: 2 }
.lastIndexOf
lastIndexOf的工作方式与indexOf
相同,lastIndexOf()
方法返回指定元素在数组中的最后一个的索引,如果不存在则返回 -1
。
[3, 2, 3].lastIndexOf(3); // -> 2
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; }
代码基本与findIndex
类似,但是没有执行回调,而是比较value
和searchedValue
。如果比较结果为 true
,则返回索引,如果找不到值,返回-1
。
logOperation('lastIndexOf', [1, 2, 3, 4, 5, 3], array => lastIndexOf(array, 3));
{ operation: 'lastIndexOf', arrayBefore: [ 1, 2, 3, 4, 5, 3 ], arrayAfter: [ 1, 2, 3, 4, 5, 3 ], mutates: false, result: 5 }
.every
every()
方法测试一个数组内的所有元素是否都能通过某个指定函数的测试,它返回一个布尔值。
[1, 2, 3].every(value => Number.isInteger(value)); // -> true
咱们可以将every
方法看作一个等价于逻辑与的数组。
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; }
咱们为每个值执行回调。如果在任何时候返回false
,则退出循环,整个方法返回false
。如果循环终止而没有进入到if
语句里面(说明条件都成立),则方法返回true
。
logOperation('every', [1, 2, 3, 4, 5], array => every(array, number => Number.isInteger(number)));
{ operation: 'every', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 1, 2, 3, 4, 5 ], mutates: false, result: true }
.some
some
方法与 every
刚好相反,即只要其中一个为true
就会返回true
。与every
方法类似,咱们可以将some
方法看作一个等价于逻辑或数组。
[1, 2, 3, 4, 5].some(number => number === 5); // -> true
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; }
咱们为每个值执行回调。如果在任何时候返回true
,则退出循环,整个方法返回true
。如果循环终止而没有进入到if
语句里面(说明条件都不成立),则方法返回false
。
logOperation('some', [1, 2, 3, 4, 5], array => some(array, number => number === 5));
{ operation: 'some', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 1, 2, 3, 4, 5 ], mutates: false, result: true }
.includes
includes
方法的工作方式类似于 some
方法,但是includes
不用回调,而是提供一个参数值来比较元素。
[1, 2, 3].includes(3); // -> true
function includes(array, searchedValue){ return some(array, value => value === searchedValue) }
logOperation('includes', [1, 2, 3, 4, 5], array => includes(array, 5));
{ operation: 'includes', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 1, 2, 3, 4, 5 ], mutates: false, result: true }
.concat
concat()
方法用于合并两个或多个数组,此方法不会更改现有数组,而是返回一个新数组。
[1, 2, 3].concat([4, 5], 6, [7, 8]) // -> [1, 2, 3, 4, 5, 6, 7, 8]
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
将数组作为第一个参数,并将未指定个数的值作为第二个参数,这些值可以是数组,也可以是其他类型的值。
首先,通过复制传入的数组创建 result
数组。然后,遍历 values
,检查该值是否是数组。如果是,则使用push
函数将其值附加到结果数组中。
push(result, value)
只会向数组追加为一个元素。相反,通过使用展开操作符push(result,…value)
将数组的所有值附加到result
数组中。在某种程度上,咱们把数组扁平了一层。
logOperation('concat', [1, 2, 3, 4, 5], array => concat(array, 1, 2, [3, 4]));
{ 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
join()
方法用于把数组中的所有元素放入一个字符串,元素是通过指定的分隔符进行分隔的。
['Brian', 'Matt', 'Kate'].join(', ') // -> Brian, Matt, Kate
function join(array, joinWith) { return reduce( array, (result, current, index) => { if (index === 0) { return current; } return `${result}${joinWith}${current}`; }, '' ) }
reduce
的回调是神奇之处:reduce
遍历所提供的数组并将结果字符串拼接在一起,在数组的值之间放置所需的分隔符(作为joinWith
传递)。
array[0]
值需要一些特殊的处理,因为此时result
是一个空字符串,而且咱们也不希望分隔符(joinWith
)位于第一个元素前面。
logOperation('join', [1, 2, 3, 4, 5], array => join(array, ', '));
{ operation: 'join', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 1, 2, 3, 4, 5 ], mutates: false, result: '1, 2, 3, 4, 5' }
.reverse
reverse()
方法将数组中元素的位置颠倒,并返回该数组,该方法会改变原数组。
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; }
其思路很简单:首先,定义一个空数组,并将数组的最后一个索引保存为变量(lastIndex)
。接着反过来遍历数组,将每个值保存在结果result
中的(lastIndex - index)
位置,然后返回result
数组。
logOperation('reverse', [1, 2, 3, 4, 5], array => reverse(array));
{ operation: 'reverse', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 1, 2, 3, 4, 5 ], mutates: false, result: [ 5, 4, 3, 2, 1 ] }
.shift
shift()
方法从数组中删除第一个元素,并返回该元素的值,此方法更改数组的长度。
[1, 2, 3].shift(); // -> 1
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; }
首先保存数组的原始长度及其初始值,然后遍历数组并将每个值向下移动一个索引。完成遍历后,更新数组的长度并返回初始值。
logOperation('shift', [1, 2, 3, 4, 5], array => shift(array));
{ operation: 'shift', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 2, 3, 4, 5 ], mutates: true, result: 1 }
.unshift
unshift()
方法将一个或多个元素添加到数组的开头,并返回该数组的新长度(该方法修改原有数组)。
[2, 3, 4].unshift(1); // -> [1, 2, 3, 4]
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; }
首先将需要加入数组值(作为参数传递的单个值)和数组拼接起来。这里需要注意的是,values
放在第一位的,也就是放置在原始数组的前面。
然后保存这个新数组的长度并遍历它,将它的值保存在原始数组中,并覆盖开始时的值。
logOperation('unshift', [1, 2, 3, 4, 5], array => unshift(array, 0));
{ operation: 'unshift', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 0, 1, 2, 3, 4, 5 ], mutates: true, result: 6 }
.slice
slice()
方法返回一个新的数组对象,这一对象是一个由 begin
和 end
决定的原数组的浅拷贝(包括 begin
,不包括end
)原始数组不会被改变。
slice
会提取原数组中索引从 begin
到 end
的所有元素(包含 begin
,但不包含 end
)。
[1, 2, 3, 4, 5, 6, 7].slice(3, 6); // -> [4, 5, 6]
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; }
咱们遍历数组从startIndex
到endIndex
,并将每个值放入result
。这里使用了这里的默认参数,这样当没有传递参数时,slice
方法只创建数组的副本。
注意:if
语句确保只在原始数组中存在给定索引下的值时才加入 result
中。
logOperation('slice', [1, 2, 3, 4, 5], array => slice(array, 1, 3));
{ operation: 'slice', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 1, 2, 3, 4, 5 ], mutates: false, result: [ 2, 3 ] }
.splice
splice()
方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。
首先,指定起始索引,然后指定要删除多少个值,其余的参数是要插入的值。
const arr = [1, 2, 3, 4, 5]; // 从位置0开始,删除2个元素后插入 3, 4, 5 arr.splice(0, 2, 3, 4, 5); arr // -> [3, 4, 5, 3, 4, 5]
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; }
其思路是在insertAtIndex
和insertAtIndex + removeNumberOfElements
上进行两次切割。这样,将原始数组切成三段。第一部分(firstPart
)和第三部分(secondPart
)加个插入的元素组成为最后数组的内容。
logOperation('splice', [1, 2, 3, 4, 5], array => splice(array, 1, 3));
{ operation: 'splice', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 1, 5 ], mutates: true, result: [ 2, 3, 4 ] }
.pop
pop()
方法从数组中删除最后一个元素,并返回该元素的值。此方法更改数组的长度。
function pop(array) { const value = array[array.length - 1]; array.length = array.length - 1; return value; }
首先,将数组的最后一个值保存在一个变量中。然后只需将数组的长度减少1
,从而删除最后一个值。
logOperation('pop', [1, 2, 3, 4, 5], array => pop(array));
{ operation: 'pop', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 1, 2, 3, 4 ], mutates: true, result: 5 }
.push
push()
方法将一个或多个元素添加到数组的末尾,并返回该数组的新长度。
[1, 2, 3, 4].push(5); // -> [1, 2, 3, 4, 5]
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; }
首先,我们保存原始数组的长度,以及在它们各自的变量中要添加的值。然后,遍历提供的值并将它们添加到原始数组中。
logOperation('push', [1, 2, 3, 4, 5], array => push(array, 6, 7));
{ operation: 'push', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 1, 2, 3, 4,5, 6, 7 ], mutates: true, result: 7 }
.fill
当咱们想用一个占位符值填充一个空数组时,可以使用fill
方法。如果想创建一个指定数量的null
元素数组,可以这样做:
[...Array(5)].fill(null) // -> [null, null, null, null, null]
function fill(array, value, startIndex = 0, endIndex = array.length) { for (let index = startIndex; index < endIndex; index += 1) { array[index] = value; } return array; }
fill
方法真正做的是替换指定索引范围内的数组的值。如果没有提供范围,该方法将替换所有数组的值。
logOperation("fill", [...new Array(5)], array => fill(array, 0));
{ operation: 'fill', arrayBefore: [ undefined, undefined, undefined, undefined, undefined ], arrayAfter: [ 0, 0, 0, 0, 0 ], mutates: true, result: [ 0, 0, 0, 0, 0 ] }
有时咱们的数组会变嵌套两到三层,咱们想要将它们扁,也就是减少嵌套的程度。例如,想将所有值都放到顶层。为咱们提供帮助有两个新特性:flat
和flatMap
方法。
.flat
flat
方法通过可指定深度值来减少嵌套的深度。
[1, 2, 3, [4, 5, [6, 7, [8]]]].flat(1); // -> [1, 2, 3, 4, 5, [6, 7, [8]]]
因为展开的深度值是1
,所以只有第一级数组是被扁平,其余的保持不变。
[1, 2, 3, [4, 5]].flat(1) // -> [1, 2, 3, 4, 5]
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)); }, [], ); }
首先,我们检查depth
参数是否小于1
。如果是,那就意味着没有什么要扁平的,咱们应该简单地返回数组。
其次,咱们检查数组参数是否属于数组类型,因为如果它不是,那么扁化就没有意义了,所以只返回这个参数。
咱们们使用了之前实现的reduce
函数。从一个空数组开始,然后取数组的每个值并将其扁平。
注意,我们调用带有(depth - 1)
的flat
函数。每次调用时,都递减depth
参数,以免造成无限循环。扁平化完成后,将返回值来回加到result
数组中。
logOperation('flat', [1, 2, 3, [4, 5, [6]]], array => flat(array, 2));
{ 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
flatMap()
方法首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。它与 map 和 深度值1的 flat 几乎相同,但 flatMap 通常在合并成一种方法的效率稍微高一些。
在上面的map
方法中,对于每个值,只返回一个值。这样,一个包含三个元素的数组在映射之后仍然有三个元素。使用flatMap
,在提供的回调函数中,可以返回一个数组,这个数组稍后将被扁平。
[1, 2, 3].flatMap(value => [value, value, value]); // [1, 1, 1, 2, 2, 2, 3, 3, 3]
每个返回的数组都是扁平的,我们得到的不是一个嵌套了三个数组的数组,而是一个包含9个元素的数组。
function flatMap(array, callback) { return flat(map(array, callback), 1); }
首先使用map
,然后将数组的结果数组扁平化一层。
logOperation('flatMap', [1, 2, 3], array => flatMap(array, number => [number, number]));
{ operation: 'flatMap', arrayBefore: [ 1, 2, 3 ], arrayAfter: [ 1, 2, 3 ], mutates: false, result: [ 1, 1, 2, 2, 3, 3 ] }
最后三种方法的特殊之处在于它们返回生成器的方式。如果你不熟悉生成器,请跳过它们,因为你可能不会很快使用它们。
.values
values
方法返回一个生成器,该生成器生成数组的值。
const valuesGenerator = values([1, 2, 3, 4, 5]); valuesGenerator.next(); // { value: 1, done: false }
function values(array) { const { length } = array; function* createGenerator() { for (let index = 0; index < length; index += 1) { const value = array[index]; yield value; } } return createGenerator(); }
首先,咱们定义createGenerator
函数。在其中,咱们遍历数组并生成每个值。
.keys
keys
方法返回一个生成器,该生成器生成数组的索引。
const keysGenerator = keys([1, 2, 3, 4, 5]); keysGenerator.next(); // { value: 0, done: false }
function keys(array) { function* createGenerator() { const { length } = array; for (let index = 0; index < length; index += 1) { yield index; } } return createGenerator(); }
实现完全相同,但这一次,生成的是索引,而不是值。
.entries
entry
方法返回生成键值对的生成器。
const entriesGenerator = entries([1, 2, 3, 4, 5]); entriesGenerator.next(); // { value: [0, 1], done: false }
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(); }
同样的实现,但现在咱们将索引和值结合起来,并在数组中生成它们。
高效使用数组的方法是成为一名优秀开发人员的基础。了解他们内部工作的复杂性是我所知道的最好的方法。
英文原文:https://dev.to/bnevilleoneill/understand-array-methods-by-implementing-them-all-of-them-iha
更多编程相关知识,请访问:编程教学!!
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!