ES6 ループと反復可能オブジェクトの例

ES6 ループと反復可能オブジェクトの例

この記事では、ES6 の for ... of ループについて説明します。

古い方法

以前は、JavaScript をトラバースする方法が 2 つありました。

まず最初に、古典的な for i ループを紹介します。これを使用すると、配列またはインデックス可能で長さプロパティを持つ任意のオブジェクトを反復処理できます。

for(i=0;i<things.length;i++) {
 var 物 = 物[i]
 /* ... */
}

2 番目は for ... in ループで、オブジェクトのキーと値のペアをループするために使用されます。

for(キー in things) {
 if(!thing.hasOwnProperty(key)) { 続行; }
 var thing = things[キー]
 /* ... */
}

for ... inループは、オブジェクトの列挙可能なプロパティすべてをループするため、余談と見なされることが多い[1]。これには、プロトタイプ チェーン内の親オブジェクトのプロパティと、メソッドとして割り当てられるプロパティが含まれます。言い換えれば、人々が予想しないようなことが起こります。 for ... in を使用する場合、通常は、不要なプロパティを回避するために、ループ ブロック内に多くのガード句が必要になります。

初期の JavaScript では、この問題をライブラリを通じて解決しました。多くの JavaScript ライブラリ (Prototype.js、jQuery、lodash など) には、each や foreach などのユーティリティ メソッドや関数があり、for i ループや for ... in ループを使用せずにオブジェクトや配列を反復処理できます。

for ... of ループは、サードパーティのライブラリを必要とせずにこれらの問題の一部を解決しようとする ES6 の方法です。

…の

for ... ループ

for(const もののもの) {
 /* ... */
}

反復可能なオブジェクトを反復処理します。

反復可能オブジェクトは、反復プロトコルを実装するオブジェクト、またはジェネレータ関数を返す @@iterator メソッドを定義するオブジェクトです。

この文には理解すべき点がたくさんあります。

  • 反復可能なオブジェクト
  • @@iterator メソッド (@@ はどういう意味ですか?)
  • イテレータ プロトコル (ここでのプロトコルとはどういう意味ですか?)
  • 待ってください、iterable と iterator は同じものではありませんか?
  • また、ジェネレータ関数とは何でしょうか?

これらの質問に一つずつ答えていきましょう。

組み込みの反復可能

まず、配列オブジェクトなど、JavaScript の一部の組み込みオブジェクトは、自然に反復可能です。次のコードに示すように、 for ... of ループ内で配列を使用できます。

定数foo = [
「リンゴ」、「オレンジ」、「ナシ」
]

for(const のもの foo) {
 console.log(もの)
}

出力は配列内のすべての要素です。

リンゴ
オレンジ

配列には、反復可能なオブジェクトを返すエントリ メソッドもあります。この反復可能オブジェクトは、ループを通過するたびにキーと値を返します。たとえば、次のコード:

定数foo = [
「リンゴ」、「オレンジ」、「ナシ」
]

for(const のもの foo.entries()) {
 console.log(もの)
}

次のように出力されます

[ 0, 'リンゴ' ]
[ 1, 「オレンジ」 ]
[ 2, 「梨」 ]

エントリ メソッドは、次の構文を使用する場合にさらに便利です。

定数foo = [
 「リンゴ」、「オレンジ」、「ナシ」
]

for(const [キー, 値] of foo.entries()) {
 console.log(キー,':',値)
}

for ループでは 2 つの変数が宣言されます。1 つは返される配列の最初の項目 (値のキーまたはインデックス) 用で、もう 1 つは 2 番目の項目 (インデックスが対応する実際の値) 用です。

単純な JavaScript オブジェクトは反復可能ではありません。次のコードを実行すると:

// 正常に実行できません const foo = {
 「リンゴ」:「オレンジ」,
 「梨」:「プルーン」
}

for(const [キー, 値] of foo) {
 console.log(キー,':',値)
}

エラーが発生します

