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データベーステーブルの定期バックアップの実装の詳細な説明

推薦する

HTMLウェブページテーブル構造化マークアップの応用に関する簡単な説明

Web テーブルの構造マークアップについて説明する前に、いくつかの画像を見てみましょう。 HTML ...

MySQLコマンドが中国語で入力できない問題の解決方法

問題を見つける最近、MySQL コマンドを使用して MySQL サーバーに接続したときに、以下のよう...

MySQL 8.0.14 のインストールと設定方法のグラフィックチュートリアル (一般)

MySQLサービス8.0.14のインストール(一般)の参考までに、具体的な内容は次のとおりです。イ...

デザイン理論: なぜ私たちは間違った場所を見ているのでしょうか?

数日前、バスで仕事に行きました。バスのカードリーダーの実際の使用シーンを実際に見て、カードリーダーの...

type=fileファイル変更フォームの名前が正常にエコーされない問題を解決

easyui フレームワークのコードは次のとおりです。 css: .ファイルボックス{ フロート:...

MySQL 上級学習インデックスの長所と短所、使用ルール

1. インデックスの利点と欠点利点: 高速検索、高速グループ化および並べ替えデメリット: ストレージ...

面接でよく聞かれる Vue 修飾子 13 個

目次1. 怠惰な2.トリム3.番号4.停止5. キャプチャ6.自分7.一度8.予防する9.ネイティブ...

Dockerfile における ENTRYPOINT と CMD の違い

Docker システムの学習チュートリアルでは、Dockerfile を使用して Docker イメ...

RHCE ブリッジング、パスワード不要のログイン、ポート番号の変更の概要

目次1. ブリッジを設定し、検証のためにパケットをキャプチャする1. ブリッジデバイスとセッションを...

Win7 64 ビット版に MySQL 5.7 をダウンロードしてインストールする際によくある問題の概要

1. 公式ウェブサイトからMySQLをダウンロードします。 これが私たちが探しているものです、win...

Zabbixで指定時間内の変化値を設定する方法の詳細な説明

背景説明: 既存の負荷分散装置には、付加価値状態にある指標があります (増加するだけで減少しないため...

Ubuntu システムにおけるネットワーク構成ファイルの分析と説明

今日は奇妙なネットワーク問題に遭遇しました。調査プロセスといくつかの構成状況を記録し、Linux で...

.Net Core を使用して数千万のデータを MySQL にインポートする手順

目次事前準備実施方法: 1. 単一のデータを挿入する2. マージデータ挿入3. MySqlBulkL...

bash を使って日付をカウントダウンする方法

重要なイベントまであと何日あるか知りたいですか? Linux bash と date コマンドが役に...

MySQL データベースでよく使用される SQL ステートメントの詳細と概要

この記事では、MySQL データベースでよく使用される SQL ステートメントを例を使用して説明しま...