JavaScriptの for…of ループについて

JavaScriptを勉強し始めると早い段階で、for ループに出会う。慣れるまではセミコロンをうっかりカンマで書いてしまったり、ループを止めるタイミングがずれてしまったりしていたが、慣れてくると、何でもかんでもforループで書きたくなって、ネストさせすぎたりしていた。懐かしいあの頃・・・
そんなforループの仲間に、for…ofというループがあるので、今日はfor …ofループについて調べてみる。

for…ofループとは?

例えばArrayを渡すと、Arrayの要素を順に見ていき、指定した処理を実行する。
文字列を渡せば、一文字ずつ指定した処理を実行する、といった具合。

JavaScript
const numbers = [1, 2, 3, 4];

for (const num of numbers) {
  console.log(num * 2);
}

// Output: 2
// Output: 4
// Output: 6
// Output: 8


const string = "platypus";

for (const letter of string) {
  console.log(letter.toUpperCase());
}

// Output: P
// Output: L
// Output: A
// Output: T
// Output: Y
// Output: P
// Output: U
// Output: S

ここまではすんなり理解できたが、for…ofループはイテラブルオブジェクトに対してしか使えないとある。
・・・イテラブルオブジェクトって何?

イテラブルオブジェクト(Iterable Object)とは?

“Iterable” は「反復可能な」とか「繰り返し可能な」と言う意味を持つので、イテラブルオブジェクトは反復可能オブジェクトと訳されている。
ArrayやStringなどは反復可能オブジェクトとなりうるデータ構造を持つので、for…ofループが使える。

先ほどのArrayも[Prototype]を展開すると下の方にSymbol.iteratorというのがある。反復するのに必要なメソッドがこのiteratorの中に用意されている。iteratorの中には次にループ処理する値を呼び出したり、全ての処理が終了したかを確認するメソッドが用意されている。

iterator

しかしここで衝撃の事実が!
普通のオブジェクトは反復可能オブジェクトではないと言う・・・
え?ArrayやStringは反復可能オブジェクトだが、オブジェクトは反復可能オブジェクトではない??

名前に引っ張られて誤解してしまっていたが、確かに通常のオブジェクト(Plain Object)のプロトタイプにはSymbol.iteratorが用意されていない。
でもfor…ofを使いたいときはどうすればいいか?

オブジェクトでのfor…ofを使ったループ処理

方法はある!
ObjectをArrayに読み変えて、反復処理ができるようにしてしまえばいいのだ。
なんだか面倒くさそうに聞こえるかもしれないが、コード自体はそれほど複雑ではない。

以下のメソッドを使用することで、通常のオブジェクトをArrayに変えて反復処理することができるようになる。

Object.keys(platypus) → [“name”, “type”, “specialFeature”]
Object.values(platypus)→ [“Platypus”, “Mammal”, “Lays eggs”]
Object.entries(platypus)→ [[“name”, “Platypus”], [“type”, “Mammal”], [“specialFeature”, “Lays eggs”]]

JavaScript
const platypus = {
  name: "Platypus",
  type: "Mammal",
  specialFeature: "Lays eggs",
};

// その1:Object.keys()を使用してプロパティのキーを反復処理
for (const key of Object.keys(platypus)) {
  console.log(key); // name, type, specialFeature が順番に表示される
}

// その2:Object.values()を使用してプロパティの値を反復処理
for (const value of Object.values(platypus)) {
  console.log(value); // Platypus, Mammal, Lays eggs が順番に表示される
}

// その3:Object.entries()を使用してプロパティと値の組み合わせを反復処理
for (const [key, value] of Object.entries(platypus)) {
  console.log(`${key}: ${value}`);
}
//Output :  name: Platypus
//Output :  type: Mammal
//Output :  specialFeature: Lays eggs

(参考)for…inループ

実はfor…ofの他に、オブジェクトのままでも使えるfor…inというのもあるのだが、特定のシナリオで使いづらいことがあるため、使用は避けた方がいいとのこと。どういう場合に使いづらいのか?気になったので調べてみた。

JavaScript
for (const key in object) {
  if (object.hasOwnProperty(key)) {
    // プロパティに対する処理
  }
}

プロトタイプチェーンの影響: for…inループは、オブジェクト自体のプロパティだけでなく、プロトタイプチェーンに含まれるプロパティも列挙する。そのため、hasOwnProperty()などで余計なプロパティが混ざらないようにするなど、注意しなければならない。

順序の保証がない: for…inループはプロパティの列挙順序を保証しないため、プロパティの順序が重要な場合には問題が生じるかもしれない。

非数値プロパティも対象:for…inループは数値以外のプロパティも対象としているのでたとえば、オブジェクトに関数をプロパティとして持っている場合、それらの関数もループの対象となってしまう。

これに対して、先ほどのObject.keys()、Object.values()、Object.entries()メソッドとfor…ofを組み合わせて使う方法であれば、余計なプロパティが入ってくることもなく、プロパティの順序も保証してくれるため、使いやすいはず。

納得できたところで本日はここまで!


カモノハシは絶滅危惧種かどうかご存知ですか?
野性のカモノハシはオーストラリアにのみ生息しています。
タスマニア州にはいるのに東南アジアやニュージーランドには1匹もおらず、動物園でさえ、その希少価値と飼育の難しさから
アメリカのサンディエゴ動物園を除いて海外の動物園での飼育も許されていません。オーストラリアの中でも東側にしか生息しておらず、その数は年々減り続けています。以下の地図のオレンジの箇所が生息エリアですが、当然シドニーの街中にはおりません。

IUCNレッドリスト
https://www.iucnredlist.org/ja/species/40488/21964009

range

最初の質問(カモノハシは絶滅危惧種かどうか)の答えですが、IUCNレッドリストでは準絶滅危惧(NT)にカテゴライズされています。現段階では「絶滅危惧」の要件を満たしていないが、近い将来そうなると考えられている種であるという評価だそうです。この可愛さを広めることでなんとか食い止めたいと思っています。人間の過ちはループしませんように。

類似投稿