$ ノードテスト.js
/path/to/test.js:6
for(const [キー, 値] of foo) {
TypeError: foo は反復可能ではありません

ただし、グローバル Object オブジェクトの静的エントリ メソッドは、プレーン オブジェクトを引数として受け入れ、反復可能なオブジェクトを返します。次のようなプログラム:

定数foo = {
 「リンゴ」:「オレンジ」,
 「梨」:「プルーン」
}

Object.entries(foo) の const [キー、値] の場合) {
 console.log(キー,':',値)
}

期待通りの出力が得られます:

$ ノードテスト.js
リンゴ:オレンジ
梨:プルーン

独自の反復可能オブジェクトを作成する

独自の反復可能なオブジェクトを作成する場合は、もう少し時間がかかります。先ほど私が言ったことを覚えているでしょう。

反復可能オブジェクトは、反復プロトコルを実装するオブジェクト、またはジェネレータ関数を返す @@iterator メソッドを定義するオブジェクトです。

これを理解する最も簡単な方法は、反復可能なオブジェクトを段階的に作成することです。まず、@@iterator メソッドを実装するオブジェクトが必要です。 @@ 表記は少し誤解を招きやすいですが、実際に行っているのは、定義済みの Symbol.iterator シンボルを使用してメソッドを定義することです。

イテレータ メソッドを使用してオブジェクトを定義し、それを反復処理しようとすると、次のようになります。

定数foo = {
 [シンボル.イテレータ]: 関数() {
 }
}

for(const [キー, 値] of foo) {
 console.log(キー、値)
}

新しいエラーが発生しました:

