# forin 和 forof 的区别

# 1. 遍历数组通常用 for 循环

ES5 的话也可以使用 forEach, ES5 具有遍历数组功能的还有 map, filter, some, every, reduce, reduceRight 等,只不过他们的返回结果不太一样,但使用 forEach 遍历数组的话,使用 break 不能中断循环,使用 return 也不能返回到外层函数。

Array.prototype.method = function() {
  console.log(this.length);
};
var myArray = [1, 2, 3, 4, 5];
myArray.name = "数组";
for (var index in myArray) {
  console.log(myArray[index]);
}

# 2. for in 遍历数组的毛病

    1. index 索引为字符串型数字,不能直接进行几何运算
    1. 遍历顺序有可能不是按照实际数组的内部顺序
    1. 使用for in会遍历数组所有的可枚举属性,包括原型。例如上例的原型方法 method 和 name 属性 所以for in更适合遍历对象,不要使用for in遍历数组 可以用for of遍历数组

for in 遍历的是数组的索引(即键名),而 for of 遍历的是数组的元素值 for of 遍历的只是组内的元素,而不包括数组的原型属性 method 和索引 name

Array.prototype.method = function() {
  console.log(this.length);
};
var myArray = [1, 2, 3, 4, 5];
myArray.name = "数组";
for (var value of myArray) {
  console.log(value);
}

# 遍历对象

遍历对象 通常用for in来遍历对象的键名

Object.prototype.method = function() {
  console.log(this);
};
var myObject = {
  a: 1,
  b: 2,
  c: 3,
};
for (var key in myObject) {
  console.log(key);
}

for in可以遍历到 myObject 的原型方法 method,如果不想遍历原型方法和属性,可以在项目内部加判断,hasOwnPropery方法可以判断某属性是否是该对象的实例属性

for (var key in myObject) {
  if (myObject.hasOwnProperty(key)) {
    console.log(key);
  }
}

同样可以通过 es5 的Object.keys(myObject)获取对象的实例属性组成的数组,不包括原型方法和属性

Object.prototype.method = function() {
  console.log(this);
};
var myObject = {
  a: 1,
  b: 2,
  c: 3,
};
for (var key of Object.keys(myObject)) {
  console.log(key + ": " + myObject[key]);
}

# 总结

  • for...of适用遍历数/数组对象/字符串/map/set 等拥有迭代器对象的集合。但不能遍历对象,因为没有迭代器的对象。与 forEach()不同的是,它可以正确响应 break、continue 和 return 语句。
  • for...of循环不支持普通对象,但如果你想迭代一个对象属性,你可以用for-in循环,或内建 Object.keys()方法
for (var key of Object.keys(someObjec)) {
  console.log(key + ": " + someObjec[key]);
}
  • 遍历 map 对象时使用解构
for (var [key, value] of phoneBookeMap) {
  console.log(key + "'s phone number is: " + value);
}
  • 向任意对象添加[Symbol.itertor]方法,就可以使用for..of循环了
    • 所有拥有Symbol.iterator的对象被称为可迭代的。
jQuery.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
  • for..of 步骤
    • a. 首先调用集合Symbol.iterator方法,从而返回一个新的迭代对象
    • b. 迭代器对象可以是任意具有.next()方法的对象,forof 循环将重复调用这个方法,每次循环调用一次。
    var zeroesForeverIterator = {
      [Symbol.iterator]: function() {
        return this;
      },
      next: function() {
        return {
          done: false,
          value: 0,
        };
      },
    };