如何遍历对象, 一般来说会想到 for-in

let obj = {  a: "Jane",  b: "Kevin",};for (let k in obj) {  console.log(k, obj[k]);}// 输入后果// a Jane// b Kevin

然而for-in会遍历对象的原型链, 一些继承属性就被遍历进去了, 如果只想遍历对象本身的属性这时候就得加判断了

let obj = {  a: "Jane",  b: "Kevin",};let newObj = Object.create(obj);newObj.c = "Duke";newObj.e = "James";for (let k in newObj) {  console.log(k, newObj[k]);}// 输入后果//  c Duke//  e James//  a Jane//  b Kevinfor (let k in newObj)  if (newObj.hasOwnProperty(k)) {    {      console.log(k, newObj[k]);    }  }// 输入后果// c Duke// e James

接下来咱们尝试一些其余的形式

ES6中提供了其余 for-of, 能够很不便的遍历 ArrayMapSetString、某些类数组如arguments等数据类型, 然而却无奈遍历一般的object对象.

查阅材料后得悉, 原来能够被 for-of 遍历的数据类型提供了 iterator 接口. 那如果咱们在对象上本人实现一个 iterator 接口, 后果会如何呢?

newObj[Symbol.iterator] = function () {  let index = 0;  let self = this;  let keys = Object.keys(self);  return {    next() {      if (index < keys.length) {        return {          value: { key: keys[index], value: self[keys[index++]] },          done: false,        };      } else {        return {          value: undefined,          done: true,        };      }    },  };};for (let { key, value } of newObj) {  console.log(key, value);}// 输入后果// c Duke// e James

当初咱们通过实现了 iterator 接口, 使得对象能够被 for-of 遍历, 那么背地的原理是什么呢? 其实, Symbol.iterator 函数返回了一个 next 函数, 每次迭代都会调用 next 函数, 通过返回值中的 value 属性拿到遍历的后果, done 属性来判断是否须要持续遍历.

接下来咱们通过手动调用来验证一下

let iterator = newObj[Symbol.iterator]();let result = iterator.next();while (!result.done) {  let { key, value } = result.value;  console.log(key, value);  result = iterator.next();}// 输入后果// c Duke// e James