JS 中的 for-in 和 of-of
for-in
for-in可遍历任何值,但常用于遍历对象。在遍历对象(起名A)时,我们可以获取到A自身的可枚举属性的key和A原型链上的可枚举属性的key,但如果A自身和原型链上的可枚举属性的key为Symbol时,无法被遍历到:
代码演示:
Object.prototype.extra = "haha";
const c = Symbol("c");
const obj = {
a: "hi",
b: Symbol("c"),
[c]: 'ha' // 可不要把 [c] 写成 c了,前者表示变量c的值,后者表示字符c
};
for(let i in obj) {
console.log(i);// a b extra
}
// 遍历null不会报错,但也不会执行花括号内容,因为没啥可遍历的
for(let i in null) {
console.log(i);
}
由于for-in会遍历到原型链上的内容,如果仅想遍历自身,则应使用hasOwnProperty(key)
进行判断,该方法会判断key是否为调用者自身的属性:
Object.prototype.extra = "haha";
const obj = {a: "hi"};
for (let i in obj) {
if (obj.hasOwnProperty(i))
console.log(i);// a
}
for-of
for-of只能用于iterable objects的遍历(比如数组、字符串、类数组等),如果遍历非iterable对象是会报错的。在遍历中我们可以获取到被遍历者的value。
const arr = ["a", "b", "c"];
for(let i of arr) {
console.log(i); // a b c
}
try {
const obj = {};
for(let i of obj) {}
} catch(e) {
console.log(e) // TypeError: obj is not iterable
}
如果想要在遍历数组时获取到索引值,可以借助数组的entries()
方法,该方法返回一个数组迭代器:
const arr = ["a", "b", "c"];
for(const [i, v] of arr.entries()) {
console.log(`${i}-${v}`); // 0-a 1-b 2-c
}
除了内置提供的可迭代对象,我们还可以通过实现iterable protocol和iterator protocol来定义自己的iterable object,其中iterable protocol用来让对象可以被用于for-of,iterator protocol则是来定义遍历时的value具体如何变化:
const obj ={};
obj[Symbol.iterator] = function() {
let val = 0;
return {
next:function() { // 必须要返回一个名为next的函数
if (val === 3)
return { // next函数的返回值必须是一个含有done属性的对象,value属性则表明遍历时获取的key值
done:true,
value:val
}
return {
done: false,
value: val++
}
}
}
}
for(let val of obj) {
console.log(val); // 0 1 2
}
for-await-of
for-await-of可用于遍历异步可迭代对象。这是ES2018中引入的,兼容性可能稍差一些。具体内容可点击蓝字查看,因为俺还没咋用过嘞。