JavaScriptで入れ子のオブジェクトがある時…
- 2階層以上の入れ子を持つ
- その全要素をループさせたい
- ただし多重ループは使わない
英語では traverse とも呼ばれてます。
オブジェクトの階層(入れ子)を無視し、
並列に全要素を全て表示・探索したいってことです。
その方法をいくつか考えてみました。
1.再帰によるオブジェクト全要素のループ探索
初めは再帰を使ったループ方法
再帰というのを一言で説明すると……
- ある再帰用の関数を用意する
- その関数内で自分自身を呼び出す
- 一定条件を満たすまで再帰を続ける
実を言うとあんまりいい方法でありません。
事実、ほとんどの再帰は単純ループで置き換えできます。
でも初めに再帰を使った方法でやってみました。
▼ 結果として次のようなコードに
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
/// 対象オブジェクト const obj = { str1: "hoge", str2: "fuga", obj: { obj: { bool1: true, bool2: false }, num1: 123, num2: 456, float: 3.14, }, arr: [1,2,3] }; /// オブジェクトの並列探索 function traverseObj(obj){ const keys = Object.keys(obj) for(let i=0; i<keys.length; ++i){ const key = keys[i] const value = obj[key] if(value.constructor === Object && !value.length){ traverseObj(value) }else{ console.log(`${key} : ${value}`); } } } /// オブジェクトの全要素ループ traverseObj(obj) |
▼ このコードの出力結果
1 2 3 4 5 6 7 8 |
str1 : hoge str2 : fuga bool1 : true bool2 : false num1 : 123 num2 : 456 float : 3.14 arr : 1,2,3 |
再帰関数に渡されたオブジェクトに対してキーでループを回し、その要素がオブジェクトなら再帰を実行、値・配列・Object以外ならそのまま表示してます。
ここではオブジェクトかの判断条件として value.constructor === Object && !value.length を使っており、配列・クラスインスタンスなどが誤検知されないようにしました。
ただ再帰の欠点は次のことです。
- 再帰関数の呼び出しのコストが大きい
- 巨大なオブジェクトの場合は不向き
もちろん数千個レベルなら問題ないです。
でも超巨大なオブジェクトだと時間がかかるかも
2.一重ループだけでオブジェクトの全要素を探索
お次は再帰も多重ループも使いません。
単純に1回だけのループでどうにかします。
▼ 実際に書いてみたコード例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
/// 対象オブジェクト const obj = { str1: "hoge", str2: "fuga", obj: { obj: { bool1: true, bool2: false }, num1: 123, num2: 456, float: 3.14, }, arr: [1,2,3], cls: new class{} }; /// オブジェクトの並列探索 function traverse(obj) { let stack = []; stack.push(obj); while (stack.length) { for (let j in stack[0]) { if (stack[0][j].constructor === Object && !stack[0][j].length ){ stack.push(stack[0][j]); }else{ console.log(`${j} : ${stack[0][j]}`); } } stack.shift(); } } /// オブジェクト全要素をループ traverse(obj); |
▼ このコードの出力結果
1 2 3 4 5 6 7 8 9 |
str1 : hoge str2 : fuga arr : 1,2,3 cls : [object Object] num1 : 123 num2 : 456 float : 3.14 bool1 : true bool2 : false |
スタック( stack )を用意し、初めに渡されたオブジェクトを入れます。このスタックにオブジェクトを次々と階層・入れ子を無視して入れることで全要素の探索をしてます。
具体的に書くなら for (let j in stack[0]) {...} の内部でループ要素がオブジェクト(Object)ならスタックに積み、それ以外なら出力してるだけです。
あとはスタックが空になるまでループするだけ
Object・Array向けのtraverse専用ライブラリもある
ちなみにこんなライブラリとかもあります。
▼ substack/js-traverse
入れ子構造の配列・オブジェクトのtraverseができます。
※ ただしnpm専用ライブラリの模様
以上、JSでのオブジェクト全要素のループでした。
間違い・ご指摘はコメント欄からどうぞ、ではまた