通過幾個事例,就可以說明 for...of 循環在 JS 是不可或缺
請教大家一個問題:什么特性讓該編程語言更加優秀?
個人見解:當該特性可以組合多個其他語言特性時。
JavaScript 中的for...of語句就是這種情況,可從ES2015開始使用。
for...of可以迭代數組,類似數組的對象以及通常所有可迭代的對象(map,set,DOM集合)。
接下我們通過事例來看看 for...of 一些有用的地方。
1. 數組的迭代
for...of的最常見應用是對數組項進行迭代。該循環可以很好且短暫地完成它,而無需其他變量來保持索引。
例如:
- const products = ['橘子', '蘋果']
- for (const product of products.entries()) {
- console.log(product)
- }
- // "橘子"
- // "蘋果"
for...of循環遍歷products,迭代的每項值分配給變量product。
數組方法 entries() 可以用于訪問迭代項的索引,該方法在每次迭代時返回一組鍵值對[index, item]。
- const products = ['橘子', '蘋果']
- for (const [index, product] of products.entries()) {
- console.log(index, product)
- }
- // 0 "橘子"
- // 1 "蘋果"
在每次迭代中,products.entries()返回一對索引和值,它們由const [index,product]表達式解構。
(1) 就地解構
首先,讓我們看一下 for...of 循環的語法:
- for (LeftHandSideExpression of Expression) {
- // statements
- }
LeftHandSideExpression表達式可以替換為賦值表達式左側的任何內容。
在上面的例子中,LeftHandSideExpression是一個變量聲明 const products,也可以是一個解構表達式 const [index, product]。
接著,我們遍歷一系列對象,提取每個對象的屬性name :
- const persons = [
- { name: '前端小智' },
- { name: '王大冶' }
- ]
- for (const { name } of persons) {
- console.log(name)
- }
- // 前端小智
- // 王大冶
循環for (const { name } of persons) 遍歷person數組的對象,同時也就地解構( {name}) person對象的 name 屬性值。
2. 類似數組遍歷
for...of 除了可以遍歷對象外,還可以遍歷類似數組的對象。
arguments是函數體內的特殊變量,表示包含函數的所有參數,arguments 也是一個類似數組對象。例如:
- function sum() {
- let sum = 0
- for (const number of arguments) {
- sum += number
- }
- return sum
- }
- sum(1, 2, 3) // 6
3.可迭代的簡要概述JavaScript中的可迭代對象是什么? 它是一個支持迭代協議的對象。
要檢查數據類型是否可迭代,可以配合Symbol.iterator方法。例如,下面的演示顯示了數組是可迭代的:
- const array = [1, 2, 3]
- const iterator = array[Symbol.iterator]()
- iterator.next() // {value: 1, done: false}
for...of接受可迭代,這很棒,因為這樣,我們就可以遍歷字符和數據結構(數組,類型化數組,集合,映射)等。
4. 字符串字符的遍歷
JavaScript 中的原始類型字符串是可迭代的。因此,我們可以輕松地遍歷字符串的字符。
- const message = 'hello';
- for (const character of message) {
- console.log(character);
- }
- // 'h'
- // 'e'
- // 'l'
- // 'l'
- // 'o'
message包含一個字符串值。由于message也是可迭代的,因此for...of循環遍歷message的字符。
5. Map 與 Set 迭代
Map是一個特殊的對象,它將一個鍵關聯到一個值。鍵可以是任何基本類型(通常是字符串,但也可以是數字等)
幸運的是,Map也是可迭代的(在鍵/值對上進行迭代),所以使用for...of可以輕松地在所有鍵/值對上循環遍歷。
- const names = new Map()
- names.set(1, 'one')
- names.set(2, 'two')
- for (const [numbe, name] of names) {
- console.log(number, name)
- }
- // 1 "one"
- // 2 "two"
for (const [number, name] of names)在names 鍵/值對映射上進行迭代。
在每個循環中,迭代器都會返回一個數組[key,value],并使用const [number,name]立即對這對數組進行解構。
同樣,以相同的方式可以遍歷Set的項:
- const colors = new Set(['white', 'blue', 'red', 'white']);
- for (color of colors) {
- console.log(color);
- }
- // 'white'
- // 'blue'
- // 'red'
6. 遍歷普通 JavaScript 對象
遍歷普通 JS 對象的屬性/值對總是很痛苦的。
通常,我要先使用Object.keys()提取對象鍵,然后使用forEach()來遍歷鍵數組:
- const person = {
- name: '前端小智',
- job: '前端分享者'
- }
- Object.keys(person).forEach(prop => {
- console.log(prop, person[prop])
- })
- // name 前端小智
- // job 前端分享者
幸運的是,新的Object.entries()函數與for...of組合提供了一個不錯的選擇:
- const person = {
- name: '前端小智',
- job: '前端分享者'
- }
- for (const [prop, value] of Object.entries(person)) {
- console.log(prop, value)
- }
- // name 前端小智
- // job 前端分享者
Object.entries(person)返回一個鍵和值元組數組:[['name', 'John Smith'], ['job', 'agent']]。然后,對于for...of循環,遍歷元組,并將每個元組解構const [prop,value]。
7. 遍歷 DOM 集合
你可能知道在 DOM 中使用HTMLCollection是多么令人沮喪。因為HTMLCollection是一個類似數組的對象(而不是一個常規數組),所以我們不能使用常規數組方法。
例如,每個 DOM 元素的children屬性都是HTMLCollection。因此,由于for...of可以在類似數組的對象上進行迭代,因此我們可以輕松地迭代子代:
- const children = document.body.children;
- for (const child of children) {
- console.log(child); // logs each child of <body>
- }
此外,for...of可以遍歷NodeList集合(可迭代)。例如,函數document.querySelectorAll(query)返回一個NodeList。
- const allImages = document.querySelectorAll('img');
- for (const image of allImages) {
- console.log(image); // log each image in the document
- }
如果你想遍歷 DOM 中的不同種類的集合,那么for...of語句是一個不錯的選擇。
8. 性能
在遍歷大數組時,for...of的速度可能比 for 要慢:
- const a = [/* big array */];
- for (let i = 0; i < a.length; i++) {
- console.log(a[i]);
- }
在每次迭代中調用迭代器比通過增加索引訪問該項目的開銷更大。但是,這種細微差別在使用大型陣列的應用程序中以及性能至關重要的應用程序中非常重要,這種情況很少發生。