再入門JavaScript: 言語編

(2002.1.3) 新規作成

(2007.1.27) 加筆し、ページを独立。

JavaScript / ECMAScriptのオブジェクトシステム、言語仕様など。すでに何らかのプログラミング言語が分かっている人が、手早くJavaScriptを理解するための手引きとして。

ECMAScript 3rd editionが言語仕様を定めているが、実装はそのとおりになっていない。実装のほうを優先する。

Internet Explorer 7, Firefox 1.5とSeaMonkey 1.0 (旧Mozilla) でテストした。

字句構造

JavaScriptのスクリプトの文字コードはUnicode (規格ではUTF-16と書いているが、UTF-8でも問題ない。) で書くことになっている。が、HTMLに埋め込むなら地のHTMLと同じ文字コードにするしかない。

コメントは次の2種類。

  1. 「/*」から「*/」まで。入れ子にはできない。
  2. 「//」から行末まで

識別子は次のとおり。アルファベットの大文字・小文字は区別される。関数名などに仮名・漢字も使える(が変態的)。

  1. 先頭文字としては,Unicode分類の,"Uppercase letter (Lu)","Lowercase letter (Ll)","Titlecase letter (Lt)","Modifier letter (Lm)","Other letter (Lo)",または"Letter number (Nl)" の文字,もしくは「$」,「_」。
  2. 2文字目からは,加えて,Unicode分類の,"Non-spacing mark (Mn)", "Combining spacing mark (Mc)","Decimal number (Nd)", "Connector punctuation (Pc)" の文字。
  1. function 関数() {
  2. AA = 10; aa = 20;
  3. document.write('日本語', AA);
  4. }
  5. 関数();

実行結果:日本語10

キーワード

キーワード (keyword) は,次のものがある。プロパティ名、メソッド名などには使えない。

  • var
  • this
  • function
  • if else
  • do while for in continue break
  • return
  • with
  • switch case default
  • throw try catch finally
  • new delete void typeof
  • instanceof
Note.

JavaScript 1.7 (Firefox 2) では、文脈から明らかであれば、キーワードをメソッド名などに用いることができる。

また、let文、yield文が追加された。

規格にて将来の拡張のために予約された識別子 (reserved word) として次のものがある。ほとんどがJavaのキーワード。現在は使われておらず、プロパティ名などにも普通に使える。

abstract boolean byte char class const debugger double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized throws transient volatile

セミコロンの自動挿入

JavaScriptの文は、「;」(セミコロン)で区切る。しかし、セミコロンがなくてもエラーにならない場合がある。行末にセミコロンがないときは、文脈から次の行に続いていることが明らかな場合を除き、セミコロンが自動的に挿入される (automatic semicolon insertion)。

  1. function x() {
  2. return
  3. 1;
  4. }
  5. document.write(x()); // undefined
  1. function x() {
  2. return 1 + // 明らかに継続行
  3. 1;
  4. }
  5. document.write(x()); // 2

型、リテラル

型 (type)

JavaScriptにはクラスはないが、型はある。型は数値などのプリミティブ (primitive) 型とオブジェクト型に分かれる。プリミティブ型が設けられたのはおそらく実行効率を考えてのことだと思う。通常使う分には、プリミティブ型とオブジェクトを区別する必要はない。

ECMAScriptでは,真偽値型 (Boolean type), undefined型 (Undefined type), 数値型 (Number type), 文字列型 (String type) とNull typeがプリミティブ型になっている。

文字列はimmutable object。

typeof演算子で表示させると次のようになる。Null型は"object"、callメソッドを持つオブジェクトは"function"と表示される。関数型があるわけではない。

  1. function write_type(v) { document.write(typeof v, "\n"); }
  2. write_type(null); // object
  3. write_type(true); // boolean
  4. write_type(undefined); // undefined
  5. write_type(1.1); // number
  6. write_type('foo'); // string
  7. write_type(/[0-9]/); // function IEでは"object"
  8. write_type({f:1}); // object
  9. write_type([1]); // object

