我們大家都至少會了解一個版本的 For 循環,它如此經典,可能每一種語言都有它的一個版本。但 JavaScript 足足有 3 種 For 循環(細究的話是 4 種),這 3 種版本還不是完全一樣,具體來說分別是:
經典的 For 循環;
For…of 和 For…in 這對;
這三種版本之間有很多區別,因此在本文中,我想介紹它們的具體內容,以及如何或何時使用它們才能獲得最佳結果。那就開始吧。
這三種版本之間有很多區別,因此在本文中,我想介紹它們的具體內容,以及如何或何時使用它們才能獲得最佳結果。那就開始吧。
小技巧:使用 Bit 將 組件 和它的所有依賴項和設置 封裝 在一起。通過更好的代碼復用、更簡單的維護和更少的開銷構建真正的模塊化應用程式:
https://bit.dev/?utm_medium=content&utm_source=bitsandpieces&utm_content=1&utm_campaign=campaign&source=post_pagef0fb5501bdf3--
首先來看經典的 For 循環;你可以在其中定義內部計數器,設置中斷條件和步進更改(通常是增加或減少計數器計數)。
for([計數器定義];[條件中斷定義];[步進定義]){
//……這裡是重複的代碼
}
for(let counter = 0; counter < 10; counter++) {
console.log(counter)
}
for(
[EXPRESSION EXECUTED ONLY ONCE AT THE START OF THE LOOP(表達式僅在循環開始時執行一次)];
[BOOLEAN CONDITION CHECKED ON EVERY STEP(每一步都檢查布爾條件)];
[EXPRESSION EXECUTED ON EVERY STEP OF THE LOOP(表達式在循環的每一步都執行)]
)
for(let a = 0, b = 0; a < 10 && b < 100; a++, b+=10) {
console.log(a, b)
}
/*
0 0
1 10
2 20
3 30
4 40
5 50
6 60
7 70
8 80
9 90
*/
for(let a = 0, b = 0; a < 10 && b < 100; console.log("Your counters are at:", ++a, b+=2)){}
/*
Your counters are at: 1 2
Your counters are at: 2 4
Your counters are at: 3 6
Your counters are at: 4 8
Your counters are at: 5 10
Your counters are at: 6 12
Your counters are at: 7 14
Your counters are at: 8 16
Your counters are at: 9 18
Your counters are at: 10 20
*/
function isItDone(a) {
console.log("fn called!")
return a < 10
}
for(let a = 0; isItDone(a); a++) {
console.log(a)
}
/*
fn called!
0
fn called!
1
fn called!
2
fn called!
3
fn called!
4
fn called!
5
fn called!
6
fn called!
7
fn called!
8
fn called!
9
fn called!
*/
const fs = require("fs")
async function read(fname) {
return new Promise( (resolve, reject) => {
fs.readFile(fname, (err, content) => {
if(err) return reject(err)
resolve(content.toString())
})
})
}
(async () => {
let files = ['file1.json', 'file2.json']
for(let i = 0; i < files.length; i++) {
let fcontent = await read(files[i])
console.log(fcontent)
console.log("--")
}
})()
注意,這裡我們可以簡單地使用循環,就好像背後沒有異步機制一樣。這就是 async/await,因為有它,我們才能重新依靠諸如 For 循環 之類的基本構造來迭代一組異步指令。過去,如果你想使用回調或 Promise 實現同一目標,則邏輯會複雜得多。這就是諸如 async.js 之類的庫誕生的起源。
順便說一句:在我的示例中,for 循環位於 IIFE內;你可能已經知道,這只是因為 await 指令需要位於異步函數內,否則 Node 是不會允許它的。
是的,它們是上一版本的非常相似的變體,但它們並不是同一種循環。
給一個簡短的定義:
For…in 循環處理對象的非符號可枚舉屬性(這裡的關鍵字是「對象」,因為 JavaScript 中的幾乎所有內容都是對象)。當你將自定義對象用作哈希圖或字典時(這是非常常見的做法),這非常有用。
但請 注意,迭代是按任意順序完成的,因此不要依賴循環來選擇所需的正確順序,並且在有必要的時候一定要自己控制好這個部分。
let myMap {
uno: 1,
dos: 2,
tres: 3
}
for(let key in myMap) {
console.log(key, "=", myMap[key]);
}
/*
uno = 1
dos = 2
tres = 3
*/
for(let k in "Hello World!") {
console.log(k)
}
/*
0
1
2
3
4
5
6
7
8
9
10
11
*/
for(let char of "Hello World!") {
console.log(char)
}
/*
H
e
l
l
o
W
o
r
l
d
!
*/
let myArr = ["hello", "world"]
for([idx, value] of myArr.entries()) {
console.log(idx, '=', value)
}
/*
0 '=' 'hello'
1 '=' 'world'
*/
const fs @= require("fs")
async function read(fname) {
return new Promise( (resolve, reject) => {
fs.readFile(fname, (err, content) => {
if(err) return reject(err)
resolve(content.toString())
})
})
}
(async () => {
let files = ['file2.json', 'file2.json']
for(fname of files) {
let fcontent = await read(fname)
console.log(fcontent)
console.log("--")
}
for(idx in files) {
let fcontent = await read(files[idx])
console.log(fcontent)
console.log("--")
}
})()
兩個循環使用 await 構造時的反應方式完全相同,從而使你可以編寫更簡單、更簡潔的代碼。
這可能是我最喜歡的一個,只是因為我非常喜歡聲明式語法或通過聲明式風格代替命令式來編寫代碼。而且,儘管前面兩個版本的循環很好用,並且都有很好的用例,但它們也是非常命令式的風格,我們需要編寫 我們的數據應該發生什麼事情,而不是簡單地編寫 我們想要數據發生什麼事情。
不管怎麼說,撇開哲學上的爭論,.forEach 方法是 For 循環的另一個版本;但這種方法是數組對象的一部分,並且在執行函數時要接收一個函數和一個額外的可選參數來重新定義函數的上下文。
對於數組中的每個元素,我們的函數都會執行,並且會收到 三個參數(是的,確實是 三個,而不是你習慣使用的一個)。它們分別是:
當前正在處理的元素。
元素的索引,這簡化了我們嘗試使用 For…of 循環完成的任務
實際正在處理的數組。以防萬一你要對它做什麼事情。
a = ["hello", "world"]
a.forEach ( (elem, idx, arr) => {
console.log(elem, "at: ", idx, "inside: ", arr)
})
/*
hello at: 0 inside: [ 'hello', 'world' ]
world at: 1 inside: [ 'hello', 'world' ]
*/
class Person {
constructor(name) {
this.name = name
}
}
function greet(person) {
console.log(this.greeting.replace("$", person.name))
}
let english = {
greeting: "Hello there, $"
}
let spanish = {
greeting: "Hola $, ¿cómo estás?"
}
let people = [new Person("Fernando"), new Person("Federico"), new Person("Felipe")]
people.forEach( greet, english)
people.forEach( greet, spanish)
const fs = require("fs")
async function read(fname) {
return new Promise( (resolve, reject) => {
fs.readFile(fname, (err, content) => {
if(err) return reject(err)
resolve(content.toString())
})
})
}
let files = ['file1.json', 'file2.json']
files.forEach( async fname => {
let fcontent = await read(fname)
console.log(fcontent)
console.log("--")
})
請注意,由於我將回調聲明為異步,因此不再需要 IIFE。
我要分享的關於 JavaScript 中 For 循環的全部信息就是這些了,我希望現在你對它們有了更清晰的了解,並可以基於這些知識和當前的編碼需求來選擇自己喜歡的循環。
有任何意見和建議,歡迎發表評論並分享本文!
https://blog.bitsrc.io/3-flavors-of-the-for-loop-in-javascript-and-when-to-use-them-f0fb5501bdf3