GOLD PLAN加入企業が100件を突破しました!

JavaScriptのObjectにあるpropertyの存在チェックについて考察する

infomation
この記事は約4分で読めます。

子・孫のオブジェクトの存在チェック [TypeError: Cannot read property ‘xxx’ of undefined]を回避する

JavaScript信者の皆さんこんにちわ。今日もJavascriptしてますか?

JavaScriptにおけるObjectはKeyとValueの組み合わせで書かれる構造体で、Javascriptを扱う上では切っても切れないものです。

// JavaScriptでよく見る風景
const ueda = {
  age: 34,
  name: 'ueda shinya',
  sex: 'male',
}
console.log(ueda.age) // 34と表示される
console.log(ueda.weight) // undefinedと表示される

このObjectの中に含まれるものを「property」と言います。上の例ではageとか、nameとか、 sexがpropertyです。propertyにアクセスするには、オブジェクト+ドット+property名でアクセスできます。

ueda.nameのような感じです。

もしそのpropertyが存在しなければUndefinedになります。これが通常のケースで、これはなんの問題もありませんね。よくある解決策として

console.log(ueda.weight || 'そんなのねぇよ')

このように書くと、ueda.weightが偽に近い値だったら’そんなのねぇよ’と表示されます。これは短絡評価と言って、左辺が真なら左辺だけ実行します。左辺(ueda.weight)が偽なら||に従い(これはORなので、右辺も評価しないと式の答えが分からないから右辺も評価する)右辺を実行します。

短絡というのは、左辺が真の時点で右辺の答えは関係なく式が真になるので、「短絡」なんですね。右辺なんか見る必要が無いわけです

[TypeError: Cannot read property ‘xxx’ of undefined]で実行時エラー

propertyが存在しなければ右辺を評価してくれればそれでいいのですが、オブジェクト(親)の中にオブジェクト(子)を入れるような書き方をすると、子が存在しない場合に「cannot read property」という実行時エラーが発生してプログラムが止まってしまいます。

// hogehoge.ageは、parent.childオブジェクトにあるageの値をセットしたい。
const hogehoge = {
  age: (parent.child.age === undefined) ? 20 : parent.child.age
}


上の例で、parent.childがundefinedだと当然child.ageもUndefinedと思いますが、残念ながらこれは実行時エラーとなり、20という値はセットされません。

前述した例のueda.weightはundefinedとなるのに、親・子となるとこれはうごかなくなります。そしてジャバスクリプターが最もよく見るであろうエラー「cannot read property ‘hogehoge’ of undefined」を吐き出して止まります。なぜundefinedと評価してくれないのでしょうね?ECMAScriptの決まりだと思うことにします。深くは考えません。

ただ現場として困るのは、上のプログラムが止まってしまうというただただ切実な問題なのです。

ifで子オブジェクトが存在するかをチェックする

解決策としていくつか考えられますが、原始的なやり方はif文で処理をわけてしまうことでしょう

if (parent.child) {
  // 子が存在する
  // よって parent.child.ageにアクセスしても実行時エラーにはならない
  // parent.child.chomechomeにアクセスすると、存在しない場合はundefinedになる
  // 存在しない場合でも実行時エラーにはならない
} else {
  // 子がいない。
}

ただこのやり方は保守性に問題があります。正直あまりスマートじゃないです。機能追加とかproperty追加の際、高確率で修正漏れするパターンです

子をハンドラ的な変数に入れれば問題なく動く

実は今回のように子のオブジェクトが存在するかどうかで悩む場合は、以下のコードで解決できちゃいます

const childObj = parent.child || {}
const hogehoge = {
  // childObjが無い場合は {}となっているので、 can not read property of ageという実行時エラーを避けられる
  // childObj.ageが無いばあいはundefindとなるため、20または正しい値が入る
  age: (childObj.age === undefined) ? 20 : childObj.age
}

というお話でした。何が来るかはっきりわからないのはJavascriptの欠点でもありますね。TypeScriptへ移住すれば、もう少しこのあたりの問題を軽減できるかもしれませんね。ただまぁ、データベース自体にデータが無い場合はダメかもしれませんが笑

ここまで読んでくれてありがとうございますっ
Nipoに興味を持ちましたか?すぐ始められますよ

個人情報の入力も無し。ワンクリックで体験アカウントで利用可能です。そのまま正式アカウントへ昇格もOK。Nipoが使えないと思ったらブラウザを閉じるだけです

開発者ブログ
クラウド日報 Nipo

コメント