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

推薦する

Vue.jsはシンプルな折りたたみパネルを実装します

この記事では、Vue.jsの具体的なコードを共有して、シンプルな折りたたみパネルを実装する例を紹介し...

XHTML CSS ページをプリンタ ページに変換する

以前は、Web ページのプリンタ対応バージョンを作成するには、印刷したときに見栄えがよくなるようにレ...

Dockerfile における ENV 命令の具体的な使用法の詳細な説明

1. Dockerfile 内の ENV 命令は、イメージの環境変数を定義するために使用されます。次...

JavaScript は詳細なコードで星座クエリ機能を実装します

目次1. タイトル2. コード3. 結果IV. 結論1. タイトルテキスト ボックスに誕生日の値を入...

JSに関する7つの面接の質問、あなたはいくつ正しく答えられますか

序文JavaScript では、これは関数呼び出しコンテキストです。この動作が非常に複雑であるからこ...

MySQL 8.0.21.0 コミュニティ エディションのインストール チュートリアル (詳細な図解)

1. MySQLをダウンロードするMySQL 公式 Web サイトにログインし、MSI インストー...

Vue 名前付きスロットの基本的な使用例

序文名前付きスロットは、スロット内の「name」属性を使用して要素にバインドされます。知らせ: 1....

Centos7にTenda U12ワイヤレスネットワークカードドライバーをインストールする際の問題を解決する

解決プロセス:方法1: CentOS7.3 のデフォルトのカーネル バージョンは低く、3.10.0-...

MySQL ALTERコマンドの知識ポイントのまとめ

テーブル名を変更したり、テーブル フィールドを変更したりする必要がある場合は、 MySQL ALTE...

HTMLページが3秒後に自動的にジャンプする3つの一般的な方法

実際には、N 秒後にページを自動的にジャンプさせるにはどうすればよいかという問題によく遭遇します。私...

カーソル ループを使用して、MySQL ストアド プロシージャで一時テーブルを読み取る

カーソルカーソルは、結果セット内のデータを表示または処理するために使用される方法です。カーソルを使用...

Docker を使用して MySQL および Redis サービスをデプロイする方法

目次Dockerを使用してMySQLサービスをデプロイする方法DockerでRedisサービスをデプ...

Quill エディタでカスタム HTML レコードを挿入する詳細な例

もう2020年です。飢えた人間は単純なテキストでは満足できなくなり、さまざまなスタイルの派手なテキス...

JavaScriptスコープについての簡単な説明

目次1. 範囲1. グローバルな範囲2. ローカルスコープ2. 変数のスコープ1. グローバル変数2...