[JavaScript] typeof arg == 'undefined' っていらないんじゃね?

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

[JavaScript] typeof arg == 'undefined' っていらないんじゃね?

以前にも 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 == nullundefined == 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 の変換テーブルは以下の通り。

9.9 ToObject (p. 36)

The operator ToObject converts its argument to a value of type Object according to the following table:

Input TypeResult
UndefinedThrow a TypeError exception.
NullThrow a TypeError exception.
BooleanCreate a new Boolean object whose [[value]] property is set to the value of the boolean. See 15.6 for a description of Boolean objects.
NumberCreate a new Number object whose [[value]] property is set to the value of the number. See 15.7 for a description of Number objects.
StringCreate a new String object whose [[value]] property is set to the value of the string. See 15.5 for a description of String objects.
ObjectThe result is the input argument (no conversion).

ということで、どうやら TypeError を投げるのは null と undefined だけっぽい。

ここまでやって今日は満足したからいい加減寝よう。

スポンサーサイト

関連記事

トラックバック 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

コメント

コメントの投稿

お名前
コメント
編集キー
 
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。