一、两者区别
-
for in 主要用来取key值,for of 主要用来取value值
-
for in 可以遍历数组和对象,for of 可以遍历数组、字符串、Map( )、Set( )......所有内置迭代器的类型
-
使用for in 遍历对象的属性时,原型链上所有属性都被遍历到,如果只想遍历自身属性,可以用
hasOwnProperty()方法过滤
二、for in 使用
Object.prototype.say = "19"; // 修改 Object.prototype
var person = { age: 18 };
for (var key in person) {
if (person.hasOwnProperty(key)) {
// hasOwnProperty 判断其是否为自身属性
console.log(key, person[key]);
// 这里用 person.key 得不到对象key的值,用person[key] 或者 eval("person."+key);
}
}
//输出
//age 18
三、for of 获取 index 值
entries() 方法返回一个数组的迭代对象,该对象包含数组的键值对 (key/value)。
let list = ['a','b','c']
for (const [index, item] of list.entries()) {
console.log(index,item)
}
//输出
//0 'a'
//1 'b'
//2 'c'
四、for of 通过 break 跳出循环
for (const item of ['a','b','c']) {
if (item === 'b') {
break;
}
console.log(item)
}
//输出
//a
五、for of 工作原理
-
一个数据结构只要部署了
Symbol.iterator属性,就被视为具有 iterator(迭代器)接口,可以使用 for of -
for of 循环首先会向被访问对象的 iterator 接口,获取一个迭代器对象,然后通过调用迭代器对象的 next() 方法来获取返回值,数组可以直接使用 for of 遍历是因为数组内置了迭代器,而Object没有内置迭代器。
-
拥有迭代器的对象称为 iterable ,而迭代器叫做 iterator ,这是两个不同的概念。
六、对象添加迭代器的方法
- 给对象添加一个名称为 Symbol.iterator 的属性方法
- 这个方法必须返回一个迭代器对象,它的结构必须如下:
{
next: function() {
return {
value: any, //每次迭代的结果
done: boolean //迭代结束标识
}
}
}
var myObject = { a: 1, b: 2, c: 3 };
//1.简单写法
myObject[Symbol.iterator] = function(){
const _this = this
const keys = Object.keys(this) //也可使用Object.getOwnPropertyNames(this)
let index = 0
return {
next(){
return {
value: _this[keys[index++]],
done: index>keys.length
}
}
}
}
//2.标准写法
Object.defineProperty( myObject, Symbol.iterator, {
enumerable: false, //默认值为true 遍历属性时是否将该属性取出,true为可取,false为不可取
writable: false, //默认值为true 是否可以修改该属性值 true可修改,false不可修改
configurable: true, //默认值为true 当设置为false 则理解为该属性不可删除不可修改
value: function() {
const _this = this
const keys = Object.keys(this)
let index = 0
return {
next(){
return {
value: _this[keys[index++]],
done: index>keys.length
}
}
}
}
});
//3.可复用的对象迭代器添加(通过原型委托)
//如果有很多对象(但不是所有对象都需要)都想要使用for…of怎么办?可以把前面介绍的为对象添加迭代器的代码封装成函数来复用,没有任何问题,但是大多数人是通过原型委托来复用的写法:
//首先创建一个基于对象原型扩展的iterable,并给它添加一个迭代器
const iterable = Object.create(Object.prototype,{
[Symbol.iterator]: {
enumerable: false,
writable: false,
configurable: true,
value: function() {
const _this = this
//也可使用: keys = Object.getOwnPropertyNames(this)
const keys = Object.keys(this)
let index = 0
return {
next(){
return {
value: _this[keys[index++]],
done: index>keys.length
}
}
}
}
}
})
//替换myObject的原型, 使myObject可迭代
//为了不丢失对象myObject原有的原型中的东西
//iterable在创建时将原型设为了Object.prototype
Object.setPrototypeOf(myObject,iterable)
//4.原型委托升级版
//如果你的myObject已经修改过原型了再调用Object.setPrototypeOf(myObject2,iterable) ,这意味着原来的原型会丢失,下面介绍解决办法:
//定义一个函数用于给obj添加迭代器
function iterable(obj){
if(Object.prototype.toString.call(obj) !== "[object Object]"){
return //非对象,不处理
}
if(obj[Symbol.iterator]){
return //避免重复添加
}
const it = Object.create(Object.getPrototypeOf(obj), {
[Symbol.iterator]: {
enumerable: false,
writable: false,
configurable: true,
value: function() {
const _this = this
//也可使用: keys = Object.getOwnPropertyNames(this)
const keys = Object.keys(this)
let index = 0
return {
next(){
return {
value: _this[keys[index++]],
done: index>keys.length
}
}
}
}
}
})
Object.setPrototypeOf(obj, it)
}
//使用:
var myObject = { a: 1, b: 2, c: 3 };
iterable(myObject)// 让myObject可迭代
//5.让所有对象支持for…of
//在对象的原型上直接添加迭代器
Object.prototype[Symbol.iterator] = function(){
const _this = this
const keys = Object.keys(this)
let index = 0
return {
next(){
return {
value: _this[keys[index++]],
done: index>keys.length
}
}
}
}