Edited at

JavaScript オブジェクトの深くネストされているプロパティに安全にアクセスする getProperty

もう何番煎じかわかりませんが、深いネストにアクセスするための関数を作ってみました。


ソースコード

function getProperty(object, propertyPath) {

if (!object) { return undefined }

let result = object;
const propertyArray = propertyPath.split('.');
for (let i = 0; i <= propertyArray.length - 1; i += 1) {
if (propertyArray[i] === '' ) { return undefined; }
if (typeof result[propertyArray[i]] === 'undefined') { return undefined; }
result = result[propertyArray[i]];
}
return result;
}

let testObj1 = {
a: {
b: {
c: false
}
}
}

var path = 'a'; console.log( getProperty(testObj1, path) );
var path = 'a.b'; console.log( getProperty(testObj1, path) );
var path = 'a.b.c'; console.log( getProperty(testObj1, path) );
var path = 'a.b.c.d'; console.log( getProperty(testObj1, path) );
var path = 'a.b.b'; console.log( getProperty(testObj1, path) );
var path = ''; console.log( getProperty(testObj1, path) );
var path = 'a.'; console.log( getProperty(testObj1, path) );
var path = '.a'; console.log( getProperty(testObj1, path) );
var path = 'a.c'; console.log( getProperty(testObj1, path) );
var path = 'b'; console.log( getProperty(testObj1, path) );
var path = 'b.c'; console.log( getProperty(testObj1, path) );

値が取得できる場合は値を取得、できない場合は、undefined が返ります。例外は発生しないので、安心して深いところにあるプロパティ値を取得することができます。

こちらの情報によると、lodashにはここで紹介したgetPropertyと同じ機能のget関数があるようですので、普通はそれを使うと思います。この記事のコードは、何かのご参考程度にしてください。

【JavaScript】ネストされたObjectのキーが存在するかチェックする | Black Everyday Company

https://kuroeveryday.blogspot.com/2016/07/key-exists-in-nested-object.html


Google検索してバグがあるものが見つかります。

Googleにヒットする、いくつかのサイトのコードにはバグがあるのでご注意ください。

魔術 黒文字列キーでネストされたJavaScriptオブジェクトにアクセスする - CODE Q&A 問題解決

https://code.i-harness.com/ja-jp/q/630d47

JavaScript 黒魔術 - 文字列をキーとしてネストしたプロパティにアクセスする | phiary

http://phiary.me/js-black-magic-nested-property-accessor/

これらのところで「reduce x && x[y]」と記載されている方法は、obj.a.b.c = false の場合に、「obj, 'a.b.c.d'」などでアクセスすると undefined ではなく false が戻るようになってしまっているバグがあるようです。

reduce という扱いが少しむずかしいループ系の関数や、それと組み合わせてのand演算子の戻り値というやり方で書いたために、ミスになってしまったのでしょう。


JSでなるべくショートハンドで書くことがよいとされる間違った文化がある。

ここが一番言いたいことなのですが、

JSでは、ショートハンドといわれる短い形式で記述するのが流行りでもあり、「記述量が少ない=バグが出にくい」と勘違いしている中途半端な開発者の人を時々見かけます。これは、そういうのが裏目に出たという典型例の一つになるのかもしれません。

ショートハンドなand演算子の戻り値は、悪い慣習です。使う価値はまずなくバグの温床です。

また、reduce, map などでは ループ時の内部値を console.log 出力もできなかったり 開始 終了処理なども記載しにくく改良もしにくいので少し気をつけて使うのがいいでしょう。

他の人のコードを動作確認する時やリファクタリングが面倒です。

reduce や map 使うな for 使え、という主張はしませんが、 for はダサいし古いから老害しか使わない。最新のできるエンジニアは reduce や map 使いましょう、かっこいいから。と盲目的に信じている愚かな中途パンパな開発者は実際にいます。

自分が経験したのは、ベンチャーで時流に乗って儲けている状況のことを自分の実力と勘違いしちゃっている若造のエンジニアにいましたね。結構な率で若者は若さゆえの過ちをそういう形でするんだよな。と興味深く観察させてもらいました。

reduce とか map とか Array.forEach とかは、結局のところ for ループを抽象化した程度のもので、その抽象化されていることによって時には、役に立たない場合があるということです。

プログラムは書くよりも読むほうが難しい、という格言を知ってほしいものです。reduceの動きなんて読むのは結構めんどくさいものです。


テストコード

この記事では、テストコードまで書きませんでしたが、console.log での出力は行いました。

よりよくやるなら、テストコード込みで開発してしまうのが、より望ましいでしょう。

手前味噌ですが、これらの記事を参考にしてみてください。

JavaScriptで(そしてどんな言語でも同じで)世界一簡単なテストフレームワークを作って使おう - Qiita

https://qiita.com/standard-software/items/559d871794bfa38651f4

JavaScriptで世界一簡単なテストフレームワークに例外捕捉機能追加した - Qiita

https://qiita.com/standard-software/items/d4fb99655e17a3a68fcb