質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

3回答

534閲覧

引数の{}について、イテレータのプロパティと返り値について

susumu-99

総合スコア44

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

1クリップ

投稿2022/11/13 06:37

たびたびお世話になります。
よろしくお願いします。

本日、イテレータの学習中に分からない箇所が数カ所あり、質問させていただきたく投稿させていただきました。

書籍に以下のコードが掲載されています。

JavaScript

1class Log{ 2 constructor(){ 3 this.messages = []; 4 } 5 add(message){ 6 const now = Date.now(); 7 console.log(`ログ追加:${message}(${now})`); 8 this.messages.push({message, timestamp: now}); //①この({…})内のmessage 9 } 10 [Symbol.iterator](){ //③ここの[Symbol.iterator]()の定義 11 let i = 0; 12 const messages = this.messages; 13 return { 14 next: () => i >= messages.length ? //②ここのnext 15 {value: undefined, done: true} : {value: messages[i++], done: false} 16 } 17 } 18}

質問は以下のとおりです。

① push()メソッドの引数が({message, timestamp: now})となっています。
今まで{}内はオブジェクトになるように思っていました。
しかしながら、ここには書いていませんが、この後段にあるLogクラスのインスタンス(new Log)ではlog.add(‘クジラを見た’)となっていて、オブジェクトではありません。
{}内は必ずしもオブジェクトにならないかもしれませんが、ではこの{message,…}は何かということを疑問に思いました。
サイト等で調べると、「分割代入」というものを見つけましたが、この場合は違うような気がしました。
このmessageが何か分かりますでしょうか?

② ここのreturn {next:…} の部分ですが、
Symbol.iterator関数内でreturn {next:…}を返し、next()メソッドの値を定義、または上書きしているのでしょうか?
メソッドの値はこういう形で定義、または上書きできるものでしょうか。

③ このSymbol.iteratorのメソッドの定義はなぜ必要なのでしょうか。
イテラブルなものはSymbol.iteratorのメソッドを元から持っているので、Symbol.iteratorのメソッドの定義は必要ないように思います。
messagesに対するSymbol.iteratorとして設定するためでしょうか?

また同じ書籍に次のコードが掲載されています。

JavaScript

1class FibonacciSequence { 2 [Symbol.iterator](){ 3 let a = 0, b = 1; 4 return { 5 next() { //このnext 6 let rval = {value: b, done: false}; 7 b += a; 8 a = rval.value; 9 return rval; 10 } 11 }; 12 } 13 }

というものがあります。
上の②の質問に関する質問になりますが、
コード中のnext()は、
Class FibonacciSequenceがSymbol.iteratorによってイテレータ化したものは、next()のメソッドを持つので、その値の定義、もしくは上書きしていると考えていいですか?
だとすると、上の質問②とは違う形でnext()のメソッドを設定しています。
この②と④の違いはどのように考えればいいのでしょうか?

質問がてんこもりになってしまい申し訳ありません。
わかるものだけでけっこうですので、どなたか知見をお持ちの方回答よろしくお願いします。

(参考書籍「初めてのJavaScript」第3版 オライリー・ジャパン P201~203)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

BeatStar

2022/11/13 09:02

最初のLogクラスのmessagesを表示するとどうなるでしょうか?
guest

回答3

0

Text

1{}はブロックでもある。

投稿2022/11/13 08:31

atcoderyellow

総合スコア481

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

susumu-99

2022/11/13 08:53

回答ありがとうございます。 なるほど!たしかにブロックも{}で括りますね。
atcoderyellow

2022/11/13 09:29

@ToWhoeverDownvotedMe 無言低評価禁止
susumu-99

2022/11/15 11:43

心無い評価がついてしまったみたいでm(__)m 回答感謝しています。 ありがとうございました。
atcoderyellow

2022/11/15 11:45

ありがとうございます。どういたしまして。
guest

0

ベストアンサー

① push()メソッドの引数が({message, timestamp: now})となっています。
今まで{}内はオブジェクトになるように思っていました。

オブジェクトを作って push() に渡している、で間違いないです。そのオブジェクトの timestamp プロパティは変数 now の内容、message プロパティは変数 message の内容になります。message には「略記プロパティ名」が使われています。

② ここのreturn {next:…} の部分ですが、

next() メソッドを持ったオブジェクトを返しています。

③ このSymbol.iteratorのメソッドの定義はなぜ必要なのでしょうか。
イテラブルなものはSymbol.iteratorのメソッドを元から持っているので、Symbol.iteratorのメソッドの定義は必要ないように思います。

クラス Log のインスタンスが反復処理可能になる(for of やスプレッド構文に使える)ために必要です。このメソッドを消すと反復可能プロトコルも反復子プロトコルもないのでイテラブルではありません。

上の質問②とは違う形でnext()のメソッドを設定しています。
この②と④の違いはどのように考えればいいのでしょうか?

クラスの内部構造が異なれば next() の実装も異なるものが必要です。

投稿2022/11/13 21:45

int32_t

総合スコア20929

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

susumu-99

2022/11/15 13:58

回答ありがとうございます。 昨日は仕事が遅く返信することができずすいません。 ①は回答を読ませていただきその通りだと思いました。 初めて「略記プロパティ名」の存在を知りました。勉強になりました。 ②も少し分かりましたが、このnextの値はどのように書けば、使用できるのだろうかと疑問は尽きません。(インスタンス名[Symbol.iterator]().nextでしょうか。でもなんか違う気がしています。) これはとりあえずおいておいて ③について、私の知識が薄く回答に頭がついていかないため、もう少し詳しく教えていただければと思いました。 [Symbol.iterator]()は、Logのインスタンスをイテレータに変えてnext()のメソッドを使用できるようにしてのかと思いましたが、ちがうんですね。 というのは、 この質問のコードの後段で、 const log = new Log(); … for(let entry of log){…} という部分が出てきますが、この[Symbol.iterator]の部分がないと、エラー表示(log is not iterable)が出て機能しません。 クラスLogのコンストラクタの中でmessagesは配列として設定していてもLogはイテラブルなものにならないんでしょうか。 また、[Symbol.iterator]はイテラブルなものをイテレータにすると思っていましたが、 この場合は、イテラブルではないものをイテラブルにするために使用しているのでしょうか。 質問を重ねて申し訳ありません。。 できましたらご教授よろしくお願いします。 ④についてはクラスの内容構造とは何なのかもう少し考えてみます。 今少しだけVueもかじっているのですが、Vueでもオブジェクトで書くものとメソッド(この表現が正しいか分かりませんが)で書くものとあって何が違うか気になっていました。 まずは③から解決できればと思っていますので、よろしくお願いします。
int32_t

2022/11/15 22:10

> このnextの値はどのように書けば、使用できるのだろうかと疑問は尽きません。 https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Iteration_protocols#%E5%8F%8D%E5%BE%A9%E5%87%A6%E7%90%86%E3%83%97%E3%83%AD%E3%83%88%E3%82%B3%E3%83%AB%E3%81%AE%E4%BD%BF%E7%94%A8%E4%BE%8B に利用例がありますが、こういうコードを書くことは稀だと思います。for of やスプレッド構文でだいたい足りるので。 > Logのインスタンスをイテレータに変えてnext()のメソッドを使用できるようにしてのかと思いましたが、ちがうんですね ええ、違います。Logインスタンス用のイテレータを作ります。 > messagesは配列として設定していてもLogはイテラブルなものにならないんでしょうか。 なりません。プロパティのイテラブルとその所有オブジェクトのイテラブルは関係ありません。あるクラスのイテラブルとそれを継承した子クラスのイテラブルは関係あります。 > イテラブルではないものをイテラブルにするために使用しているのでしょうか。 はい。イテレータを提供するからイテラブルになります。イテレータを提供しなければイテラブルではありません。
susumu-99

2022/11/16 10:11

何度も回答いただきありがとうございます。大変助かります。 回答を読ませてもらいなんとなくは分かった気がしますが、もう一度考えてみます。 その後ベストアンサーにさせていただきます。 ありがとうございました。
susumu-99

2022/11/17 14:30

お世話になります。 何度もすいません。 MDNサイトのご紹介ありがとうございます。 大変分かりやすい内容でした。 ただ不明な箇所が一カ所あり教えていただければと思いコメントを書かせていただきました。 このサイトの最後の「括弧表記の使用法」のソースコード、 function logIterable(it) { if (!(Symbol.iterator in it)) { console.log(it, ' is not an iterable object.'); return; } const iterator = it[Symbol.iterator](); for (const letter of iterator) { console.log(letter); } } logIterable(['a', 'b', 'c']); logIterable('abc'); logIterable(123); の部分ですが、 自分で書いても、またソースコードをコピペしてもエラーが出ます。 エラー内容は、 Uncaught TypeError: Cannot use 'in' operator to search for 'Symbol(Symbol.iterator)' in abc at logIterable というものです。 このソースコードの意味はだいたい分かります。 でも、エラー内容では、細かいことは分かりませんが、'abc'では’in’が使用できないという意味だと思うのですが、なぜこの表示がでるのか知りたいと思っています。 (また、このlogIterable('abc');をコメント化すると、 Uncaught TypeError: Cannot use 'in' operator to search for 'Symbol(Symbol.iterator)' in 123 at logIterable と出ます。) どうかよろしくお願いします。
int32_t

2022/11/17 22:12

> このサイトの最後の「括弧表記の使用法」のソースコード、 どのサイトのことでしょうか。 > 'abc'では’in’が使用できないという意味だと思うのですが はい。文字列リテラルや数値に in は使用できません。
susumu-99

2022/11/18 00:59

回答ありがとうございます。 先ほどの回答で教えていただいたMDNのサイトです。
susumu-99

2022/11/19 21:57

紹介していただいたMDNのサイト改めて見させていただきました。 ジェネレータやSetなどまだ分からない箇所もありましたが、回答で教えていただいた箇所も多く、なんとなくですが内容が分かったように思います。 少しでも分かると面白いですね!サイトの紹介ありがとうございました。
int32_t

2022/11/20 22:00

人が書いているものですから、MDNの内容が間違っていたり古い仕様に基づいていたりということは、たまにあります。
susumu-99

2022/11/21 13:33

たまにあるんですか。 モジラーなのに… まだ最後の質問が自己解決できていませんが、この質問についてはこれでクローズとさせていただきます。 重ね重ねありがとうございました。 この質問で回答をいただき解決できた内容のまとめは後日トップに掲載したいと思います。 回答いただけて大変助かりました。
guest

0

① push()メソッドの引数が({message, timestamp: now})となっています。
今まで{}内はオブジェクトになるように思っていました。

この場合もオブジェクトですよ。ただ所謂連想配列っていうやつです。

② ここのreturn {next:…} の部分ですが、
Symbol.iterator関数内でreturn {next:…}を返し、next()メソッドの値を定義、または上書きしているのでしょうか?
メソッドの値はこういう形で定義、または上書きできるものでしょうか。

これも連想配列として返していますね。

ただ、

JavaScript

1 return { 2 next: () => i >= messages.length ? //②ここのnext 3 {value: undefined, done: true} : {value: messages[i++], done: false} 4 }

とした場合、nextは「関数」となります。() => { ... }アロー関数と言っていたはずです。(C++とかだとラムダ式って呼ばれるタイプ)
JavaScriptでは関数も整数も文字列もクラスオブジェクトもすべてオブジェクトとみなすので、アロー関数で指定しています。

今回のコードをもうちょっと読みやすく書くと、

return { next: () => { return (i >= messages.length ? {value: undefined, done: true} : {value: messages[i++], done: false}); } }

となります。return の直後に書かれているi >= messages.length ? ... : ... は条件演算子(三項演算子とも)といい、if文みたいなやつです。
つまり、i >= messages.length を満たすなら ○○、そうじゃないなら△△という感じですね。

よって、iがmessages.length以上なら{value: undefined, done: true}を返し、そうでないなら{value: messages[i++], done: false}を返す。
返されているのは上記でも書いた、連想配列。

その処理をするアロー関数をnextとする。つまりnext関数を定義してますね。

③ このSymbol.iteratorのメソッドの定義はなぜ必要なのでしょうか。
イテラブルなものはSymbol.iteratorのメソッドを元から持っているので、Symbol.iteratorのメソッドの定義は必要ないように思います。
messagesに対するSymbol.iteratorとして設定するためでしょうか?

それは配列 messagesの方ですよね? Logクラスの方ではありません。
そして、ちょっと[Symbol.iterator]()という書き方は私にとっては初めて見たので調べてみました。
「JavaScript Symbol.iterator」でggると、反復可能なオブジェクト - javascript.infoがヒットしました。
こちらによると、

JavaScript

1let logList = new Log(); 2// 何らかの処理 3for (let log of logList) { 4 alert(log); 5}

のようにfor...of...でそのまま使えるようにするための定義らしいです。(for...ofが内部で使うためだと思う)

投稿2022/11/13 09:22

編集2022/11/13 09:31
BeatStar

総合スコア4958

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

susumu-99

2022/11/15 14:12

回答ありがとうございます。 連想配列とはJavaScriptでいうオブジェクトのことですね! for…ofは配列でも使用できます。 また、私もこの質問の直前に読んだ知識になりますが、[Symbol.iterator]はイテラブルなものをイテレータにするために使用するものらしいです。 ・イテラブルというのはfor…ofの使用できるもの ・イテレータはnext()を使用できるもの という認識です。 そのためイテレータはイテラブルと違い配列からnext()により1つずつ要素を引き出せるようになります。 あとの内容は…だいたい知っていました。 回答いただけたこと大変感謝しています。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問