JavaScript中的(for ... in)和(for ... of)语句有什么区别?

Muk*_*mar 337 javascript arrays object

我知道什么是for... in循环(它迭代密钥),但第一次听到for... of(它迭代值).我对for... of循环感到困惑.我没有得到.这是下面的代码:

var arr = [3, 5, 7];
arr.foo = "hello";

for (var i in arr) {
   console.log(i); // logs "0", "1", "2", "foo"
}

for (var i of arr) {
   console.log(i); // logs "3", "5", "7"
    //it is does not log "3", "5", "7","hello"
}
Run Code Online (Sandbox Code Playgroud)

我得到的是,for... of迭代属性值.那么为什么它不记录(返回)"3", "5", "7","hello"而不是"3", "5", "7"?但for... in循环迭代每个键("0","1","2","foo").这里for... in循环也迭代foo密钥.但是对于...不是对foo财产价值的迭代,即"hello"为什么它是这样的?

简而言之:

在这里我控制台for... of循环.它应该是日志,"3", "5", "7","hello"但在这里记录"3", "5", "7".为什么?

示例链接

Ber*_*rgi 252

for in 循环遍历对象的可枚举属性名称.

for of(ES6中的新增功能)确实使用特定对象的迭代器并循环其生成的值.

在您的示例中,数组迭代器确实会生成数组中的所有值(忽略非索引属性).

  • 一个助记符:'o'f - >不是'o'bjects,'i'n - >不是'i'terables (27认同)
  • `for ... of`在ES6中被标准化. (9认同)
  • `in` 给你索引。这足以记住差异。如果你把逻辑应用到其他方面。 (9认同)
  • 您的助记符*很*感谢,但我不断回到这个答案。 (6认同)
  • 另一个助记符... for..in..keys` ===外键===使用`for ... in`作为键!因此,对值使用`for ... of`。 (3认同)
  • @Placoplatr 对于该助记符,您必须记住它是“NOT”而不是“IS”。在所有其他翻转否定的助记符中,你会忘记哪些是翻转的,哪些不是。因此,在我看来,任何依赖于否定的助记符都无法大规模发挥作用。如果您只专注于 javascript,那就足够了。 (3认同)
  • 从我读到的一些文章中:想想项链上的珍珠和字典中的单词。项链的珍珠是珍珠的阵列。字典中**的单词是一个对象。使用 **of** 循环遍历数组。使用 **in** 循环对象。 (3认同)
  • 这很奇怪,我发誓我读到某处它被移回ES7,但显然那不是真的.我的错. (2认同)
  • 另一个助记符:`for ... of` :: arrays :: arrays总是有一个长度,所以你可以认为`for ...`*[nth element]*`的...`*[q elements]* (2认同)
  • 这些名称很容易混淆...名称选择不当 (2认同)
  • `for...in` ⇒ ***in*** 对象的键 — `for...of` ⇒ ***of*** 数组的项 (2认同)

Ali*_*ahi 197

我在以下网址找到了完整的答案:https://www.typescriptlang.org/docs/handbook/iterators-and-generators.html(虽然它是用于类型脚本,但对于javascript也是如此)

两个for..offor..in语句都遍历列表; 迭代的值虽然不同,但for..in返回正在迭代的对象上的键列表,而for..of返回正在迭代的对象的数值属性的值列表.

以下示例说明了这种区别:

let list = [4, 5, 6];

for (let i in list) {
   console.log(i); // "0", "1", "2",
}

for (let i of list) {
   console.log(i); // "4", "5", "6"
}
Run Code Online (Sandbox Code Playgroud)

另一个区别是for..in可以操作任何物体; 它用作检查此对象的属性的方法.for..of另一方面,主要是对可迭代对象的值感兴趣.内置对象(如Map和Set implement Symbol.iterator属性)允许访问存储的值.

let pets = new Set(["Cat", "Dog", "Hamster"]);
pets["species"] = "mammals";

for (let pet in pets) {
   console.log(pet); // "species"
}

for (let pet of pets) {
    console.log(pet); // "Cat", "Dog", "Hamster"
}
Run Code Online (Sandbox Code Playgroud)

  • 我记得它:对于`index`来说是"in".然后"of"将是每个索引/键/项的"值". (6认同)

Ela*_*lar 34

对于......循环

为...在循环,消除计数逻辑和退出条件在for循环的弱点得到改善.

例:

const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

for (const index in digits) {
  console.log(digits[index]);
}
Run Code Online (Sandbox Code Playgroud)

但是,您仍然需要处理使用索引来访问数组值的问题,这很糟糕; 它几乎使它比以前更混乱.

此外,当你需要向数组(或另一个对象)添加额外的方法时,for ... in循环会让你遇到大麻烦.因为for ... in循环遍历所有可枚举属性,这意味着如果向数组的原型添加任何其他属性,那么这些属性也将出现在循环中.

Array.prototype.decimalfy = function() {
  for (let i = 0; i < this.length; i++) {
    this[i] = this[i].toFixed(2);
  }
};

const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

for (const index in digits) {
  console.log(digits[index]);
}
Run Code Online (Sandbox Code Playgroud)

打印:

0

1

2

3

4

6

7

8

9

function(){for(let i = 0; i <this.length; i ++){this [i] = this [i] .toFixed(2); }}

这就是为什么在循环数组时不鼓励使用in循环.

注意:forEach循环是JavaScript中的另一种for循环.但是,forEach()实际上是一个数组方法,因此它只能与数组一起使用.也无法停止或中断forEach循环.如果在循环中需要这种类型的行为,则必须使用基本的for循环.

对于...循环

对...的循环用于遍历任何类型的数据是可迭代.

例:

const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

for (const digit of digits) {
  console.log(digit);
}
Run Code Online (Sandbox Code Playgroud)

打印:

0

1

2

3

4

6

7

8

9

这使得for循环成为所有for循环中最简洁的版本.

但等等,还有更多!for循环还有一些额外的好处,可以解决for和for循环的弱点.

您可以随时停止或中断for循环.

const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

for (const digit of digits) {
  if (digit % 2 === 0) {
    continue;
  }
  console.log(digit);
}
Run Code Online (Sandbox Code Playgroud)

打印:

1

3

7

9

而且您不必担心向对象添加新属性.for ... of循环只会遍历对象中的值.

  • “ * for ... in循环通过消除计数逻辑和退出条件来改善for循环的弱点*” –不,这不是它的工作。一点也不。 (2认同)
  • @Bergi你能否澄清一下为什么你认为这不是它所做的,以及你实际上认为它改进了什么? (2认同)
  • 它没有任何改善,它有自己的存在理由。它的作用与for循环(var index = 0; index &lt;arr.length; index ++)循环(其中index计数器是整数,与您的示例不同)完全不同。 (2认同)
  • 您为示例选择的数组值与数组索引值相对应,这有点令人困惑...... (2认同)
  • @Barrosy在“for(以数字表示的const索引)”中,[“index”是一个**字符串**](/sf/ask/205361621/)。它既不是计数器也不是整数,这是一个很大的问题。只是[永远不要在数组上使用 `for...in` 枚举](/sf/ask/35035311/)! (2认同)

Ale*_*ine 30

for of用于迭代可迭代对象并for in用于迭代对象属性

这里有一个要记住的技巧:

for of不适用于对象(所以它适用于可迭代对象)

for in不适用于i terables(所以它适用于对象)

另一个技巧:

for in返回骰子(键)中的for of对象,同时返回值

  • 啊,明白了——所以这与我的预期相反。这应该很容易记住。谢谢您的回答。 (4认同)

bni*_*and 21

这是一个有用的助记符,用于记住for...inLoop 和for...ofLoop之间的区别。

“索引,对象”

for...in Loop=> 迭代数组中的索引

for...of Loop=> 迭代对象的对象。


小智 21

//for in,迭代对象中的键和数组中的索引

 let obj={a:1, b:2}
    
    for( const key in obj)
      console.log(obj[key]); //would print 1 and 2
      console.log(key);      //would print a and b

 let arr = [10, 11, 12, 13];

  for (const item in arr) 
    console.log(item);   //would print 0 1 2 3
Run Code Online (Sandbox Code Playgroud)

//for of,迭代数组或任何可迭代对象中的值

let arr = [10, 11, 12, 13];

for (const item of arr )
  console.log(item);  //would print 10  11  12  13
Run Code Online (Sandbox Code Playgroud)


小智 16

简短的回答:for...in循环,而for...of循环

for (let x in ['a', 'b', 'c', 'd'] {
    console.log(x); 
}

// Output
0
1
2
3


for (let x of ['a', 'b', 'c', 'd'] {
    console.log(x); 
}

// Output
a
b
c
d
Run Code Online (Sandbox Code Playgroud)


sim*_*eco 10

两个循环之间的另一个区别,之前没有人提到过:

拆解for...in已被弃用。使用for...of来代替。

来源

所以如果我们想在循环中使用解构,为了获取每个数组元素的索引,我们应该使用带有Array方法的循环:for...ofentries()

for (const [idx, el] of arr.entries()) {
    console.log( idx + ': ' + el );
}
Run Code Online (Sandbox Code Playgroud)


Wil*_*een 9

区别for..infor..of

for..infor..of被循环其在数据结构用于迭代构建体。唯一的区别在于它们的迭代方式:

  1. for..in遍历对象的所有可枚举的属性键
  2. for..of迭代一个可迭代对象的。可迭代对象的示例是数组,字符串和NodeLists。

例:

let arr = ['el1', 'el2', 'el3'];

arr.addedProp = 'arrProp';

// elKey are the property keys
for (let elKey in arr) {
  console.log(elKey);
}

// elValue are the property values
for (let elValue of arr) {
  console.log(elValue)
}
Run Code Online (Sandbox Code Playgroud)

在此示例中,我们可以观察到for..in循环遍历对象的键,该对象在此示例中是数组对象。键是0、1、2,它们对应于我们添加的数组元素和addedProp。这是arrchrome devtools中数组对象的外观:

在此处输入图片说明

您会看到我们的for..in循环只不过是迭代这些值而已。


for..of我们的例子循环迭代的数据结构。此特定示例中的值为'el1', 'el2', 'el3'。可迭代数据结构将使用的返回for..of值取决于可迭代对象的类型。例如,数组将返回所有数组元素的值,而字符串将返回字符串的每个单独字符。

  • 为什么不输出“arrProp”? (7认同)
  • @AlifRamdani 在这种情况下,特别是因为有问题的对象是一个数组。这就是@Willem 的意思:“可迭代数据结构使用‘for..of’返回的值取决于可迭代对象的类型。” 对于数组来说,这只是数字索引。 (7认同)

Ahm*_*zad 9

请记住,它for in用于对象,而它for of用于数组、字符串等。

但是,您甚至不需要使用for in. 您始终可以使用for of

const person = {name: 'John', age: 31};

for (let key in person) {
   console.log(key, ': ', person[key]);  // name: John
}                                        // age: 31

for (let [key, value] of Object.entries(person)) {
   console.log(key, ': ', value); // The same output
} 
Run Code Online (Sandbox Code Playgroud)


小智 8

for...in语句以任意顺序遍历对象的可枚举属性。可枚举属性是内部[[Enumerable]]标志设置为true的那些属性,因此,如果原型链中有任何可枚举的属性,则for...in循环也将在这些属性上进行迭代。

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

例:

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

let iterable = [3, 5, 7];

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

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

for (let i of iterable) {
  console.log(i); // logs: 3, 5, 7
}
Run Code Online (Sandbox Code Playgroud)

与早期的,你可以跳过添加hasOwnPropertyfor...of循环。


小智 7

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

循环将遍历对象本身的所有可枚举属性以及对象从其构造函数的原型继承的属性

您可以将其视为"for in"基本上迭代并列出所有键.

var str = 'abc';
var arrForOf = [];
var arrForIn = [];

for(value of str){
  arrForOf.push(value);
}

for(value in str){
  arrForIn.push(value);
}

console.log(arrForOf); 
// ["a", "b", "c"]
console.log(arrForIn); 
// ["0", "1", "2", "formatUnicorn", "truncate", "splitOnLast", "contains"]
Run Code Online (Sandbox Code Playgroud)

  • “formatUnicorn”、“truncate”、“splitOnLast”、“contains”打印出来,因为 stackoverflow 覆盖了 `String.prototype`。 (2认同)

小智 6

有些已经定义的数据类型使我们可以轻松地对其进行迭代,例如数组,映射,字符串对象

普通的for迭代迭代器,作为响应,为我们提供了按插入顺序排列的键,如以下示例所示。

  const numbers = [1,2,3,4,5];
   for(let number in number) {
     console.log(number);
   }

   // result: 0, 1, 2, 3, 4
Run Code Online (Sandbox Code Playgroud)

现在,如果我们对for进行相同的尝试,那么作为响应,它将为我们提供值而不是键。例如

  const numbers = [1,2,3,4,5];
   for(let numbers of numbers) {
    console.log(number);
  }

  // result: 1, 2, 3, 4, 5
Run Code Online (Sandbox Code Playgroud)

因此,查看两个迭代器,我们可以轻松地区分两者之间的差异。

注: - 对于只能与Symbol.iterator

因此,如果我们尝试遍历普通对象,那么它将给我们带来错误,例如-

const Room = {
   area: 1000,
   height: 7,
   floor: 2
 }

for(let prop in Room) {
 console.log(prop);
 } 

// Result area, height, floor

for(let prop of Room) {
  console.log(prop);
 } 
Run Code Online (Sandbox Code Playgroud)

房间不是可重复的

现在进行迭代,我们需要定义一个ES6 Symbol.iterator,例如

  const Room= {
    area: 1000, height: 7, floor: 2,
   [Symbol.iterator]: function* (){
    yield this.area;
    yield this.height;
    yield this.floors;
  }
}


for(let prop of Room) {
  console.log(prop);
 } 

//Result 1000, 7, 2
Run Code Online (Sandbox Code Playgroud)

这是For inFor of之间的区别。希望它可以清除差异。


小智 6

for...of循环仅适用于可迭代对象。在 JavaScript 中,可迭代对象是可以循环的对象。

String、Array、TypedArray、Map 和 Set 都是内置的可迭代对象,因为它们的每个原型对象都实现了 @@iterator 方法。因此,for...of 循环适用于提到的对象类型。

JavaScript 中的对象默认是不可迭代的。因此,for...of 循环不适用于对象。

简而言之,for...of 适用于字符串和数组,但不适用于对象。

为...在适用于可枚举标志设置为 true 的属性。

通过简单赋值或属性初始值设定项创建的属性的枚举标志默认为 true。通过 Object.defineProperty 创建的属性的可枚举标志默认为 false。

这是带有示例的更详细的帖子:https://dev.to/swastikyadav/difference- Between-forof-and-forin-loop-in-javascript-j2o


Uda*_*ale 5

for-in

for-in循环用于以任意顺序遍历集合的可枚举属性。集合是一个容器类型对象,其项目可以使用索引或键。

var myObject = {a: 1, b: 2, c: 3};
var myArray = [1, 2, 3];
var myString = "123";

console.log( myObject[ 'a' ], myArray[ 1 ], myString[ 2 ] );
Run Code Online (Sandbox Code Playgroud)

for-in循环一次性提取集合的可枚举属性(并一次迭代一个。可枚举属性是可以出现在for-in循环中的集合的属性。

默认情况下,数组和对象的所有属性都出现在for-in循环中。但是,我们可以使用Object.defineProperty方法手动配置集合的属性。

var myObject = {a: 1, b: 2, c: 3};
var myArray = [1, 2, 3];

Object.defineProperty( myObject, 'd', { value: 4, enumerable: false } );
Object.defineProperty( myArray, 3, { value: 4, enumerable: false } );

for( var i in myObject ){ console.log( 'myObject:i =>', i ); }
for( var i in myArray ){ console.log( 'myArray:i  =>', i ); }
Run Code Online (Sandbox Code Playgroud)

在上面的例子中,属性dmyObject和指数3myArray未出现在for-in,因为它们与配置循环enumerable: false

for-in循环问题很少。在数组的情况下,for-in循环也会考虑methods使用myArray.someMethod = f语法添加到数组上,但是,myArray.length仍然是4

for-of

for-of循环迭代集合的值是一种误解。for-of循环遍历一个Iterable对象。一个可迭代对象是一个对象,该对象Symbol.iterator在其原型之一上直接具有带有名称的方法。

Symbol.iterator方法应该返回一个Iterator。迭代器是一个拥有next方法的对象。此方法在调用返回valuedone属性时。

当我们使用循环迭代一个可迭代对象时for-ofSymbol.iterator该方法将在获得迭代器对象后被调用。对于每一个迭代for-of循环,next该迭代器对象的方法将被调用,直到done在返回next()调用返回false。for-of如果调用value返回的属性,则每次迭代循环接收的值next()

var myObject = { a: 1, b: 2, c: 3, d: 4 };

// make `myObject` iterable by adding `Symbol.iterator` function directlty on it
myObject[ Symbol.iterator ] = function(){
  console.log( `LOG: called 'Symbol.iterator' method` );
  var _myObject = this; // `this` points to `myObject`
  
  // return an iterator object
  return {
    keys: Object.keys( _myObject ), 
    current: 0,
    next: function() {
      console.log( `LOG: called 'next' method: index ${ this.current }` );
      
      if( this.current === this.keys.length ){
        return { done: true, value: null }; // Here, `value` is ignored by `for-of` loop
      } else {
        return { done: false, value: _myObject[ this.keys[ this.current++ ] ] };
      }
    }
  };
}

// use `for-of` loop on `myObject` iterable
for( let value of myObject ) {
  console.log( 'myObject: value => ', value );
}
Run Code Online (Sandbox Code Playgroud)

for-of回路处于ES6新等都是可迭代Iterables。该Array构造类型都有Symbol.iterator它的原型方法。Object遗憾的是,构造函数没有它 but Object.keys()Object.values()并且Object.entries()方法返回一个可迭代对象(您可以console.dir(obj)用来检查原型方法)。for-of循环的好处是任何对象都可以迭代,甚至是你的自定义DogAnimal类。

使对象可迭代的简单方法是实现ES6 Generator而不是自定义迭代器实现。

与 不同for-infor-of循环可以在每次迭代中等待异步任务完成。这是awaitfor语句文档之后使用关键字实现的。

for-of循环的另一个优点是它支持 Unicode。根据 ES6 规范,字符串以 UTF-16 编码存储。因此,每个字符都可以使用16-bit32-bit。传统上,字符串使用 UCS-2 编码存储,该编码支持只能存储在其中的字符16 bits

因此,String.length返回16-bit字符串中的块数。像表情符号这样的现代字符需要 32 位。因此,这个字符将返回length2.for-in循环遍历16-bit块并返回错误的index。但是,for-of循环会根据 UTF-16 规范迭代单个字符。

var emoji = "";

console.log( 'emoji.length', emoji.length );

for( var index in emoji ){ console.log( 'for-in: emoji.character', emoji[index] ); }
for( var character of emoji ){ console.log( 'for-of: emoji.character', character ); }
Run Code Online (Sandbox Code Playgroud)