JavaScriptの(for…in)ステートメントと(for…of)ステートメントの違いは何ですか?


410

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

私が得たのは、for... ofプロパティ値を反復処理することです。では、なぜ"3", "5", "7", "hello"代わりにログを返さない(返す)の"3", "5", "7"ですか?ただし、for... inループは各キー("0", "1", "2", "foo")を反復します。ここでもfor... inループはfooキーを反復します。ただしfor... offooプロパティの値(つまり)を反復しません"hello"。なぜそんな感じなの?

要するに長い話:

ここでfor... ofループをコンソールします。ログに記録する必要があります"3", "5", "7","hello"が、ここではログに記録し"3", "5", "7"ます。どうして ?

リンクの例


1
あなたがそれを逃した場合に備えて、ここに開始リンクdeveloper.mozilla.org/en-US/docs/Web/JavaScript/Reference/…があります
Anthony Russell

1
私の理解によると、for ... offor ... in配列での使用に関する問題を修正するために言語に取り入れられました。Array.prototype追加のプロパティを使用できるように修正することができるため、予期しない数値以外のキーを取得する可能性があるため、それらを反復するのは安全ではありません。
系統発生2015年

2
将来の読者のために:これは、JavaScriptのofキーワード(for…ofループ)の複製ではない可能性があります。一般的な概要を尋ねるのではなく、機能の特定の動作について尋ねるからです。
アプシラー2015年

2
for <key> in」と「for <value> of」を言うことに慣れ、IEがサポートしていないことに気付くfor..of
ボットネット

回答:


304

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

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

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


9
for ... ofES6で標準化されています。
ジャスティン

2
それは奇妙なことですが、どこかで読んだことが、それがES7に戻されたと確信していますが、明らかにそうではありませんでした。私の悪い。
Alexander O'Mara 2016

40
ニーモニック: 'o'f-> not' o'bjects、 'i'n-> not' i'terables
Placoplatr

4
別のニーモニック::: for... of配列::配列には常に長さがあり、for.. [n番目の要素] [q要素]と考えることができますof..
Nathan Smith

14
別のニーモニック... for..in..keys===外部キー=== for...inキーに使用!そのためfor...of、値に使用します。
Gunther

237

私は完全な答えを見つけます: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"
}

別の違いは、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"
}

1
さらに、for(let i of {}){console.log(i);のような呼び出し }はTypeErrorをスローします:VM391:1 Uncaught TypeError:{}は少なくともChromeでは<anonymous>:1:14で反復可能ではありません
kboom

勝利のためのTS-例は正しくありません。後者は//「猫」、「犬」、「ハムスター」ではなく「哺乳類」を返す必要があります
martinp999

8
私はそれを覚えていindexます。そして、 "of"はvalues各インデックス/キー/アイテムのとなります。
SherylHohman

いいですね、これは私にとって王様になるでしょう:通常、let thisItem = items[all];変数を作成する必要があるアイテムの反復にfor-insを使用することでfor...of、ショートカットを手助けします!
Vasily Hall

私はそれを覚えています:for...inとしてObject.keys()、何を推測しますか?配列はオブジェクトなので、インデックスも返します。:)
Sujeet Agrahari

38

for ... inループ

以下のために...でループカウントロジックと終了条件を排除することによって、ループのための弱点を改善します。

例:

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

プリント:

0

1

2

4

5

6

7

8

9

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

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

forEachループは、JavaScriptの別のタイプのforループです。ただし、これforEach()は実際には配列メソッドであるため、配列でのみ使用できます。forEachループを停止または解除する方法もありません。ループでそのような動作が必要な場合は、基本的なforループを使用する必要があります。

for ... ofループ

...のループが反復可能である任意のタイプのデータをループに使用されています。

例:

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

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

プリント:

0

1

2

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

5

7

9

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


2
" for ... inループは、カウントロジックと終了条件を排除することにより、forループの弱点を改善します "-いいえ、それはそれが行うことではありません。どういたしまして。
Bergi

1
@Bergiなぜそれが何をしていないのか、そしてあなたが実際にそれが改善していると思うのはなぜだと思いますか?
Elar

2
何も改善せず、独自の存在理由があります。for (var index=0; index<arr.length; index++)ループとはまったく異なる処理をindex行います(例とは異なり、カウンターは整数です)。
Bergi

例のために選択した配列の値が配列のインデックスの値に対応することを混乱させるようなものです...
Sergey

20

違いfor..infor..of

両方for..infor..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ます。これは、arr配列オブジェクトがchrome devtoolsでどのように見えるかです。

ここに画像の説明を入力してください

私たちのfor..inループは、これらの値を単に繰り返すこと以外に何もしていません。


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


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
}

以前と同様に、ループの追加hasOwnPropertyをスキップできfor...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"]

for in キーが追加された場合にのみキーが表示され、formatUnicorn
Milad

1
stackoverflowがオーバーライドするため、「formatUnicorn」、「truncate」、「splitOnLast」、「contains」が出力されますString.prototype
jasonxia23

6

すでに定義されているデータ型がいくつかあります。これにより、配列、マップ、文字列オブジェクトなどを簡単に反復できます。

