2010年01月31日
JavaScript基礎文法最速マスター
- Perl基礎文法最速マスター - Perl入門〜サンプルコードによるPerl入門〜
- Ruby基礎文法最速マスター - Route 477
- PHP基礎文法最速マスター - Shin x blog
- Python基礎文法最速マスター - D++のはまり日誌
- Brainf*ck基礎文法最速マスター - 医者を志す妻を応援する夫の日記
- Haskell基礎文法最速マスター - think and error
JavaScript 版は誰も書いていなかったようなので書いてみます。こういう解説記事的なものを書くのは初めてなので変なところがあったら指摘して頂けるとありがたいです。
1/31 23:58追記
コメント欄のos0xさんのご指摘を基に一部追記・修正を行いました。
まえがき
本記事は主に JavaScript の文法面について解説します。基本的に ECMAScript 第3版の範囲内の文法について取り扱いますが,そこからはみ出す部分については適宜注釈をつけておきます。
JavaScript の標準仕様
JavaScript の仕様は標準化団体 Ecma International によって ECMAScript として定められています。この ECMAScript を各社が実装したのが Mozilla 等の JavaScript や Microsoft の JScript, Adobe の ActionScript などです(詳細はECMAScript - Wikipedia参照)。ただ単に JavaScript と言った場合はこれらの実装をひっくるめて呼んでいることが多いようです。
JavaScript の実行 (ブラウザ編)
JavaScript で書かれたを実行するためにはブラウザを用いるのが一番手っ取り早いです。1行で済むスクリプトを実行する場合,ブラウザのロケーションバーに以下のように打ち込みます。
javascript: 実行したいプログラム
例えば,メッセージを表示させるなら以下のようにします。
javascript: alert("aaa");
ブックマークレットはこのようにして JavaScript プログラムを実行させています。
上記の仕組みで実行できるのは1行に収まる(改行を含まない) JavaScript だけです。改行ではなくセミコロンで文を区切ることで複数の文を含むプログラムも実行できますが,そのようなプログラムは読み書きしづらく大変です。複数行の JavaScript を実行させるためには, JavaScript のソースコードだけではなく以下のような HTML を書き,それをブラウザに読み込ませる必要があります。
<html> <head> <title>JavaScript テスト</title> <script type="text/javascript"> </script> <script type="text/javascript" src="ファイル名"></script> </head> <body> <script type="text/javascript"></script> </body> </html>
JavaScript の実行 (ブラウザ以外編)
ブラウザ上の JavaScript と比較するとマイナーですが,他の言語のようにシェル上で JavaScript を実行できる実装もあります。ここでは詳細には触れません。
基礎
print文
JavaScript の標準ライブラリには入出力に関する関数が一切定義されていません!文字列を出力する場合は,ブラウザで実装されている alert 関数を用いる事が多いです。
alert("Hello, world");
また,最近は多くのブラウザで console.log がサポートされているので,コンソールウインドウにメッセージを出すこともできます。 console.log を使うと文字列だけでなく様々なオブジェクトを出力することができます。
console.log("Hello, world"); console.log([1, 2, 3]);
コメント
コメントは C 系の言語と同じです。
// 一行のコメント /* 複数行の コメント */
文法チェック
次世代バージョンの JavaScript (ECMAScript 5) では Strict モードという,より厳密に文法チェックが行われるモードが導入されます。メジャーな処理系はまだ Strict モードをサポートしていませんが,今から JavaScript を覚えるのなら厳密な書き方を身につけておいた方が良いでしょう。
Strict モードにするためには,スクリプトの先頭に以下を書き込みます。このコード自体はただの文字列なので, Strict モードに対応していないブラウザには何の影響も与えません。
"use strict";
文
文の最後にはセミコロン ( ; ) を付けます。付けない場合自動で補われますがたまに変な挙動を起こすのでできるだけ付けるようにしましょう。
変数の宣言
var で宣言します。変数に型はありません。
var hoge = 1; hoge = "a"; // 数字も文字も代入できる
宣言していない変数に値を代入することもできますが,その場合はグローバル変数が作られそこに代入されます (厳密にはちょっと違いますが)。未定義変数への代入操作は Strict モードではエラーになるのでできるだけ使わないようにしましょう。
a = 1; // エラーにならない
数値
JavaScript の数値は全てが実数型です。整数型という概念はありません。
var d = 123456; // 10進数の整数 var h = 0xffff; // 16進数 var o = 0123; // 8進数 (Strictモードでは10進数となります) var f = 12.345; // 実数
数値演算
JavaScript には実数型しかないので,演算の結果も実数型になります。ただし, ビット演算の場合は小数点以下を切り捨てて整数に変換してから行われます。
var a = 1 + 2; // => 3 a = 3 - 2; // => 1 a = 1 * 5; // => 5 a = 3 / 2; // => 1.5 (整数同士の割り算でも結果は実数) a = 3 % 2; // => 1 (余り) a = 255.1 & 2.1; // == 255 & 2 => 2 (ビット演算は整数に変換(小数点以下切り捨て)してから行われる) a = 12.3 >> 1; // => "6" (同上)
代入演算子とインクリメント・デクリメント
C 系言語と同じように使えます。
var a = 0; a += 3; // => 3 a -= 2; // => 1 a *= 3; // => 3 a /= 3; // => 1 a = 0; var b = a++; // => a == 1, b == 0 var c = ++a; // => a == 2, b == 2 var d = a--; // => a == 1, b == 2 var e = --a; // => a == 0, b == 0
文字列
文字列はシングルクオート( ' )かダブルクオート ( " )で囲みます。両者は全く等価です。シングル・ダブルクオートのどちらの場合でも \t (タブ), \n (改行) などの特殊文字を利用することができます。変数展開などの便利な機能はありません。
var a = "abc\tdef"; // "abc[tab]def" ([tab]はタブ文字) var b = 'abc\tdef"; // "abc[tab]def"
文字列操作
結合
var join1 = 'aaa' + 'bbb'; var join2 = ['aaa', 'bbb', 'ccc'].join(',');
分割
var record = 'aaa,bbb,ccc'.split(/,/);
長さ
var length = 'abcdef'.length; // => 5 var jplen = 'あいうえお'; // => 5
切り出し (substrは多くの環境でサポートされていますが非標準なメソッドなので一応注意)
var substr = 'abcd'.substr(1, 2); // => bc var substring = 'abcd'.substring(1, 2); // => b
検索
// 見つかった場合はその位置,見つからなかった場合は-1が返る var result1 = 'abcd'.indexOf('cd'); // => 2 var result2 = 'abcd'.indexOf('ef'); // => -1
配列
配列の生成方法いろいろ。
var ary1 = [1, 2, 3]; // => [1, 2, 3] var ary2 = new Array(3); // => [undefined, undefined, undefined] var ary3 = new Array(3, 4, 5); // => [3, 4, 5]
配列の参照と代入
var ary = [1, 2, 3]; ary[2]; // => 3 (配列のインデックスは0オリジン) ary[0] = 3; // => ary == [3, 2, 3]
要素の個数
ary.length
配列の操作
var ary = [1, 2, 3]; // 先頭を取り出す var a = ary.shift(); // => a == 1, ary == [2,3] // 先頭に追加 ary.unshift(5); // => ary == [5,2,3] // 末尾を取り出す var b = ary.pop(); // => b == 3, ary == [5,2] // 末尾に追加 ary.push(9); // => ary == [5,2,9] // 部分コピーを得る var c = ary.slice(1, 2); // => c == [2, 9], ary == [5, 2, 9] // 一部を置き換える var d= ary.splice(1, 2, "a", "b", "c"); // => d == [2, 9], ary == [5, "a", "b", "c"]
連想配列 (のようなもの)
JavaScript には連想配列というものはありませんが,任意のオブジェクトを連想配列のように扱うことができます。
// オブジェクトの定義。JSON はこの表記法を基にしている var a = {a: 123, b: 456}; a['a']; // => 123 (連想配列風アクセス) a.b; // => 456 (プロパティ風アクセス) a['c'] = 789; // 要素の追加 a.d = 123;
以下のような書き方も可能ですが,普通はやりません。
"abc"['length']; // => 3 (プロパティの取得) "a,b,c"['split'](/,/); // => ["a", "b", "c"] (メソッド呼び出し)
連想配列風のアクセスとプロパティ風のアクセスは表記が異なるだけで意味上の差はありません。
制御文
if文
if (条件) { hoge(); fuga(); } // if中の文が1つだけの場合は 括弧 ( "{", "}" ) を省略可能 if (条件) hoge();
if-else文
if (条件) { } else { }
while文
var i = 0; while (i < 5) { i++; }
for文
for (var i = 0; i < 5; i++) { }
for in文
var obj = {a: 1, b: 2}; for (var i in obj) { alert(obj[i]); // => 1, 2 }
for each文 (Firefoxのみ対応)
var obj = {a: 1, b: 2}; for each (var v in obj) { alert(v); // => 1, 2 }
Array#forEach (最近のブラウザのみ対応)
["a", "b", "c"].forEach(function(v, i) { alert(i + ": " + v); // => "0: a", "1: b", "2: c" })
関数
関数は以下のように書きます。
function sum3a(a, b, c) { return a + b + c; }
JavaScriptの関数はファーストクラスのオブジェクトなので,無名の関数を作って変数に代入することもできます。
var sum3b = function(a, b, c) { return a + b + c; };
sum3aはコンパイル時に定義され,sum3bは実行時に定義されます。それ以外の点で両者に差はありません。
Firefox だと以下のような短縮表記が使えます (式クロージャ記法)。
var sum3b = function(a, b, c) a + b + c;
ファイル入出力
サーバとの通信は行えますが煩雑なので省略 (XMLHttpRequestでググってください)
JavaScriptのオブジェクト指向
JavaScript はプロトタイプベースの(純粋?)オブジェクト指向言語です。変数に代入できるものは全てundefinedなどの特殊な値を除きほとんどがオブジェクトです。
オブジェクトの定義
var obj = {a: 123, b: 3}; obj.a; // => 123
メソッド
var man = { hello: function() { alert('hello!'); }, bye: function() { alert('bye'); } }; man.hello(); // => hello!
クラスのようなもの
関数を作りその prototoype プロパティをいじることでクラスのようなオブジェクトを作ることができます。
// クラス (のようなもの) の定義 // コンストラクタとなる関数 var Man = function(name, age) { // プロパティの初期化 this.name = name; this.age = age; }; // メソッド・プロパティの定義 Man.prototype = { sayName: function() { alert("My name is " + this.name + "."); } } // インスタンスの作成 var bob = new Man('Bob', 35); bob.sayName(); // => My name is Bob.
継承
prototype に親クラスのオブジェクトを代入することで継承が実現できます。
var Animal = function() {}; Animal.prototype = { sleep: function() { alert('zzz...'); } }; var Human = function() {}; Human.prototype = new Animal(); Human.prototype.workHarder = function() { alert("I'm tired..."); this.sleep(); }; var me = new Human(); me.workHarder(); // => I'm tired... => zzz...
雑多なtips
真偽値
JavaScript では以下の値が false として扱われます。
これ以外は全て true として扱われます。
==と===
==による比較は自動的に型変換が行われてから比較されるため,意図せぬ結果をもたらす場合があります。
'0' == 0; // => true '' == 0; // => true '100' == 100 // => true
このような事態を防ぐために,型変換を行わない比較演算子 === を用いるとよいでしょう。
'0' === 0; // => false '' === 0; // => false '100' === 100 // => false
for in文の落とし穴既存のオブジェクト拡張の落とし穴
for in 文には prototype で定義されたプロパティも列挙してしまうので注意が必要です。
Object.prototype = {doHoge: function() {}}; var obj = {a: 1, b: 2}; for (var i in obj) { alert("i = " + obj[i]); // => "a = 1", "b = 2", "doHoge = function() {}" }
このような挙動を回避するためには, hasOwnProperty を使ってそのオブジェクト自体が持っているプロパティかどうかを確認しましょう。
Object.prototype = {doHoge: function() {}}; var obj = {a: 1, b: 2}; for (var i in obj) { if (obj.hasOwnProperty(i)) alert("i = " + obj[i]); // => "a = 1", "b = 2" }
既存のオブジェクト,特に全てのオブジェクトのプロトタイプである Object.prototype を拡張する場合は効果範囲が大きいので慎重に行ってください。
変数のスコープ
変数のスコープは宣言した関数内全体になります。関数内のどの位置で変数宣言しても,関数内全体からその変数を参照できます。
var a = 0; function() { alert(a); // => undefined (関数内で後に定義したaを参照するため) var a = 1; // ここで a に値が代入される if (true) { var b = 1; // ここで定義した b は関数内ならどこからでも参照出来る } alert(b); // => 1 (if文の中で宣言した b を参照できる) }
Firefox だと以下のようにしてスコープがブロック内に限定される変数を宣言することができます。
if (true) { let b = 1; } alert(b); // => undefined (letで宣言するとスコープがif文の中に限定される)
thisの指す物
メソッド内で使われている this が指すものは,そのメソッドの呼び出され方によって変わります。具体的には, obj.hoge(); の形で呼び出された場合,thisはobjになり,hoge();の形で呼び出された場合はthisは window (グローバルオブジェクト)になります。
var smith = { name: "Smith", sayName: function() { alert(this.name); } }; smith.sayName(); // => Smith var john = {name: "John"}; john.sayName = smith.sayName; // 関数を代入 john.sayName(); // => John var sayName = john.sayName; sayName(); // => undefined (thisがwindowを指すためthis.name == window.name == undefined)
既存のオブジェクトの拡張
既存のオブジェクトの prototype をいじることで既存のオブジェクトを拡張できます。
[1, 2, 3].sum(); // => Error (sum is not a function) Array.prototype.sum = function() { var sum = 0; for (var i = 0; i < this.length; i++) { sum += this[i]; } return sum; }; [1, 2, 3].sum(); // => 6
JavaScript参考資料
言語リファレンス
MDCのドキュメントがよくまとまっていて使いやすいです。
JavaScriptのオブジェクト指向について
自分は以下のページでオブジェクト指向を学びました
- 208 http://reader.livedoor.com/reader/
- 144 http://b.hatena.ne.jp/hotentry
- 112 http://twitter.com/
- 94 http://www.google.co.jp/reader/view/
- 92 http://b.hatena.ne.jp/hotentry/it
- 89 http://www.google.com/reader/view/
- 56 http://www.google.co.jp/reader/view/?hl=ja&tab=wy
- 50 http://longurl.org
- 40 http://b.hatena.ne.jp/
- 32 http://b.hatena.ne.jp/entrylist
- 2010-01-31 ろ日記 3/18 16%
- 2010-01-31 bi_naの日記 3/57 5%
- 2010-01-31 素人がプログラミングを勉強するブログ 3/60 5%