本文章記錄本人在深刻學習js
循環中看書理解到的一些東西,加深記憶和而且整理記錄下來,方便以後的複習。html
在大部分編程語言中,代碼執行的時間多數消耗在循環的執行上。算法
js
定義了4種類型的循環:for, while, do while, for in
。編程
for
循環是最經常使用的循環結構,它由四個部分組成:segmentfault
當遇到一個for
循環的時候,初始化體首先執行,而後進入前測條件。若是前測條件的計算爲true
,就會執行循環體,而後運行後執行條件。數組
Javascriptfor (var i = 0; i < 10; i++) { // 循環體 };
while
循環是一個簡單的前測循環,由一個前測條件和一個循環體構成。在執行循環體以前,先對前測條件進行計算。若是爲true
就執行循環體。不然就會跳過循環體。瀏覽器
Javascriptvar i = 1; while (i < 10) { // 循環體 i ++; };
do while
循環是js
中惟一的一種後測試的循環,它包括兩個部分:循環體和後側條件。記住:在一個do while
循環中,循環體至少會運行一次,後測條件決定循環體是否再次運行。編程語言
Javascriptvar i = 1; do { // 循環體 } while (i++ < 10)
for in
循環有一個很是特殊的用途:能夠枚舉任何對象的命名函數屬性。函數
Javascriptfor (var attr in object) { // 循環體 };
每一次循環,屬性都會被對象的屬性的名字(一個字符串)填充,直到全部的對象屬性遍歷完纔會返回。返回的屬性包括對象的使實例屬性和對象從原型鏈基礎來的屬性。性能
想要提升循環性能,第一步選用哪一種循環。在這四個循環裏面,for in
循環執行的速度都比其餘三個循環要慢。學習
大部分狀況下咱們都不會採用for in
循環,可是其餘的循環類型性能都至關,難以肯定哪一種循環執行速度更快。選擇循環類型應該基於需求而不是性能。
能夠經過設計for
和while
循環來完成特定動做的重複性操做。從3個目標來分析如何正確的選用for
和while
循環。
語義角度比較
for
和while
循環能夠按照下面的模式來進行互相的轉換。
Javascriptfor (initialization; test; increment) // 聲明而且初始化循環變量,循環條件,遞增循環變量 statements // 可執行的循環語句
至關於:
Javascriptinitialization // 聲明而且初始化循環變量 while (test) { // 循環條件 statements // 可執行的循環語句 increment // 遞增循環變量 }
for
循環是以循環變量的變化來控制循環進程的,即for
循環流程是預先計劃好的,雖然中途可能會因存在異常狀況或特別狀況而退出循環,可是循環的規律是有章可循的。這樣的話就方便預知循環的次數和每次循環的狀態信息等等。
while
循環根據特定條件來決定循環操做,因爲條件是動態的,沒法預知條件幾時是true
或者false
,所以該循環操做就具備很大的不肯定性,每一次循環時都不知道下一次循環狀態如何,只能經過條件的變化來肯定。
因此for
循環一般用於有規律的重複操做中。while
循環一般用於特定條件的重複操做,以及依據特定事件控制的循環等操做。
思惟模式角度比較
for
循環和while
循環在思惟模式上也存在差別。
for
循環中,將循環的三個要素(起始值、終止值和步長)定義爲3個基本表達式做爲結構語法的一部分固定在for
語句裏面,使用小括號;
進行語法分隔,這樣有利於js
的進行快速預編譯。
在閱讀到for
循環結構的第一行代碼的時候,就可以獲取到整個循環結構的控制方式,而後再根據上面的表達式來決定是否執行循環體內的語句。
Javascriptfor (var i = 0; i < 10; i++) { alert(i); };
能夠按照下面的邏輯思惟進行總結:
1 < i < 10
、步長爲i++
。alert(i);
。這種把循環操做的環境條件和循環操做語句分離開的設計可以提升程序的執行效率,同時可以避免由於把循環條件與循環語句混合在一塊兒而形成的錯誤。
在for
循環的特異性致使在執行復雜的條件時效率會大大的下降。相對而言,while
循環就比較適合運http://naotu.baidu.com/viewshare.html?shareId=auuohz8fwm8k的條件,它將複雜的循環控制放在循環體內執行,而while
語句自身僅用於測試循環條件,這樣就避免告終構的分隔和邏輯的跳躍。
Javascriptvar a = true, b = 1; while (a) { // 在循環體內間接計算迭代 if (9 < b) { a = false; } alert(b); b++; }
從達到目標的角度比較
有一些循環的循環次數在循環以前就能夠先預測,如計算1到100的數字和。而有一些循環具備不可預測性們沒法事前肯定循環的次數,甚至沒法預知循環操做的趨向,這些構成了在設計循環結構時候必須考慮的達成目標須要解決的問題,即便是相同的操做,若是達到的目標的角度不一樣,可能重複了操做的設計也就不一樣。
許多複雜的算法都是經過比較容易實現的遞歸實現。如階乘函數。
Javascriptfunction factorial(n) { if (0 === n) { return 1; } else { return n * factorial(n - 1); } };
遞歸函數的問題:錯誤定義或者缺乏終結條件會致使函數運行時間過長,使瀏覽器出現假死現象。遞歸函數還會受到瀏覽器調用棧的大小的限制。
在ES6中js
擁有了尾遞歸優化,詳情請看迎接ECMAScript 6, 使用尾遞歸
能夠經過遞歸函數實現的算法均可以經過迭代來實現。迭代算法一般包括幾個不一樣的循環,分別對應算法過程當中的不一樣方面。雖然迭代也會致使性能問題,可是使用優化的循環就能夠代替長時間運行的遞歸函數,能夠提升新能,由於運行一個循環比反覆調用一個函數的開銷要小。
使用迭代來實現合併排序算法:
Javascriptfunction merge(left, right) { var result = []; while (left.length > 0 && right.length > 0) { if (left[0] < right[0]) { result.push(left.shift()); } else { result.push(right.shift()); } } return result.concat(left).concat(right); }; function mergeSort(items) { if (items.length === 1) { return items; } var work = []; for (var i = 0, len = items.length; i < len; i++) { work.push(items[i]); }; work.push([]); for (var lim = len; lim > 1; lim = (lim + 1) / 2) { for (var j = 0, k = 0; k < lim; j++, k += 2) { work[j] = merge(work[k], work[k + 1]); } work[j] = []; }; return work[0]; };
循環結構是最浪費資源的一種流程。循環結構中的一點小的損耗都會被放大,從而影響程序運行的效率。
優化結構
循環結構經常是與分支結構混合在一塊兒,因此如何嵌套也就很是的講究。例如,設計一個循環結構,結構內的循環語句只有在特定的條件下才被執行,
Javascriptvar a = true; for (var i = 0; i < 10; i++) { if (a) {} //條件判斷 };
在這個循環裏面,if
語句會被反覆的運行,若是這個if
語句是一個固定的條件檢測表達式,若是if
的條件不會受到循環結構的影響,那麼用下面這種結構設計會更加複合:
Javascriptif (a) { for (var i = 0; i < 10; i++) { }; }
可是if
條件表達式受循環結構的制約,那就不能使用這種結構嵌套了。
避免沒必要要的重複操做
在循環裏面常常會存在一些沒必要要的損耗。下面一個例子:
Javascriptfor (var i = 0; i < 10; i++) { var a= [1,2,3,4,5,6,7,8,9,10]; alert(a[i]); };
在這個循環裏面,每循環一次就會在定義一個新的數組,很明顯這是一個重複的操做,把數組放到循環體外面會更加的高效:
Javascriptvar a= [1,2,3,4,5,6,7,8,9,10]; for (var i = 0; i < 10; i++) { alert(a[i]); };
妥善定義循環變量
對於for
循環來講,它主要利用循環變量來控制整個結構的運行。當循環變量僅用於結構內部的時候,不妨在for
語句外面定義循環的變量,這樣也能夠優化循環結構。
最後,若是文章有什麼錯誤和疑問的地方,請指出。與sf各位共勉!