目次
配列トラバーサル メソッドの概要
1.forEach
メソッドは、配列の要素ごとに指定された関数を 1 回実行します
使用法: 3 つのパラメーターをコールバック関数に順番に渡します: 配列の現在の値、配列内の現在のアイテムのインデックス、および配列オブジェクト
arr.forEach(callback(currentValue [, index [, array]]))
意識しなければならないのは
- forEach() は呼び出されたときに元の配列を変更しませんが、コールバック関数が呼び出されたときに元の配列を変更する場合があります
- forEach() は常に undefined を返し、チェーンできません
- 初期化されていない値 (スパース配列) に対して操作を実行しないでください。コールバック関数を直接スキップします。
let items = [1, 2,, 4]
let num = 0
let temp = items.forEach(ele => {
console.log(ele)
num++
})
console.log("num: " + num)
console.log("temp: " + temp)
// 1
// 2
// 4
// num: 3 跳过了未初始化的值,只执行了3次
// temp:undefined
2.地図
メソッドは新しい配列を作成します。その結果は、配列内の要素ごとに提供された関数を 1 回呼び出すことによって返される値です。
用法:
var new_array = arr.map(function callback(currentValue[, index[, array]]) {
// Return element for new_array
})
注意点:
- map が呼び出されると、元の配列は変更されず、新しい配列が生成されて返されます
- 値が割り当てられていない場合、コールバックは呼び出されません
- コールバックが値を返さない場合、新しい配列もアイテムを保持し、値は未定義です
- まばらな配列に遭遇すると、 map() は空のスペースをスキップしますが、この値は保持します
var numbers = [1, 4, 9];
var roots = numbers.map(Math.sqrt);
// roots的值为[1, 2, 3], numbers的值仍为[1, 4, 9]
var items= [1, 2,, 4,];
var filteredNumbers = items.map(function(num, index) {
if(index < 3) {
return num;
}
});
console.log(filteredNumbers) // [1, 2, , undefined]
次のような間違いが起こりやすいです。
["1", "2", "3"].map(parseInt);
期待される出力 [1, 2, 3] 実際の結果は [1, NaN, NaN]
ここで parseInt は実際に currentValue と index の 2 つのパラメーターをコールバック関数として受け取ります。
// parseInt(string, radix) -> map(parseInt(value, index))
/* 第一次 (index is 0): */ parseInt("1", 0); // 1 当radix参数为0,parseInt() 会根据十进制
/* 第二次 (index is 1): */ parseInt("2", 1); // NaN 当radix该参数小于 2 或者大于 36 返回NaN
/* 第三次 (index is 2): */ parseInt("3", 2); // NaN 用2进制来解析,应以 0 和 1 开头,所以结果为 NaN
// 解决办法:
function returnInt(element) {
return parseInt(element, 10);
}
['1', '2', '3'].map(returnInt); // [1, 2, 3]
// 还可以用更简单的方法避免陷阱:
['1', '2', '3'].map(Number); // [1, 2, 3]
3. for...of / for...in
for...of は、反復可能なオブジェクト (Array、Map、Set、String、TypedArray、arguments オブジェクトなどを含む) で反復ループを作成し、カスタムの反復フックを呼び出し、それぞれの個別のプロパティの値に対してステートメントを実行します。
for...in は、Symbol 以外のオブジェクトの列挙可能なプロパティを任意の順序でトラバースします。
for...of と for...in の違い
- The order of the for...in iteration is not in order. 配列が反復され、重要な順序でアクセスされる場合は、整数インデックスを使用して for ループ、forEach、for...of を実行するのが最適です。
- for..in は、プロトタイプ チェーンのプロパティを含むすべての列挙可能なプロパティを返します。
- for...in ループがキーで、for...of ループが値です。
// for...in 语句以任意顺序迭代对象的可枚举属性。
// for...of 语句遍历可迭代对象定义要迭代的数据。
Object.prototype.objCustom = function() {};
Array.prototype.arrCustom = function() {};
let iterable = [3, 5, 7];
iterable.foo = 'hello';
for (let i in iterable) {
console.log(i); // 0, 1, 2, "foo", "arrCustom", "objCustom"
}
for (let i in iterable) {
if (iterable.hasOwnProperty(i)) {
console.log(i); // 0, 1, 2, "foo"
}
}
for (let i of iterable) {
console.log(i); // 3, 5, 7
}
4.いくつか
このメソッドは、配列内の少なくとも 1 つの要素が指定された関数テストに合格するかどうかをテストします。ブール型の値を返します
注意点:
- 一部は元の配列を変更しません
- 空の配列呼び出しは、どのような場合でも false を返します
- まばらな配列に遭遇すると、map() は空のスペースをスキップし、コールバック関数を実行しません
- 一部がトラバースする配列の長さは、コールバックが最初に実行されたときに決定されているため、コールバックで配列に追加された値はコールバックによってアクセスされず、削除された値にはアクセスされません。
function isBiggerThan10(element, index, array) {
return element > 10;
}
[2, 5, 8, 1, 4].some(isBiggerThan10); // false
[12, 5, 8, 1, 4].some(isBiggerThan10); // true
// 使用箭头函数更简洁的写法
[2, 5, 8, 1, 4].some(x => x > 10); // false
[12, 5, 8, 1, 4].some(x => x > 10); // true
// 空数组
[].some(x => x < 10) // false
//第一次执行回调已经确定元素的范围,新增的不会被访问到
let item = [1, 2, 5]
let isBiggerThan = item.some(x => {
item.push(20)
return x > 10
})
console.log(item) // [1, 2, 5, 20, 20, 20]
console.log(isBiggerThan) // false
// 已经被删除的元素也不会被访问到
var item = [1, 2, 15]
let isBiggerThan = item.some(x => {
item.pop() // 删除最后一项元素
return x > 10
})
console.log(item) // [1]
console.log(isBiggerThan) // false
5.すべて
メソッドを使用して、配列内のすべての要素が指定された関数のテストに合格するかどうかをテストします。ブール値を返します。
注意点:
- every は元の配列を変更しません
- スパース配列に遭遇すると、コールバック関数は空のスペースを直接スキップします
- いくつかと同じように、最初にコールバックが実行されたときにトラバースされた配列の長さが決定されており、コールバックで配列に追加された値はコールバックによってアクセスされず、削除された値はアクセスされません。アクセスされる
- 空の配列呼び出しは、どのような場合でも true を返します
// 空数组
[].every(x => x < 10) // true
// 稀疏数组,跳过未赋值的值
[13,,20].every(x => x > 10) // true
6.フィルター
メソッドは、提供された関数によって実装されたテストのすべての要素を含む新しい配列を作成します。
注意点:
- filter は元の配列を変更せず、新しいフィルター処理された配列のみを返します
- callback は割り当てられたインデックスでのみ呼び出され、削除されたインデックスや割り当てられていないインデックスでは呼び出されません
- some and every と同様に、最初にコールバックが実行されたときにトラバースされた配列の長さが決定されており、コールバックで配列に追加された値はコールバックによってアクセスされず、削除された値にはアクセスされません。
function isBigEnough(element) {
return element >= 10;
}
var filtered = [12, 5, 8, 130, 44].filter(isBigEnough);
// filtered is [12, 130, 44]
7.見つける
メソッドは、提供されたテスト関数を満たす配列内の最初の要素の値を返します。それ以外の場合は undefined を返します
注意点:
- find メソッドは元の配列を変更しません
- スパース配列が find メソッドを呼び出す場合、コールバック関数は値のないインデックスをスキップしません。これは、find メソッドが値インデックスのみをトラバースするメソッドよりも効率が悪いことを示しています。
- 最初の呼び出しはインデックス範囲を決定し、配列に追加された新しい要素はコールバックによってアクセスされず、削除された値は引き続きアクセスされます (未定義)
// 稀疏数组,不会跳过
let num = 0;
let hasRight [1,2,3,,5].find(x => {
console.log(num) // 0 1 2 3 4
num++
return x > 5
})
console.log(hasRight) // undefined
8.findIndex
メソッドは、提供されたテスト関数を満たす配列内の最初の要素のインデックスを返します。それ以外の場合は -1 が返されます。
注意点:
- findIndex は元の配列を変更しません
- 疎数の初期化されていない値のインデックスはスキップされません
- インデックス範囲は最初の呼び出しによって決定され、配列に追加された新しい要素はコールバックによってアクセスされず、削除された値には引き続きアクセスされます
const array1 = [5, 12, 8, 130, 44];
const isLargeNumber = array1.findIndex(element => element > 13); // 3
9.減らす
メソッドは、 array 内の各要素に対して(昇順で) 指定されたレデューサー関数を実行し、その結果を単一の戻り値に集約します。
使用法: reduce は、コールバック ( reducer)、初期値initialValue (オプション)の 2 つのパラメーターを受け入れます。
- レデューサーは、 Accumulator アキュムレータ、CurrentValue 現在値、CurrentIndex 現在インデックス、SourceArray 元配列の 4 つのパラメータを受け入れます。
- コールバック関数が初めて呼び出されたときの最初のパラメーターの値として、initialValue が渡されない場合、デフォルト値は配列の最初の要素です
注意点:
- reduce は元の配列を変更しません
- reduce は、疎数の初期化されていない値のインデックスをスキップします
- 配列が空で初期値が指定されていない場合、TypeError がスローされます。
- 配列の要素が 1 つだけで初期値がない場合、または初期値が指定されているが配列が空の場合、reduce はコールバックを実行せずに一意の値を返します。
- 初期値が指定されていない場合、reduce はコールバック メソッドをインデックス 1 から実行し、最初のインデックスをスキップします。初期値を指定すると、インデックス 0 から始まります。
- オブジェクトの配列のプロパティを蓄積するには、初期値を指定する必要があります
[0, 1, 2, 3, 4].reduce((prev, curr) => prev + curr ); // 10
// 提供初始值
[0, 1, 2, 3, 4].reduce((accumulator, currentValue, currentIndex, array) => {
return accumulator + currentValue;
}, 10 ); // 20
// 箭头函数
[ 0, 1, 2, 3 ].reduce(
( acc, cur ) => acc + cur,
0
);
// 空数组
[].reduce((prev, curr) => prev + curr ); // TypeError
// 提供了初始值
[].reduce((prev, curr) => prev + curr, 20 ); // 20
// 数组长度为1
[15].reduce((prev, curr) => prev + curr ); // 15
//累加对象数组
var initialValue = 0;
var sum = [{x: 1}, {x:2}, {x:3}].reduce(function (accumulator, currentValue) {
return accumulator + currentValue.x;
},initialValue)
console.log(sum) // 6
// 无初始值,得到不是期望的返回
var sum = [{x: 1}, {x:2}, {x:3}].reduce(function (accumulator, currentValue) {
return accumulator + currentValue.x;
})
console.log(sum) // "[object Object]23"
10. まとめ
forEach | 地図 | の | のために...で | いくつかの | 毎日 | フィルター | 探す | 検索インデックス | 減らす | |
---|---|---|---|---|---|---|---|---|---|---|
元の配列を変更するかどうか | × | × | × | × | × | × | × | × | × | × |
戻り値はありますか | × | √ | × | × | √ | √ | √ | √ | √ | √ |
戻り型 | × | 配列 | × | × | ブール値 | ブール値 | 配列 | 値/未定義 | インデックス/-1 | 累積値 |
スパース配列 | 飛び越える | スキップ、空白のまま | 通常のトラバーサル | 飛び越える | 飛び越える | 飛び越える | 飛び越える | 通常のトラバーサル | 通常のトラバーサル | 通常のトラバーサル |