やりたいこと
以下のようにネストが深いハッシュの場合、親がundefiend
になるので一括で初期化ができない。hash['a']のキーが存在するのか不明な時はめんどくさい。
const hash = {}
hash['a']['b']['c'] = 1
愚直にやるなら
各階層でキーが存在するかを確認し初期化する必要がある。めんどくさい。
const hash = {}
if(!hash['a']) hash['a'] = {}
if(!hash['a']['b']) hash['a']['b'] = {}
hash['a']['b']['c'] = 1
Object.assignを使う
@akebi_mh 様からコメント頂きました。Object.assignを使うとワンライナーで実現できます。
const hash = {};
Object.assign(hash, {a:{b:{c:1}}});
再帰関数を使う
再帰関数を使って初期化していく方法。
この関数には問題があります。後半の「この解決策の問題点」を必ず参照してください
// hashオブジェクトに対して値が無ければ初期化する関数
const setProperty = (obj, ...keys) => {
const key = keys[0]
// 次のキーが無ければ終了
if (keys[1] === undefiend || keys[1] === null) {
obj[key] = {}
return
}
// プロパティがなければ初期化する
if (!obj[key]) {
// 次の値が数値ならば配列にする
if (Number.isInteger(keys[1])) {
obj[key] = []
} else {
obj[key] = {}
}
}
setProperty(obj[key], ...keys.slice(1))
}
使用例
解説
三点リーダ
「...」は可変長引数。使用例のようにsetPropertyに複数の引数を与えることができる
Number.isInteger
数値かどうか判定する。'0'
は文字列、0
は数値と分けてくれる。
.slice(1)
部分配列を返す。1なので、2番目の値以降の部分配列にする
この解決策の問題点
obj
は引数で取っているが、関数内で更新している。そのためESLintのno-param-reassign
が発生してしまう。解決策求ム。
まとめ
あとちょっとでもっといい感じにできそう。良いアイディアお待ちしています。