ウェブサイト検索

javascript - (for...in) と (for...of) 文の違いは何ですか?


私は 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 doesn't log "3", "5", "7", "hello"
}

私は、for... of がプロパティの値を反復処理することを理解しています。それなら、なぜ "3", "5", "7", "hello" ではなく "3", "5", "7" がログに出力されるのですか?

for... in ループは各キー("0"、"1"、"2"、"foo")を繰り返し処理し、foo キーも繰り返し処理しますが、for... of は foo プロパティの値、つまり "hello" を繰り返し処理しません。なぜそうなるのでしょうか?

ここで私は for... of ループをコンソールに出力します。本来は "3", "5", "7", "hello" とログに表示されるはずですが、実際には "3", "5", "7" と表示されます。なぜでしょうか?

例のリンク

回答 #1

for in はオブジェクトの列挙可能なプロパティ名をループします。

`for of`(ES6で新登場)は、オブジェクト固有のイテレーターを使用し、それによって生成された値をループします。

あなたの例では、配列イテレーターは配列内のすべての値を生成します(インデックス以外のプロパティは無視されます)。

回答 #2

私は Iterators and Generators で完全な答えを見つけました(TypeScript 向けですが、これは JavaScript にも同じです)

どちらの for..of と for..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
}

もう一つの違いは、for..in は任意のオブジェクトで動作するという点です。これは、そのオブジェクトのプロパティを調べる方法として使われます。一方、for..of は主に反復可能なオブジェクトの値に関心があります。Map や Set などの組み込みオブジェクトは 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"
}

回答 #3

for..in と for..of の違い:

for..in と for..of の両方は、データ構造を反復処理するために使用されるループ構文です。それらの唯一の違いは、反復処理する対象のエンティティです。

  1. for..in はオブジェクトのすべての列挙可能な プロパティキー を反復処理します
  2. for..of は 反復可能なオブジェクトの値 を反復処理します。反復可能なオブジェクトの例としては、配列、文字列、および NodeList があります。

例:

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)
}

この例では、for..in ループがオブジェクトのキーを反復処理していることがわかります。この例ではオブジェクトは配列オブジェクトです。キーは 0、1、2(配列要素に対応)および addedProp です。chrome devtools での arr 配列オブジェクトの見た目は以下の通りです:

ご覧の通り、私たちのfor..inループは、これらのキーを単に反復処理する以上のことは何もしていません。


私たちの例のfor..ofループは、データ構造の値を反復処理します。この特定の例での値は'el1', 'el2', 'el3'です。for..ofを使用して反復可能なデータ構造が返す値は、反復可能オブジェクトの種類によって異なります。たとえば、配列はすべての配列要素の値を返しますが、文字列は文字列の各文字を返します。

回答 #4

for...inループ

for...inループは、カウントするロジックと終了条件を排除することで、forループの弱点を改善しています。

例:

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

for (const index in digits) {
  console.log(digits[index]);
}

しかし、配列の値にアクセスするためにインデックスを使うという問題にはまだ対処しなければならず、それは最悪です;以前よりも混乱させるような気さえします。

さらに、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]);
}

印刷:

1

2

3

4

5

6

7

8

9

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

これが、配列をループする際に for...in ループが推奨されない理由です。

注意:forEachループは、JavaScriptにおける別の種類のforループです。しかし、forEach()は実際には配列のメソッドであるため、配列でのみ使用できます。また、forEachループを停止したり中断したりする方法はありません。そのような動作がループに必要な場合は、基本的なforループを使用する必要があります。

for...ofループ

for...of ループは、反復可能な任意の種類のデータをループするために使用されます。

例:

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

for (const digit of digits) {
  console.log(digit);
}

印刷:

1

2

3

4

5

6

7

8

9

これにより、for...of ループはすべての for ループの中で最も簡潔なバージョンになります。

でも待って、まだあります!for...ofループには、forループやfor...inループの弱点を補ういくつかの追加の利点もあります。

for...of ループはいつでも停止したり中断したりすることができます。

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);
}

印刷:

1

3

5

7

9

そして、オブジェクトに新しいプロパティを追加することを心配する必要はありません。for...of ループはオブジェクト内の値だけをループします。

回答 #5

これは、for...in ループと for...of ループの違いを覚えるための便利な記憶法です。

「~の中のインデックス、対象」

for...in ループ => 配列の インデックスを 反復処理します。

for...of ループ => オブジェクトの オブジェクトの 上で反復します。

回答 #6

`for of` はイテラブルを反復処理するために使用され、`for in` はオブジェクトのプロパティを反復処理するために使用されます

覚えておくためのコツはこちらです:

for of は object のためのものではありません(だからイテラブルのためのものです)

for in は iterable のためのものではありません(だからオブジェクト用です)

もう一つのコツ:

for in はオブジェクトの キー を返し、for of は値を返します

回答 #7

//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

//for of、配列や任意の反復可能オブジェクトの値を反復します

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

for (const item of arr )
  console.log(item);  //would print 10  11  12  13

回答 #8

短い答え: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

回答 #9

これまで誰も言及していない、二つのループのもう一つの違い:

分割代入の for...in は非推奨です。代わりに for...of を使用してください。

ソース

ですので、もしループ内で分割代入を使って、各配列要素のインデックスと値の両方を取得したい場合は、Arrayメソッドentries()とともにfor...ofループを使用する必要があります:

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

回答 #10

ただし、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
} 

回答 #11

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
}

先ほどと同様に、for...of ループで hasOwnProperty を追加するのを省略できます。

回答 #12

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"]

回答 #13

すでに定義されているいくつかのデータ型があり、それらを簡単に反復処理することができます。例えば、Array、Map、Stringオブジェクトなどです。

通常の for in はイテレーター上を反復し、それに応じて挿入順に並んだキーを提供します。以下の例に示されています。

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

   // result: 0, 1, 2, 3, 4

では、もし同じことを for of で試すと、応答としてキーではなく値が提供されます。例えば

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

  // result: 1, 2, 3, 4, 5

したがって、両方のイテレーターを見てみると、両者の違いを簡単に区別することができます。

注意:- for...of は 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);
 } 

Room は反復可能ではありません

さて、反復処理を行うには、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

これはfor inとfor ofの違いです。違いが明確になることを願っています。

関連記事