js中數組的遍歷方式
for
for 循環遍歷是最普通的一種方式,通過數組中自帶的索引進行數組元素的獲取,這種方式可以支持 break、continue、return的打斷形式。具體如下:
for (var i = 0; i < arr.length; i++) {
// 通過索引進行數組元素的獲取
console.log(arr[i])
if (i === 3) {
// 可以使用break跳出當前循環 效果跟 return 一樣
break
// return
} else if (i === 2) {
// 可以使用continue跳過當次循環
continue
}
}
forEach
forEach是一個方法,這個方法是在 Array 類的 prototype 上,所以所有的Array的實例上都有這個方法。forEach方法沒有返回值,參數有兩個。形式為:arr.forEach(callbackFn[, thisValue]),其中 callbackFn 是個函數,這個函數有三個參數,可以分別記為 item、index、array,見名知意:第一個參數 item 表示的是被遍歷的數組每一項,index 表示的是當前被遍歷項的數組下標,array 表示的是被遍歷的數組對象,此處即為arr。callbackFn 是必傳參數。forEach函數還有一個可傳參數 thisValue,這個參數是一個對象,作用是在 callbackFn 函數中this的引用。如果不傳 thisValue,則默認值為 undefined。
注意點:
- forEach不能被break、continue、return打斷;
- 如果callbackFn是箭頭函數,則傳入的 thisValue 不起作用,因為箭頭函數綁定的this是模塊this
var arr1 = [1, 2, 3]
var arr2 = ['a', 'b', 'c']
arr1.forEach(function(item, index, array) {
// 這個函數內的this指向arr2
// item 是arr1數組中的每一項
// index 是arr1數組的索引值,Number類型
}, arr2)
for in
for in 不僅遍歷數組還可以遍歷對象(當然,數組也是一種特殊的對象),for in 有如下的特點:
- 跟 forEach 一樣不能被break、continue、return打斷;
- 可以遍歷對象的屬性;
- 遍歷的對象屬性包含構造函數的
prototype上添加的屬性和當前實例上添加的屬性(可以通過Object.prototype.hasOwnProperty方法進行區分是不是當前實例的屬性)
具體以實例說明如下:
典型使用方式
var arr = [1, 2, 3, 4]
for (var attr in arr) {
// 數組索引
console.log(attr) // 輸出的結果為 0, 1, 2, 3
// 數組value
console.log(arr[attr]) // 輸出的結果為 1, 2, 3, 4
}
遍歷Array.prototype 上添加的屬性
Array.prototype.addProperty = 'myadd'
var arr = [1, 2, 3, 4]
for (var attr in arr) {
console.log(attr) // 輸出的結果為 0, 1, 2, 3, addProperty
}
遍歷實例上添加的屬性
var arr = [1, 2, 3, 4]
arr.instanceProperty = 'myadd'
for (var attr in arr) {
console.log(attr) // 輸出結果為 0, 1, 2, 3, instanceProperty
}
通過 hasOwnProperty 進行屬性的區分
Array.prototype.addProperty = 'add'
var arr = [1, 2, 3, 4]
arr.instanceProperty = 'myadd'
for (var attr in arr) {
if (arr.hasOwnProperty(attr)) {
console.log(attr) // 輸出結果為 0, 1, 2, 3, instanceProperty
}
console.log(attr) // 輸出結果為 0, 1, 2, 3, instanceProperty, addProperty
}
for of
for of 是 es6中新增的語句,用於遍歷迭代器,也就是說只要實現了iterator接口的實例都能被for of所迭代。在js對象中實現了iterator接口的有:String、Array、Map、Set、Generator、通過計算生成的entries|keys|values、類數組對象arguments|DOMList,由於Object沒有實現iterator接口,所以不能通過for of進行迭代。數組的迭代器方法可以通過Array.prototype[Symbol.iterator]找到。for of有如下特點:
- 跟for循環一樣可以被break、continue、return打斷;
- 不能遍歷到Array原型上的屬性;
- 不能遍歷到數組實例上添加的屬性;
- for of 只能遍歷到數組的value,而不能得到數組的索引
具體實例說明如下:
典型用法
var arr = [1, 2, 3, 4]
// arr 上添加屬性
arr.addProperty = 'add'
// Array.prototype 上添加屬性
Array.prototype.addPro = 'test'
for(var attr of arr) {
if (attr === 3) {
continue
}
console.log(attr) // 輸出結果:1, 2, 4
// 不能遍歷到addProperty、addPro
}
map
map的用法跟forEach非常的類似,跟forEach一樣都是 Array.ptototype 上的方法,通過原型鏈,所有的Array實例都可以訪問到map方法。map方法的參數跟forEach一樣,一個回調函數和一個this對象:arr.map(callbackFn[, thisValue]),並且callbackFn的參數跟forEach中的callbackFn中的參數也是一樣的。map跟forEach的區別在於,map是有返回值的,返回值是一個新的數組實例。map方法的目標並不是用來對原數組進行遍歷,而是在原數組的基礎上進行一些變換從而得到一個新的數組。這些變換並不會影響到原數組。下面看一下map方法的典型用法:
var arr = [1, 2, 3, 4]
// map 方法有返回值,返回值是一個新的數組
var arr2 = arr.map(function(curValue, index, ar) {
// callbackFn 也需要返回值,返回值會成為新數組的子項。與原數組一一對應
return curValue * 2
})
console.log(arr)
// 輸出結果為:[1, 2, 3, 4]
console.log(arr2)
// 輸出結果為:[2, 4, 6, 8]
forEach和map的 callbackFn中雖然可以得到被遍歷數組的每一項,但是我們如果要改變原數組需要使用一點手段。callbackFn方法的參數傳入同普通方法的參數一樣,都是將數據的引用傳入到了函數中。所以我們如果直接更改參數的引用的話,我們將不能變更原數組的內容。如下例所示:
var arr = [1, 2, 3, 4]
arr.map(function(curVal, index, ar) {
curVal *= 2
})
console.log(arr) // 輸出結果 1, 2, 3, 4
上面的做法並不能改變原數組,因為curVal是一個引用,我們在callbackFn中將curVal的引用重新進行了賦值,引用的指向改變了。所以arr中對應的值並不會發生改變,因為arr中對應的值的引用與curVal的引用指向已經不一樣了。我們把實例改一下:
var arr = [
{value: 1},
{value: 2},
{value: 3},
{value: 4}
]
arr.map(function(curVal, index, ar) {
curVal.value *= 2
})
console.log(arr) // 輸出結果為:[{value: 2}, {value: 4}, {value: 6}, {value: 8}]
這里我們將 curVal.value 的引用重新指向,但是curVal的指向並沒有被修改,也就是說 curVal 的引用指向還是跟 arr 中對應項的引用指向保持一致,所以最終輸出的結果會發生變化。還有一種做法,我們利用第二個和第三個參數來修改原來的數組:
var arr = [1, 2, 3, 4]
arr.map(function(curVal, index, ar) {
ar[index] *= 2
})
console.log(arr) // 輸出的結果為:2, 4, 6, 8
forEach 的效果同map
every
every 類似 forEach和map,都是 Array.prototype上的方法,該方法的返回值是boolean,callbackFn的返回值也是一個boolean,如果為true則繼續遍歷,直到返回值為false或者到達數組邊界結束遍歷。every方法常用來判斷當前數組中所有項是否滿足指定條件。
var arr = [1, 2, 3, 4, 5]
var b1 = arr.every(function(curVal) {
return curVal < 10
})
var b2 = arr.every(function(curVal) {
return curVal < 4
})
console.log(b1) // 結果為 true
console.log(b2) // 結果為 false
iterator
iterator 是一個方法,Array 構造函數的原型上通過 Symbol.iterator 指向這個方法。該方法執行的到結果是一個 Iterator 對象,通過 Object.prototype.toString.call(arr[Symbol.iterator]) 得到的結果是 "object Array Iterator"。所有的 數組實例都可以直接通過 Symbol.iterator 獲得 iterator 方法。我們可以通過 iterator 進行數組的遍歷。具體代碼如下:
var arr = [1, 2, 3, 4]
var it = arr[Symbol.iterator]()
var item = null
while(!(item = it.next()).done) {
console.log(item.value) // 結果: 1, 2, 3, 4
}
除了通過next方法進行遍歷之外,我們還能使用 for of 來遍歷iterator
var arr = [1, 2, 3, 4]
var it = arr[Symbol.iterator]()
for (var attr of it) {
console.log(attr) // 結果:1, 2, 3, 4
}
關於iterator的詳細內容參見 Iterator 和 阮老師博客
keys、values、entries
這三個方法是 es6 中新增的,返回值是一個 iterator。得到 iterator 之后就可以使用 iterator 的遍歷方式進行遍歷。三個方法略有區別:
keys:通過keys方法得到的iterator可以遍歷數組的索引值
var arr = [1, 2, 3, 4]
var keys = arr.keys()
for (var attr of keys) {
// 輸出的是數組的索引值
console.log(attr) // 結果:0, 1, 2, 3
}
values:通過values方法得到iterator,可以遍歷到一個對象,對象的形式為:
{value: 1}。鍵為固定的value,值是對應的數組值。
var arr = [1, 2, 3, 4]
var values = arr.values()
for (var attr of values) {
// 輸出的是數組的索引值
console.log(attr) // 結果:{value: 1}, {value: 2}, {value: 3}, {value: 4}
}
// 通過結構的方式
for (var { value } of values) {
// 輸出的是數組的索引值
console.log(value) // 結果:1, 2, 3, 4
}
entries:通過values方法得到iterator,可以遍歷到一個數組,數組的形式為:
[index, value]。數組的第一項是被遍歷數組的索引,數組的第二項是被遍歷數組的值。
for (var attr of [1, 2, 3, 4].entries()) {
console.log(attr) // 結果為:[0, 1], [1, 2], [2, 3], [3, 4]
}
// 通過解構的方式進行遍歷
for (var [index, value] of [1, 2, 3, 4].entries()){
console.log(index) // 結果為 0, 1, 2, 3
console.log(value) // 結果為 1, 2, 3, 4
}
(完)
