JavaScriptをやっていて割と悩むのがunllとundefinedってどっちを使ったら良いのか問題。他のプログラミング言語とかだとnullにあたるものはあるけど、undefinedの方はあまり見かけないです。他の言語でnullが普通なので、自分はnullで初期化するようなことも今まであったのですが『サバイバルTypeScript』を読んでいて考えが変わったので、違いとかも含めてまとめておこうと思います。
nullとundefinedの違い
nullは自然発生しない
undefinedは言語仕様上自然発生するので、全くお目にかからないということはないと思います。初期値なしの変数宣言とかオブジェクトに存在しないプロパティや配列にない要素にアクセスしたときとか。
let value;
console.log(value);
//undefined
const obj = {};
console.log(obj.foo);
//undefined
const arr = [];
console.log(arr[0]);
//undefined
上記の例に限らず、よくわからない値の時はundefinedが返ってくる印象はありましたが、nullの方で返ってくることはあまりないです。ライブラリによってはnullを返すようなこともあるらしいのですが、JavaScriptとしてはnullを提供することはないようです。
undefinedは変数
nullもundefinedもプリミティブ型ではありますが、undefinedは変数でありnullはリテラルになります。undefinedは変数なので、undefinedという変数を作ることはできます。
typeof演算子の結果が異なる
この辺の仕様もよく知らなかったのですが、nullは”object”になるんです。undefinedは”undefined”です。
typeof undefined;
// "undefined"
typeof null;
// "object"
そういえばnullで分岐作る時にこの仕様を引いてバグを作り込みそうになったこともあったような・・・
JSONにおける違い
JSON.stringifyした時とかにプロパティの値がnullの場合は値が保持されますが、undefinedは削除されます。この仕様もよく知らなかったですね。バックからはnullで来ることもあるので、nullが保持される印象はありましたが・・・
console.log(JSON.stringify({ foo: undefined }));
//{}
console.log(JSON.stringify({ foo: null }));
//{"foo": null}
undefinedとnullの使い分け
これは微妙な問題ですよね。コーディング規約としてチームで指針を決める必要はあるのかなとは思いますよね。バックエンド側はnullを利用している言語も多いので、そことの許容具合なども決める必要が場合よってはあるのかなと思います。
undefinedに寄せるというのは1つ方向性としてはありなのかと思います。
一方で、「nullは使わずundefinedに統一しよう」はシンプルなルールです。これなら共通認識として持つことがしやすく、チームワークもしやすくなります。実際にTypeScriptの開発チームでは「nullは使わない」というたった1行のシンプルなガイドラインを示し、数多くの開発者が参加しやすくなるようにしています。
サバイバルTypeScript
逆に使い分け自体を意識せず、レビュー対象としないというのも方針としては理解できます。そんなに神経質な使い分けをしない方が、変な手戻りも発生せず実用としては十分です。
nullをundefinedに変換することは手間が伴うので、もし統一を考えるのならundefined側になるかと思います。存在しないオブジェクトプロパティや配列要素にアクセスした時にもnullを返すようにとかは、流石にやりすぎな感があります。
私見
ここまでの違いや意見を見てきた中で、個人的にはnullを意図的に使う理由があまりないのかなと思いました。特にフロントエンドの仕様としてはundefined中心に使用していくのが無難かと思います。
チーム開発として考えるなら、undefinedをなるべく使わようにしていくけど、レビューとしてきっちり指摘事項に上げるまではしない感じにはなりますかね。新規でジョインしたメンバーには指針としては共有したいところですね。