〽️ フツーのif文との違い。 〽️ なぜfor inは配列に不向きなのか? 〽️ オブジェクトの値をループする方法。
JavaScriptコードの「?」をまとめたページはこちら⬆︎。
「「3//オブジェクトのプロパティを処理」」 for(let a in obj) { } 「「3//配列の値を処理」」 for(let b of arr) { }
こんにちは、「ふ」です。
JavaScriptコードの「これって何?」、今回はこちら⬇︎。
「「1for」」(let j 「「1in」」 obj) { } 「「4for」」(let k 「「4of」」 array) { }
for in/of文は、指定されたグループの内容に対して、ループ処理を行う構文です。
通常のfor文が
for(i=0;i<10;i++) { }
というように、自分で反復条件や対象や範囲を設定するのに対して、for inやfor of文は
for(j in 「「1obj」」) { } for(k of 「「4array」」) { }
配列やオブジェクトなどの指定先を決めて、その内容に対する反復処理を行います。
範囲があらかじめ決まっているので、無限ループ回避のための継続条件を指定する必要もありません。
今回はfor in文とfor of文のそれぞれの役割について、紹介していきます。
また1番頭を悩ませるところである「for inが配列に適さない理由」や「オブジェクトの値を得る方法」についても紹介していきます。
2つのループ処理を理解して、自分でも使いこなせるようになりましょう。
for of文から見ていきましょう。
for of文は、配列や文字列などの「順番をもったもの」から「値」をindex順に取り出し、反復処理を行うことができます。
for(変数 of 対象の配列など) { 処理 }
記述はforのあとに丸括弧で引数のスペースを作り、その中に変数、反復処理の対象を「of」で繋ぎます。
let arr1 = ["a","b","c"];
3つの値が入っている配列を作りました。
この配列の値を順にconsole.logしたい。フツーのfor文でやってみます。
for(i=0; i<arr1.length; i++) { console.log(arr1[i]); } 「「3// ▶︎ a」」 「「3// ▶︎ b」」 「「3// ▶︎ c」」
カウンターとして使う変数「i」を用意し、arr1のインデックスとして使うことで値にアクセスしています。
それではfor of文を使ってこの処理を行ってみましょう。
for(let j of arr1) { }
ここで用意した「j」はカウンター変数ではありません。
「j」自体が、arr1の中に含まれている値をインデックスに沿って順番に呼び出します。
for(let j of arr1) { console.log(j); } 「「3// ▶︎ a」」 「「3// ▶︎ b」」 「「3// ▶︎ c」」
「j」そのものをconsole.logすると、値を順番に出力することができました。
for of文を使うと、フツーのfor文と比べて手続きがとてもシンプルになります。
for(i=0; i<arr1.length; i++) { console.log(arr1[i]); }
通常のfor文で行っている処理は、
① 「 i = 0 」←カウンター変数を宣言、初期化
② 「 i < arr1.length 」←継続条件を明記(無限ループ防止のため)
③ 「 i++ 」←反復処理の順序を明記
④ 「 arr1[ i ] 」←カウンター変数を配列のインデックスとして使うことで、値を取得
というように、配列の値を反復処理するために4つの手順が必要です。
一方、for of文。
for(let j of arr1) { console.log(j); }
宣言した変数「j」には、対象の値そのものが入ります。そして反復処理の対象には、あらかじめ要素の数や順番の決まっている配列「arr1」が指定されています。
そのため、
① 変数は宣言だけ。arr1[ 0 ]から処理を始めることが強制されるので、初期化は必要なし。
② 継続条件はarr1の要素の数。指定の必要なし。
③ 反復処理の順番はarr1のインデックス順。指定の必要なし。
④「 j 」には値そのものが入るので、あらためてarr1を呼び出して添字経由で値を取得する必要もなし。
といったよう。
値は予め取得され、反復に関する条件は指定先のarr1に強制的に定義されるため、コード・内部的な処理の両方をシンプルに実装することができます。
for in文です。
for inは、オブジェクトや配列の「値」ではなく、プロパティやインデックスに対して反復処理をおこないます。
for(変数 in 対象のオブジェクトなど) { 処理 }
記述についてはfor in文と同じ要領で、変数宣言と対象となるグループを「of」で繋ぎます。
let obj1 = { a:1, b:2 }
簡単なオブジェクトを作ってみました。
for in文でプロパティを取り出してみましょう。
for(let c in obj1) { console.log(c); } 「「3 //▶︎ a」」 「「3 //▶︎ b」」
プロパティを取り出すことができました。
for(「「4let」」 a in obj) { } for(「「4let」」 b of array) { }
ちょっと脱線しますが、for in/of文で変数を宣言するときの「let」の記述について。
書籍やサイトでの構文を見ていると、変数名の前に必ず「let」もしくは「const」をつけて宣言されています。しかし調査中に気付いたことなのですが、
for(a in obj) { } for(b of array) { }
というように、変数宣言の際の「let」を省略してもプログラムはフツーに動きました。
4つのブラウザ(Chrome、Safari、Firefox、Edge)で動作確認済みです。
「letは必要ないんじゃないか?」と思う「ふ」でありますが、他の文献などにならって記事内では「let」を付けてコードを紹介していくことにします。
for inでオブジェクトのプロパティを取り出せるのはわかりました。
では値のほうを取り出して処理するにはどうすればいいのでしょうか?
for of文は「反復可能なグループ」に対してしか、使うことができません。「反復可能」というのは、Array(配列)やString(文字列)などの「順番を持っているもの」のことです。
ときに、オブジェクトは「順番」を持っていません。
フツーにfor ofを使って値の取得を試みてみます。
let obj3 = { bba:"anko", bbi:"inko" bb}; for(let c of obj3) { console.log(c); } 「「3▶︎ Uncaught TypeError: obj is not iterable (オブジェクトは反復できません)」」
「オブジェクトは反復できない(順番を持っていない)のでダメ!」とエラーが出ます。
どうすればいいのか?
ここではオブジェクトの値に対してループ処理を行う方法を2つ、紹介します。
Object.values(オブジェクト名)
Object.valuesメソッドは、オブジェクトの値を配列状にして取得することができます。先ほどのobj3に対して、
console.log(Object.values(obj3)); 「「3//▶︎ (2) ['anko', 'inko'] 」」
obj3の値が配列になって返りました。つまり、「順番を持つもの」として取得できたことになります。
これを使って、
for(let c of 「「1Object.values(obj3)」」) { console.log(c); } 「「3// ▶︎ anko // ▶︎ inko」」
値を順番にconsole.logすることができました。
あるいはfor inを使って、
for(let c in obj) { console.log(「「1obj[c]」」); } 「「3// ▶︎ anko // ▶︎ inko」」
for inで取得したプロパティを利用して、オブジェクトの値のほうにアクセスしています。このやり方でも値に対してのループ処理が可能です。
ちょっとふしぎなのが、
console.log(「「4obj.c」」); 「「3//▶︎ error」」
通常のオブジェクト→プロパティにアクセスするための「. 」でつなぐとエラーとなります。
console.log(「「1obj[c]」」);
⬆︎というように、プロパティを角括弧で囲まないとうまく動いてくれません。
ふしぎ。謎が解明されたら追記したいと思います。
for in文について調べていると、「配列には使うべきではない」とされているのを目にします。
その理由は、「順序が保証されていない」からとのこと。←一体どういうことなのでしょうか?
let arr2 = ["イチロー","ジロー"];
配列を作りました。現在のインデックスと値は、
console.log(arr2); 「「3 ▶︎ 0:"イチロー"」」 「「3 ▶︎ 1:"ジロー"」」
となっています。for inを使って値を取り出してみましょう。
for(let m in arr2) { console.log(arr2[m]); } 「「3▶︎ イチロー」」 「「3▶︎ ジロー」」
あれ? フツーに順番通りに出力できました。
「for inを配列に使うな」と言ったのは誰じゃ!?となりますよね。
ただしこれ、配列に対して順番に処理がなされているだけで、インデックスに基づいていないんです。
let arr2 = ["イチロー","ジロー"];
ここで、この配列に要素を追加します。
arr2[3] = "シロー";
arr2[2]ではなく、[3]に要素を追加。
そうするとarr2の値の数は、
console.log(arr2.length); 「「3▶︎ 4」」
要素は「タロー」「ジロー」「シロー」の3つになったはずなのに、lengthは「4」と出力されました。インデックスと値を確認してみましょう。
console.log(arr2); 「「3 ▶︎ 0:"イチロー"」」 「「3 ▶︎ 1:"ジロー"」」 「「3 ▶︎ 2:「「4undefined」」」」 「「3 ▶︎ 3:"シロー"」」
インデックス[2]のところに、「undefined(未定義)」が追加されています。
配列は「順番を持つ」ものなので、[2]を飛ばして[3]の値を追加したとき、自動的に「未定義の[2]」が追加されるのです。
ちょっとふしぎな配列のこの性質ですが、便利な側面も持っています。
たとえば「出席状況を調べる」といった用途の場合、「undefined」を「欠席」として扱うことができるからです。
ここでfor in文が登場。
反復処理を使って、出席状況を調べてみましょう。
for(let n in arr2) { 「「3//値が存在するなら」」 if(arr2[n]) { 「「3//出席者の名前を出力」」 console.log(arr2[n]); } 「「3//値が存在しなければ」」 else { 「「3//欠席と出力」」 console.log("欠席"); } }
インデックスの値が存在すれば出席者の名前、存在しなければ「欠席」と出力するようにしました。
結果は............
「「3▶︎ イチロー」」 「「3▶︎ ジロー」」 「「3▶︎ シロー」」
ん? 欠席の表示が出ないですね?
インデックス[2]を「欠席」として扱いたかったのですが、「もともと無いもの」とみなされてしまいました。
〜つまりfor in文は、「インデックスを元に処理をしているわけではない」ということです。
こんどはfor of文を使ってやってみましょう。
for(let n of arr2) { 「「3//値が存在するなら」」 if(n) { 「「3//出席者の名前を出力」」 console.log(n); } 「「3//値が存在しないなら」」 else { 「「3//欠席と出力」」 console.log("欠席"); } }
for of文は「順番を持ったグループに、インデックスに基づいてループ処理を行う」構文です。
「「3▶︎ イチロー」」 「「3▶︎ ジロー」」 「「3▶︎ 欠席」」 「「3▶︎ シロー」」
結果。ちゃんとインデックスに基づいて反復処理がなされました。
インデックス[2]の人(←おそらくサブロー)の席は、「欠席」と出力されます。
これが、「for inが配列などの『順番をもつもの』に適さない理由」です。
順番が保証されていないといっても、「0,1,2」がいきなり「2,1,0」とかになってしまうわけではありません。
フツーに配列にfor inで値を取り出すと、順番に値が出てきます。ただしこれは「順番に処理がなされている」だけで、インデックスに基づいているわけではありません。
「順番が保証されていない」というのは、「インデックスに基づいていない」という意味だったのです。
・インデックスやプロパティに対して反復処理を行う。
・「順番のないもの」にも使えるため、オブジェクト向き。
・インデックスに従わないで処理をするため、順番に厳密な処理をしたい場合には不向き。
・値に対して反復処理を行う。
・インデックスを元に処理を行うため、配列向き。
・「順番のないもの」に処理を施す場合には、指定先の加工が必要になる。
これまで見てきたことをまとめると⬆︎のようになります。
for inとfor of。両者の違いをよく理解して、使い分けるようにしてください。
最後までお読みくださり、ありがとうございます。
これからもJavaScriptのサンプルコードで「?」となりそうなものを調査し、記事にしていきたいと思います。ぜひ参考にして、学習に役立ててください。
for(you in study) { Let's meet again! }
JavaScriptの点3つ「 ... 」 〜スプレッド構文(演算子)について。
2022.02.14
本質は「オブジェクトの複製」にあり。
JavaScript、乱数の範囲や重複を指定〜Math.random使い方。
2021.11.17
整数/範囲/重複の有無を自在にあやつろう。
JavaScriptの矢印「=>」〜これはアロー関数というものです。
2022.01.09
使い方とメリットについて解説。
ブログのクリックをGoogle Analyticsで計測。
2021.11.30
新たなツールは導入せずともOK。
swift、web、ガジェットなど。役立つ情報や観ていてたのしいページを書いていきたいと思います。