不同點:
時間點不同:for in 在js出現之初就有,for of出現在ES6之后
遍歷的內容不同:for in用于遍歷對象的可枚舉屬性(包括原型鏈上的可枚舉屬性),for of用于遍歷可迭代對象的值
看個例子
// for in
const arr = ['a','b','c','d']
for(const index in arr) {console.log(index)
}
// 打印結果:'0' '1' '2' '3',可以發現打印的是數組的下標,數組是特殊的對象,下標是數組對象身上的可枚舉屬性,打印的就是這個可枚舉屬性// for of
for(const item of arr) {console.log(item)
}
// 打印結果:'a' 'b' 'c' 'd',for of打印的就是數組里的每一項元素的值
可枚舉屬性
通過Object.getOwnPropertyDescriptor(obj, property),可以拿到屬性描述符
// 還是以數組為例,獲取數組的屬性'0'
console.log(Object.getOwnPropertyDescriptor(['a'],'0'))
/*** {* configurable: true,* enumerable: true,* value: "a",* writable: true* }*/
/* 可以看到返回了一個對象,這個對象就是屬性描述符,屬性描述符的屬性一般被稱為特性,可以看到,第二個特性enumerable就代表屬性是否可枚舉可枚舉的屬性就可以通過for in與Object.keys遍歷,數組身上有一個length屬性,但上面我們用for in 循環的時候并沒有打印length,說明length屬性是一個不可枚舉屬性,我們來看一下length屬性的屬性描述符:
*/
console.log(Object.getOwnPropertyDescriptor(['a'],'length'))
/*** {* configurable: false,* enumerable: false,* value: 1,* writable: true* }*/
// 可以看到數組身上的length屬性的屬性描述符里,enumerable為false,它是一個不可枚舉屬性,屬性描述符還有其他的特性,此處就不展開描述了,感興趣可以自行查閱
可迭代對象
實現了[Symbol.iterator]方法的對象,就被稱為可迭代對象
對象進行for…of循環時,會調用Symbol.iterator方法,返回該對象的默認遍歷器
ES6 規定,默認的 Iterator 接口部署在數據結構的Symbol.iterator屬性,或者說,一個數據結構只要具有Symbol.iterator屬性,就可以認為是“可遍歷的”(iterable)
鏈接: link
const obj = {[Symbol.iterator] : function () {return {next: function () {return {value: 1,done: true};}};}
};
上面的代碼中,對象obj是可遍歷的(iterable),因為具有Symbol.iterator屬性。執行這個屬性,會返回一個遍歷器對象。該對象的根本特征就是具有next方法。每次調用next方法,都會返回一個代表當前成員的信息對象,具有value和done兩個屬性
所以,對象只要實現了[Symbol.iterator]方法,就是可迭代的,即可使用for…of遍歷
原生具備 Iterator 接口的數據結構如下
Array
Map
Set
String
TypedArray
函數的 arguments 對象
NodeList 對象
案例:數組的Symbol.iterator屬性
let arr = ['a', 'b', 'c'];
let iter = arr[Symbol.iterator]();iter.next() // { value: 'a', done: false }
iter.next() // { value: 'b', done: false }
iter.next() // { value: 'c', done: false }
iter.next() // { value: undefined, done: true }
實現[Symbol.iterator]方法好麻煩,怎么這么復雜,于是有Generator 函數
Generator函數可以直接返回一個遍歷器對象
由于 Generator 函數就是遍歷器生成函數,因此可以把 Generator 賦值給對象的Symbol.iterator屬性,從而使得該對象具有 Iterator 接口
var myIterable = {};
myIterable[Symbol.iterator] = function* () {yield 1;yield 2;yield 3;
};[...myIterable] // [1, 2, 3]
for(const item of myIterable){console.log(item)} //1,2,3
上面代碼中,Generator 函數賦值給Symbol.iterator屬性,從而使得myIterable對象具有了 Iterator 接口,可以被…運算符和for…in遍歷了
async await,async await就是生成器函數的語法糖,配合promise,用生成器函數加yield也可以實現async await同樣的效果
參考:鏈接: link
鏈接: link