Skip to content

Latest commit

 

History

History
83 lines (66 loc) · 2.65 KB

如何让for...of遍历对象.md

File metadata and controls

83 lines (66 loc) · 2.65 KB

如何让for...of遍历对象

前一段时间面试的时候被问过这个问题,所以记录一下。

for...of为什么可以遍历数组,却不能对象

当一个数据结构只要部署了Symbol.iterator属性,就被视为具有iterator 接口,就可以用for...of循环遍历它的成员。也就是说,for...of循环内部调用的是数据结构的Symbol.iterator方法。

先看看数组的Symbol.iterator

const a = [1,2,3];

const iterator = a[Symbol.iterator]();

iterator.next(); // { value: 1, done: false }
iterator.next(); // { value: 2, done: false }
iterator.next(); // { value: 3, done: false }
iterator.next(); // { value: undefined, done: true }

当我每次调用next方法时,都会返回一个对象,表示当前数据成员的信息。这个对象具有valuedone两个属性,value属性返回当前位置的成员,done属性是一个布尔值,表示遍历是否结束,即是否还有必要再一次调用next方法。

Iterator 的遍历过程是这样的:

  • 创建一个指针对象(Symbol.iterator()返回的对象),指向当前数据结构的起始位置。

  • 第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。

  • 第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。

  • 不断调用指针对象的next方法,直到它指向数据结构的结束位置。

重写Object的Symbol.iterator方法

要想让for...of能遍历对象也很简单,只需要像数组一样,提供一个iterator的接口即可。

const obj = {
    name: 'tom',
    age: 12
};

obj[Symbol.iterator] = function () {
  let values = Object.values(this);
  let length = values.length;
  let index = 0;
  return {
    next: function () {
      if(index <= length - 1) {
        return {
          value: values[index++],
          done: false
        }
      } else {
        return {
          value: undefined,
          done: true
        }
      }
    }
  }
}
const objIterator = obj[Symbol.iterator]();
objIterator.next();// {value: 'tom', done: false}
objIterator.next();// {value: 12, done: false}
objIterator.next();// {value: undefined, done: true}

for(let value of obj) {
  console.log('value:',value);
}
// value:  'tom'
// value:  12

原生具有iterator接口的数据结构

  • Set
  • Map
  • String
  • Array
  • Nodelist
  • TypeArray
  • 函数的arguments对象

总结

for...of之所以能遍历数组是因为数组的原型上有Symbol.iterator方法,相当于给for...of提供一个可遍历的接口,所以想要for...of遍历对象,重写Object原型上的Symbol.iterator方法即可。