摘要:所以結果的不同就是后者能將循環內容至少執行一次。當此語句省略時,表示不進行條件判斷,循環將一直執行,只有在循環中使用來跳出循環。支持對數組和類數組對象進行循環,不支持普通對象的循環。支持對字符串進行循環遍歷。
JavaScript中直接提供的循環,主要有以下幾種
while 循環和其他語言一樣,JavaScript中的while循環有兩種形式:
while (condition) { // 循環內容 } do { // 循環內容 } while (condition)
其中兩種形式的不同在于,對condition判斷的位置不同,前者先判斷,再執行循環體;而后者先執行循環體一次,再進行條件判斷。所以結果的不同就是后者能將循環內容至少執行一次。
for 循環for循環的語法:
for (init; condition; step) { // 循環體代碼塊 }
init 語句 中的內容,會在循環代碼開始前執行一次,通常用來聲明一些變量。
condition 語句 會在每次循環開始時,進行判斷。如果第一次就不滿足,則不會進入循環。
step 語句 會在每次循環結束時執行,通常是遞增或遞減condition中的某個變量。
var arr = [0, 10, 20, 30]; for (var j = 0; j < arr.length; j++) { console.log(arr[j]); } // 如果在循環體中不會改變數組的長度,用一個變量存儲數組長度是個更高效的選擇 for (var i = 0, l = arr.length; i < l; i++) { console.log(arr[i]); } var k = 0, length = arr.length; for (; k < length; k++) { console.log(arr[k]); }
for循環中的init語句,通常用來聲明初始變量,其可以有多個,用,分隔即可。而且由于此語句是在循環開始前執行,且只用執行一次,所以如果在外部已經聲明過要用的變量了,for循環中的這個語句可以直接省略,如上例中的第三個for循環所示。
for循環的條件語句是在每次循環體開始前進行判斷,如果為true,則執行循環體內容,否則結束循環。當此語句省略時,表示不進行條件判斷,循環將一直執行,只有在循環中使用break來跳出循環。
for循環的step語句,最常見的就是使用++或者-- 運算符的表達式,不過也可以使用其他任意值的,而且也可以省略,換到循環體中進行改變賦值。
for-in 循環for-in循環是JavaScript中專門提供用來遍歷對象屬性的。
var zs = { name: "zhang san", gender: "male", age: 26 }; for (var key in zs) { console.log("%s : %s", key, zs[key]); } // name : zhang san // gender : male // age : 26
不過需要注意一點問題,請看如下示例:
function Person(name, gender) { this.name = name; this.gender = gender; } Person.prototype.sayHello = function() { console.log("Hello,I am", this.name, ". I"m a", this.gender); }; var zs = new Person("zhang san", "male"); for (var key in zs) { console.log("%s : %s",key, zs[key]); } // name : zhang san // gender : male // sayHello : function () { // console.log("Hello,I am", this.name, ". I"m a", this.gender); // }
這次循環遍歷中,它還輸出了zs原型鏈上的屬性sayHello。這反應出一個問題,for - in 循環會遍歷整個原型鏈,雖然可以使用hasOwnProperty方法進行過濾僅獲取自身屬性,但其訪問的仍是整個原型鏈,遍歷范圍較廣,所以其效率比較低,通常來說,其效率僅為普通for循環的1/7。
在JavaScript中,由于數組也是對象,所以此方法也可以用來遍歷數組。
var arr = [1, 2, 3, 4]; for (var i in arr) { console.log(typeof i); if (arr.hasOwnProperty(i)) console.log("arr[%s] : %d", i, arr[i]); else console.log("arr.%s : ", i, arr.[i]); } // string // arr[0] : 1 // string // arr[1] : 2 // string // arr[2] : 3 // string // arr[3] : 4 // string // arr.where : function ... // string // arr.groupBy : function ... // string // arr.has : function ...
這個輸出的結果或許不是你想象的樣子,然而他就是這樣。我們認為的索引,實際是對象的鍵名,所以其是String類型。對于數組來說,和對象一樣,在其原型上擴展的方法where、groupBy、has也都被輸出了。 或許會有疑問,數組不是有length屬性嗎,為什么沒有輸出呢?原因在于數組的length屬性是不可枚舉屬性,for - in循環不會訪問這些屬性。關于此的更多知識可參考MDN - 屬性的可枚舉性和所有權
Array 在 Javascript 中是一個對象, Array 的索引是屬性名。事實上, Javascript 中的 “array” 有些誤導性, Javascript 中的 Array 并不像大部分其他語言的數組。首先, Javascript 中的 Array 在內存上并不連續,其次, Array 的索引并不是指偏移量。實際上, Array 的索引也不是 Number 類型,而是 String 類型的。我們可以正確使用如 arr[0] 的寫法的原因是語言可以自動將 Number 類型的 0 轉換成 String 類型的 "0" 。所以,在 Javascript 中從來就沒有 Array 的索引,而只有類似 "0" 、 "1" 等等的屬性。
for - in 循環原本就是用來遍歷對象的,用其來遍歷數組并不合適,不過也有例外的情況,比如稀疏數組:
var arr = new Array(1000); arr[0] = 1; arr[99] = 3; arr[999] = 5; // for循環 for (var i = 0, l = arr.length; i < l; i++) { console.log("arr[%s]", i, arr[i]); } console.log("i :" , i); // ... // arr[0] 1 // ... // arr[99] 3 // ... // arr[999] 5 // i : 1000 // for - in 循環 var count = 0; for(var j in arr){ count ++ ; if(arr.hasOwnProperty(j)){ console.log("arr[%s]", j, arr[j]); } } console.log("count : ", count); // arr[0] 1 // arr[99] 3 // arr[999] 5 // i : 1000
直接使用普通的for循環,循環次數為數組長度1000次,而使用for - in循環,僅僅循環了3次。
上面看起來循環的效率是高了不少,但是在前面已經說過了,for - in 的專職是對象的遍歷(類似的還有Object.keys()),因此上面的方案并非是一個完美的方案,更好的做法是用是數組本身的遍歷方法forEach(forEach為ES5中新增,需要IE9+)。
var arr = new Array(1000); arr[0] = 1; arr[99] = 3; arr[999] = 5; var count = 0; arr.forEach(function(value, index) { count++; console.log(typeof index); console.log(index, value); }); console.log("count", count); // number // 0 1 // number // 99 3 // number // 999 5 // count 3
這樣就高效地進行了循環遍歷,而且數組的索引index也被正確地識別為了number類型。
或許你會想到jQuery中提供的工具方法$.each()和$.map()或者實例jQuery對象的each和map方法,但是結果會讓你失望的,依舊會是循環1000次,以下是示例:
var count1 = 0; $.each(arr, function(index, value) { count1++; console.log(index, value); }); console.log("count1",count1); // count1 1000 var count2 = 0; $.map(arr,function(value,index){ count2++; console.log(index, value); }); console.log("count2",count2); // count2 1000
從上面對比來看Array.prototype.forEach方法似乎不錯,但其循環效率仍然不如普通的for循環,不過優勢在于在稀疏數組的處理。
不過forEach方法,嚴格來算并不算是循環,原因在于,它并不能響應循環應有的break和continue語句。準確地講,它是一個遍歷函數,對每個元素執行指定的回調函數。
for-of循環ES6中又新增了for - of 循環,它與for - in循環類似,但又有所不同。
for - of 支持對數組和類數組對象進行循環,不支持普通對象的循環。
for - of 支持對字符串進行循環遍歷。
for - of 支持對Map 和 Set (ES6 中新增的類型)對象遍歷。
for - of 不支持普通對象的循環遍歷。
// 數組 var arr = [0, 1, 2, 3, 4, 5]; for (let index of arr) { if (index === 1) continue; if (index === 4) break; console.log(typeof index); console.log(index, arr[index]); } // number // 0 0 // number // 2 2 // number // 3 3
當索引為1時直接進行下一次循環,而當索引為4時,直接退出循環,因此輸出如上結果,也同樣正確識別索引為number類型。
// 類數組 // 類數組 var divs = document.querySelectorAll("div"); for (let i of divs) { console.log(i.classList); } // ["container", "md-doc", value: "container md-doc"] // ["doc-cata", value: "doc-cata"] // ["nicescroll-rails", "nicescroll-rails-vr", value: "nicescroll-rails nicescroll-rails-vr"] // ["nicescroll-cursors", value: "nicescroll-cursors"] // ["nicescroll-rails", "nicescroll-rails-hr", value: "nicescroll-rails nicescroll-rails-hr"] // ["nicescroll-cursors", value: "nicescroll-cursors"] for (let k in divs) { console.log(k, divs[k].classList); } // "0" ["container", "md-doc", value: "container md-doc"] // "1" ["doc-cata", value: "doc-cata"] // "2" ["nicescroll-rails", "nicescroll-rails-vr", value: "nicescroll-rails nicescroll-rails-vr"] // "3" ["nicescroll-cursors", value: "nicescroll-cursors"] // "4" ["nicescroll-rails", "nicescroll-rails-hr", value: "nicescroll-rails nicescroll-rails-hr"] // "5" ["nicescroll-cursors", value: "nicescroll-cursors"] // length undefined // item undefined // keys undefined // values undefined // entries undefined // forEach undefined
在for - of循環用于類數組對象的處理時,需要注意,of關鍵字前面的變量即為類數組對象中的鍵值,如上例所示,在for - of循環中i即代表著DOM nodelist 中的每個對象,而在for - in 循環中k代表的僅僅是對象的鍵名。
參考鏈接深入了解 JavaScript 中的 for 循環
JavaScript while循環
JavaScript for循環
MDN - 屬性的可枚舉性和所有權
原文發表在我的博客JavaScript 循環,歡迎訪問!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/82174.html
摘要:主線程不斷重復上面的三步,此過程也就是常說的事件循環。所以主線程代碼執行時間過長,會阻塞事件循環的執行。參考資料這一次,徹底弄懂執行機制任務隊列的順序機制事件循環搞懂異步事件輪詢與中的事件循環 1. 說明 讀過本文章后,您能知道: JavaScript代碼在瀏覽器中的執行機制和事件循環 面試中經常遇到的代碼輸出順序問題 首先通過一段代碼來驗證你是否了解代碼輸出順序,如果你不知道輸出...
摘要:有兩個主要因素有助于改善循環性能每次迭代完成的工作和迭代次數。第一個是標準的循環,它與其他類語言的語法相同循環體這可能是最常用的循環結構。解析循環由四部分組成初始化,預測試條件,循環體和后執行。它將會不斷執行,直到返回所有屬性為止。 翻譯:瘋狂的技術宅https://medium.freecodecamp.o... 本文首發微信公眾號:前端先鋒歡迎關注,每天都給你推送新鮮的前端技術...
摘要:此事件隊列的美妙之處在于它只是函數等待被調用和移動到調用棧的一個臨時存放區域。在事件循環不斷監視調用棧是否為空現在確實是空的時候調用創建一個新的調用棧來執行代碼。在執行完之后進入了一個新的狀態這個狀態調用棧為空事件記錄表為空事件隊列也為空。 這篇文章是對個人認為講解 JavaScript 事件循環比較清楚的一篇英文文章的簡單翻譯,原文地址是http://altitudelabs.com...
摘要:總之,是用來循環帶有字符串的對象的方法。循環里引入了一種新的循環方法,它就是循環,它既比傳統的循環簡潔,同時彌補了和循環的短板。 forEach 循環 JavaScript誕生已經有20多年了,我們一直使用的用來循環一個數組的方法是這樣的: for (var index = 0; index < myArray.length; index++) { console.log(myAr...
摘要:概述本篇主要介紹的運行機制單線程事件循環結論先在中利用運行至完成和非阻塞完成單線程下異步任務的處理就是先處理主模塊主線程上的同步任務再處理異步任務異步任務使用事件循環機制完成調度涉及的內容有單線程事件循環同步執行異步執行定時器的事件循環開始 1.概述 本篇主要介紹JavaScript的運行機制:單線程事件循環(Event Loop). 結論先: 在JavaScript中, 利用運行至...
閱讀 2023·2021-10-09 09:41
閱讀 1600·2021-09-28 09:36
閱讀 1104·2021-09-26 09:55
閱讀 1293·2021-09-10 11:17
閱讀 1145·2021-09-02 09:56
閱讀 2762·2019-08-30 12:58
閱讀 2934·2019-08-29 13:03
閱讀 1855·2019-08-26 13:40