Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
2
Help us understand the problem. What is going on with this article?
@hanetsuki_dev

フロントエンド2年目のエンジニアが再帰処理を必要にかられて使えるようになったお話

パーソンリンクアドベントカレンダー 10日目 & Qiita初投稿です!
エンジニアになって2年目のウサギです。
現在は、フロントエンドメインで開発して飯を食べてます。そんな私の備考録です。

出会いは突然に

[
  { name: "タカシ",
    children: [
      { name: "ミツル" },
      { name: "ナツキ",
        children: [
          { name: "アイナ" },
          { name: "ナオキ" }
        ]
      },
      { name: "ヨツハ" },
      { name: "フタバ",
        children: [
          { name: "リク" }
        ]
      }
    ]
  },
  { name: "ソラ",
    children: [
      { name: "ハナ" }
    ]
  }
]

上記のような階層構造を処理する際に、ユニークになるkeyが一つも存在しないので何か付与する必要がありました。
ユニークになるkey無いと、対象となる値の更新や参照が困難になる為です。

JavaScriptでオブジェクトデータを扱う(登録・参照・更新・削除)
(...こんな感じのことをやるのにユニークになるkeyが必要だった)

そのときたどり着いたのが親子関係がはっきりしているパス情報を作成することでした。

よしメソッド作ろう!と意気込んだものの...階層構造のネストがどこ続いていなかったりどこまでも続いていたり、
この手のJSONを処理するのは初めてでした。

(入れ子 尽きるまで object js)検索

我ながら頭の悪そうな検索ワードでGoogle先生に尋ねたところ
再帰関数 なるものに出会いました。

再帰関数ってなんなんだ??
再帰関数を学ぶと、どんな世界が広がるか

つまりはこうだ、

// 関数をconstで定義する
const func = function(count) {
  console.log(`console: ${count}`);

  if (count) {
    // 関数の中でconstで定義したfuncを呼び出す。
    func(count--);
  }
};

// 初期値を引数に渡す
func(10);

// 結果
// console: 10
// console: 9
// console: 8
// console: 7
// console: 6
// console: 5
// console: 4
// console: 3
// console: 2
// console: 1
// console: 0

関数の中でその関数を呼び出すことでループをすることができるそうだ。スゲぇー

着手してみた

早速コードを書いて、usersの各値にpathを埋め込んでいきましょう。

// 上記のJSONを変数で定義します。。
const users = [
  { name: "タカシ",
    children: [
      { name: "ミツル" },
      { name: "ナツキ",
        children: [
          { name: "アイナ" },
          { name: "ナオキ" }
        ]
      },
      { name: "ヨツハ" },
      { name: "フタバ",
        children: [
          { name: "リク" }
        ]
      }
    ]
  },
  { name: "ソラ",
    children: [
      { name: "ハナ" }
    ]
  }
]

// 関数funcを定義
const func = (users, path=[]) => {
  users.forEach((user, i) => {

    // userにpathを追加
    user.path = [...path, i];

    if (user.children) {
      // user.childrenがあれば関数を再び呼び出す
      func(user.children, user.path);
    }
  });
};

func(users);
console.log(users);

// 結果
// [
//   { name: "タカシ",
//     path: [ 0 ],
//     children: [
//       {
//         name: "ミツル",
//         path: [ 0, 0 ]
//       },
//       { name: "ナツキ",
//         path: [ 0, 1 ],
//         children: [
//           {
//             name: "アイナ",
//             path: [ 0, 1, 0 ],
//           },
//           {
//             name: "ナオキ",
//             path: [ 0, 1, 1 ],
//           }
//         ]
//       },
//       {
//         name: "ヨツハ",
//         path: [ 0, 2 ],
//       },
//       {
//         name: "フタバ",
//         path: [ 0, 3 ],
//         children: [
//           {
//             name: "リク",
//             path: [ 0, 3, 0 ]
//           }
//         ]
//       }
//     ]
//   },
//   {
//     name: "ソラ",
//     path: [ 1 ],
//     children: [
//       {
//         name: "ハナ",
//         path: [ 1, 0 ]
//       }
//     ]
//   }
// ]

※図解
タカシ, path: [ 0 ]
┗ ミツル, path: [ 0, 0 ]
┗ ナツキ, path: [ 0, 1 ]
    ┗ アイナ, path: [ 0, 1, 0 ]
    ┗ ナオキ, path: [ 0, 1, 0 ]
┗ ヨツハ, path: [ 0, 2 ]
┗ フタバ, path: [ 0, 3 ]
    ┗ リク, path: [ 0, 3, 0 ]
ソラ, path: [ 1 ]
┗ ハナ, path: [ 1, 0 ]

引数にusersの配列とそれまでのpathを渡して各userごとにpathの埋め込んでいくという作業を再帰的に行なっています。
pathに関してはforEachのindexをaddする形で使っています。

user.path = [...path, i];は引数pathを スプレッド構文 を利用して展開して利用しています。
スプレッド構文はシンタックスシュガーです。

  // スプレッド構文を用いない場合
  user.path = path;
  user.path.push(i);


  // スプレッド構文を用いた場合
  user.path = [...path, i];

この二つは同じ結果になります。詳しくは、@Nossaさんがまとめてくれている記事がありますのでそちらをご覧ください。

最後に

再帰関数をある程度利用することでjsを扱う上での視野が広がった気がします。
また、記事に間違いや不明な点があれば遠慮なくご指摘いただけますと幸いです‎✧。٩(ˊωˋ)و✧*。

明日は、@kuwakuwakuwaさん担当です!

2
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
hanetsuki_dev
物創り大好きフロントエンドエンジニア。 イラスト描くのも好きなウサギ
personlink
株式会社パーソンリンクの公式アカウントです。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
2
Help us understand the problem. What is going on with this article?