リテラルは,プリミティブ型の値を生成する数値,文字列リテラル,booleanリテラル (true/false)、undefined、nullリテラルのほか、関数定義、プロパティ名とプロパティ値の組でオブジェクトを生成するオブジェクトリテラル, 正規表現リテラル、配列もある。

当然ながら、リテラルへの代入はできない(左辺値とはならない)。

プリミティブ値

undefined
宣言されたが未初期化の状態。変数を宣言せずに使用するとundefinedではなくエラーにになる。
  1. var y;
  2. document.write(y); // undefined
  3. document.write(x); // Error: x is not defined
null
ナル値。
  1. x = 10;
  2. x = null;
  3. document.write(x); // null
true / false
メジャーなプログラミング言語と同様、JavaScriptでも二値で真偽を表す。0, '0'は偽になる。true, falseが真偽値の代表。==演算子による比較では、trueと比較してもよい。珍しい。
  1. function is_true(x, b) { document.write(x == b, "\n"); }
  2. is_true(1, true); // true
  3. is_true(0, true); // false
  4. is_true('0', true); // false
  5. is_true(1, false); // false
  6. is_true(0, false); // true
  7. is_true('0', false); // true

文字列リテラル

文字列リテラルは,ダブルクォーテーションかシングルクォーテーションで囲む。どちらで囲んでも扱いに違いはない。

エスケープシーケンスは次のいずれか。

エスケープシーケンス説明
¥''
¥""
¥¥¥
¥b
¥f
¥n改行文字 (LF) ¥u000a
¥r復帰文字 (CR) ¥u000d
¥t文字タブ文字 (HT) ¥u0009
¥v
¥xhh 16進数表記。hは2桁で,0〜9,a〜f,A〜F
¥uddddUnicode表記。dは4桁で,0〜9,a〜f,A〜F

正規表現リテラル

「/」で囲んだ部分は正規表現リテラルになる。Rubyと同じ。

制御構造、ループ

if文、do - while文、for文がある。中身の文が一つだけのときは、C/C++と同様、{ } を省略できる。 { } を省略せずに書いているサイト・サンプルが非常に多い。

if文

  1. x = 1;
  2. // 条件式には () が必要。Cと同じ。
  3. if (x == 1)
  4. document.write('111'); // 1文だけなら{}省略可。Cと同じ。
  5. else
  6. document.write('xxx');

while文

  1. x = 1;
  2. while (x < 10)
  3. x++; // 文がひとつなら{}省略できる。後置++も大丈夫。
  4. document.write(x);

do - whileもC/C++と同じ。

  1. var x = 1;
  2. do {
  3. document.write(x, ' ');
  4. } while (++x <= 10);

continue, break文もある。

for文

for文は、次の3つの書き方がある。C/C++風の書き方と、in演算子を使った書き方。2番目の書き方ではvar宣言で関数スコープ(forブロックではない)の変数を宣言できる。

  1. for (式1; 式2; 式3) ...
  2. for (var宣言; 式2; 式3) ...
  3. for (要素 in コンテナ) ...
  1. function f() {
  2. for (i = 0; i < 3; i++)
  3. document.write(i, ' '); // 0 1 2
  4. }
  5. f();
  6. document.write(i, '<br>'); // 3
  1. j = 2;
  2. function g() {
  3. for (var j = 10; j < 15; j += 2)
  4. document.write(j, ' '); // 10 12 14
  5. document.write(j, ' '); // 16
  6. }
  7. g();
  8. document.write(j, '<br>'); // 2

for-in文は、オブジェクトのプロパティ名を順に変数に代入し、それで文を実行する。JavaScriptのオブジェクトはただのハッシュなので、keyを得るといえる。

  1. ary = [1, 3, 5];
  2. for (v in ary)
  3. document.write(ary[v], ' ');

変数

スコープ、シャドーイング

変数のスコープは、大域スコープと関数スコープしかない。ループのブロックでは新しいスコープは導入されない。

