ES6-遍歷陣列
陣列是一種很重要的資料結構。那麼我們如何遍歷陣列呢?
我們如何遍歷陣列中的元素?20年前JavaScript剛萌生時,你可能這樣實現陣列遍歷:
for (var index = 0; index < myArray.length; index++) {
console.log(myArray[index]);
}
自ES5正式釋出後,你可以使用內建的forEach方法來遍歷陣列:
myArray.forEach(function (value,index) {
console.log(index+":"+value);
});
這段程式碼看起來更加簡潔,但這種方法也有一個小缺陷:你不能使用break語句中斷迴圈,也不能使用return語句返回到外層函式。另外,forEach方法是Array物件的方法,所以對於DOM的類陣列,如NodeList物件,則不能遍歷。
當然,如果只用for迴圈的語法來遍歷陣列元素也很不錯。
那麼,你一定想嘗試一下for-in迴圈:
for (var index in myArray) { // 千萬別這樣做
console.log(myArray[index]);
}
這絕對是一個糟糕的選擇,為什麼呢?
- 在這段程式碼中,賦給index的值不是實際的數字,而是字串“0”、“1”、“2”,此時很可能在無意之間進行字串算數計算,例如:“2” + 1 == “21”,這給編碼過程帶來極大的不便。
- 作用於陣列的for-in迴圈體除了遍歷陣列元素外,還會遍歷自定義屬性。舉個例子,如果你的陣列中有一個可列舉屬性myArray.name,迴圈將額外執行一次,遍歷到名為“name”的索引。就連陣列原型鏈上的屬性都能被訪問到。
- 最讓人震驚的是,在某些情況下,這段程式碼可能按照隨機順序遍歷陣列元素
- 簡而言之,for-in是為普通物件設計的,你可以遍歷得到字串型別的鍵,因此不適用於陣列遍歷
強大的for-of迴圈
每個具有遍歷器方法的物件都稱為”可遍歷”物件。
for of遍歷一種資料集合時,首先會尋找這個集合是否有遍歷器方法,沒有就丟擲錯誤,有就呼叫這個方法。遍歷器方法返回一個遍歷物件,遍歷物件的根本特徵就是具有next方法。每次呼叫next方法,都會返回一個代表當前成員的資訊物件,具有value和done兩個屬性。
for of就是不斷呼叫next方法來遍歷的
ES6規定,遍歷器方法儲存在物件的[Symbol.iterator]屬性中(這個屬性的名字是內建的Symbol值,防止重名)
let obj = {
a:1,
b:2
};
console.log(obj[Symbol.iterator]); //undefined
for(let x of obj){
console.log(x);
}
// Uncaught TypeError: obj is not iterable
物件沒有預設的iterator介面([Symbol.iterator]),所以用for of遍歷時就丟擲了錯誤。
我們來給這個物件定義一個[Symbol.iterator]屬性。
obj[Symbol.iterator]=function(){
return {
next: function(){
return { value:1, done:false }
}
};
}
for(let x of obj){
console.log(x);
}
有了遍歷器方法後,for of就能遍歷這個物件了,不過done屬性為false,這個遍歷就永遠不會結束,它會一直列印1。
物件(Object)之所以沒有預設部署Iterator介面,是因為物件的哪個屬性先遍歷,哪個屬性後遍歷是不確定的,需要開發者手動指定。本質上,遍歷器是一種線性處理,對於任何非線性的資料結構,部署遍歷器介面,就等於部署一種線性轉換。不過,嚴格地說,物件部署遍歷器介面並不是很必要,因為這時物件實際上被當作Map結構使用,ES5沒有Map結構,而ES6原生提供了。
具有[Symbol.iterator]屬性的物件有:陣列、某些類似陣列的物件、Set和Map結構。我們可以自己定義物件的[Symbol.iterator]屬性來覆蓋預設的[Symbol.iterator]屬性
let arr=[1,2,3];
arr[Symbol.iterator]=function(){
let index=0;
return {
next:function(){
if(index<arr.length){
index++;
return {
value:1,
done:false
}
}else{
return {
value:"遍歷結束",
done:true
}
}
}
}
};
//模擬for of迴圈
let iterator = arr[Symbol.iterator]();
iterator.next(); // {value: 1, done: false}
iterator.next(); // {value: 1, done: false}
iterator.next(); // {value: 1, done: false}
iterator.next(); // {value: "遍歷結束", done: true}
for(let x of arr){
console.log(x); // 1 1 1
}
ES6陣列遍歷方法
ES6給陣列原型添加了幾種新的遍歷陣列方法:Array.prototype.entries() Array.prototype.keys()和Array.prototype.values()(瀏覽器支援不好)
for…of迴圈內部呼叫的是資料結構的Symbol.iterator方法來遍歷。
Array.prototype.entries() Array.prototype.keys()和Array.prototype.values()這些方法返回一個新的Symbol.iterator方法,for of內部呼叫的就是新迭代物件
Array.prototype.entries()
作用:遍歷陣列的鍵值對
引數:無
返回值:返回一個新的Array Iterator物件,該物件包含陣列中每個索引的鍵/值對
var arr = ["a", "b", "c"];
var iterator = arr.entries();
console.log(iterator); // Array Iterator {}
console.log(iterator.next()); // {value: [0, "a"], done:false}
console.log(iterator.next()); // {value: [0, "a"], done:false}
console.log(iterator.next()); // {value: [0, "a"], done:false}
var iterator2 = arr.keys();
console.log(iterator); // Array Iterator {}
console.log(iterator.next()); // {value: 0, done: false}
console.log(iterator.next()); // {value: 1, done: false}
console.log(iterator.next()); // {value: 2, done: false}
//陣列預設的遍歷器物件
for(let x of arr[Symbol.iterator]()){
console.log(x);
}
// for of呼叫arr.keys()返回的遍歷物件
for(let x of arr.keys()){
console.log(x);
}
// for of呼叫arr.entries()返回的遍歷物件
for(let [index,value] of arr.entries()){
console.log(index,value);
}
console.log(arr.keys()===arr.entries()); //false
arr.entries()返回新的遍歷物件,它包含了陣列每個索引的鍵值對
arr.keys()返回新的遍歷物件,它包含陣列中每個索引的鍵
擴充套件運算子(…)也可以將某些資料結構轉為陣列。
[...[1,2,3]] //[1,2,3]
[...document.querySelectorAll('div')] // NodeList物件轉換為Array例項
擴充套件運算子背後呼叫的是遍歷器介面(Symbol.iterator),如果一個物件沒有部署這個介面,就無法轉換。擴充套件運算子呼叫物件的遍歷器方法,進行遍歷。
let arr2=['a','b','c'];
var iterator=arr2.entries();
console.log([...iterator]);
圖片