JavaScript 循環

JavaScript中直接提供的循環,主要有如下幾種javascript

while 循環

和其餘語言同樣,JavaScript中的while循環有兩種形式:java

while (condition) {
    // 循環內容
}

do {
    // 循環內容
} while (condition)

其中兩種形式的不一樣在於,對condition判斷的位置不一樣,前者先判斷,再執行循環體;然後者先執行循環體一次,再進行條件判斷。因此結果的不一樣就是後者能將循環內容至少執行一次。node

for 循環

for循環的語法:數組

for (init; condition; step) {
    // 循環體代碼塊
}
  • init 語句 中的內容,會在循環代碼開始前執行一次,一般用來聲明一些變量。函數

  • condition 語句 會在每次循環開始時,進行判斷。若是第一次就不知足,則不會進入循環。工具

  • step 語句 會在每次循環結束時執行,一般是遞增或遞減condition中的某個變量。oop

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循環所示。post

for循環的條件語句是在每次循環體開始前進行判斷,若是爲true,則執行循環體內容,不然結束循環。當此語句省略時,表示不進行條件判斷,循環將一直執行,只有在循環中使用break來跳出循環。this

for循環的step語句,最多見的就是使用++或者-- 運算符的表達式,不過也可使用其餘任意值的,並且也能夠省略,換到循環體中進行改變賦值。prototype

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類型。對於數組來講,和對象同樣,在其原型上擴展的方法wheregroupByhas也都被輸出了。 或許會有疑問,數組不是有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(forEachES5中新增,須要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對象的eachmap方法,可是結果會讓你失望的,依舊會是循環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方法,嚴格來算並不算是循環,緣由在於,它並不能響應循環應有的breakcontinue語句。準確地講,它是一個遍歷函數,對每一個元素執行指定的回調函數。

for-of循環

ES6中又新增了for - of 循環,它與for - in循環相似,但又有所不一樣。

  • for - of 支持對數組類數組對象進行循環,不支持普通對象的循環。

  • for - of 支持對字符串進行循環遍歷。

  • for - of 支持對MapSet (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 循環,歡迎訪問!

相關文章
相關標籤/搜索