通俗来讲:

for in 遍历对象,并且只会遍历可枚举对象[标识值(enumerable)为true]
for of 遍历数组(但是,如果真是只遍历数组,建议使用原生forEach,性能更佳!)

Object.prototype.objCustom = function() {}; 
Array.prototype.arrCustom = function() {};

let iterable = [3, 5, 7];
iterable.foo = 'hello';

for (let i in iterable) {
  console.log(i); // logs 0, 1, 2, "foo", "arrCustom", "objCustom"
}

for (let i in iterable) {
  if (iterable.hasOwnProperty(i)) {
    console.log(i); // logs 0, 1, 2, "foo"
  }
}

for (let i of iterable) {
  console.log(i); // logs 3, 5, 7
}

无论是for...in还是for...of语句都是迭代一些东西。它们之间的主要区别在于它们的迭代方式。

for...in 语句以任意顺序迭代对象的可枚举属性。

for...of 语句遍历可迭代对象定义要迭代的数据。

最核心的问题就是: 可枚举属性和可迭代对象是什么意思?

可枚举属性是指那些内部 “可枚举” 标志设置为 true 的属性,对于通过直接的赋值和属性初始化的属性,该标识值默认为即为 true,对于通过 Object.defineProperty 等定义的属性,该标识值(enumerable)默认为 false。

可迭代对象 JavaScript内置的数据结构都有其对应的迭代器实现,如果硬在数组中定义对象成员变量,可行是可行,但是,并不会被数组的迭代器调用。

举一个栗子:

let demo = [1,2,3];
demo.demo = "demo";
for(let value of demo) {
    console.log(value); // logs: 1,2,3
}
for(let value in demo) {
    console.log(value); // logs: 0,1,2,demo
}

创建空对象时,除非必要,否则务必使用Object.create(null),原因就是原型链已被污染

Object.prototype.xxx = "xxx";
let Lindo1 = {};
for(let value in Lindo1) {
    console.log(value); // logs: xxx 
}
let Lindo2 = Object.create(null);
for(let value in Lindo2) {
    console.log(value); // logs: undefined
}

Last modification:July 13, 2020
如果觉得文章对你有所收获,可以请笔者喝杯咖啡