通常のforはイテレータを反復し、それに応じて、以下の例に示すように、挿入順にキーを提供します。

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

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

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

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

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

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

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

部屋は反復可能ではありません

ここで反復するために、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 inFor ofの違いです。それが違いを晴らしてくれることを願っています。


5

2つのループのもう1つの違いは、これまで誰も言及していませんでした。

解体for...inは非推奨です。for...of代わりに使用してください。

ソース

したがって、ループで分解を使用する場合、各配列要素のインデックスの両方を取得するには、Arrayメソッドでループを使用する必要があります。for...ofentries()

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

1
はい@GalMargalit、私はそれを注意深く読みました。for each...inが非推奨であることに同意しますが(最初の点)、それについては書きませんでした...「破壊for...inは非推奨です。for...of代わりに使用してください」と書きました。(2番目のポイント):developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…@GalMargalitに同意しますか?
simhumileco

1
ははは、正解です、私は注意深く読みませんでした!確かに、私は基本的に同じことを考えていて、あなたが別のものを参照していると思っていました。
Gal Margalit

2

誰もがこの問題が発生する理由を説明しましたが、それを忘れて、間違った結果が得られた理由を頭にかざすのは、依然として非常に簡単です。特に、大きなデータセットで作業しているときに、一見すると結果が適切であるように見える場合。

Object.entriesあなたを使用すると、すべてのプロパティを確実に通過します:

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

for ( var [key, val] of Object.entries( arr ) ) {
   console.log( val );
}

/* Result:

3
5
7
hello

*/

2

良い答えはたくさんありますが、良い例を示すために5セントを置くことにしました。

forループ

列挙可能なすべての小道具を反復します

let nodes = document.documentElement.childNodes;

for (var key in nodes) {
  console.log( key );
}

forループ

すべての反復可能な値を反復します

let nodes = document.documentElement.childNodes;

for (var node of nodes) {
  console.log( node.toString() );
}


2

私が最初にfor inofループの学習を始めたときも、自分の出力と混同されていましたが、いくつかの調査と理解によって、次のような個々のループについて考えることができます。

  1. するために... ループ返すインデックス個々のプロパティのをと持っていない何の効果への影響のプロパティの値を、それが上の情報ループして戻っプロパティではなく値を。例えば

let profile = { name : "Naphtali", age : 24, favCar : "Mustang", favDrink : "Baileys" }

上記のコードは単にprofileと呼ばれるオブジェクトを作成しているだけので、両方の例で使用します。したがって、プロファイルオブジェクトが表示されたときに混乱しないようにしてください。

それでは、以下のfor ... inループを使用してみましょう

for(let myIndex in profile){
    console.log(`The index of my object property is ${myIndex}`)
}
 // Outputs : 
        The index of my object property is 0
        The index of my object property is 1
        The index of my object property is 2
        The index of my object property is 3

今、私たちは持っているということで、出力理由四(4)当社のプロパティのプロファイルから、我々はすべて知っているが始まるなど、オブジェクトとインデックス0を... nはそう、我々は、プロパティのインデックスを取得0,1,2,3を私たちがしているので、for..inループでの作業。

  1. for ... of loop *、プロパティ値、 または その両方を返すことができます。その方法を見てみましょう。javaScriptでは、配列の場合のようにオブジェクトを通常通りループすることができないため、オブジェクトから選択したものにアクセスするために使用できる要素がいくつかあります。

    • Object.keysobject-name-goes-here)>>> オブジェクトのキーまたはプロパティを返します。

    • Object.valuesobject-name-goes-here)>>> オブジェクトのを返します。

    • Object.entriesオブジェクト名は-行く-ここで)>>>戻り値の両方のキーオブジェクトの。

以下はその使用例です。Object.entries()に注意してください。

Step One: Convert the object to get either its key, value, or both.
Step Two: loop through.


// Getting the keys/property

   Step One: let myKeys = ***Object.keys(profile)***
   Step Two: for(let keys of myKeys){
             console.log(`The key of my object property is ${keys}`)
           }

// Getting the values of the property

    Step One: let myValues = ***Object.values(profile)***
    Step Two : for(let values of myValues){
                 console.log(`The value of my object property is ${values}`)
               }

Object.entries()を使用する場合は、オブジェクトの2つのエントリ、つまりキーと値を呼び出す必要があります。どちらのエントリでも両方を呼び出すことができます。以下の例。

Step One: Convert the object to entries, using ***Object.entries(object-name)***
Step Two: **Destructure** the ***entries object which carries the keys and values*** 
like so **[keys, values]**, by so doing, you have access to either or both content.


    // Getting the keys/property

       Step One: let myKeysEntry = ***Object.entries(profile)***
       Step Two: for(let [keys, values] of myKeysEntry){
                 console.log(`The key of my object property is ${keys}`)
               }

    // Getting the values of the property

        Step One: let myValuesEntry = ***Object.entries(profile)***
        Step Two : for(let [keys, values] of myValuesEntry){
                     console.log(`The value of my object property is ${values}`)
                   }

    // Getting both keys and values

        Step One: let myBothEntry = ***Object.entries(profile)***
        Step Two : for(let [keys, values] of myBothEntry){
                     console.log(`The keys of my object is ${keys} and its value 
is ${values}`)
                   }

