for in 和 for of 的区别

在我们日常的开发中,遍历某个 数据 / 值 是随时随地都会遇到的一种需求,js可实现遍历的方法多种多样,今天我们就来详细聊聊 for in 和 for of

for in 和 for of 简单来说就是它们两者都可以用于遍历,可能大部分人觉得比较简单,都差不了多少,也没有对这两种方法做一个详细的区分,今天我们就来学习总结一下。

首先,在MDN官网就说明了 for...of与for...in的区别 ,有兴趣的伙伴可以去官网再仔细研究一下

for in 和 for of 的本质区别

1、使用的目标不一样

1-1、for in 适用于 可枚举属性,例如 对象、数组、字符串。

那么什么是可枚举属性呢?

属性的 enumerable 值为 true 就为可枚举的,通过Object.getOwnPropertyDescriptors() 或 Object.prototype.propertyIsEnumerable() 进行查看 / 验证  

const obj = {
  name: 'zhangsan',
  age: 18
}
console.log(Object.getOwnPropertyDescriptors(obj)) 
// { 
//   name: { value: 'zhangsan', writable: true, enumerable: true, configurable: true },
//   age: { value: 18, writable: true, enumerable: true, configurable: true } 
// }


const arr = [1, 2, 3]
console.log(Object.getOwnPropertyDescriptors(arr)) 

// {
//   '0': { value: 1, writable: true, enumerable: true, configurable: true },    
//   '1': { value: 2, writable: true, enumerable: true, configurable: true },    
//   '2': { value: 3, writable: true, enumerable: true, configurable: true },    
//   length: { value: 3, writable: true, enumerable: false, configurable: false }
// }

const str = 'abc'
console.log(Object.getOwnPropertyDescriptors(str)) 
// {
//   '0': { value: 'a',  writable: false, enumerable: true, configurable: false},
//   '1': { value: 'b', writable: false, enumerable: true, configurable: false },
//   '2': { value: 'c', writable: false, enumerable: true, configurable: false },
//   length: { value: 3, writable: false, enumerable: false, configurable: false }
// }

1-2、for of 适用于 可迭代对象,像Array、String、Map、Set、函数的arguments对象、nodeList对象

那么什么是可迭代呢?

ES6中,具有Symbol.iterator 属性,它对应的值是一个函数,调用这个函数后可得到一个对象,每次调用这个对象的next() 方法能得到目标的每一项,只要符合这个特点就是可迭代的

const str = 'zxt'
const it_str = str[Symbol.iterator]()
console.log(it_str.next()) // { value: 'z', done: false }
console.log(it_str.next()) // { value: 'x', done: false }
console.log(it_str.next()) // { value: 't', done: false }

const arr = ['a', 'b']
const it_arr = arr[Symbol.iterator]()
console.log(it_arr.next()) // { value: 'a', done: false }
console.log(it_arr.next()) // { value: 'b', done: false }

2、遍历的范围不一样

for in 能遍历自身的可枚举属性 && 原型上的可枚举属性

for of 一般只能遍历自身的可枚举属性(具体和迭代器内部的实现有关)

 我们现在改造 for of 的迭代器,让其也能遍历到原型上可枚举的属性,代码如下:

const arr = [7]
// 在原型上添加属性 foo
Array.prototype.foo = 4
arr[Symbol.iterator] = function() {
  const _this = this
  Object.keys(this.__proto__).forEach(item => this.push(this.__proto__[item]))
  return {
    i: 0,
    next(){
      return this.i < _this.length ? {value: _this[this.i++], done: false} : {value: undefined, done: true}
    }
  }
}

for(let value of arr) {
  console.log(value) 
}

// 输出结果  7 4

3、得到的结果不一样

for in 得到的是key(并且不能保证顺序)

for of 一般得到的是value(具体和迭代器内部的实现有关)

 我们现在改造 for of 的迭代器,让其遍历也能的是key,代码如下:

const arr = [7, 8]
arr[Symbol.iterator] = function() {
  const _this = this
  return {
    i: 0,
    next(){
      return this.i < _this.length ? {value: this.i++, done: false} : {value: undefined, done: true}
    }
  }
}

for(let value of arr) {
  console.log(value) // 0  1
}

以上就是我对 for in 和 for of 的总结,如其他小伙伴还有什么问题欢迎评论区留言讨论,谢谢~~

你可能感兴趣的:(javascript)