JavaScript中For循環的3種版本和使用場景

2021-02-19 前端之巔

我們大家都至少會了解一個版本的 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 循環的各個部分要更靈活一些。實際上,你應該將它們視為:

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 循環處理對象的非符號可枚舉屬性(這裡的關鍵字是「對象」,因為 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
*/

很簡單,不是嗎?但請注意,因為就像我說的那樣,JavaScript 中的幾乎所有內容都是一個對象,因此你可以在確實需要 For…of 的時候結束 For…in。例如,如果你要遍歷一個字符串(它是一個對象)中的每個字符,那麼如果你使用 For…in 將會發生以下情況:

for(let k in "Hello World!") {
   console.log(k)
}
/*
0
1
2
3
4
5
6
7
8
9
10
11
*/

我們沒有遍歷字符串的每個字母,而是遍歷了每個屬性;正如你所看到的,我們實際上是在處理與數組非常相似的結構(對於字符串類型)。這是有道理的,因為"Hello World!"[1] 不僅能正常執行,還可以返回這個位置的實際字符(也就是字母「e」)。相反,如果你想遍歷每個字符,則需要使用另一個變體:For…of

for(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 方法是 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' ]
*/

簡單明了,你可以看到我們是怎樣在函數內輕鬆使用所有屬性的。下面這個示例針對的是,你希望在 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

相關焦點

  • 初學JavaScript應該清楚函數、事件、關鍵字和保留字、注釋的使用
    在JavaScript中,變量全部統一使用var關鍵字來定義。這在C#中是不會允許的。最終x1變量的值就是true。X1變量一開始是整數,後來是字符串,最後變成了布爾類型,數據類型一直在變化,這就是弱類型的體現。JavaScript語言是區分大小寫的。並且標識符只能以字母、下劃線和美元符號$開頭,並且也不能是關鍵字和保留字,但標識符中可以包含保留字和關鍵字。第3節.
  • 20個常用的JavaScript簡寫技巧
    給多個變量賦值 我們可以使用數組解構來在一行中給多個變量賦值。 3. 三元運算符 我們可以使用三元(條件)運算符在這裡節省 5 行代碼。 4.
  • 第一篇:JavaScript基本語法
    語句JS語句同Java語句相同,在語句中可以包含變量、關鍵字、運算符和表達式,語句結束符使用英文分號「;」,在語句的結尾也可以不使用結束符。JS代碼塊一般在函數、條件結構、循環結構內部使用。JavaScript關鍵字見下表:變量和常量在JS語句中聲明的標識符稱為變量,變量的值在JS程序運行過程中可以被修改。每個變量都對應某個存儲空間,用於存儲程序使用的數據,通過變量名稱可以訪問對應的存儲空間,即可以訪問存儲空間存儲的數據。
  • 初見成效,使用Js操作DOM對象
    DOM即文檔對象模型描繪了一個層次化的節點樹,運行開發人員添加、移除和修改頁面的某一部分。DOM處於javascript 的核心地位上。每個載入瀏覽器的 HTML 文檔都會成為 Document 對象。Document 對象使我們可以從腳本中對 HTML 頁面中的所有元素進行訪問。
  • 0基礎學習JavaScript一定要知道如何使用VS2019去編寫代碼
    在圖2左側選擇「Web」下面的「HTML頁」,使用默認的名稱「HtmlPage1.html」,點擊「添加」按鈕。VS2019就會為我們創建出一個具有Html代碼的頁面。JavaScript代碼就是在Html頁面上使用的,在瀏覽器中解釋和執行。
  • 第三篇:JavaScript語句流程控制
    在一個程序執行的過程中,語句的執行順序對程序的結果是有直接影響的。也就是說程序的流程對運行結果有直接的影響。語句流程控制是用來控制程序中各條語句的執行順序,它可以把語句組合成能完成一定功能的代碼段。流程控制方式主要有:順序結構、條件結構和循環結構。
  • JavaScript函數 - 遞歸
    2.但是在工作中,一般情況下禁止使用遞歸。方法:1.首先去找臨界值,既無需計算,獲得的值。2.找這一次和上一次的關係3.假設當前的函數已經可以使用,調用自身計算上一次的運行結果,再寫出這次的運行結果特點:1.必須有參數2.必須由return返回值
  • 在JavaScript中分解數字的三種方法
    本文基於Free Code Camp基本算法腳本「分解數字」 在數學中,非負整數n的階乘可能是一個棘手的算法。在本文中,我將解釋三種方法,第一種使用遞歸函數,第二種使用while循環,第三種使用for循環。
  • jQuery使用hide()和show()隱藏顯示元素,toggle()顯示和隱藏切換
    Hide()方法和show()方法通常配合使用,一起實現Html元素的顯示和隱藏得到某種動態效果。一、顯示/隱藏基本使用下面我們列舉一個例子,實際演示一下jQuery的顯示和隱藏方法的使用。圖3這樣呈現出來的效果,元素的顯示和隱藏不是一下子出來的,而是慢慢的顯示和隱藏。三、更多的使用方法針對show()和hide()方法,還可以具有第二個參數,用於執行一段JS代碼回調函數。
  • jquery中淡入淡出切換效果函數使用方法?
    jquery是javascript很常用和熱門的一個類庫,前端開發人員必須學習的一個js類庫,接下來來看看怎麼使用jquery中的怎麼切換使用淡入淡出方法。jquery最大的特點就是極大地簡化了 JavaScript 編程。而且使用起來也是很簡單的,比javascript更方便簡單。
  • 騰訊連連小程序發布2.0版本,優化IoT場景使用體驗
    9月22日,騰訊雲正式對外發布騰訊連連微信小程序2.0版本,新版本在視覺體驗及關鍵功能上全面增強並優化消費者體驗。具體來說,用戶可以通過微信掃一掃直接拉起騰訊連連小程序,消費者無需下載APP。此外2.0版本也發布了標準藍牙設備接入協議。去年,騰訊雲正式推出騰訊連連微信小程序,企業藉助騰訊連連可以降低物聯網產品的研發門檻,加快研發速度。同時,騰訊連連還可以提供以微信小程序為載體的、面向消費者的應用入口,打造針對物聯網產業的全套C2B開放平臺服務,推動萬物互聯進程加速。此次2.0版本的多項升級,標誌著騰訊連連物聯網服務能力的全面進化。
  • 國外有機廢氣處理處理可程式不循環3種方法
    國外有機廢氣處理處理可程式不循環3種方法   國外有機廢氣處理,認準無錫冠亞,專業生產供應國外有機廢氣處理,品質好,價格低。本公司專注研發做國外有機廢氣處理, 可按需求量身定製,免費提供監測服務等。
  • C4D教程-製作三維無限循環場景動畫
    【教程介紹】 製作三維無限循環場景動畫 Motion Design School – Cinema 4D Infinite 3D Loops Masterclass 深入了解如何在Cinema
  • 高校教材,不妨試試循環回收使用
    這些教材若循環使用一年,節約費用可援建約4萬所希望小學。在義務教育階段,部分免費教材循環使用已經展開,然而這僅僅只是教材總量的一小部分。通過調研和查閱國內目前在二手教材方面的一些研究資料了解到,不包括中小學,僅國內各大高校每年約有900萬左右的畢業生,每人每學期至少有2本教材可再次使用,到離校時每名學生有10本左右的閒置教材,即每年畢業季有近1億本二手教材可回收利用。
  • 如何優雅地使用javascript遞歸畫一棵結構樹
    本文轉載自【微信公眾號:趣談前端,ID:beautifulFront】經微信公眾號授權轉載,如需轉載與原文作者聯繫遞歸和尾遞歸簡單的說,遞歸就是函數自己調用自己,它作為一種算法在程序設計語言中廣泛應用。
  • JavaScript模擬輪播圖效果
    分析步驟:1)確定事件(onload)綁定函數2)獲取元素的src屬性並修改值3)設置定時器,運行函數代碼:<html> <head>   <meta charset="UTF-8">
  • 使用場景擴展 比亞迪DiLink3.0系統發布
    [愛卡汽車 科技頻道 原創]  比亞迪在2018年推出了DiLink智能網聯繫統,功能豐富的車機系統、可旋轉中控大屏,一時成為當時市場中熱議的對象。DiLink系統的出現,也為旗下王朝系列車型帶來了全新的車機使用體驗。
  • 解釋 Python 2 和 Python 3 的版本之間差別
    隨著 Python 2 的不斷發展,更多的功能被添加進來,包括將 Python 的類型和類在 Python 2.2 版本中統一為一層。Python 3Python 3 被視為 Python 的未來,是目前正在開發中的語言版本。作為一項重大改革,Python 3 於 2008 年年末發布,以解決和修正以前語言版本的內在設計缺陷。
  • 25 歲的 JavaScript 都經歷了什麼?
    「JavaScript 是幾天內就完成了,最初只在一個瀏覽器中使用。微軟的第一個瀏覽器附帶了他們自己風格的 JavaScript 叫 JScript。今天,JavaScript 還被用於構建桌面應用、行動裝置應用、健身追蹤器、機器人和眾多嵌入式系統。它甚至是詹姆斯·韋伯太空望遠鏡的一部分。
  • 《捕魚達人3》V1.0.3版本更新 加入全新場景
    關鍵字:  捕魚達人3版本更新    捕魚達人3V1.0.3版本更新       捕魚達人3更新至V1.0.3版本,新的版本加入了收集系統,玩家可以收集掉落的卡牌來兌換武器,同時加入了全新的火焰大炮,最重要的是加入了一個全新的特效魚類火焰鬥魚,小夥伴們趕緊來更新最新版本吧。