在英語中,Loop 這個詞指的是由彎曲的曲線所產(chǎn)生的形狀。類似的概念,,Loop 這個詞已經(jīng)被用于編程中,。如果你看到下圖,你就會清楚的知道指令的流動是如何在一個循環(huán)的動作中不斷重復(fù)的,。
在編程中,,循環(huán)的概念并不是什么新概念,它們常常在編碼時使用,。雖然不是的語言其語法不同,,但基本概念是相同的,根據(jù)需要重復(fù)相同的代碼塊,。JavaScript增加了循環(huán)類型(包括各種類型的循環(huán)),,并使其與它們的工作更加舒適和高效。在本文中,,我們將學(xué)習(xí)JavaScript中所有可用的循環(huán),。
循環(huán)的定義
在計(jì)算機(jī)編程中,,Loop 是一個重復(fù)特定代碼塊的過程,。
JavaScript的循環(huán)類型
在JavaScript中有七種循環(huán)類型。我們已經(jīng)把它們列出來,,這樣可以幫助你更清楚地了解他們的工作流程和使用情況,。本文還將幫助你區(qū)分這七種循環(huán)類型,比如在哪里,、何時或如何使用它們,。讓我們開始吧。
while 循環(huán)
while 循環(huán)是JavaScript中可用的最基本的循環(huán)類型之一,。你一定聽說過,,JavaScript不是唯一的編程語言。
while 語句生成一個循環(huán),,在條件為true 的情況下,,在一個特定的語句塊中執(zhí)行該循環(huán)。每次執(zhí)行代碼塊之前,,條件都會被檢查。
語法
while (條件) {
// 代碼塊
}
示例
var i = 8;
while (i < 10) {
console.log('我小于10')
i++
}
在上面的例子中,,條件(i < 10) 先會被檢查,,如果條件為true ,while 中的代碼塊就會被執(zhí)行,,而且再下一次迭代之前,,i 的值將增加1 ,主要是因?yàn)槲覀円呀?jīng)添加了一個i++ 語句。
do-while 循環(huán)
do-while 和while 略有不同,,因?yàn)樗粋€額外的特性,,最少執(zhí)行一次。
語法
do {
// 代碼塊
}
while (條件)
示例
var i = 8;
do {
console.log('我的值是' + i)
i++
}
while (i > 7 && i < 10)
你可以看到,,我們的條件是(i > 7 && i < 10) ,,但i=7 的時候值已經(jīng)打印出來了。因?yàn)檫@個循環(huán)技術(shù)首先執(zhí)行代碼塊,,而不是考慮條件,,執(zhí)行完代碼塊之后,在第二輪的時候才執(zhí)行條件,。對于第二次循環(huán)遍歷代碼塊時,,只有條件為true 才將執(zhí)行。
for 循環(huán)
while 循環(huán)和for 循環(huán)的工作方式完全相同,,即使執(zhí)行時間也沒有太大差別,。那么,另一個提供相同功能的循環(huán)系統(tǒng)需要什么呢,?
在for 循環(huán)中,,循環(huán)的變量聲明和初始化,條件查詢和循環(huán)變量的遞增或遞減都可以在相同的行中完成,。它增加了可讀性,,降低了出錯的幾率。
語法
for ([變量初始化];[條件];[變量遞增或遞減]) {
// 代碼塊
}
示例
for (var i = 0; i < 10; i++) {
console.log('我的值是: ' + i)
}
正如上面的示例所示,,變量初始化i = 0 ,,條件i < 10 和變量的遞增i++ 都在同一行中聲明。它更容易理解,,可讀性更好,,是不是?
for 循環(huán)的使用和前面所說的while 循環(huán)完全相同,。但是為了讓代碼更容易閱讀和理解,,大多數(shù)的時候我們使用for 循環(huán)而不是while 循環(huán)。
forEach()
它是數(shù)組的原型方法(甚至是map 和set ),。forEach() 方法根據(jù)索引順序index ,,每次使用數(shù)組中的每個元素調(diào)用一個給定的函數(shù)(或回調(diào)函數(shù))。注意,,forEach() 沒有對沒有值的數(shù)組元素運(yùn)行給定的函數(shù),。
語法
array.forEach(function(currentValue, index, array){
// 函數(shù)主體
})
forEach() 方法以函數(shù)作為參數(shù)。該函數(shù)由三個參數(shù)組成:
currentValue :保存正在處理的當(dāng)前值
index :保存該特定數(shù)組中的值的索引
array :保存了整個數(shù)組
你可以使用forEach() 遍歷一個集合set ,,也可以使用它迭代一個映射map ,。
示例
var array = [10, 20, "hi", , {}, function () {console.log('我是一個函數(shù)')}]
array.forEach(function(item, index){
console.log('array [' + index + '] 是: '+ item)
})
forEach() 方法遍歷的是array 數(shù)組,。如果你沒有使用索引index ,你只能使用array.forEach(function(item){}) ,??梢韵鄳?yīng)地使用參數(shù),但不是每次都要使用這三個參數(shù),。
使用forEach() 讓我們遍歷數(shù)組變得非常的簡單,。不必?fù)?dān)心循環(huán)變量、條件和其他任何東西,,它會處理所有迭代的問題,。
forEach() 和for 的區(qū)別
你可以使用一個從0 開始到array.length (該數(shù)組長度)簡單的遍歷一個數(shù)組。那么為什么還要提出不同的選擇呢,?
一個經(jīng)驗(yàn)法則是,,如果你可以選擇使用原型方法,你就應(yīng)該使用原型方法,。因?yàn)?,原型方法更清楚地知道對象,并對最佳方法進(jìn)行了優(yōu)化,。下面這個示例能更好的來說明他們的區(qū)別之處:
var arr = [];
arr[0]=0;
arr[10]=10;
for(var i=0; i<arr.length; i++){
console.log("I am for:" + i);
}
arr.forEach(function(){
console.log("I am forEach");
});
如果你運(yùn)行上面的代碼,,你會發(fā)現(xiàn)for 打印了11 次,而forEach() 只打印了兩次:
原因是,,for 循環(huán)是一個簡單的for 循環(huán),,對它的用途一無所知。它從0 到arr.length ,。然而,當(dāng)你使用forEach() 的時候,,它知道arr 只有兩個元素,,雖然長度是10 。累此,,它實(shí)際上只迭代了兩次,。
根據(jù)這個,如果你想在循環(huán)中跳過繁重的工作,,迭代一個iterable ,,你應(yīng)該使用forEach() 。然而,,僅僅迭代(相同數(shù)量的迭代)的迭代時間相對于for 循環(huán)來說是次要的,。因?yàn)榈阅芨谩?/p>
map()
map 是數(shù)組的另一個原型方法。map() 方法將創(chuàng)建一個新的數(shù)組,,該數(shù)組的返回值由一個給定的數(shù)組的函數(shù)執(zhí)行生成,。
語法
var newArray= oldArray.map(function (currentValue, index, array){
//Return element for the newArray
});
map() 方法以函數(shù)作為參數(shù),,該函數(shù)有三個參數(shù):
currentValue : 在數(shù)組中處理的當(dāng)前元素
index :數(shù)組中正在處理的當(dāng)前元素的索引值
array :數(shù)組映射的調(diào)用
示例
var num = [1, 5, 10, 15];
var doubles = num.map(function(x) {
return x * 2;
});
在上面的示例中,名為doubles 的新數(shù)組將輸出doubles=[2, 10, 20, 30] 和num 數(shù)組仍舊是num=[1, 5, 10, 15] ,。
for…in
這個方法主要是對象的迭代,。for...in 在語句中迭代對象的可枚舉屬性。對于每個不同的屬性,,可以執(zhí)行語句,。
因?yàn)槲覀冎罃?shù)組也是一種特殊的對象,所以不要認(rèn)為數(shù)組不能用這個來進(jìn)行迭代,。
語法
for (variableName in object) {
Block of code
}
示例
var obj = {a: 1, b: 2, c: 3};
for (var prop in obj) {
console.log('obj.'+prop+'='+obj[prop]);
};
為什么在數(shù)組中使用for...in 迭代不可?。?/p>
for...in 不應(yīng)該在數(shù)組迭代中使用,,特別是index 順序非常重要,。
實(shí)際上,數(shù)組索引和一般對象屬性之間沒有區(qū)別,,數(shù)組索引只是可枚舉屬性,。
for...in 不會每次都以任何特定的順序返回index 值。for...in 在迭代中,,這個循環(huán)將返回所有可枚舉屬性,,包括那些具有非整數(shù)名稱的屬性和繼承的屬性。
因此,,建議在遍歷數(shù)組時使用for 或forEach() ,。因?yàn)榈捻樞蚴且蕾囉诂F(xiàn)實(shí)的迭代,并且遍歷一個數(shù)組,,使用for...in 可能不會以一致的順序訪問元素,。
var arr = [];
arr[2] = 2;
arr[3] = 3;
arr[0] = 0;
arr[1] = 1;
在這種情況下,使用forEach() 將輸出一個0, 1, 2, 3 ,。但使用for...in 并不能保證會輸出什么,。
對于for...in 還有一件事你應(yīng)該記住,它遍歷對象的所有屬性,,包括繼承的(來自父類),。如果只想在對象自己的屬性上進(jìn)行迭代,那么應(yīng)該執(zhí)行下面這樣的操作:
for(var prop in obj){
if(obj.hasOwnProperty(prop)){
Code block here
}
}
for…of
這是ES6中新引入的一種循環(huán)類型,。使用for...of 語句,,你可以遍歷任何可迭代的對象,比如Array ,、String ,、Map 、WeakMap ,、Set ,、參數(shù)對象,、TypeArray ,甚至一般對象,。
語法
for (variable of iterable) {
Block of code
}
示例
var str= 'paul';
for (var value of str) {
console.log(value);
}
map的迭代
let itobj = new Map([['x', 0], ['y', 1], ['z', 2]]);
for (let kv of itobj) {
console.log(kv);
}
// => ['x', 0]
// => ['y', 1]
// => ['z', 2]
for (let [key, value] of itobj) {
console.log(value);
}
// => 0
// => 1
// => 2
for...in 循環(huán)主要遍歷對象,,其實(shí)際的插入順序中是可枚舉的屬性;for...of 迭代任何可迭代對象的給定值(而不是屬性名),。
Object.prototype.objProto = function() {};
Array.prototype.arrProto = function() {};
let iterable = [8, 55, 9];
iterable.title = 'VoidCanvas';
for (let x in iterable) {
console.log(x); // logs 0, 1, 2, title, arrProto, objProto
}
for (let i of iterable) {
console.log(i); // 8, 55, 9
}
正如你所見,,for...of 都是關(guān)于對象自己value 的迭代,而for...in 將會考慮原型和繼承的屬性,。如果你想在對象上迭代(而不是迭代),。for...of 將會考慮它自己的所有屬性,但迭代的情交下,,它只會考慮適合這種迭代的元素,。這就是為什么在上面的例子中,for...of 沒有迭代屬性,。
本文根據(jù)@Sandip的《The Output Element》所譯,,整個譯文帶有我們自己的理解與思想,如果譯得不好或有不對之處還請同行朋友指點(diǎn),。如需轉(zhuǎn)載此譯文,,需注明英文出處:http:///all-type-of-loops-in-javascript-a-brief-explanation。
|