関数定義のなかでのvar宣言で、関数スコープの変数を宣言できる。var宣言は、関数ブロックの先頭で実行されたかのように扱われる。

関数スコープ: var宣言でシャドーイング (shadowing) される。また、varは関数の最初で宣言したとみなされる。

  1. x = 10;
  2. function f() { var x; document.write("f: ", x); }
  3. function g() { x=15; document.write("g: ", x); var x; }
  4. x = 20;
  5. f(); // undefined
  6. g(); // 15
  7. document.write("global: ", x); // 20

変数への代入

代入「=」は、変数が指すオブジェクトのコピーではなく、変数が指すオブジェクトの切り替えになる。複数の変数からひとつのオブジェクトを参照できる。いまどきのプログラミング言語と同じ。

  1. x = {f:1};
  2. y = x;
  3. x.f = 2;
  4. document.write(y.f); // 2

変数の束縛の時期

変数の値への束縛は、関数の実行時に行われる。次の例は、関数g()の定義のときに変数xが束縛されるわけではないことを示す。だから、クロージャではない。

  1. var x = {f:1}
  2. function g() { document.write(x.f); }
  3. x = {f:"hoge"}
  4. g(); // hoge

関数定義

関数を定義するには,functionにて次のように書く。

関数宣言
function 関数名 ( 仮引数リスト ) { 本体 }
関数式
function ( 仮引数リスト ) { 本体 }

関数式は関数オブジェクトを生成し、そのオブジェクトを返す。このオブジェクトを変数に代入することもできる (first-class object; 第一級のオブジェクト)。

文法では、関数式にも関数名を指定できるが、単に無視される。

  1. var g = function foo() { alert('hoge'); }
  2. // foo(); // Error: foo is not defined
  3. g();

後述するが、JavaScriptのメソッドはただの関数。

演算子

演算子の優先順位と結合は次のとおり。

演算子結合
(前置単項) delete void typeof ++ -- + - ‾ !
* / %
+ -
<< >> >>>
< > <= >= instanceof in
== != === !==
&
^
|
&&
||
(3項演算子) ? :
= *= /= %= += -= <<= >>= >>>= &= ^= |=
,

変わっているのは、厳密な比較演算子「===」、「!==」。内容で比較するのは==と同じだが、暗黙の型変換などを行わない。

  1. function is_eq(x, y) {
  2. document.write(x == y, " ", x === y, '<br>'); }
  3. is_eq('0', false); // true false
  4. is_eq('1', true); // true false
  5. is_eq('a', 'a'); // true true
  6. is_eq(new String('a'), 'a'); // true false

また、>>>は符号なし右シフト。

Coreライブラリ・リファレンス

Internet ExplorerとFirefox / SeaMonkeyでは、実装しているオブジェクト、メソッドにだいぶ違いがある。portableなプログラムを書こうと思うなら、これらの差異を吸収してくれるライブラリを使うのがいい。以下では、共通するオブジェクト、メソッドについて解説する。

Objectオブジェクト

http://www.tohoho-web.com/js/object.htm http://msdn.microsoft.com/library/default.asp?url=/library/en-us/script56/html/d24ef8fc-217b-4828-94e1-19f72780bae0.asp http://developer.mozilla.org/ja/docs/Core_JavaScript_1.5_Reference ○IEでのプロパティ、メソッド

プロパティ

prototype
constructor Property [M]
propertyIsEnumerable Property [Mではメソッド]

メソッド

isPrototypeOf Method [M]
hasOwnProperty Method [M]
toString Method [M]
valueOf Method [M]

Functionオブジェクト

プロパティ arguments [M] callee caller [M] constructor [M] length [M] 引数の数 prototype [M] メソッド apply [M] call [M] toString [M] valueOf [M] ○Mozillaのみ name toSource

windowオブジェクト

navigatorオブジェクト

documentオブジェクト

リンク

prototype.js v1.5.0 の使い方
JavaScriptのライブラリprototype.js の解説(日本語)。