背景
JavaScriptを書いていて、オブェクトが存在しないうちに要素を参照してエラーになってしまう。そういった事態を避けるためには、存在チェックをする必要があります。今回は、バグ修正を行う中で存在チェックの方法について調べたので、それらの方法と使うべき場面について私見を述べます。
選択肢の根拠となったJavaScriptの仕様等について最初に書きます。結論から早く見たい!という方は判定方法アイデアからどうぞ
すべてのパターンを網羅したわけではないので、あくまでもアイデアとして活用していただけると幸いです
目次
前提となるJavaScriptの仕様
falsy(偽値)
JavaScriptでは、条件文や繰り返し文などの場面で、強制的に論理型に型変換して偽となる値(falsy)という概念があります。以下はMDNに書かれているfalsyのリストです。
nullundefinedfalseNaN0-00n""document.all
参照:Falsy (偽値) - MDN Web Docs 用語集: ウェブ関連用語の定義 | MDN
つまり、undefinedは条件文ではfalseとして扱われ、文を簡潔にできます。
論理積
論理積は、一組の論理型のオペランドがすべてtrueであるときにtrue、それ以外falseを返す演算子です。また、
一般的には、この演算子は左から右に向けて評価した際に最初の偽値のオペランドに遭遇したときにはその値を、またはすべてが真値であった場合は最後のオペランドの値を返します。
参照:論理積 (&&) - JavaScript | MDN
とあります。つまり左側の式がfalseになる場合右の式は実行されないということになります。こちらも分岐を減らし簡潔なコードを書くために有用だと思いました。
等価演算子と厳密等価演算子
JavaScriptには等価演算子(==)と厳密等価演算子(===)があります。MDNによる両者の説明をChat-GPTにまとめてもらうと、
等価演算子 (==) は、オペランドの型が異なる場合に自動で型変換を行い、その結果を比較します。
例えば、数値と文字列を比較するときには文字列が数値に変換されます。
一方、厳密等価演算子 (===) は型変換を行わず、オペランドの型が異なる場合には必ず false を返します。
これが両者の最も大きな違いです。等価演算子 (==) は型の違いを無視して比較するのに対し、厳密等価演算子 (===) は型まで含めて厳密に比較します。
今回は、オブジェクトがnullになる可能性がない、とした上でundefinedになる判定を行うとしました。オブジェクトがnullになる可能性がある場合は、厳密比較を用いればそれぞれを判定することが可能と思います。
判定方法アイデア
今回バグ修正をしたコードは
if(object.property) {
です。これでは存在チェックなしにobjectのpropertyにアクセスしているので読み込めずエラーになります。
1. undefinedとの比較
if(object !== undefined && object.property) {
今回考えた選択肢の中で一番冗長ですが、逆に読んだ人が意図を一番理解しやすいものでもあります。左の式はobjectがundefinedの場合のみfalseになり、右の式が見られないためエラーは発生しません。あえて厳密比較を採用したのは2.と差別化するためであり、通常の比較でも問題なく動作します。
2. undefinedがfalsyであることを利用
if(object && object.property) {
今回の中では一番バランスがいい書き方かと思います。1に比べると意図は理解しづらいですが、シンプルに記述できるのがよいと思います。ただobjectの中身がundefined以外のfalsyの値であったときにも条件に当てはまるので、それを別で検出したい場合は違う方法がよいかと思われます。
TIP : 二重否定について
if(!!object && object.property) {
とすると、二重否定という表現になります。JavaScriptの論理否定演算子!は、結果を反転するだけでなく、falsyの値を明示的に論理型に変換することができます。つまり、二重否定を用いることで、truthyはtrueに、falsyはfalseに明示的に変換をすることができます。
(今回は論理型が求められているわけではないので正直必要ないですが、調べていて論理型が必要な時使えるなと思ったので、ご参考までに...)
3. オプショナルチェーンを利用
if(object?.property) {
?.の書き方はES2020から追加されたオプショナルチェーンという方法で、
参照が
nullまたはundefinedの場合にエラーとなるのではなく、式が短絡されundefinedが返される
参照:オプショナルチェーン (?.) - JavaScript | MDN
のだそうです。つまり、undefinedかチェックするだけならこれで十分ということになります。
ただこの書き方はES2020から追加された記述であるため、それ以前のバージョンでは適用ができないので注意が必要です。
まとめ
選択肢をいくつか書きましたが、プロジェクトの関係やバージョンの関係によって導入できるもの、できないものや、時々で適切なものが変わってくると思います。そうしたときの判断基準となる部分としてこちらの情報を生かしていただけると幸いです。