初めてのjavascript3章(演算子と文)

1章、2章に引き続き3章です。演算子と文の章です。

文の形式

文の終わりは、「jsを解釈するエンジンが、対象の文を完全な物だと判断でき、かつ、終わりが改行文字」または「;」で示す。
改行文字単体で文の終わりを示すわけではない。


ということは、1行に複数の文を書ける。

var num; num = 1; alert(num); 

複数行にまたがっても書ける。これは長い条件文とかを書く際に便利だ。

var num 
 = 1;

代入文

  • 1行で複数の代入ができる。
var a, b;
a = b = 1;

//以下と同じ
var a = 1, b = 1;

以下のような書き方は意味が違う。

var a, b = 1;  //var a, bを宣言し、bに1を代入
  • 代入分の返り値は代入した値
var x, y;
function hoge(){return (x = 1)}
y = hoge();

//xもyも1になる

演算時の暗黙の変換について

jsでは演算時に値の型変換がおこることがある。

  • 文字列 => 数値の変換

+以外の演算子に対するオペランド文字列は、数字の形式をしているものはnumeric型に変換される。

3 * 2.0     // => 6
3 * "2.0"   // => 6
"3" * "2.0" // => 6


文字列に関わらず、numeric型に変換されるようです。

//Number(false) => 0 
3 * false       // => 0
  • 数値 => 文字列の変換

+演算子は、オペランドに文字列が含まれる場合は、もう一方のオペランドもstring型に変換される

3 + "2"        // => "32"
false + "hoge" // => "falsehoeg"

/演算子の結果は切り捨てでなく浮動小数

おぉ。rubyと違うね。

3 / 2   // => 1.5

条件文

  • if文
var num = 1;

if(num == 1){
  //numは1だよ
}else if(num == 2){
 //numは1じゃない && 2だよ
}else{
  //numは1でも2でもないよ
}


ifの実行文が1行なら簡潔に書ける
if(num == 1) alert("numは1");

  • switch文
var num = 1;

switch(num){
  case 1 :
    //numは1
    break;
  case 2 :
  case 3:
    //numは2か3
    break;
  default :
    //numは1,2,3のいずれでもない
}


breakしないと、全てのcaseを見に行くので注意。上の例でbreak入れないと、numの値に関係なく、default節が必ず実行される。
「numは2か3」を表現する際、「case (2 || 3)」とはかけない。switch文の最初の式は(上の例ではnum)、numといった値だけでなく式を書くこともできる。

同値演算子と、厳密等価演算子

2つの値が同じかどうか調べる。

2 == "2"           // => true
null  == undefined // => true

数値への暗黙の変換がここでも行われるんですね。

2 === "2"          // => false
null === undefined // => false


この2つに対する否定の演算子もあります。

2 != "2"    // => false
2 !== "2"   // => true

比較演算子

この時も暗黙の型変換が行われます。

2 < "10"      // => true

論理演算子

&&や||は、式の結果が出た時点で、残りの条件を評価しません。

1 || x    // => true
0 && x    // => false
true && q 
q is not defined

ループ

  • while
var i = 0;

while(i < 10){
  document.writeln(i + "<br />");
  i++;
}
  • for
for(var i = 0; i < 10; i++){
  document.writeln(i + "<br />");
}
  • for(変数名 in オブジェクト){}とHash

この形式のforループ(一部のブラウザでは実装されていないものもある)は、オブジェクトの中身を順番にとってきます順序は任意でした)。オブジェクトがHashなら、そのキーを順々にとってきます。これを使った面白い例が紹介されていました。

本(p.69)に以下のようなことが書いてありました。要約すると以下のような感じ。

JavaScriptのオブジェクトも連想配列(Hashのこと)の例です。例えば、documentオブジェクトにwritelnという関数がありますが、これは、documentオブジェクトのプロパティの1つです。


