undefine/nullの関係

[新着] Webテンプレートを仮オープンしました



0   名前: ラマ : 2006/05/10(水) 10:34  ID:ya6xOqUo
私が勝手にそうなのでは、と思っているのですが、
確証がもてずコーディング上迷っていることがあります。
あまり良い質問ではありませんが、ご教授頂ければ幸いです。

1.undefinedという型は、内部的にはnullと同値。
コーディング上はnullでundefinedの代用が可能。

ECMA 262を見ると
undedined:値の設定されてない変数を参照した場合の値
null     :null,空,もしくは、存在しない参照

とあり、実装上、undefinedがnullの一部になると考えています。
(要は、内部的にはundefinedはnullとして扱われ、undefinedが比較された時、nullをundefinedとして返す。)
これは、正しいでしょうか。

2.存在しない変数、コンストラクタへの参照は例外になる。
実際やってみるとIEでもNNでも例外が発生します。
これは、仕様と考えて、例外が発生したら未定義変数としても問題ないものでしょうか。

1   名前: Pid ◆byEkK9OALr : 2006/05/10(水) 10:34
> undefinedという型は、内部的にはnullと同値。コーディング上はnullでundefinedの代用が可能。

null と undefined は別の値ですし,代用できないと思います。おそらく,ラマさんの疑問は,以下のようになることから生じたと推測します。

var obj = { };
obj.prop == null;      // true
obj.prop == undefined; // true


しかし,これは JavaScript の等価演算子 x == y に,以下のような暗黙の型変換ルールが存在するためです(詳しくは ECMA 262-3 の 11.9.3 に)。

・(Undefined) == (Null) は true を返す。
・(Number) == (String) は,(String) を Number に変換して比較する。
・(Boolean) == (Object) は,(Boolean) を Number に変換して比較する。

厳密等価演算子を使えば,よりはっきりするでしょう。x === y は比較時に型変換を行いません。

var obj = { };
obj.prop === null;      // false
obj.prop === undefined; // true


したがって,一度も設定されたことのないプロパティの値は,厳密には null ではなく undefined です。ただ,null と undefined は,上記のような内部的な型変換によって,同じ値と見なされることもある,ということです(ですから,ラマさんの疑問はもっともなことです)。


> 例外が発生したら未定義変数としても問題ないものでしょうか

変数の値を取得しようとしてスコープチェーンを辿ったときに,最後のグローバルオブジェクトを探索しても見つからなかった場合に,未定義エラーが発生します(スコープチェーンの詳細は http://www.hawk.34sp.com/stdpls/jsnotes/)。

しかし,設定する場合は,未宣言の変数でもいきなり使用できます。この場合,スコープチェーンの最後,つまりグローバルオブジェクトのプロパティ(グローバル変数)になります。

オブジェクトによっては,読み取り専用のプロパティに代入しようとすると例外を投げる場合もあります。ですから,「例外が発生→未定義である」とは必ずしも言えないと思います。

2   名前: ラマ : 2006/05/10(水) 10:34  ID:ya6xOqUo
>厳密等価演算子を使えば,・・
そうでした。(汗)
なんとなくnullとundefinedが分かってきました。
Pid様の繰り返しになりますが、
undefined:一度も設定されたことのない変数の値
null :nullという値(nullが設定されない限り変数はnullにはならない。)
ということでしょうか。

>必ずしも言えないと思います。
以下のソースに問題を感じますでしょうか?
alert(doesExist("Array.prototype"));
function doesExist(sVar){
  try{ eval(sVar); }catch(e){ return false; }
  return true;
}


3   名前: Pid ◆byEkK9OALr : 2006/05/10(水) 10:34
> nullが設定されない限り変数はnullにはならない

その通りですね。良い例が思い浮かばなかったのですが,

var node = document.createElement ('table');

// HTMLTableElement は,tHead プロパティを持つが,初期値は null
typeof node.tHead; // 'object'(typeof null は 'object' を返す)

// スペルミスしてしまった! thead というプロパティは存在しない
typeof node.thead;  // 'undefined'


のように,本来のプロパティ(null)かそうでないか(undefined)をチェックすることもできます(特に DOM 関連のプロパティは,accessKey とか rowSpan とか htmlFor とか,うっかりミスしやすいものが多いので)。


> 以下のソースに問題を感じますでしょうか?
>>2 のコードだと,

doesExist ('Array.xyzxyz'); // 存在しないプロパティだが true


になってしまいますが,これは構わないのでしょうか。


----------

本題から少し離れますが,私自身これまで「プロパティ」「変数」を曖昧に使っていた(すみません m(_ _)m)ので,いったん整理させて下さい。

JavaScript では以下を区別する必要があります(括弧内の数字は ECMA 262-3 の節番号)。


* A. プロパティ prop の探索(プロトタイプチェーン)

 obj.prop → C1.prototype.prop → C2.prototype.prop → …… → Object.prototype.prop

ここまで探索して見つからなければ undefined を返します(§8.6.2.1)。

なお,obj.prop.prop2 が undefined.prop2 となった場合,例外 TypeError を投げます(§11.2.1,9.9)。


* B. 変数 variable の探索(スコープチェーン)

 func1.variable → func2.variable → func3.variable → …… → Global.variable

ここで,func1,func2 は,その関数を実行する不可視のオブジェクト(Activation オブジェクト)ですが,とりあえず今は「variable の宣言が func1 内に見つからなければ,より上位の func2,func3,……最終的に Global まで文脈をさかのぼって variable を探す」ということで,お茶を濁します。

Global まで探索しても見つからなければ null.variable を返します(§10.1.4)。null.variable を参照しようとすると例外 ReferenceError が発生します(§8.7.1)。null.variable を設定しようとすると Global.variable を作成します(§8.7.2)。

なお,ブラウザ上では,Global は window になります。つまり,グローバルな変数・関数は,ブラウザ上では window のプロパティ・メソッドとなります。

4   名前: ラマ : 2006/05/10(水) 10:34  ID:ya6xOqUo
返信が遅れました。すみません。
(ごた続きで徹夜続きです・・)

>> nullが設定されない限り変数はnullにはならない
>その通りですね。

これで、すっきりです。
なんとなく、変数が宣言されたら、
内部でひとつポインタ領域とってNULLを設定する短絡的なイメージがあって混乱してました。
(・・よく考えるとポインタ領域だけとるってことはないですね。)

>>以下のソースに問題を感じますでしょうか?
我ながらひどい質問でした。
しかも、こんな関数を使う場面もなさそうですね・・。
失礼しました。

>「プロパティ」「変数」・・

prototypeは、継承用でsubからsuperへと内側に入っていくイメージで、
variavleは、スコープの広い方へ向かっていくイメージな感じですね。
勉強になります。

-------

PID様、変な質問に丁寧にお答え下さり、大感謝です。
ありがとうございました。

一覧へ戻る