不明なパーツのセクションにコメントします。


1

for-inループ

for-inloopは、コレクションの列挙可能なプロパティを任意の順序でトラバースするために使用されます。コレクションは、アイテムがインデックスまたはキーを使用できるコンテナタイプのオブジェクトです。

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

console.log( myObject[ 'a' ], myArray[ 1 ], myString[ 2 ] );

for-inloop は、コレクションの列挙可能なプロパティ(keys)を一度にすべて抽出し、一度に1つずつ反復します。列挙可能なプロパティは、に表示できるコレクションのプロパティです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 ); }

上記の例では、プロパティdmyObjectインデックス3のはmyArray表示されないfor-in、それらがで構成されているので、ループenumerable: false

for-inループに関する問題はほとんどありません。配列の場合、for-inループも構文methodsを使用して配列に追加されたと見なされmyArray.someMethod = fますが、myArray.length残り4ます。

for-ofループ

for-ofコレクションの値に対してループが繰り返されるのは誤解です。for-ofループはIterableオブジェクトを反復します。イテラブルは、Symbol.iteratorそのプロトタイプの1つに直接名前が付けられたメソッドを持つオブジェクトです。

Symbol.iteratorメソッドはIteratorを返す必要があります。イテレータはnextメソッドを持つオブジェクトです。このメソッドは、return valueおよびdoneproperties と呼ばれます。

ループを使用して反復可能なオブジェクトを反復する場合、反復子オブジェクトを取得すると、メソッドが呼び出されます。ループの反復ごとに、この反復子オブジェクトのメソッドは、呼び出しによって返される値がfalseを返すまで呼び出されます。プロパティが呼び出しによって返された場合、すべての反復でループによって受信された値。for-ofSymbol.iteratorfor-ofnextdonenext()for-ofvaluenext()

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

for-ofループはES6の新機能で、そうしている反復処理可能反復可能オブジェクトがArrayコンストラクタタイプがありSymbol.iterator、そのプロトタイプのメソッドを。Objectコンストラクタは悲しげにそれを持っていませんがObject.keys()Object.values()及びObject.entries()方法は、(反復可能を返すに使用できるconsole.dir(obj)プロトタイプの方法を確認すること)。for-ofループの利点は、カスタムDogAnimalクラスであっても、オブジェクトを反復可能にすることができることです。

オブジェクトを反復可能にする簡単な方法は、カスタムイテレータ実装ではなくES6ジェネレータを実装することです。

とは異なりfor-infor-ofループは各反復で非同期タスクが完了するのを待つことができます。これはawaitforステートメントドキュメントの後にキーワードを使用して実現されます。

for-ofループのもう1つの優れた点は、Unicodeをサポートしていることです。ES6仕様によれば、文字列はUTF-16エンコーディングで保存されます。したがって、各文字はどちらか取ることができます16-bit32-bit。従来、文字列は、内部に16 bitsのみ格納できる文字をサポートするUCS-2エンコーディングで格納されていました。

したがって、文字列内String.length16-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 ); }


0

https://javascript.info/arrayからの次の説明は非常に役に立ちました。

配列項目を循環させる最も古い方法の1つは、インデックスのforループです。

let arr = ["Apple", "Orange", "Pear"];

for (let i = 0; i < arr.length; i++) { alert( arr[i] ); } But for arrays there is another form of loop, for..of:

let fruits = ["Apple", "Orange", "Plum"];

// iterates over array elements for (let fruit of fruits) { alert( fruit ); } The for..of doesn’t give access to the number of the current element, just its value, but in most cases that’s enough. And it’s shorter.

技術的には、配列はオブジェクトであるため、for..inを使用することもできます。

let arr = ["Apple", "Orange", "Pear"];

for (let key in arr) { alert( arr[key] ); // Apple, Orange, Pear } But that’s actually a bad idea. There are potential problems with it:

ループfor..inは、数値のプロパティだけでなく、すべてのプロパティを反復処理します。

ブラウザやその他の環境では、いわゆる「配列のような」オブジェクトがあり、配列のように見えます。つまり、これらには長さとインデックスのプロパティがありますが、通常は必要としない他の非数値のプロパティとメソッドもある場合があります。for..inループはそれらをリストします。したがって、配列のようなオブジェクトを操作する必要がある場合、これらの「追加の」プロパティが問題になる可能性があります。

for..inループは、配列ではなく汎用オブジェクト用に最適化されているため、10〜100倍遅くなります。もちろん、それはまだ非常に高速です。スピードアップはボトルネックでのみ問題になる場合があります。しかし、それでも違いを認識する必要があります。

一般に、配列にはfor..inを使用しないでください。


0

for...inLoopとfor...ofLoopの違いを覚えておくための便利なニーモニックを以下に示します。

「インデックスイン、オブジェクト」

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

for...of Loop=> オブジェクトのオブジェクトを反復処理します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.