プロパティとは、オブジェクトが持つ、属性、関数をまとめたもの。documentオブジェクトは、title、bgColor等、文章の性質を決める属性(HTMLでいう属性と同じ)と関数を持っています。この2つをあわせてプロパティといいます。(狭義のプロパティは属性のみだと思うけど・・・)


JavaScriptでは、これらのプロパティを含むオブジェクトをHashとして取り扱います。Hashのキーにプロパティ名を、値にその実装(関数ならfunction型のオブジェクトか)が入っています。


よって、for文を使うと、documentオブジェクトの全てのプロパティ(DontEnum属性のついているプロパティは列挙できませんでした。たとえば、組み込みのプロパティは列挙できません)について調べてることができる。

for(docprop in document){
  document.writeln(docprop + "=" + eval("document." + docprop) + "<br ;>");
}

結果は以下のような感じ。

title= document propaties
referrer=
styleSheets= [object StyleSheetList]
baseURI= file://localhost/Users/luke/app/js/study/3-8.html
compareDocumentPosition= function compareDocumentPosition() { [native code] }
textContent= null
isSameNode= function isSameNode() { [native code] }
lookupPrefix= function lookupPrefix() { [native code] }
isDefaultNamespace= function isDefaultNamespace() { [native code] }
lookupNamespaceURI= function lookupNamespaceURI() { [native code] }
isEqualNode= function isEqualNode() { [native code] }
getFeature= function getFeature() { [native code] }
setUserData= function setUserData() { [native code] }
getUserData= function getUserData() { [native code] }
DOCUMENT_POSITION_DISCONNECTED= 1
DOCUMENT_POSITION_PRECEDING= 2
DOCUMENT_POSITION_FOLLOWING= 4
DOCUMENT_POSITION_CONTAINS= 8
・・・


rubyで書くと、JavaScriptのオブジェクトってこんなイメージかな?

class Hoge
  private
    
  PROPATIES = 
    {:hoge => 1,
     :fuga => lambda{|x| x * 2}}

  def method_missing(method_id,*args)    
    prop = PROPATIES[method_id]
   
    if prop
      if prop.respond_to?(:call)
        prop.call(*args)
      else
        prop
      end
    else
      super
    end
  end
end

Hoge.new.hoge    # => 1
Hoge.new.fuga(2) # => 6 

追記

id:javascripterさんよりコメントで訂正頂いたとこを追記しました。その際にレファレンスを教えて頂きました。

これは便利だー。MozillaのdevelopreサイトはJavaScriptユーザーには勉強にもってこいっすね。


今回指摘頂いたとこは、以下のレファレンス部分に書いてありました。

指定された変数を、オブジェクトの全プロパティに対して任意の順序で反復します

for...in ループは組み込みプロパティに対しては反復しません。これらには、String の indexOf メソッドや Object の toString メソッドといった、オブジェクトの全組み込みメソッドも含まれます。しかしながら、このループは (組み込みプロパティを上書きしたものも含む) すべてのユーザー定義プロパティに対して反復します。


これに関しては、DontEnum属性を持つプロパティは列挙されないとのことです。以下がとても参考になりました。

ここで注目して欲しいのは、 List 1.8 で length というプロパティが出力されていないことです。List 1.6 から、文字列オブジェクトが length というプロパティを持つことは確実です。しかし、for in でメンバを列挙しても length プロパティは見つかりませんでした。これはいったい何故でしょうか。

実はこれは、文字列オブジェクトの length プロパティが DontEnum という属性を持っているからなのです。この DontEnum属性を持つプロパティは for in ループで列挙されなくなります。

このように、オブジェクトのプロパティには属性というものが存在します。属性を持つプロパティは、その所有する属性に定義された性質を持つことになるのです。

属性には、上記の for in で列挙されない DontEnum の他に、代入処理が無視される ReadOnly、delete 演算子での削除処理が無視される DontDelete、直にアクセスできない Internal があります。


プロパティの中には属性を持つものがあるんですね。プロパティの属性をユーザーが決めることはできないので、属性を持つプロパティは組み込みオブジェクトのプロパティだということです。