【JavaScript】オブジェクトのプロパティの存在をチェックする 4 つの方法と特性の違い

 オブジェクトの中に特定のプロパティが存在するかをチェックする方法はいくつかあります。しかし、どの方法を使うか迷うことはないでしょうか。今回はそれらの方法を一通り整理し、それぞれの特性についてまとめてみます。

値を直接評価する方法

このようなコードを書いたことがあるのではないでしょうか。

const obj = { prop1: 1, prop2: 2 };
if(obj.prop1) {
  console.log(obj.prop1);
}

非常にシンプルかつ短いコードになるため、私も頻繁に使う方法です。しかし落とし穴があるので注意しましょう。例えば prop1 の値が 0 や空文字列や false の場合です。以下のコードは prop1 の値が 0 の場合を示しています。

const obj = { prop1: 0, prop2: 2 };
if(obj.prop1) {
  console.log(obj.prop1);
}

お分かりの通り、obj.prop1if 文で評価したら偽になりますので、console.log() は実行されません。この上記のコードが正しく動作するためには、以下のいずれかを評価したい場合に限られます。

  • prop1 が存在し、かつ、その値が真であることをチェックする
  • prop1 の値は必ず真の値にしかならないという前提のもと、prop1 の存在をチェックする

prop1 にどのような値がセットされるのか分からない状況で prop1 の存在のみをチェックしたい場合には不適切になります。

undefined で評価する方法

前述のように、プロパティの値が偽になる可能性がある状況でプロパティの存在をチェックするには、値が undefined と一致するかどうかを評価する方法が考えられます。

const obj = { prop1: 0, prop2: 2 };
if(obj.prop1 !== undefined) {
  console.log(obj.prop1);
}

もし存在しないプロパティを呼び出すと、その値は unfefined になります。そのため、上記のコードではプロパティの値が undefined でないことをチェックしています。

ただし、ちょっとした問題もあります。意図的に行うことは稀でしょうが、オブジェクトに undefined をセットしたプロパティを定義できてしまいます。

const obj = { prop1: undefined, prop2: 2 };
if(obj.prop1 !== undefined) {
  console.log(obj.prop1);
}

undefined をセットしたプロパティは無効にはならず、依然、存在するプロパティとして居座り続けます。しかし、obj.prop1 は存在するにもかかわらずその値は undefined ですから console.log() は実行されません。

もしプロパティの値に undefined がセットされる可能性があるなら、この方法は使えませんので注意しましょう。

余談となりますが、古参のウェブ開発者の中には「undefined は上書きできるから undefined で評価するのは危険だ、void(0) で評価した方が良い」と思われる方もいらっしゃるでしょう。しかし現在ではその心配には及びません。現在ではすでに undefined は上書き変更できない仕様になっています。

厳格モードでなければ undefined を上書きしてもエラーにはなりませんが、値自体は変更されません。

undefined = 1; // エラーにはなりません。
console.log(undefined); // 値は変更されず undefined と出力されます。

厳格モードでは undefined を上書きしようとした時点でエラーになります。

'use strict';
undefined = 1; // エラーになります

in 演算子で評価する方法

前述の undefined の不足を補うなら in 演算子を使うことができます。

const obj = { prop1: undefined, prop2: 2 };
if ('prop1' in obj) {
  console.log(obj.prop1);
}

これで晴れて console.log() が実行され、コンソールに undefined と表示されます。

では次のコードをご覧ください。

const obj = { prop1: undefined, prop2: 2 };
if ('valueOf' in obj) {
  console.log(obj.valueOf);
}

オブジェクトを定義する際に valueOf というプロパティはセットしていません。しかし console.log() は実行されてしまいます。valueOf はオブジェクトを生成したときに勝手に作られるビルトインプロパティの一つです。これはオブジェクトを console.log() でコンソールに出力してみると分かります。

const obj = { prop1: undefined, prop2: 2 };
console.log(obj);

Chrome であれば次のように出力されるでしょう。

このようにビルトインプロパティがいくつか存在します。ビルトインプロパティに対して、JavaScript コードで定義したプロパティは「ダイレクトプロパティ」と呼ばれます。

hasOwnProperty() メソッドを使う方法

前述のビルトインプロパティの問題を解決するには hasOwnProperty() メソッドを使うことができます。

const obj = { prop1: undefined, prop2: 2 };
if(obj.hasOwnProperty('valueOf') === true) {
  console.log(obj.valueOf);
}

hasOwnProperty() メソッドはビルトインプロパティを除外してダイレクトプロパティのみの存在をチェックするメソッドです。上記のコードでは console.log() は実行されません。hasOwnProperty() メソッドをもう少し専門的に説明すると、このメソッドはプロトタイプチェーンをたどらずにプロパティの存在をチェックします。

では、少し特殊なことを試してみましょう。JavaScript の特性上、ビルトインオブジェクトは上書きできてしまいます。上書きしてしまった場合の hasOwnProperty() メソッドの挙動を見てみましょう。

const obj = { valueOf: '意図的に上書きしました' };
if(obj.hasOwnProperty('valueOf') === true) {
  console.log(obj.valueOf);
}

このコードでは console.log() は実行されます。ビルトインプロパティと同じ名前でプロパティをセットしてしまうと、その名前のプロトタイプチェーンは切られ、ダイレクトプロパティとして再定義されます。そのため、hasOwnProperty() メソッドはその存在を認識することになります。

まとめ

オブジェクトのプロパティの存在をチェックするためだけに、これほどの方法があると悩みそうです。ちなみに私は hasOwnProperty() メソッドを使ったことはありません。また、undefined を評価する方法もほとんど使ったことがありません。値を直接評価する方法と in 演算子を使う方法の 2 つの方法を使い分けることがほとんどです。状況によって一概にどれが良いとは言えませんが、みなさんはどの方法がお好みでしょうか。

今回は以上で終わりです。最後まで読んでくださりありがとうございました。それでは次回の記事までごきげんよう。

Share