javascript
foreach循环怎么获取全部返回值_JavaScript中For循环的3种版本和使用场景
我們大家都至少會了解一個版本的 For 循環,它如此經典,可能每一種語言都有它的一個版本。但 JavaScript 足足有 3 種 For 循環(細究的話是 4 種),這 3 種版本還不是完全一樣,具體來說分別是:
經典的 For 循環;
For…of 和 For…in 這對;
還有精美的函數版本:.forEach。
這三種版本之間有很多區別,因此在本文中,我想介紹它們的具體內容,以及如何或何時使用它們才能獲得最佳結果。那就開始吧。
這三種版本之間有很多區別,因此在本文中,我想介紹它們的具體內容,以及如何或何時使用它們才能獲得最佳結果。那就開始吧。
小技巧:使用 Bit 將 組件 和它的所有依賴項和設置 封裝 在一起。通過更好的代碼復用、更簡單的維護和更少的開銷構建真正的模塊化應用程序:
https://bit.dev/?utm_medium=content&utm_source=bitsandpieces&utm_content=1&utm_campaign=campaign&source=post_page-----f0fb5501bdf3----------------------
經典的 For 循環首先來看經典的 For 循環;你可以在其中定義內部計數器,設置中斷條件和步進更改(通常是增加或減少計數器計數)。
具體的語法為:for([計數器定義];[條件中斷定義];[步進定義]){//……這里是重復的代碼
}以前你肯定寫過這種代碼,最常見的形式是:for(let?counter = 0; counter < 10; counter++) {
console.log(counter)
}雖說這種代碼可以運行得很好,但是 For 循環的各個部分要更靈活一些。實際上,你應該將它們視為: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 循環,或者在不一定影響計數器的情況下執行每一步的代碼。這里舉幾個例子。例如,這是一個完全有效的循環: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!
*/那么如何在經典的 For 循環中處理 異步代碼 呢?多虧了我們的新朋友 async/await,這很容易: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 和 For…of是的,它們是上一版本的非常相似的變體,但它們并不是同一種循環。
給一個簡短的定義:
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
*/
???console.log(k)
}
/*
0
1
2
3
4
5
6
7
8
9
10
11
*/我們沒有遍歷字符串的每個字母,而是遍歷了每個屬性;正如你所看到的,我們實際上是在處理與數組非常相似的結構(對于字符串類型)。這是有道理的,因為"Hello World!"[1] 不僅能正常執行,還可以返回這個位置的實際字符(也就是字母“e”)。相反,如果你想遍歷每個字符,則需要使用另一個變體:For…offor(let char?of "Hello World!") {
??console.log(char)
}
/*
H
e
l
l
o
W
o
r
l
d
!
*/現在是不是更清楚一些了?用例是一樣的,但是有了它,你就可以訪問可迭代的值(字符串是可迭代的,數組、映射、集合和 arguments 或 NodeList 這樣類似數組的結構也是可迭代的);當然也包括你自己的對象,只要把它們定義為可迭代即可。拿上面的示例來說,沒有直接的方法來獲取循環的當前索引,當然除非你在循環之外定義它并在每個步驟上都更新它;或者你可以針對數組使用 entries 方法,則可以同時獲取索引和值,如下所示: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 循環這可能是我最喜歡的一個,只是因為我非常喜歡聲明式語法或通過聲明式風格代替命令式來編寫代碼。而且,盡管前面兩個版本的循環很好用,并且都有很好的用例,但它們也是非常命令式的風格,我們需要編寫 我們的數據應該發生什么事情,而不是簡單地編寫 我們想要數據發生什么事情。
不管怎么說,撇開哲學上的爭論,.forEach 方法是 For 循環的另一個版本;但這種方法是數組對象的一部分,并且在執行函數時要接收一個函數和一個額外的可選參數來重新定義函數的上下文。
對于數組中的每個元素,我們的函數都會執行,并且會收到 三個參數(是的,確實是 三個,而不是你習慣使用的一個)。它們分別是:
當前正在處理的元素。
元素的索引,這簡化了我們嘗試使用 For…of 循環完成的任務
實際正在處理的數組。以防萬一你要對它做什么事情。
a.forEach ( (elem, idx, arr) => {
???console.log(elem, "at: ", idx, "inside: ", arr)
})
/*
hello at:??0?inside: [ 'hello', 'world'?]
world at:??1?inside: [ 'hello', 'world'?]
*/簡單明了,你可以看到我們是怎樣在函數內輕松使用所有屬性的。下面這個示例針對的是,你希望在 forEach 方法上使用第二個可選參數的情況: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)通過覆蓋被調用函數 greet 的上下文,我可以在不影響其代碼的情況下更改其行為。最后,為了表明這一方法也可以與異步代碼一起使用,下面是示例: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
總結
以上是生活随笔為你收集整理的foreach循环怎么获取全部返回值_JavaScript中For循环的3种版本和使用场景的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql cluster 数据文件_m
- 下一篇: AMD RX 570显卡规格参数怎么样