この記事では 25 の配列メソッドを紹介します。25 の配列メソッドを実装することで、これらの配列メソッドを理解し、効率的に使用できるようになります。一定の参考値があるので、困っている友達が参考になれば幸いです。
指定された配列でメソッドを使用するには、[].メソッド名
を渡すだけです。これらのメソッドは Array .prototype# で定義されています## 物体。ここでは、これらのフェーズは使用せず、代わりに、独自のバージョンを定義し、それらのバージョンに基づいて構築する簡単な方法から始めます。
Array.prototype.map = function map() { // implementation };
function map(array) { // implementation }
class## を使用することもできます。 # キーワードと Array
コンストラクターを拡張して、次のようにメソッドを実装します。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;"> class OwnArray extends Array {
public constructor(...args) {
super(...args);
}
public map() {
// implementation
return this;
}
}</pre><div class="contentsignin">ログイン後にコピー</div></div>
唯一の違いは、配列パラメーターを使用する代わりに、
キーワードを使用することです。 。 ただし、クラスメソッドは無用な混乱を招くと思うので、最初のメソッドを採用します。
これで、最も簡単なメソッド
forEach を実装することから始めましょう! #コレクション クラス
Array.prototype.forEachこのメソッドは、元の配列を変更せずに、配列の各要素に対して提供された関数を 1 回実行します。
[1, 2, 3, 4, 5].forEach(value => console.log(value));
実装
function forEach(array, callback) { const { length } = array; for (let index = 0; index < length; index += 1) { const value = array[index]; callback(value, index, array) } }
配列をループし、要素ごとにコールバックを実行します。ここで注意すべき点の 1 つは、このメソッドは何も返さないため、デフォルトでは unknown を返すということです。
メソッド リップル
配列メソッドを使用する利点は、操作を連鎖できることです。次のコードを考えてみましょう。 function getTodosWithCategory(todos, category) {
return todos
.filter(todo => todo.category === category)
.map(todo => normalizeTodo(todo));
}
の実行結果を変数に保存する必要がなくなり、コードがより単純になります。
残念ながら、forEach
は元の配列を返しません。つまり、次のことは実行できません。
// 无法工作 function getTodosWithCategory(todos, category) { return todos .filter(todo => todo.category === category) .forEach((value) => console.log(value)) .map(todo => normalizeTodo(todo)); }
ヘルプ関数 (情報の出力)
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, }); }
を返し、それ以外の場合は
false を返します。もちろん、良いアイデアがあれば、コメントで提案してください。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;"> 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;
}</pre><div class="contentsignin">ログイン後にコピー</div></div>
次に、logOperation
を使用して、前に実装した
メソッドをテストします。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;"> logOperation(&#39;forEach&#39;, [1, 2, 3, 4, 5], array => forEach(array, value => console.log(value)));</pre><div class="contentsignin">ログイン後にコピー</div></div>
印刷結果: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;"> {
operation: &#39;forEach&#39;,
arrayBefore: [ 1, 2, 3, 4, 5 ],
arrayAfter: [ 1, 2, 3, 4, 5 ],
mutates: false,
result: undefined
}</pre><div class="contentsignin">ログイン後にコピー</div></div>
.map
map メソッドは元の配列を返します。
callback 関数は、順番に要素ごとに 1 回呼び出されます。 callback
各実行後の戻り値 (unknown
を含む) が結合されて、新しい配列が形成されます。 実装
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;"> 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;
}</pre><div class="contentsignin">ログイン後にコピー</div></div>
メソッドに提供されたコールバック関数は、古い値をパラメータとして受け取り、新しい値を返します。この値は、同じインデックスの下の新しい配列に保存されます。ここでは、変数
ここでは、新しい配列を返し、古い配列は変更しないことに注意してください。 テスト
logOperation('map', [1, 2, 3, 4, 5], array => map(array, value => value + 5));
結果の出力:
{ 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 フィルター コールバックは値を false
として返し、各値は新しい配列に保存されて返されます。[1, 2, 3, 4, 5].filter(number => number >= 3); // -> [3, 4, 5]
Implementation
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; }
各値を取得し、提供されたコールバック関数が
true または ここでは、渡された配列に配置された同じインデックスに値を保存するのではなく、
result 配列に対して
push
result に空のスロットができなくなります。
テスト
logOperation('filter', [1, 2, 3, 4, 5], array => filter(array, value => value >= 2));
実行:
{ operation: 'filter', arrayBefore: [ 1, 2, 3, 4, 5 ], arrayAfter: [ 1, 2, 3, 4, 5 ], mutates: false, result: [ 2, 3, 4, 5 ] }
#reduce() このメソッドはアキュムレータとして関数を受け取り、配列内の各値 (左から右へ) が減算され始め、最終的に a 値 として計算されます。
reduce() このメソッドは 4 つのパラメータを受け入れます: 注意这里的回调接受两个参数: 这里,当咱们对数组进行迭代时, 实现 咱们创建了两个变量 然后,检查 每次迭代, 测试 运行: 有什么操作比搜索特定值更常见?这里有一些方法可以帮助我们。 .findIndex 运行: .find .indexOf .lastIndexOf lastIndexOf的工作方式与 代码基本与 .every 咱们可以将 咱们为每个值执行回调。如果在任何时候返回 .some 咱们为每个值执行回调。如果在任何时候返回 .includes .concat 首先,通过复制传入的数组创建 .join .reverse 其思路很简单:首先,定义一个空数组,并将数组的最后一个索引保存为 .shift 首先保存数组的原始长度及其初始值,然后遍历数组并将每个值向下移动一个索引。完成遍历后,更新数组的长度并返回初始值。 .unshift 首先将需要加入数组值(作为参数传递的单个值)和数组拼接起来。这里需要注意的是, 然后保存这个新数组的长度并遍历它,将它的值保存在原始数组中,并覆盖开始时的值。 .slice 方法返回一个新的数组对象,这一对象是一个由 咱们遍历数组从 注意: .splice 首先,指定起始索引,然后指定要删除多少个值,其余的参数是要插入的值。 其思路是在 .pop 首先,将数组的最后一个值保存在一个变量中。然后只需将数组的长度减少 .push 首先,我们保存原始数组的长度,以及在它们各自的变量中要添加的值。然后,遍历提供的值并将它们添加到原始数组中。 .fill 当咱们想用一个占位符值填充一个空数组时,可以使用 有时咱们的数组会变嵌套两到三层,咱们想要将它们扁,也就是减少嵌套的程度。例如,想将所有值都放到顶层。为咱们提供帮助有两个新特性: .flat 因为展开的深度值是 首先,我们检查 其次,咱们检查数组参数是否属于数组类型,因为如果它不是,那么扁化就没有意义了,所以只返回这个参数。 咱们们使用了之前实现的 注意,我们调用带有 .flatMap 在上面的 每个返回的数组都是扁平的,我们得到的不是一个嵌套了三个数组的数组,而是一个包含9个元素的数组。 首先使用 最后三种方法的特殊之处在于它们返回生成器的方式。如果你不熟悉生成器,请跳过它们,因为你可能不会很快使用它们。 .values 首先,咱们定义 .keys 实现完全相同,但这一次,生成的是索引,而不是值。 .entries初期値 (または最後のコールバック関数の戻り値)、現在の要素の値、現在のインデックス、およびreduce() が含まれる配列
と呼ばれます。 正確には、この値の計算方法をコールバックで指定する必要があります。 reduce
を使用した簡単な例を見てみましょう: 一連の数値を合計する: [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
帮助咱们找到数组中给定值的索引。 [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
与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
是获取给定值索引的另一种方法。然而,这一次,咱们将实际值作为参数而不是函数传递。同样,为了简化实现,可以使用前面实现的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
}
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()
方法测试一个数组内的所有元素是否都能通过某个指定函数的测试,它返回一个布尔值。 [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
方法与 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
方法的工作方式类似于 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()
方法用于合并两个或多个数组,此方法不会更改现有数组,而是返回一个新数组。 [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()
方法用于把数组中的所有元素放入一个字符串,元素是通过指定的分隔符进行分隔的。 ['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()
方法将数组中元素的位置颠倒,并返回该数组,该方法会改变原数组。实现
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()
方法从数组中删除第一个元素,并返回该元素的值,此方法更改数组的长度。 [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()
方法将一个或多个元素添加到数组的开头,并返回该数组的新长度(该方法修改原有数组)。 [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()
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()
方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。 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()
方法从数组中删除最后一个元素,并返回该元素的值。此方法更改数组的长度。实现
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()
方法将一个或多个元素添加到数组的末尾,并返回该数组的新长度。 [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
方法。如果想创建一个指定数量的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
方法通过可指定深度值来减少嵌套的深度。 [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()
方法首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。它与 map 和 深度值1的 flat 几乎相同,但 flatMap 通常在合并成一种方法的效率稍微高一些。map
方法中,对于每个值,只返回一个值。这样,一个包含三个元素的数组在映射之后仍然有三个元素。使用flatMap
,在提供的回调函数中,可以返回一个数组,这个数组稍后将被扁平。 [1, 2, 3].flatMap(value => [value, value, value]); // [1, 1, 1, 2, 2, 2, 3, 3, 3]
实现
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 ]
}
generator 类
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
方法返回一个生成器,该生成器生成数组的索引。 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();
}
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
更多编程相关知识,请访问:编程教学!!
以上が25 の配列メソッドを実装して理解する (コレクション)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。