JavaScript復習

今年のゴールデンウィークは10連休だ!

HTML5 + JavaScriptまたはサーバーサイドJavaScriptにそなえて、JavaScriptを勉強しなおしてみる。前者はともかく、後者は、採用が増えたとしてもマイナーなままな気もするが。
Webのサーバ側は、Perl + CGIが当たり前の時代から、サーバやら言語やらフレームワークやら選択肢が増えて、ちらっとためすのもたいへん。サーバーサイドJavaScriptをつかうかどうかも、なにがしかの基準でほかと使い分けになるのだろうか。

JavaScript: The Good Parts ―「良いパーツ」によるベストプラクティス

JavaScript: The Good Parts ―「良いパーツ」によるベストプラクティス

JavaScriptパターン ―優れたアプリケーションのための作法

JavaScriptパターン ―優れたアプリケーションのための作法

上の2冊を駆け足で読んでみた。
The Good PartsとJavaScriptパターンの内容は、重複している点も多かった。JavaScriptパターンは十分コンパクトな内容だったとおもうが、それをさらにコンパクトにしたのがThe Good Partsという印象。

環境構築

JavaScriptの実行環境は、ブラウザなり、ここ最近ちらほら名前を聞くNode.jsなりもある。今回、勉強したいのはAjaxとかサーバーサイドJavaScriptでなくて、それ以前のもっと基本的なことだ。
Javaのjrunscript(Rhino)で、xxxx.jsファイルを実行していく。

println

Rhinoには、ブラウザにダイアログを表示するalertでなくて、コンソール出力してくれるprintlnがある。でも、UTF-8JavaScriptのファイルを実行したら、日本語が文字化けた。文字化けないようにちょっぴり修正。JavaVMの言語じゃなかったら、自分には、こう簡単には修正できなかったところだ。

var embeded_println = println;

var println = function (string, encoding) {
    var tempString = string
        + java.lang.System.getProperty("line.separator");
    var enc = encoding || "UTF-8";
    var bytes = new java.lang.String(tempString).getBytes(enc);
    java.lang.System.out.write(bytes, 0, bytes.length);

};

JavaScriptの特徴

勉強するにつれて「Javaとはぜんぜん違うな」という印象を持つようなった。自分のメインのプログラミング言語Javaだけど、少なくとも、Javaの知識と照らし合わせないほうが無難そうだ。自分の今の段階の勉強方針としては、Javaとはちがうということをはっきりさせたほうが良さそうだ。

プロトタイプベースのオブジェクト指向言語
関数もオブジェクト

JavaScriptでは、

  • 関数の宣言は、関数オブジェクトの生成に相当する
  • 関数を引数にとる関数もあり。
  • 関数を返り値にする関数もあり。

Javaは違うけど、Scalaはそうだな。Rubyも、Procとかブロックとかあった。

typeofを使うと、型がわかる。

js> typeof "1";
string
js> typeof 1;
number
js> typeof null;
object
js> typeof true;
boolean
js> typeof println;
function
js> typeof x;
undefined

組み込みで、Object関数がある。Javaには、Objectクラスがあるが、Javaとちがって、JavaScriptにはそもそもクラスというものはない。同じObjectという名前であっても混同してはだめ。まったく別物。Object関数を実行するとオブジェクトを生成できる。

Object関数は、prototypeというプロパティをもつ。このprototypeの型は、objectである。

js> typeof Object;
function
js> typeof Object.prototype;
object
js> typeof new Object;
object
js> typeof new Object();
object
js> typeof Object();
object
js> typeof {};
object

組み込みで、Function関数がある。Function関数を実行すると関数オブジェクトを生成できる。
Function関数は、prototypeというプロパティをもつ。このprototypeの型は、functionである。
Function関数で生成した関数は、prototypeというプロパティをもつ。このprototypeの型は、objectである。functionではない。

js> typeof Function;
function
js> typeof Function.prototype;
function
js> typeof new Function;
function
js> typeof new Function();
function
js> typeof Function();
function
js> typeof (new Function()).prototype
object

js> typeof function(){};
function
js> typeof function(){}.prototype;
object

文法

デフォルト値の設定
var a;
var b = a || "default value";
println(a);
println(b);
比較

比較は、

  • ===
  • !==

でおこなう。

  • ==
  • !=

は使わないほうがよい。==や!=を使うと、自動の型変換があって、挙動がややこしいらしい。

var

varの有無は、JavaScriptに不慣れなうちは、気づきにくいバグにつながる場合もあるので、注意。

  • 関数の外側
    • varをつけて宣言した変数
      • グローバルオブジェクトのプロパティになる。
    • varをつけていない変数
      • グローバルオブジェクトのプロパティになる。
  • 関数の内側
    • varをつけて宣言した変数
      • ローカル変数になる。
    • varをつけていない変数
      • グローバルオブジェクトのプロパティになる。
      • thisが指しているオブジェクトのプロパティになる。
スコープ
  • {....}はスコープにならない。
    • if(....) {....} else {....}の{....}はスコープにならない。
    • for(....){....}の{....}はスコープにならない。
    • while(....){....}の{....}はスコープにならない。
  • ある関数の外側か内側かでは、スコープになる。
    • function xxxx(....) {....};の{....}はスコープになる。
      • ある関数の内側で、varで宣言した変数は、その関数の外側からは見えない。
      • ある関数の内側で、宣言した関数は、その関数の外側からは見えない。
名前空間
  • Javaのパッケージのようなものは、JavaScriptにはない。
this

thisの挙動はとてもわかりづらい。本を読んでも、実際に実行して試してみても、イマイチわからなかった。あらためまして、なんともだなあ。

  • 関数の外側の場合
    • thisはグローバルオブジェクトを指す。
      • ブラウザだったらwindowとか。
  • 関数の内側の場合
    • newをつけないで関数を実行した場合
      • thisはグローバルオブジェクト
      • thisはこの関数をメソッドにしているオブジェクト
    • newをつけて関数を実行した場合
      • thisはその関数オブジェクト自身を指す。

http://bonsaiden.github.com/JavaScript-Garden/ja/:tile
ここにあるthisの例がわかりやすかった。

オブジェクトの生成

ごく単純なオブジェクトの生成

とりあえず、オブジェクトを生成して、後からプロパティをたしていく。

var person = new Object();
person.name = "テスト名";
person.age = 35;
person.favoriteThings = ["寿司", "プログラミング"];
person.introdude = function() {
    var i;
    for(i = 0; i < this.favoriteThings.length; i++) {
        println("I love " + this.favoriteThings[i]);
    }
};

person.introdude();
var person2 = {
    name:"テスト名", 
    age:35, 
    favoriteThings:["寿司", "プログラミング"],
    introdude:function () {
        var i;
        for(i = 0; i < this.favoriteThings.length; i++) {
            println("I love " + this.favoriteThings[i]);
        }
    }
};

person2.introdude();
よりJavaScritの機能を活かしたオブジェクトの生成

よりJavaScritの機能を活かしたオブジェクトの生成としては、

  • クロージャを活用する。
  • prototypeプロパティを活用する。

の2つがある。


関数

関数はひとつのオブジェクトである。宣言するたびにオブジェクトが生成される。宣言のしかたはいろいろ。


継承

JavaScript自身は、プロトタイプベースのプログラミング言語であり、クラスベースのプログラミング言語のような継承はサポートしていない。

継承は、Function関数のprototypeプロパティなどを活かしつつ、ケースバイケースで自分で実現する。面倒なような、柔軟なような。

継承を実現する方法としては、

のようなJavaScriptのライブラリが提供している継承の機能を使ったほうが手間は少ない。