21
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

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

Last updated at Posted at 2019-01-17

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

ソースコード

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検索してバグがあるものがありました。

JavaScript 黒魔術 - 文字列をキーとしてネストしたプロパティにアクセスする | phiary
http://phiary.me/js-black-magic-nested-property-accessor/

obj.a.b.c = false の場合に、「obj, 'a.b.c.d'」とアクセスすると undefined が返ってくるべきですが false が戻るようになってしまっているバグがあるようです。

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

なるべく短く書いた方がよい、という変な慣習がある

「記述量が少ない=バグが出にくい」と勘違いしている人の実際の発言も聞いたことがありますが、JavaScriptプログラマの間に、ショートハンドといわれる短い形式で記述するのが流行っている感じがしています。

上で指摘したバグを引き起こしているand演算子の戻り値というショートハンドは使い勝手がかなり悪いものです。使う価値はまずなくバグの温床となってしまいます。

reduce というループを書かなくても短い記述で合算値を求める構文もあります。短く書けてよい、と思われがちですが開始 終了処理などが記載しにくいので、機能追加する場合に reduce から forなどのループ処理に書き換えなければいけなくなる時もあるので、少し気をつけて使う方がよいと思います。後で改良するときに対応しくいので結局最初から、reduce使わずに for of などを使っていた方がよかった、と感じることがいくつかあったりしました。

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

シンプルで読みやすいコードの方が即座に理解できるし、故に不具合も減るからいいのに、と思ってしまいます。

reduceの動きは詳細まで把握しにくいので for ループで書いておいた方が内部値を確認しやすかったり、仕様変更時に break や continue でいろいろ対応できるというメリットもあるものなのです。

プログラムは書くよりも読むほうが難しい、という格言があります。

それゆえに読みやすいプログラムを書くのはなかなかさまざまな配慮が必要だったりします。

テストコード

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

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

以前下記の記事を書いたことがあります。

JavaScriptで(そしてどんな言語でも同じで)世界一簡単なテストフレームワークを作って使おう - Qiita
https://qiita.com/standard-software/items/559d871794bfa38651f4

JavaScriptで世界一簡単なテストフレームワークに例外捕捉機能追加した - Qiita
https://qiita.com/standard-software/items/d4fb99655e17a3a68fcb

ライブラリ

最近はこちらのライブラリを開発しています。そこにもこのgetPropertyを組み込んでいます。

standard-software/partsjs: JavaScript Code Parts TypeSafe Library Compatible with any js platform
https://github.com/standard-software/partsjs

getProperty
https://github.com/standard-software/partsjs/blob/v5.3.3/source_code/object/object_common.js#L99

getProperty を同時複数で行える inProperty
https://github.com/standard-software/partsjs/blob/v5.3.3/source_code/object/inProperty.js#L51

21
15
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?