[JavaScript] typeof arg == 'undefined' っていらないんじゃね?
- 2008-09-24
- カテゴリ: Client Side
- タグ: Tips JavaScript
以前にも JavaScript の null と undefined に関する記事を書いたことがあったが、またしても性懲りもなく null と undefined の挙動につまずいて、 ECMAScript 3 の仕様書まで調べ直したので、メモ代わりにエントリー化。
Abstract
このエントリーの内容をざっくりとまとめると、
something == null
がどういう値を返すのかが気になって、ECMAScript 3 の仕様書までさかのぼって調べてみると、
null == null undefined == undefined null == undefined undefined == null
のパターンでのみ true
を返すということがわかった、という話。細かい経緯は続きで。
経緯
JavaScript の null と undefined の関係が何かとややこしいのは以前のエントリーでも書いたとおりで、関数に引数が渡されたか渡されなかったかを判別するためには、 typeof
演算子を使って↓のように書かなければいけないということになっている。
function fn(arg) { if (typeof arg == 'undefined') { // some processes } }
とはいえ、毎回毎回 if (typeof arg == 'undefined') ...
を書くのはあまりにも面倒なので、僕はよく if (arg == null) ...
と書いていた。これだと、 undefined だけでなく、 null が渡されたときも true を返してしまうけれど、実装上 null と undefined を厳格に区別しなければいけないシーンというのは少なかったので、特に問題はないと思っていた。
で、今日ふとした時に、「arg == null
って本当に arg が null か undefined の時にだけ true を返すの?」という疑問が浮かんだので、それについて調べてみた次第。万が一、 false == null
とかが true を返してしまったら大変だったので。
結論から言えば、 Abstract に書いた通りの組み合わせでしか arg == null
が true を返すことはない。ECMAScript の仕様書の該当箇所は↓。
11.9.3 The Abstract Equality Comparison Algorithm (pp. 55-56)
- The comparison x == y, where x and y are values, produces true or false. Such a comparison is performed as follows:
- 1. If Type(x) is different from Type(y), go to step 14.
- 2. If Type(x) is Undefined, return true.
- 3. If Type(x) is Null, return true.
- (略)
- 14. If x is null and y is undefined, return true.
- 15. If x is undefined and y is null, return true.
- 16. If Type(x) is Number and Type(y) is String, (略)
- 17. If Type(x) is String and Type(y) is Number, (略)
- 18. If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
- 19. If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
- 20. If Type(x) is either String or Number and Type(y) is Object, (略)
- 21. If Type(x) is Object and Type(y) is either String or Number, (略)
- 22. Return false.
↑を解釈すると、まず 2 と 3 の規則から、「null == null
」と「undefined == undefined
」がわかる。null と undefined は、それぞれ Null 型と Undefined 型の唯一の値だから、「(1) x の型と y の型が同じで、かつ x の型が (2) Undefined 型か、(3) Null 型かのどちらかであれば true 」というのは、「null == null
と undefined == undefined
は true」と言うのと同じこと。
次に、x の型と y の型が同じではない場合を見てみると、 14 と 15 から明らかに「null == undefined
」と「undefined == null」
が true。さらに、 16 と 17 と 20 と 21 は Null 型とも Undefined 型とも関係のない条件 (null が仕様上 Object 型でない点に注意) なのでスルーして、 18 と 19 の条件は、どのみち Boolean が消えて「Number == null
」や「Number == undefined
」が再度評価されるだけなので大勢に影響はなし。
結局残るのは 22 だけになって、「↓の組み合わせ以外は false」という結論に至る。
null == null undefined == undefined null == undefined undefined == null
ここまで到達するのにすごく時間がかかってしまったが、結論としては、typeof arg == 'undefined'
の代わりは、多くの場合 arg == null
でもよさそう、という話。
おまけ 1
実は、typeof arg == 'undefined'
とほぼ等価な表現として、arg === undefined
がある。こちらは、 arg の値が undefined であったときにだけ true を返す。ただし、ECMAScript の仕様で undefined は書き換えることができてしまうので、void
演算子を使って↓のように書く方が安全。
arg === void 0
まぁ、arg == null
とかに比べると何をやっているかがわかりづらいというのが難点だったりするけど。
おまけ 2
null と undefined の共通点として、ドット記法 (.) や角括弧記法 ([]) でプロパティにアクセスしたときに、どちらも TypeError
を吐くっていう点が挙げられる。だから、null と undefined を一緒くたに扱うのは単なる手抜きではなくて、実用上の理由があったりもする。例えば、↓のケース。
function fn(arg) { var field = arg.field; // arg が null か undefined なら TypeError }
で、ついでに「ドット記法や角括弧記法でアクセスしたときに TypeError
を吐くのは本当に null と undefined だけなのか」という点も仕様書をあたって調べてみた。引用は省くが、仕様書でまず見るべきところは、 11.2.1 Property Accessors (pp. 43-44) の頁。読んでみると、Expression . Identifier
となるときに、まず Expression
にあたる部分に対して ToObject
という内部メソッドを呼んでいるということがわかる。で、 ToObject
の変換テーブルは以下の通り。
The operator ToObject converts its argument to a value of type Object according to the following table:
Input Type Result Undefined Throw a TypeError exception. Null Throw a TypeError exception. Boolean Create a new Boolean object whose [[value]] property is set to the value of the boolean. See 15.6 for a description of Boolean objects. Number Create a new Number object whose [[value]] property is set to the value of the number. See 15.7 for a description of Number objects. String Create a new String object whose [[value]] property is set to the value of the string. See 15.5 for a description of String objects. Object The result is the input argument (no conversion).
ということで、どうやら TypeError
を投げるのは null と undefined だけっぽい。
ここまでやって今日は満足したからいい加減寝よう。
関連記事
- [JavaScript] UUID.jsを作成しました
- [メモ] とても単純なボックスを表示する XHTML + CSS
- [JavaScript] typeof arg == 'undefined' っていらないんじゃね?
- [JavaScript] Activationオブジェクトらへんで誤解があったらしい
- 普段使っているFirefoxの検索プラグインを晒してみました
トラックバック URL
- http://liosk.blog103.fc2.com/tb.php/149-3e6d0cd6
トラックバック
- JavaScript:undefined値の判定
-
JavaScriptでは初期化されていない変数には全て「undefined」という値が入っています。 var a; alert(a); //undefinedが入っている これを利用して、変数が定義済みかどうかを判別することが可能です。…が、やり方がいろいろあるみたいなので、まとめてみることにしま…
- 2011-05-27
- 発信元: 泥のように
- typeof演算子で存在判定するとき
-
どーもこんちわ。id:Syoichi(@syoichi) さんのTumblr見て、必要な使いどころ思いだすために書いてみたけどあんまりなさげだった CoffeeScriptでの存在確認演算子のコンパイル結果が2パターンある話
- 2012-10-11
- 発信元: nrm://lab.kss.inc