JavaScriptでの未定義のプロパティの評価方法と仕様書の解釈について

このQ&Aのポイント
  • JavaScriptにおいて、未定義のローカル変数を評価する際にはtypeofを使用する必要がある。
  • 一方、存在が保証されているオブジェクトの存在しないプロパティを評価する場合は、obj.propertyがnullなためundefinedを返す。
  • ECMA-262 3rd Edition仕様書の解釈によれば、このような処理が行われることが確認できる。
回答を見る
  • ベストアンサー

obj.property のundefined判定

obj.property のundefined判定 未定義のローカル変数を評価すると、以下の結果になります。 <script type="text/javascript"><!-- var a; if(a === undefined){ alert('a is undefined!'); } // エラーは発生しない if(b === undefined){ alert('b is undefined!'); } // 「ReferenceError: b is not defined」のエラーが発生し、if文が評価されない if('undefined' === typeof b){ alert('b is undefined!'); } // エラーは発生しない //--></script> 未定義のローカル変数は undefined との比較ではチェックできず、typeof でチェックする必要があることが分かります。 対して、「存在が保証されているオブジェクトの存在しないプロパティ」でチェックすると、以下の結果になります。 <script type="text/javascript"><!-- var obj = { a:'valueA', b:'valueB' }; if(obj.property === undefined){ alert('obj.property is undefined!'); } // エラーは発生しない if('undefined' === typeof obj.property){ alert('obj.property is undefined!'); } // エラーは発生しない //--></script> 不思議に思い、ECMA-262 3rd Edition仕様書を読んでみたところ、下記文言が見つかりました。 ---------- 8.6.2.1 [[Get]] (P) O の [[Get]] メソッドがプロパティ名 P で呼出されると、次のステップがとられる: 1. O が P という名前のプロパティを持っていなければ、ステップ 4 へ進む。 2. そのプロパティの値を取得する。 3. Result(2) を返す。 4. O の [[Prototype]] が null ならば、undefined を返す。 5. [[Prototype]] の [[Get]] メソッドを、プロパティ名 P で呼び出す。 6. Result(5) を返す。 http://www2u.biglobe.ne.jp/~oz-07ams/prog/ecma262r3/8_Types.html#section-8.6.2 ---------- この場合、ステップ4の「obj.property が nullなため undefined を返す」という処理が行われた、という解釈で合っているでしょうか? ほぼ正しいと感じているのですが、「仕様書の中で見るべきところが合っているのか」に自信が持てず、確信に至っていません…。

質問者が選んだベストアンサー

  • ベストアンサー
  • fujillin
  • ベストアンサー率61% (1594/2576)
回答No.1

よくわかってませんけれど… >ステップ4の「obj.property が nullなため ~~ objの[[prototype]](obj.propertyではない)がnullなので~~ ではないのでしょうか? プロパティの有無は、 property in object でも判別可能みたい。 var org = function() { this.a = 'valueA', this.b = 'valueB'; } org.prototype.c = 'valueC'; var obj2 = new org(); alert(obj2.c); //valueC alert('c' in obj2); //true alert('property' in obj2); //false alert(obj2.hasOwnProperty('c')); //false

think49
質問者

お礼

改めて読み直して、頭を抱えました…。 「obj.prototype がnullならば、undefined を返す」と書きたかったはずなのにw fujillinさんが回答された内容は、私の理解と一致しています。 とりあえず、「問題ない」ってことなのかな? しばらく待って、新しい回答がつかなければ締め切りたいと思います。 ありがとうございます。 > プロパティの有無は、 property in object でも判別可能みたい。 babu_babooさんが同じような回答をされていましたね。 hasOwnProperty() は存在しないプロパティを評価したら、false を返し、 in演算子は存在しないプロパティを評価したら、false を返す、ということは分かりました。 (in演算子はちょっと分かりづらいですが、最終的には [[HasProperty]]メソッドを呼び出して、true, false を返しています。) hasOwnProperty - MDC https://developer.mozilla.org/ja/Core_JavaScript_1.5_Reference/Global_Objects/Object/hasOwnProperty 11.8.7 in 演算子 (The in operat - 11 式 (Expressions) http://www2u.biglobe.ne.jp/~oz-07ams/prog/ecma262r3/11_Expressions.html#section-11.8.7 8.7.1 GetValue (V) - 8 型 (Types) http://www2u.biglobe.ne.jp/~oz-07ams/prog/ecma262r3/8_Types.html#section-8.7.1 8.6.2.4 [[HasProperty]] (P) - 8 型 (Types) http://www2u.biglobe.ne.jp/~oz-07ams/prog/ecma262r3/8_Types.html#section-8.6.2.4 今回、私が疑問に感じたのは「obj.property を評価するときに、なぜ "ReferenceError: obj.property is not defined" にならないのか?」というものです。 未定義のローカル変数では ReferenceError が返るので、直感的に「未定義のプロパティ参照も ReferenceError になるはずだ」と思ってしまったんです。 だから、「プロパティ評価は、typeof演算子ないしhasOwnProperty() メソッドを使用した方が無難」と今までは考えていたのですが、どうも undefined との比較でも通ってしまうようなので「実際のところはどうすべきなのだろう?」と思いまして。

