1.什么是Iterator ?
遍歷器(Iterator)它是一種介面,為各種不同的資料結構提供統一的訪問機制,任何資料結構只要部署 Iterator 介面,就可以完成遍歷操作,
Iterator 的作用有三個:
1.是為各種資料結構,提供一個統一的、簡便的訪問介面;
2.是使得資料結構的成員能夠按某種次序排列;
3.是 ES6 創造了一種新的遍歷命令for...of回圈,Iterator 介面主要供for...of消費,
2.Iterator怎么用 ?
for...of陳述句在可迭代物件(包括 Array,Map,Set,String,TypedArray,arguments 物件等等)上創建一個迭代回圈,呼叫自定義迭代鉤子,并為每個不同屬性的值執行陳述句
/**
* 語法
* @variable 每次迭代中屬性的值
* @iterable 被迭代列舉其屬性的物件
*/
for (variable of iterable) {
//statements
}
const array1 = ['a', 'b', 'c']; for (const element of array1) { console.log(element); } // a // b // c
接下來一起來實踐一下上面那些型別是不是真的可以用
// Array let arr = [10, 20, 30]; for (let value of arr) { value += 1; console.log(value); } // 11 // 21 // 31 // Map let map = new Map([["a", 1], ["b", 2], ["c", 3]]); for (let entry of map) { console.log(entry); } // ["a", 1] // ["b", 2] // ["c", 3] // Set let set = new Set([1, 1, 2, 2, 3, 3]); for (let value of set) { console.log(value); } // 1 // 2 // 3 // String let str = "boo"; for (let value of str) { console.log(value); } // "b" // "o" // "o" // TypedArray let typedArr = new Uint8Array([0x00, 0xff]); for (let value of typedArr) { console.log(value); } // 0 // 255 // arguments (function() { for (let argument of arguments) { console.log(argument); } })(1, 2, 3); // 1 // 2 // 3View Code
那其他的型別用for of會怎么樣?
比如一個普通的object型別

產品:“那我就要把for of用在物件上”
我:“物件不能用for of,你看這不都報錯了嘛”
產品:“不聽不聽,你是不是不想做”
我:“好吧好吧,既然你想要用,那就滿足你”
首先要了解遍歷器 Iterator 的協議,傳送門:MDN 迭代協議,
簡而言之就是:
迭代協議具體分為兩個協議:可迭代協議和迭代器協議,
可迭代協議:
可迭代協議允許 JavaScript 物件定義或定制它們的迭代行為,例如,在一個 for..of 結構中,哪些值可以被遍歷到,一些內置型別同時是內置可迭代物件,并且有默認的迭代行為,比如 Array 或者 Map,而其他內置型別則不是(比如 Object)),
要成為可迭代物件, 一個物件必須實作 @@iterator 方法,這意味著物件(或者它原型鏈上的某個物件)必須有一個鍵為 @@iterator 的屬性,可通過常量 Symbol.iterator 訪問該屬性:
迭代器協議:
迭代器協議定義了產生一系列值(無論是有限個還是無限個)的標準方式,當值為有限個時,所有的值都被迭代完畢后,則會回傳一個默認回傳值,
只有實作了一個擁有以下語意(semantic)的 next() 方法,一個物件才能成為迭代器:
var obj = {
data: [1,2,3],
[Symbol.iterator]() {
var nextIndex = 0, self = this;
return {
next() {
var done = nextIndex >= self.data.length;
var value = https://www.cnblogs.com/jandr/p/done ? undefined : self.data[nextIndex++]
return { value: value, done: done }
}
}
}
}
for (const item of obj) { console.log(item) }
// 1
// 2
// 3
由此可見,普通物件不可直接使用for of,在[Symbol.iterator]屬性上部署遍歷器生成的方法后即可被for of使用(原型鏈上的物件具有該方法也可)
實際上,物件之所以沒有默認部署 Iterator 介面,是因為物件的哪個屬性先遍歷,哪個屬性后遍歷是不確定的,需要開發者手動指定,
那知道了上面遍歷器的協議,我們可以通過更簡單的方式判定上述六種型別是否實作了遍歷器介面了
Array.prototype.hasOwnProperty(Symbol.iterator); // true Set.prototype.hasOwnProperty(Symbol.iterator); // true Map.prototype.hasOwnProperty(Symbol.iterator); // true String.prototype.hasOwnProperty(Symbol.iterator); // true (function(){ console.log(arguments.hasOwnProperty(Symbol.iterator)) })(1,2,3) // true Uint8Array.prototype.__proto__.hasOwnProperty(Symbol.iterator) // true
3. 與for in的區別
可能看到for of 有人想到for in,那這兩個長這么像,他兩有啥區別呢,咱們一起來看看
var arr1 = ['a', 'b', 'c', 'd']; // 輸出鍵名 for (let a in arr1) { console.log(a); // 0 1 2 3 }
// 輸出鍵值 for (let a of arr1) { console.log(a); // a b c d }
// 注意:還有個細節
// for...of回圈呼叫遍歷器介面,陣列的遍歷器介面只回傳具有數字索引的屬性,這一點跟for...in回圈也不一樣,
let arr2 = [3, 5, 7];
arr2.foo = 'hello';
for (let i in arr2) {
console.log(i); // "0", "1", "2", "foo"
}
for (let i of arr2) {
console.log(i); // "3", "5", "7"
}
4. 與其他回圈的區別
var arr = Array(10).fill(1);
// for i 回圈法,不夠簡潔
for (var i = 0; i < arr.length; i++) {
console.log(arr[i])
}
// forEach 回圈,不能手動跳出回圈
arr.forEach(function (value) {
console.log(value);
})
// for i 回圈獲取的是鍵名,而不是鍵值,因此不大適用于遍歷陣列
for (var i in arr) {
console.log(i)
}
// for of 可以跳出回圈,語法簡潔
for (var i of arr) {
console.log(i)
}
經比較,遍歷物件用for in, 遍歷陣列用for of
實際上,要實作物件的Iterator介面還有更簡潔的方法,就是使用generator
let obj = { * [Symbol.iterator]() { yield 'hello'; yield 'world'; } }; for (let x of obj) { console.log(x); } // hello // world
看到這里有人又奇怪了,這個 * 號是個什么鬼?
答案是 Generator 函式,Generator 函式是一個普通函式,但是有兩個特征,一是,function關鍵字與函式名之間有一個星號;二是,函式體內部使用yield運算式,定義不同的內部狀態(yield在英語里的意思就是“產出”),
詳情請戳這里
2020-06-09 11:23:51
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/72109.html
標籤:JavaScript
上一篇:Vue專案如何部署?實戰教你