for(const [キー, 値] of foo) {
^
TypeError: Symbol.iterator メソッドの結果がオブジェクトではありません

これは、Symbol.iterator メソッドを呼び出そうとしているが、呼び出しの結果がオブジェクトではないことを通知する JavaScript です。

このエラーを解消するには、イテレータ メソッドを使用して、イテレータ プロトコルを実装するオブジェクトを返す必要があります。つまり、イテレータ メソッドは次のキーを持つオブジェクト (関数) を返す必要があります。

定数foo = {
 [シンボル.イテレータ]: 関数() {
 戻る {
 次へ: 関数() {
 }
 }
 }
}

for(const [キー, 値] of foo) {
 console.log(キー、値)
}

上記のコードを実行すると、新しいエラーが発生します。

for(const [キー, 値] of foo) {
^
TypeError: イテレータの結果が未定義なのでオブジェクトではありません

今回は、JavaScript は Symbol.iterator メソッドを呼び出そうとしたことを通知します。オブジェクトは確かにオブジェクトであり、 next メソッドを実装していますが、 next の戻り値は JavaScript が予期したオブジェクトではありません。

次の関数は、value と done という 2 つのキーを持つ特定の形式のオブジェクトを返す必要があります。

次へ: 関数() {
 //...
 戻る {
 完了: false、
 値: '次の値'
 }
}

完了キーはオプションです。値が true の場合 (反復子が反復処理を終了したことを示します)、反復処理は終了しています。

done が false または存在しない場合は、値キーが必要です。値キーは、これをループすることによって返される値です。

したがって、最初の 10 個の偶数を返す単純な反復子を含む別のプログラムをコードに追加します。

クラス First20Evens {
 コンストラクタ() {
 this.currentValue = 0
 }

 [シンボル.イテレータ]("シンボル.イテレータ") {
 戻る {
 次へ: (function() {
 this.currentValue+=2
 現在の値が20以上の場合
  {done:true} を返す
 }
 戻る {
  値:this.currentValue
 }
 }).bind(これ)
 }
 }
}

const foo = new First20Evens;
for(fooのconst値) {
 console.log(値)
}

ジェネレータ

イテレータ プロトコルを実装するオブジェクトを手動で構築することが唯一の選択肢ではありません。ジェネレーター オブジェクト (ジェネレーター関数によって返される) もイテレータ プロトコルを実装します。上記の例は、ジェネレータを使用して構築すると次のようになります。

クラス First20Evens {
 コンストラクタ() {
 this.currentValue = 0
 }

 [シンボル.イテレータ]("シンボル.イテレータ") {
 関数*()を返す{
 (i=1;i<=10;i++) の場合 {
 もし(i % 2 === 0) {
  利回り i
 }
 }
 }()
 }
}

const foo = new First20Evens;
for(fooのconst項目) {
 コンソール.log(アイテム)
}

この記事ではジェネレーターについて詳しく説明しません。入門書が必要な場合は、この記事をお読みください。今日の重要なポイントは、Symbol.iterator メソッドがジェネレーター オブジェクトを返すようにでき、そのジェネレーター オブジェクトが for ... of ループ内で「そのまま機能する」ということです。 「正常に動作する」とは、ジェネレータが値を生成しなくなるまで、ループがジェネレータの next を呼び出し続けることを意味します。

$ ノードサンプルプログラム.js
2
4
6
8
10

参考文献

オブジェクトの各列挙可能なプロパティ: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in

要約する

ES6 ループと反復可能オブジェクトに関するこの記事はこれで終わりです。ES6 ループと反復可能オブジェクトの詳細については、123WORDPRESS.COM で以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • ES6イテレータと反復可能オブジェクトの実装
  • es6 for ループにおける let と var の違いの詳細な説明
  • ES6 チュートリアル for loop と Map、Set の使用状況分析
  • ES6 の新機能 2: イテレータ (トラバーサル) と for-of ループの詳細な説明
  • ES6 イテレータと for.of ループの使い方の学習 (要約)
  • CommonJSとES6のモジュールループ読み込み処理の違いを詳しく解説
  • ES6 入門チュートリアル: イテレータと for...of ループの詳細な説明
  • ES6 Iterator インターフェースと for...of ループの使用法の分析

<<:  Linux で ping は成功するがポートが利用できない問題を解決する方法

>>:  MySQLデータベーステーブルの定期バックアップの実装の詳細な説明

推薦する

JavaScriptはキュー構造プロセスを実現する

目次1. キューを理解する2. カプセル化キュー3. 太鼓をたたいて花を渡す場合1. キューを理解す...

MySQLデータベースインデックスの詳細な紹介

目次マインドマップシンプルな理解インデックスモデルの進化二分探索木自己バランス型二分木BツリーB+ ...

タグのhref属性とonclickイベントの使用例

a タグは主にページ ジャンプを実装するために使用され、これは href 属性または onclick...

Docker での MySQL 8.0.20 のインストールと設定のチュートリアル

Dockerは参考までにMySQLバージョン8.0.20をインストールします。具体的な内容は以下のと...

インターフェーステストプラットフォームを構築するためのDjango+Vue+Dockerの詳細な説明

1. 冒頭の2つの単語みなさんこんにちは。私の名前はLin Zonglinです。私はテストエンジニア...

Docker JVM メモリ使用量の表示

1. Docker コンテナのホスト マシンに入り、指定されたイメージを実行しているコンテナ ID ...

1 つ以上の Linux インスタンスから SSH キー ペアのバインドを解除します。

キーペアの分離1 つ以上の Linux インスタンスから SSH キー ペアのバインドを解除します。...

ElementUIはドロップダウンオプションと複数選択ボックスのサンプルコードを実装します

目次ドロップダウン複数選択ボックスアップグレード - すべてのオプションを追加改訂と改善を求める製品...

Vue は Tencent Map を統合して API を実装します (デモ付き)

目次執筆の背景プロジェクトの説明事前準備注記執筆の背景以前のプロジェクトではTencent Maps...

jsを使用して簡単なスネークゲームを書く

この記事では、参考までに、jsで書かれたシンプルなスネークゲームの具体的なコードを紹介します。具体的...

HTML タイトル属性をラップする方法

数日前にプログラムを書いていたとき、プロンプト情報 (TITLE) を新しい行で囲みたいと思いました...

Vueのミックスインと継承について詳しく説明します

目次序文ミキシンMixin ノート (重複名)ローカルミックスイングローバル ミックスイン継承するミ...

Linuxのファイル操作の知識ポイントを詳しく解説

ファイル操作に関連するシステムコール作成するint creat(const char *ファイル名,...

CSS 動的高さ遷移アニメーション効果の実装

この質問は、Nuggets のメッセージから生まれました。友人が、次のコードの高さ遷移アニメーション...

HTMLリンクタグのrel属性

<link> タグは、現在のドキュメントと Web コレクション内の他のドキュメントとの...