obj && obj.hoge && obj.hoge.fuga ... を少し簡単に書く

Qiitaにも投稿してみた


JSerの皆様につきましては、JSON.parseしたデータなど、多段ネストしたオブジェクトのプロパティにアクセスするとき、

const obj = {hoge: {fuga: {piyo: 1}}};

const value = obj && obj.hoge && obj.hoge.fuga && obj.hoge.fuga.piyo || 0;

のようなコードを書いてウンザリしてることと思われます。どうやって回避してますか?

回避策1

const value = propOf(obj, 'hoge', 'fuga', 'piyo') || 0;
function propOf(obj, var_args) {
  let result = obj;
  const args = Array.prototype.slice.call(arguments, 1);

  while (args.length > 0) {
    const p = args.shift();
    result = result[p];

    if (result === null || result === undefined) {
      return null;
    }
  }
    
  return result;
}

回避策2

アロー関数が使える今なら、こういう書き方でもいいんじゃないかと思い始めた。

const value = safe(() => obj.hoge.fuga.piyo) || 0;
function safe(f) {
  try {
    return f();
  } catch (e) {
    return null;
  }
}

俺ならこう書く、というアイディアがあれば教えてください。

関数の可変長な仮引数を直接コンストラクタに渡す

ある関数が受け取る可変長引数を、コンストラクタに直接渡す方法

要するにコンストラクタが可変長引数を受け取るのでファクトリ関数も可変長引数を使えるようにしたいんですよ。

ES2015ならばこう。

'use strict';
class Hoge {
  constructor(...args) {
    console.log(`引数は${args.length}個`);
  }
}

function createHoge(...args) {
  return new Hoge(...args);
}

createHoge(1);
createHoge(1, 2)
createHoge(1, 2, 3);

で、本題は次、スプレッド演算子とレストパラメータが使えない場合。LTSのnode.js v4系等ではどうするか?

普通の関数ならapplyでいい。

'use strict';
function hoge(var_args) {
  console.log(`引数は${arguments.length}個`);
}

function execHoge(var_args) {
  var args = Array.from(arguments);
  hoge.apply(null, args);
}

execHoge(1);
execHoge(1, 2)
execHoge(1, 2, 3);

しかし相手がコンストラクタの場合、new Hoge.apply(null, args) とするとapplyはコンストラクタじゃねーぞと言われてしまう。

ここは bind を使って頑張れば実現できそうな感じです。

'use strict';
class Hoge {
  constructor(var_args) {
    console.log(`引数は${arguments.length}個`);
  }
}

function createHoge(var_args) {
  var args = Array.from(arguments);
  args.unshift(null);
  return new (Function.prototype.bind.apply(Hoge, args))();
}

createHoge(1);
createHoge(1, 2)
createHoge(1, 2, 3);

bind.apply(Hoge, args)とするのがポイント、bindに対してapplyを実行することで引数を束縛したHogeコンストラクタを生成できるのだ。

非常にわかりにくいですねー。以上、今後全く役立たない技でしたー。