再入門JavaScript: 式と文

制御構造、ループ

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

if文

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

while

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

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

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

continue, break文もある。

try

JavaScriptには例外機構もある。

TryStatement :
    try Block Catch
    try Block Finally
    try Block Catch Finally

Catch :
    catch ( Identifier ) Block

Finally :
    finally Block

catch は, ただ一つの Identifier しか引数に取ることができない。

印象がなかったが, 1999年の 3rd edition から使えるようになっていたらしい。

関数定義

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

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

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

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

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

JavaScript の関数宣言/定義では、変数や戻り値の型を宣言できない。実行時に自分でテストするしかない。

関数は, 常に戻り値を返す。明示的に return しなかった場合, 暗黙に undefined が戻り値になる。最後に評価した式の値ではない。これはあまり上手くない仕様だが、今更変えられない。

型宣言がないので、return 忘れなどを検出できない。

JavaScriptのメソッドは, クラスに所属しているわけではなく, ただの関数。

ES2015 で「アロー関数」が導入された。関数式をものすごく短く書くことができる。

演算子

[2020-12] ES2020 で追加された ?., ??

演算子の優先順位と結合は次のとおり。評価 (実行) 順とは異なる。

優先
順位
演算子 説明 結合
1 . メンバアクセス
...[ ... ] メンバアクセス
... ( ... ) 関数呼び出し
?. Optional chaining [ES2020で導入]. 左辺が nullish (null or undefined) でないときメンバアクセス. 右辺は短絡評価。
2 new オブジェクトの生成
3 ++ -- 後置インクリメント・デクリメント なし
4 delete プロパティの削除
void typeof
++ -- 前置インクリメント・デクリメント
+ - 単項: 正号, 負号
~ ! ビット否定, 論理否定
5 ** 累乗 (べき乗) [ES2016 で導入]
6 * / % 乗算, 除算, 剰余. 剰余は実数で計算.
7 + - 二項演算子: 加算, 減算
8 << >> >>> ビットシフト. >>> は符号なし右シフト。
9 < > <= >= 比較
instanceof in
10 == != === !== 比較. 型に厳しいかどうか
11 & ビット論理積 (and)
12 ^ ビット排他的論理和 (xor)
13 | ビット論理和 (or)
14 && 論理積 (and). 左辺値か右辺値を返す. 短絡評価する.
15 || 論理和 (or). 左辺値か右辺値を返す. 短絡評価する.
?? Null合体 (Nullish coalescing) [ES2020で導入]. 偽ではなく null or undefined で判定。論理和 (or) と並べて書けない (SyntaxError).
16 ? : 3項演算子. 第2項と第3項は短絡評価する.
17 =
**= *= /= %= += -= <<= >>= >>>= &= ^= |=
代入.
18 , 順列

大なりイコールは >= のみ。=> はアロー関数 (Arrow function; ES2015 で導入) になる。

[2020-12] &&=, ||= は提案中。まだ標準ではない。

短絡評価 (short-circuit evaluation) は遅延評価と同じ。評価を省略できる式は実行されない。

比較演算子 =====

変わっているのは、厳密な比較演算子「===」と「!==」。== と異なり, 暗黙の型変換を行わない。現代では, ==!= は使うべきでなく, 常に ===!== を使うべき、となっている。

switch文でも, 比較には === が用いられる。

いろいろな値同士を比較した結果。意外なことが多いが、特に注意を要するところは赤字にした。オブジェクト同士の比較には、比較演算子は一切使えない。ひどい。

加えて、Object.is() による比較も、わずかに異なる。この、わずかに、というのが実に不味い。

x y x == y x === y Object.is()
'5' 5 true false false == では型変換される
5.0 5 true true true JavaScript の Number型は実数
+0 -0 true true false Object.is() だけが +0 と -0 を区別する。
0 NaN false false false 0 と NaN はいずれも偽だが、等しくない.
NaN NaN false false true NaN は NaN 自身とも等しくない!
Infinity Infinity true true true 無限大同士は等しい.
1 1n true false false 整数型 BigInt 値と数値は === だと等しくない!
'あい' 'あい' true true true 文字列プリミティブは、内容で比較される.
'あい' new String('あい') true false false Stringオブジェクトだと不一致! プリミティブをnew してはならない。
1 true true false false true の数値表現は1だが, === だと型が違うので false.
2 true false false false 真の値一般と等しい訳ではない. つまり Boolean 型に変換されてから比較されるわけではない。
false false true true true false 同士は等しい.
0 false true false false false の数値表現は 0
NaN false false false false falseも, 偽の値一般と等しい訳ではない。
null null true true true
null 0 false false false null と 0 も異なる.
undefined 0 false false false 同様に, undefined と 0も異なる.
undefined undefined true true true
null undefined true false false === の場合, nullundefined も異なる.
Symbol("foo") "foo" false false false シンボルは文字列と別物。
[1,2,3] [1,2,3] false false false オブジェクトは, 内容ではなく, 同じ参照かどうかで判定!
[] [] false false false たとえ空配列でも同様。
{} {} false false false オブジェクトは、中身の値ではなく、同じ参照かどうか。

変数

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

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

関数定義のなかでのvar宣言で,「関数スコープ」の変数を宣言できる。var宣言は、関数ブロックの先頭で実行されたかのように扱われる。大域変数はシャドーイング (shadowing) される。

JavaScript
[RAW]
  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

ES2015 (ES6) で, letconst が導入された.

let は, 変数の再宣言は禁止されるが再代入できる変数。const は変数の再宣言も再代入もできない。スコープは, if 文や for 文などのブロック内で宣言されれば, そのブロック内になる。

var は、変数の再宣言も許し、スコープは関数になる。

現代では, var はほぼほぼ使われない。let を使う機会も, for-of文ぐらいで、ほとんどない。基本的にいつでも const でよい。

変数への代入

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

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

変数の束縛の時期

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

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

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

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

基礎的なオブジェクト

1) 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]

2) Functionオブジェクト

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

4) Symbolオブジェクト (ES2015で導入)

5) Error オブジェクト