ES6 の構文では、配列はトラバーサルに関連するいくつかの新しいメソッドを追加しました。これらの関数は本質的に構文糖衣ですが、理論的には、コードはそれらがなくても記述できます。しかし、それらの存在は私たちの業務処理をより便利にしてくれるので、実際の開発ではそれらを使いこなすことが非常に必要です。初めて接する学生にとっては、特に分かりにくいかもしれませんが、この記事では、実際の事例を使って文法や使い方を詳しく解説しています。
すべての配列メソッドに共通するもの:パラメータはコールバック関数を受け取ります
次のコールバック関数のすべてのパラメーターは、仮パラメーターです。つまり、例として forEach を使用すると、パラメーターをelement 、index 、およびarrayとして記述する必要はありません。それらを表すために多くのカスタム パラメータ名を使用することがわかります。パラメータを順番に。
目次
1. forEach
2.地図
3.フィルター
4.ソート
5.減らす
6. 毎
1. forEach
基本的な構文:
forEach((element, index, array) => { /* … */ }) // return undefined
element は配列内の各要素を参照し、index は各要素に対応するインデックスを参照し、array は配列自体を参照します。しかし、arr.forEach() を介して記述すると、3 番目のパラメーター配列は不要になることがよくあります。forEach は値を返しません
まず、最も理解しやすく、最も一般的に使用されている配列メソッドは forEach だと思います。forEach は基本的に for ループの代わりであり、配列のループに最適であり、他のループ可能なデータ (nodelist、Map、Set など) のループにも使用できます。それ自体には戻り値はなく、データ量に基づいたループ操作のみを実行します。
forEach の一般的な使用法は、nodeList (ノード コレクション) をトラバースし、dom 内の複数のオブジェクトに対して統一された操作を実行することです。以下の例を見てください。
const inventors = [
{ first: 'Albert', last: 'Einstein', year: 1879, passed: 1955 },
{ first: 'Isaac', last: 'Newton', year: 1643, passed: 1727 },
{ first: 'Galileo', last: 'Galilei', year: 1564, passed: 1642 },
{ first: 'Marie', last: 'Curie', year: 1867, passed: 1934 },
{ first: 'Johannes', last: 'Kepler', year: 1571, passed: 1630 },
{ first: 'Nicolaus', last: 'Copernicus', year: 1473, passed: 1543 },
{ first: 'Max', last: 'Planck', year: 1858, passed: 1947 },
{ first: 'Katherine', last: 'Blodgett', year: 1898, passed: 1979 },
{ first: 'Ada', last: 'Lovelace', year: 1815, passed: 1852 },
{ first: 'Sarah E.', last: 'Goode', year: 1855, passed: 1905 },
{ first: 'Lise', last: 'Meitner', year: 1878, passed: 1968 },
{ first: 'Hanna', last: 'Hammarström', year: 1829, passed: 1909 }
];
// 选择dom元素
const list = document.querySelector('.list')
// 对数组进行遍历,数组中每有一个元素就添加一个dom对象
inventors.forEach(function(inventor, index) {
const listItem = document.createElement('li')
listItem.textContent = `${index}: ${inventor.first},
born ${inventor.year}`
list.appendChild(listItem)
})
// 箭头函数写法:
inventors.forEach((inventor, index) => {
const listItem = document.createElement('li')
listItem.textContent = `${index}: ${inventor.first},
born ${inventor.year}`
list.appendChild(listItem)
})
forEach の他の 2 つの使用シナリオを次に示します。
<button class="div">click me</button>
<button class="div">click me</button>
<button class="div">click me</button>
<button class="div">click me</button>
<button class="div">click me</button>
<script>
// 获取所有button,赋予他们新的内容,并且绑定事件
const buttons = document.querySelectorAll('.div')
buttons.forEach((button, index) => {
button.textContent = '我是一个按钮'
button.addEventListener('click', () => {
console.log('我是一个按钮, 并且我的缩印是' + index)
})
})
</script>
// 根据刚才的inventors数组,计算所有科学家生命总长度
let totalYearsLived = 0
inventors.forEach(function(inventor) {
let yearLived = inventor.passed - inventor.year
totalYearsLived += yearLived
})
console.log(totalYearsLived) // 861
2.地図
基本的な構文:
let newArr = map((element, index, array) => { /* … */ })
// return new array
map は forEach に似ていますが、最大の違いは新しい配列を返すことです。元の配列は変更されません。要素、インデックス、配列は forEach と同じ意味です。
次の 2 つの例は、map の基本的な使用法を示しています。
const inventors = [
{ first: 'Albert', last: 'Einstein', year: 1879, passed: 1955 },
{ first: 'Isaac', last: 'Newton', year: 1643, passed: 1727 },
{ first: 'Galileo', last: 'Galilei', year: 1564, passed: 1642 },
{ first: 'Marie', last: 'Curie', year: 1867, passed: 1934 },
{ first: 'Johannes', last: 'Kepler', year: 1571, passed: 1630 },
{ first: 'Nicolaus', last: 'Copernicus', year: 1473, passed: 1543 },
{ first: 'Max', last: 'Planck', year: 1858, passed: 1947 },
{ first: 'Katherine', last: 'Blodgett', year: 1898, passed: 1979 },
{ first: 'Ada', last: 'Lovelace', year: 1815, passed: 1852 },
{ first: 'Sarah E.', last: 'Goode', year: 1855, passed: 1905 },
{ first: 'Lise', last: 'Meitner', year: 1878, passed: 1968 },
{ first: 'Hanna', last: 'Hammarström', year: 1829, passed: 1909 }
];
// 得到所有inventor的全名,并将他们组成一个新的数组
let fullnameArr = inventors.map(function(inventor) {
return inventor.first + ' ' + inventor.last
})
// 箭头函数写法
let fullnameArr = inventors.map(inventor => inventor.first + ' ' + inventor.last)
const numArr = [1, 4, 98, 170, 35, 87]
// 得到numArr中每一个数字的2倍
let doubleNumArr = numArr.map(num => num*2)
console.log(doubleNumArr) // [2, 8, 196, 340, 70, 174]
3.フィルター
基本的な構文:
filter((element, index, array) => { /* … */ } )
// return shallow copy
filter は、map および forEach と非常によく似た構文を持つ別の配列メソッドです。filter 中国語はフィルタリングであり、配列内の修飾された配列を抽出するのに特に適しています。トラバーサルの各ラウンドはブール値を返し、 trueである要素が新しい配列に追加され、最後にフィルターがこの新しい配列を返します。
filter は配列メソッドで、2 番目によく使用され、非常に使いやすいと思います。多くの場合、条件に応じていくつかの配列要素をフィルター処理する必要があり、フィルターは現時点で非常に便利です。初心者にとって最大の難関は、コールバック関数の戻り値がブール値であり、通常、このブール値が式の形式で表示されることを理解することです。ただし、 filter は最終的にarray の浅いコピーを返します。つまり、浅いコピーの要素の値を変更すると、以前の配列の要素にも影響します。
const inventors = [
{ first: 'Albert', last: 'Einstein', year: 1879, passed: 1955 },
{ first: 'Isaac', last: 'Newton', year: 1643, passed: 1727 },
{ first: 'Galileo', last: 'Galilei', year: 1564, passed: 1642 },
{ first: 'Marie', last: 'Curie', year: 1867, passed: 1934 },
{ first: 'Johannes', last: 'Kepler', year: 1571, passed: 1630 },
{ first: 'Nicolaus', last: 'Copernicus', year: 1473, passed: 1543 },
{ first: 'Max', last: 'Planck', year: 1858, passed: 1947 },
{ first: 'Katherine', last: 'Blodgett', year: 1898, passed: 1979 },
{ first: 'Ada', last: 'Lovelace', year: 1815, passed: 1852 },
{ first: 'Sarah E.', last: 'Goode', year: 1855, passed: 1905 },
{ first: 'Lise', last: 'Meitner', year: 1878, passed: 1968 },
{ first: 'Hanna', last: 'Hammarström', year: 1829, passed: 1909 }
];
// 获取所有出生在1500年和1600年之间的科学家
const fifteen = inventors.filter(function(inventor) {
return inventor.year >= 1500 && inventor.year < 1600
})
// 箭头函数写法
const fifteen = inventors.filter(inventor => inventor.year >= 1500 && inventor.year < 1600)
console.log(fifteen)
// 例子2:获取所有名字中有字母a的科学家
const nameHasA = inventors.filter(function(inventor) {
return inventor.last.includes('a')
})
// 箭头函数写法
const nameHasA = inventors.filter(inventor => inventor.last.includes('a'))
console.log(nameHasA)
4.ソート
基本的な構文:
sort()
sort((a, b) => { /* … */ } )
// 返回sort后被改变的原数组
sort の構文は前のメソッドとは異なり、パラメーターを渡さずに直接呼び出すことができます。また、比較のためにコールバック関数を渡すこともできます。並べ替えの目的は、配列内の要素を並べ替えることです。ここで、aとb は、比較のための最初の要素と比較のための 2 番目の要素をそれぞれ参照します。戻り値はソートされた元の配列です
比較関数がない 場合、sort はUnicode位置に従って要素をソートします。つまり、「Banana」は「Cat」の前にランク付けされます。これは、b が c よりも高いためです。1 は 2 よりも高いため、110 も 20 よりも前にランク付けされます。次の 2 つの例を参照してください。
const numArr = [1, 4, 98, 170, 35, 87]
// 纯数字排序
const sortNoParams = numArr.sort()
console.log(sortNoParams) // [1, 170, 35, 4, 87, 98]
const nameArr = ['Hanna', 'Meitner', 'Blodgett', 'Nicolaus', 'Einstein']
// 字符串排序
const newNameArr = nameArr.sort()
console.log(newNameArr) // ['Blodgett', 'Einstein', 'Hanna', 'Meitner', 'Nicolaus']
ただし、sort で比較関数を渡すと、sort は a と b のサイズに従ってソートされます。基本的なルールは次のとおりです。
比较函数(a, b) 戻り値 |
ソート順 |
---|---|
> 0 | a b _ の後 |
< 0 | a b 前に |
=== 0 | のa 順番 を守る b |
つまり、比較関数を実行するたびに数値を返す必要があります。数値が 0 より大きい場合、配列は昇順で並べ替えられ、0 未満の場合、配列は降順で並べ替えられます。0 の場合、順序は変更されません。伝統的に、私たちは一般的に 1 と -1 を返し、それぞれ 0 より大きいことと 0 より小さいことを表します。使用方法は次のとおりです。
function compareFn(a, b) {
if (在某些排序规则中,a 小于 b) {
return -1;
}
if (在这一排序规则下,a 大于 b) {
return 1;
}
// a 一定等于 b
return 0;
}
通常我们把返回值写为1和-1来代表返回值是否大于0
但如果是纯数字之间进行比较,那么以上函数可以简写:
function compareFn(a, b){
return a - b
}
今回は、数値の配列をソートする前の例を繰り返しますが、今回はコールバックの比較関数を使用します。結果は、数値の実際のサイズに従って並べ替えられます。
const numArr = [1, 4, 98, 170, 35, 87]
const sortedArr = numArr.sort(function(a, b) {
return a - b
})
// 箭头函数写法
const sortedArr = numArr.sort((a, b) => a - b)
console.log(sortedArr) // [1, 4, 35, 87, 98, 170]
const nameArr = ['Hanna', 'Meitner', 'Blodgett', 'Nicolaus', 'Einstein']
const sortName = nameArr.sort((a, b) => {
if(a < b) {
return -1
} else if(a > b) {
return 1
}
return 0
})
console.log(sortName) // ['Blodgett', 'Einstein', 'Hanna', 'Meitner', 'Nicolaus']
5.減らす
基本的な構文:
reduce((previousValue, currentValue, currentIndex, array) => { /* … */ }
, initialValue)
// 返回一个类型不一定的结果
reduce は、配列メソッドの中で最も分かりにくく、最も特殊な関数と言えます。
reduce はパラメータとしてコールバック関数と初期値も受け入れます. このコールバック関数は,前の値 (合計値) ,現在の値,現在のインデックス,配列の 4 つのパラメータを受け入れることができます. reduce にはオプションの 2 番目のパラメータ があります.これは初期値です.価値。満たされていない場合、最初の要素の初期値が存在せず、現在のインデックスの値も 1 になるため、走査は array の 2 番目の要素であるインデックス 1 から開始されます。初期値を入力すると、走査の最初のラウンドの現在のインデックスは 0 になり、現在の要素は配列要素になり、前の要素も初期値になります。配列全体をトラバースするコールバック関数の結果を返します
reduce は特に一般的に使用される配列メソッドではありませんが、場合によっては、コードの複雑さを大幅に軽減できます. 複数の例を使用して、reduce の実用的な使用法をいくつか示します.
const numArr = [1, 4, 98, 170, 35, 87]
// 得到numArr的元素的和
let sum = numArr.reduce((previous, current) => {
return previous + current
})
console.log(sum) // 395
// 如果最初值存在的话
let withInitial = numArr.reduce((previous, current) => {
return previous + current
}, 100)
console.log(withInitial) // 495
上記のコードを一見すると、少し混乱するかもしれませんが、次の表は理解に役立ちます
コールバックの数 | previousValue |
currentValue |
currentIndex |
戻り値 | |
---|---|---|---|---|---|
トラバーサルの最初のラウンド | 1 |
4 | 1 |
5 |
|
トラバーサルの第 2 ラウンド | 5 |
98 |
2 |
103 | |
トラバーサルの第 3 ラウンド | 103 | 170 | 3 |
273 | |
トラバーサルの第 4 ラウンド | 273 | 35 | 4 |
308 |
この配列には 6 つの要素があるため、合計 6 回トラバースされます。上記の例は、最初の 4 つのラウンドのプロセスと結果です。オブジェクトの配列内の値を集計するために reduce を使用する方法の別の例を次に示します。
let shoppingCart = [
{
product: 'phone',
qty: 1,
price: 500,
},
{
product: 'Screen Protector',
qty: 1,
price: 10,
},
{
product: 'Memory Card',
qty: 2,
price: 20,
},
];
// 计算购物车内的价格总和
let total = shoppingCart.reduce(function (previousValue, currentValue) {
return previousValue + currentValue.qty * currentValue.price;
}, 0);
console.log(total) // 550
上記は reduce の 2 つの基本的な使用法であり、より複雑なシナリオにも適用できます。もう 1 つの一般的なシナリオは、配列内の同じ型のオブジェクトを 1 つのカテゴリにグループ化して、新しい配列を形成することです。
const people = [
{ name: 'Kyle', age: 26 },
{ name: 'John', age: 31 },
{ name: 'Sally', age: 42 },
{ name: 'Jill', age: 42 },
]
// 把年龄相同的人分为一组
const peopleGroupedByAge = people.reduce((groupedPeople, person) => {
const age = person.age
// 首先给每个存在的年龄段创建一个空数组
// 然后用push将每个元素放入相应的数组
if (groupedPeople[age] == null) groupedPeople[age] = []
groupedPeople[age].push(person)
return groupedPeople
}, {}) // 初始值是一个空对象,这样才能使用增加属性
console.log(peopleGroupedByAge)
/*
{
26: [{ name: 'Kyle', age: 26 }],
31: [{ name: 'John', age: 31 }],
42: [
{ name: 'Sally', age: 42 },
{ name: 'Jill', age: 42 }
]
}
*/
6. 毎
基本的な構文:
every((element, index, array) => { /* … */ } ) // return boolean
最後に、every() というより単純な関数を作成します。every メソッドは、配列内のすべての要素が条件を満たしているかどうかを確認するために使用されます。いずれかの条件が満たされない場合、コールバック関数はfalseを返します。すべてのトラバーサルが true を返す場合、すべてのトラバーサルが最終的に true を返します
every 自体の概念は理解しやすいです。例を使用してその役割を説明します。
const inventors = [
{ first: 'Albert', last: 'Einstein', year: 1879, passed: 1955 },
{ first: 'Isaac', last: 'Newton', year: 1643, passed: 1727 },
{ first: 'Galileo', last: 'Galilei', year: 1564, passed: 1642 },
{ first: 'Marie', last: 'Curie', year: 1867, passed: 1934 },
{ first: 'Johannes', last: 'Kepler', year: 1571, passed: 1630 },
{ first: 'Nicolaus', last: 'Copernicus', year: 1473, passed: 1543 },
{ first: 'Max', last: 'Planck', year: 1858, passed: 1947 },
{ first: 'Katherine', last: 'Blodgett', year: 1898, passed: 1979 },
{ first: 'Ada', last: 'Lovelace', year: 1815, passed: 1852 },
{ first: 'Sarah E.', last: 'Goode', year: 1855, passed: 1905 },
{ first: 'Lise', last: 'Meitner', year: 1878, passed: 1968 },
{ first: 'Hanna', last: 'Hammarström', year: 1829, passed: 1909 }
];
// 检查是不是所有发明家的last name都至少4个字母并且出生于1400年以后
let checkInventors = inventors.every(inventor => {
return inventor.last.length >= 4 && inventor.year>1400
})
console.log(checkInventors) // true
最後に、注意すべき点が 1 つだけあります.今日言及されているすべての配列メソッドは、空の配列要素をトラバースしません。
console.log([1, , 3].every((x) => x !== undefined)); // true
console.log([2, , 2].every((x) => x === 2)); // true
上記は ES6 の一般的な配列トラバーサル メソッドです。それらをマスターすることはビジネスにとって非常に重要であり、適切な状況下で多くの練習を行う必要があります。