think49
質問者

補足

すみません…、自己解決しました。(汗) 「プロパティアクセス演算子」で obj.property の評価についての解説があり、最終的にはやはり [[Get]]メソッド を使用していました。 11.2.1 プロパティアクセス演算子 - 11 式 (Expressions) http://www2u.biglobe.ne.jp/~oz-07ams/prog/ecma262r3/11_Expressions.html#section-11.2.1 8.7.1 GetValue (V) - 8 型 (Types) http://www2u.biglobe.ne.jp/~oz-07ams/prog/ecma262r3/8_Types.html#section-8.7.1 8.6.2.1 [[Get]] (P) - 8 型 (Types) http://www2u.biglobe.ne.jp/~oz-07ams/prog/ecma262r3/8_Types.html#section-8.6.2.1 検証頂き、ありがとうございました。

関連するQ&A

  • こちらのソースですが、なぜundefinedがでるのでしょうか?

    こちらのソースですが、なぜundefinedがでるのでしょうか? また、undefinedを消す方法はありますか? よろしくお願いいたします。 <script> window.onload = function(){ var hairetu = Array(1,2,3,4,5,6,7,8,9,10); for(var i=0; i<hairetu.length; i++){ var hoge; if(hairetu[i] % 2 == 0 && hairetu[i] % 3 == 0){ hoge += hairetu[i] + '\n'; }else if(hairetu[i] % 2 == 0){ hoge += hairetu[i] + '\n'; }else if(hairetu[i] % 3 == 0){ hoge += hairetu[i] + '\n'; }else { hoge += hairetu[i] + '\n'; } } alert(hoge); } </script>

  • undefinedはNullまたはオブジェクトではありません。

    ホームページビルダーでHPを作っていたのですが、 プレビューで確認したところ、 「undefinedはNullまたはオブジェクトではありません。」 というスクリプトエラーが出てしまいました。 どうすれば良いのでしょうか? アクセス解析のHTMLを書き込んでから発生しているので、恐らくそれと関係があると思うのですが…。 御存知でしたら教えて下さい。

  • ボタンに書かれている文字の入れ替え

    2つのボタンのどちらを押しても、ボタンに書かれているアルファベットが入れ替わるようにしたいのですが、うまくいきません。 alert(obj1)、alert(obj2)などとして、A,Bともに読み込まれているようなのですが、alert(tmp)の時はundefinedがでます。 どこが間違っているのかよろしければ教えてください。 <!doctype html> <html> <head> <meta charset="utf-8"> <title>勉強中</title> </head> <body> <script> function change_alphabet() { var tmp; var obj1 = document.getElementById("button_1").value; var obj2 = document.getElementById("button_2").value; // alert(obj1); // alert(obj2); tmp = obj1.innerHTML; // alert(tmp); obj1.innerHTML = obj2.innerHTML; obj2.innerHTML = tmp; // alert(obj2); } </script> < input type = "button" id = "button_1" value = "A" style = "width: 25px; height: 25px" onclick = "change_alphabet()" > < input type = "button" id = "button_2" value = "B" style = "width: 25px; height: 25px" onclick = "change_alphabet()" > <body> </html>

  • 変数の未定義の判定(JavaScript)

    JavaScriptである名前の変数の定義済み、未定義の判定をする際に 以下のようにするとエラーになりますが、何か方法がないでしょうか。 if (myval == "undefined") {  alert("未定義"); }

  • ネストしない複数のif文でelseは必要でしょうか

    if文についての疑問を質問させてください。 if文はelseを挟むことで複数指定したり入れ子にしたりして使えますが、 elseを未入力で下記のように複数指定することは問題があるのでしょうか。 また、このように24個のifを並べるという書き方はよろしくないものなのでしょうか。 <script type="text/javascript"> (function() { var image_obj = new Image(); image_obj.src = "../image/"; var jikan_obj = new Date(); var htime = jikan_obj.getHours(); if(htime==0){alert('日が変わりました');} if(htime==1){alert('夜中です');} if(htime==2){alert('2時です。');} if(htime==3){alert('真夜中です');} if(htime==4){alert('もうじき朝です');} if(htime==5){alert('新聞が届きました');} if(htime==6){alert('朝です');} if(htime==7){alert('忙しいです');} //これが23まで続きます。 if(htime==23){alert('もうじき日が変わります');} })(); </script>

  • $obj->decode($bytes)って何?

    Encode.pmのPODを読んでいます。その一文です。 [$obj =] find_encoding(ENCODING)  Returns the encoding object corresponding to ENCODING. Returns undef if no matching ENCODING is find.  This object is what actually does the actual (en|de)coding.  $utf8 = decode($name, $bytes);  is in fact   $utf8 = do{    $obj = find_encoding($name);    croak qq(encoding "$name" not found) unless ref $obj;    $obj->decode($bytes)   };  with more error checking. まず  This object is what actually does the actual (en|de)codeing. 直訳すると、「このオブジェクトは実際のエンコードやデコードを実際に行うものです。」となります。実際の、実際の、と二つ並ぶのはあまり語感が良くないと思いますが、でもこのPODを書いたのは文学者ではないですから、原文の方に問題があるのではないかと思います。 次に「このオブジェクト」とは何を指しているのでしょう。find_encoding関数のことを言っているのでしょうか? というのは、下に  $utf8 = decode($name, $bytes); は実際には、  $utf8 = do{   $obj = find_encoding($name);   croak qq(encoding "$name" not found) unless ref $obj;   $obj->decode($bytes) }; だと書いています。{}の中で一番重要なのはfind_encoding関数だと言いたいのではないかと・・・ そうすると  This object is what actually does the actual (en|de)codeing. は、  「実際にエンコードやデコードを行っているのはこの関数です。」 と訳するのが正しいでしょうか? 最後に、  $obj->decode($bytes) $objという文字コードで記述されている$bytesという文字列をutf-8に変換したもの、という意味なはず。 でも浅学な私には、どのような文法でこのコードが書かれているか分かりません。 Perlにおいて、変数と言えば$objだったり@objだったり%objだったりします。そしてそのリファレンスはこれら変数の前に「\」を付ければ良くて、リファレンスはスカラー変数となるから、 $refobj=\($|@|%)obj; となります。 元の変数が(@|%)objの場合、元の変数の一要素を取り出すには、 $obj([index]|{'index'})=$refobj->index; となります。 これが私の知っている矢印記法の唯一の使い方です。 お手数ですが、どなたか教えていただけないでしょうか?

    • ベストアンサー
    • Perl
  • prototypeで前の値を潰さない方法は?

    function obj() { this.name = "名前です"; } var obj01 = new obj(); alert(obj.name); というコードの場合、obj.nameでobj関数に設定されたnameプロパティの値「名前です」をアラートすることができます。このobj関数を変更せず、あとからプロパティと値を追加したい場合、prototypeメソッド(って言って間違いありませんか?)を用いて以下のように実現することができます。 function obj() { this.name = "名前です"; } obj.prototype.age = "年齢です"; var obj01 = new obj(); alert(obj.name+" / "+obj.age); newする前に記述するのがポイントなんですよね。これにより、obj関数(オブジェクト)にageというプロパティと値「年齢です」が追加され、アラートできるようになりました。また最近、連想配列を使うことで複数のプロパティと値を一気にセットできる便利な方法を発見しました。 function obj() { this.name = "名前です"; } obj.prototype.age = "年齢です"; obj.prototype = { "country":"日本出身です", "city":"東京出身です", "hobby":"音楽鑑賞です" }; var obj01 = new obj(); alert(obj.country+" / "+obj.city+" / "+obj.hobby); //alert(obj.age); //alert(obj.name); と、このように複数のプロパティと値をセットし、後で利用することができます。 前置きが長くてすみません、ここからが質問です。 最後の例の場合、連想配列によってセットされたプロパティの値は存在しますが、それ以前にprototypeで設定したageプロパティは存在しなくなっています。alert(obj.age)の行をコメントアウトしていますが、実行するとundefinedと表示されます。そして2つ目のコメントアウト行alert(obj.name);は問題なくnameプロパティの値をアラートできています。 つまり、prototypeメソッドを使って先に追加したプロパティと値は、「obj.prototype=連想配列」で実行した時点で潰されてしまっているようでした。 この連想配列を使ったプロパティ追加を行う際、先に「obj.prototype.プロパティ名」で追加していたプロパティと値を残しておく方法はありませんでしょうか?

  • javascriptのクラス名操作について

    javascriptのgetElementsByClassNameについて質問があります。 下記のようなクラス名を削除して別のクラスをつけるサンプルプログラムを作成しましたがjavascriptのエラーが出てクラスの追加できません。 ※エラー内容:Uncaught TypeError: Cannot read property 'classList' of undefined ---------以下プログラム-------------- <div class="a">aaa</div> <script> var obj = document.getElementsByClassName("a"); obj[0].classList.remove("a"); obj[0].classList.add("b"); </script> --------以上---------------------------- 「obj[0].classList.remove」をした時の前後で「console.log("obj");」をしたところ、 remove後のobjの値が空になっていました。 なぜこうなるか分からないため、分かる方ご教授の程よろしくお願い致します。

  • Notice:Undefined index が。

    教えて下さい。 01: <?php 02: class Reload { 03: var $id; 04: var $val; 05: var $flag; 06: function Reload($id = 'RELOAD') { 07: $this->id = $id; 08: if ($_GET[$this->id]) 09: $this->val = $_GET[$this->id]; 10: elseif ($_POST[$this->id]) 11: $this->val = $_POST[$this->id];       以下略 こういういうコードがある本に出ているのですが、これをCentOS 5.4で include したスクリプトを実行すると、 Notice: Undefined index: ID in /xxx/abc.php on line 8 (および on line 10 にも ) と警告が出ます。 この警告をなくすために、id=""; を 3行目の下に入れてみると、 Parse error: syntax error, unexpected T_VARIABLE, expecting T_FUNCTION in /xxx/abc.php on line 4 (id=""; を挿入した行) となります。 なお、windows7 で xampp 上でテストしているときは、上記スクリプト(id=""; をする前)でも不具合は出なかったのですが、対処法が分からず途方に暮れています・・・。  どのように修正すればよいでしょうか。  よろしくお願いいたします。

    • ベストアンサー
    • PHP
  • returnがundefinedになってしまう。

    登録フォームhtml(php)からonclickで呼び出すvalidate functionから、ある値の有効性をチェックする別のcheck_data functionを呼び出しています。 check_data functionのソースは以下です。 function check_data(data) { var ajaxRequest; try{ //Opera 8.0+,Firefox,Safari ajaxRequest = new XMLHttpRequest(); }catch(e){ //Internet Explorer Browsers try{ ajaxRequest = new ActiveXObject("Msxml2.XMLHTTP"); }catch(e){ try{ ajaxRequest = new ActiveXObject("Microsoft.XMLHTTP"); }catch(e){ //something went wrong alert("your browser broke!"); return false; } } } //Create a function that will receive date sent from the server ajaxRequest.onreadystatechange = function(){ if(ajaxRequest.readyState==4){ var ajaxDisplay = document.getElementById('data_msg'); ajaxDisplay.innerHTML = ajaxRequest.responseText; var val = ajaxRequest.responseText; return val; } } var date = new Date(); var timestamp=date.getTime(); //var data = document.getElementById('data').value; data = data; var queryString = "?tm=" + timestamp + "&data=" + data; ajaxRequest.open("GET","data_check.php" + queryString, true); ajaxRequest.send(null); } これを validate functionから var vdata = check_data(data); alert(vdata); みたいな感じで呼び出しています。 alertにしているのは単に値が正確に返っているかチェックするためです。 しかし、このvdataに入ってるはずの値がundefinedになってしまうのです。 check_data function内でvar val = ajaxRequest.responseText; をalert(val)する場合には正確な値がalertされるのですが、 validate functionから呼び出してvar vdata = check_data(data); する部分で何故かundefinedになってしまうのです。 responseTextでデータが取得される前にreturnされてしまいundefined になるのかとも思うのですが、たとえばreturn val;の代わりにreturn 10; などにしてもvalidate functionから呼び出すと、undefinedになってしまいます。 何が問題なんでしょうか? IE6とFireFox3.03で同様の結果になります。 因みに function test() { var test = 'ok'; return test; } をvalidate functionから呼び出した場合は キチンと'ok'がalertされます。

専門家に質問してみよう