良い方法が分からず困っております
ベストプラクティスを知りたいということですね。
データの持ち方として「一貫性を持たせる」事が重要になります。
一つの変数・プロパティは一つの値「文字列 or オブジェクト」しか格納できませんので、
名前と子供要素の両方が持ちたければ下記のような「名前」と「子孫」を定義して一生深く掘っていく仕組みを作るのが良いでしょう。
js
1const food = {
2 name: '食べ物',
3 children: {
4 fruits: {
5 name: 'フルーツ',
6 children: {
7 banana: {
8 name: 'バナナ',
9 children: {}
10 },
11 apple : {
12 name: 'りんご',
13 children: {}
14 },
15 mandarin: {
16 name: 'みかん',
17 children: []
18 },
19 }
20 }
21 }
22}
いやちょっとまって?
これ使いにくいでしょ?
私はfood.fruits
で"フルーツ"
を取り出したいのに、
なんでfood.children.fruits.name
にしなきゃいけないんだ?
フルーツはまだいいわ
food.fruits.apple
で"アップル"
に辿り着こうと思ったら
food.children.fruits.children.apple.name
とかありえんわ!
こうなると思います。
ではどうするか?
検索関数もセットで準備しましょう。
js
1// childrenを再帰的に掘っていく関数を実装
2const getItem = (list, path) => {
3 const paths = path.split('.');
4 // パスかリストのどちらかを掘り終えたら検索終了
5 if (!paths[0]) return list;
6 if (!list.children) return {};
7
8 // null値やundefined値はプロパティを所持していないので
9 // アクセスを試みた時点でエラーとなる現象を回避する為に空のオブジェクトを返させる
10 const result = list.children[paths[0]] || {};
11
12 // 先頭要素だけ消し飛ばして更に子供要素に入っていく
13 return getItem(result, paths.slice(1).join('.'));
14}
15
16// food.fruits.appleで検索したいのでlistという変数を作って更にネストさせる
17const list = {
18 name: 'リスト',
19 children: {
20 food: {
21 name: '食べ物',
22 children: {
23 fruits: {
24 name: 'フルーツ',
25 children: {
26 banana: {
27 name: 'バナナ',
28 children: {},
29 },
30 apple: {
31 name: 'りんご',
32 children: {},
33 },
34 mandarin: {
35 name: 'みかん',
36 children: {},
37 },
38 }
39 }
40 }
41 }
42 }
43}
44
45console.log(getItem(list, "").name); // リスト
46console.log(getItem(list, "food").name); // 食べ物
47console.log(getItem(list, "food.fruits").name); // フルーツ
48console.log(getItem(list, "food.fruits.apple").name); // りんご
49
50// 洒落た出力がしたければこんなテストも出来る
51console.log(JSON.stringify(
52 ["", "food", "food.fruits", "food.fruits.apple"].map(
53 path => getItem(list, path).name
54 ), null, 2
55));
56// [
57// "リスト",
58// "食べ物",
59// "フルーツ",
60// "りんご"
61// ]
【おまけ】 これで良くねという別解
Mapやオブジェクトのキーには別にコロン.
等の文字列を含めても構いません。
js
1const list = {
2 "food": "食べ物",
3 "food.fruits": "フルーツ",
4 "food.fruits.apple": "りんご",
5 "food.fruits.banana": "バナナ",
6 "food.fruits.mandarin": "みかん",
7}
8
9console.log(list["food.fruits.apple"]); // りんご
10
11// 子供要素の一覧を検索出来る関数も作ってみた
12const filterChildren = (list, path) =>
13 Object.keys(list).filter(key => key.indexOf(path + '.') == 0);
14
15console.log(filterChildren(list, "food.fruits"));
16// ["food.fruits.apple", "food.fruits.banana", "food.fruits.mandarin"]
これで良いじゃんと、代替案も添えて提案するのも出来るエンジニアの仕事の一つです。