JavaScript

その他の演算子

 JavaScript は、その他にもいくつかの演算子をサポートしています。以下、順に紹介しましょう。

条件演算子( ?: )

 条件演算子( ?: )は、JavaScript で唯一の三項演算子です。三項演算子というのは、オペランドを 3つ取るという意味です。この演算子は「 ?: 」と表記されますが、実際の使い方は少し違います。先頭のオペランドの後ろに「 ? 」を置き、その後ろに 2番目のオペランド、その後ろに「 : 」を置いて、最後に 3番目のオペランドを記述します。次の例を見てください。

x > 0 ? x : -x
// x の絶対値。

 条件演算子のオペランドには任意の型の値を指定できます。先頭のオペランドが評価され、論理値として解釈されます。先頭のオペランドの値が true と評価できる場合は、2番目のオペランドの値を評価し、その値を返します。先頭のオペランドの値が false と評価できる場合は、3番目のオペランドの値を評価し、その値を返します。つまり、2番目のオペランドか、3番目のオペランドのいずれかのみが評価され、両方が評価されることはありません。

 このやり方は if 文を使用しても実現できますが、?: 演算子のほうが簡単です。典型的な例は、変数が定義されているかどうか( true と評価される値を持つかどうか)をチャックし、定義されていればその値を使用し、定義されていなければデフォルトの値を使用する、という用法です。次の例を見てください。

greeting = "hello " + (username ? username : "there");

 これと同じことは if 文でも可能ですが、条件演算子( ?: )を使用したほうが少ない行数で簡潔に記述できます。if 文の例を次に紹介します。

greeting = "hello ";
if (username)
  greeting += username;
else
  greeting += "there";

typeof 演算子

 typeof は単項演算子です。オペランドは 1つだけです。オペランドの値は任意です。typeof 演算子は、オペランドのデータ型を示す文字列を返します。JavaScript のさまざまな値に対して typeof 演算子を使った時の値を、次の表にまとめておきます。

x typeof x
undefined "undefined"
null "object"
true または false "boolean"
任意の数値または NaN "number"
任意の文字列 "string"
任意の関数 "function"
任意の関数ではないネイティブオブジェクト "object"
任意のホストオブジェクト 実装で定義された文字列。
ただし、"undefined"、"boolean"、"number"、"string" 以外。

 typeof 演算子の使用例を紹介しておきます。

(typeof value == "string") ? "'" + value + "'" : value

 typeof 演算子は、switch 文と組み合わせて使った場合も便利です。なお、typeof 演算子のオペランドを指定するときに、括弧( () )で囲んで指定することができます。このように記述すると、typeof は、演算子のキーワードではなく、関数名のように見えるかもしれません。

typeof(i)

 オペランドの値が null の場合も、typeof"object" という文字列を返すことに注意してください。null とオブジェクトを区別したい場合には、明示的に null かどうかをテストするようにしてください。typeof は、ホストオブジェクトに対して "object" 以外の文字列を返す場合があります。しかし、実際には、クライアントサイド JavaScript 中のホストオブジェクトの大半は、"object" という型を持ちます。

 オペランドが関数以外のオブジェクトと配列の場合、typeof 演算子は "object"(オブジェクト型)としか返さないので、オブジェクト型とその他の基本型とを区別することしか出来ません。どのオブジェクト型であるのかを知るには、別の手法が必要です。例えば、instanceof 演算子(「関係演算子」を参照)やクラス属性、constructor プロパティを使います。

 JavaScript では、関数はオブジェクトの一種ですが、関数は戻り値を持つので、ほかのオブジェクトとは異なると判断し、typeof 演算子は "function" という文字列を返します。JavaScript では、関数と「呼び出し可能なオブジェクト」とを微妙に区別します。すべての関数は呼び出し可能です。一方で、呼び出し可能なオブジェクトは、本当の意味では関数ではありませんが、関数と同じように呼び出すこともできます。ECMAScript 3 では、呼び出し可能なネイティブオブジェクトについては、すべて "function" を返すように規定しています。ECMAScript 5 仕様では、この仕様を拡張して、ネイティブオブジェクトでもホストオブジェクトでも呼び出し可能なオブジェクト全てに対して、typeof"function" という文字列を返すように規定しています。多くのブラウザでは、ホストオブジェクトのメソッドとして JavaScript の関数オブジェクトを使っています。しかし、Microsoft 社は、クライアントサイド用のメソッドとしては、呼び出し可能なオブジェクトを使うようにしています。IE9 より前の IE では、typeof 演算子は、このような呼び出し可能なオブジェクトに対して "object" という文字列を返します。IE9 では、クライアントサイドメソッドは、関数オブジェクトになっています。本当の関数と呼び出し可能なオブジェクトとの違いについては、別ページで説明予定です。

delete 演算子

 delete 演算子は単項演算子で、オペランドに指定されたオブジェクトプロパティや配列要素を削除します( C++ プログラマの方は、JavaScript の delete 演算子は C++ の delete 演算子とは全く違うということに注意してください。JavaScript では、メモリの解放はガーベジコレクションによって自動的に処理され、プログラマは明示的なメモリの解放を気にする必要はありません。オブジェクトの削除のために、C++ スタイルの delete は全く必要ありません)。代入演算子、インクリメント演算子、デクリメント演算子のように、delete 演算子の値そのものではなく、プロパティを削除するという副作用のために使われるのが一般的です。例をいくつか紹介します。

var o = { x: 1, y: 2 };
// このオブジェクトから始める。

delete o.x;
// プロパティの 1つを削除する。

"x" in o
// => false: このプロパティは、もう存在しない。

var a =[1,2,3];
// この配列から始める。

delete a[2];
// 配列の最後の要素を削除する。

a.length
// => 2: この時点では配列は要素を 2つしか持たない。

 削除されたプロパティや配列要素には、単に undefined が設定されるだけではありません。プロパティが削除されると、プロパティは存在しなくなります。存在しないプロパティを読み出すと undefined が返されるので、これだけでは区別できないのですが、in 演算子(「関係演算子」を参照)を使うことでプロパティが存在するかどうかをテストできます。

 delete 演算子のオペランドには、左辺値を指定します。もしも左辺値ではない場合、delete 演算子は何も処理をせず、true を返します。左辺値を指定した場合は、delete 演算子は指定された左辺値を削除しようとします。指定された左辺値が削除できた場合には、delete 演算子は true を返します。しかし、すべてのプロパティが削除できるわけではありません。コア言語やクライアントサイドの組み込みプロパティのいくつかは削除できないようになっています。また、var 文を使って宣言したユーザ定義の変数も削除できません。function 文で定義された関数や、関数の仮引数についても削除できません。

 ECMAScript 5 では、オペランドが変数や関数、関数の仮引数の場合、delete 演算子は SyntaxError をスローします。delete 演算子は、オペランドとしてプロパティアクセス式(「プロパティアクセス式」を参照)を指定した時にのみ動作します。strict モードでは、再定義不可( nonconfigurable )のプロパティを削除しようとすると、delete 演算子は TypeError 例外を発生させます。非 strict モードでは、前述のような場合にも例外は発生せず、delete 演算子は false を返し、オペランドが削除できなかったことを示すだけです。

 次にいくつか例を示しましょう。

var o = {x:1, y:2};
// 変数を宣言し、オブジェクトを代入する。

delete o.x;
// オブジェクトのプロパティの 1つを削除。true が返される。

typeof o.x;
// プロパティはもう存在しないので "undefined" になる。

delete o.x;
// 存在しないプロパティを削除。true が返される。

delete o;
// 宣言された変数は削除できない。false が返される。
// strict モードでは例外が発生。

delete 1;
// 整数値は削除できない。true が返される。

this.x = 1;
// var を使わずにグローバルオブジェクトのプロパティを定義する。

delete x;
// 削除する。strict モードでなければ、true が返される。
// strict モードでは例外が発生。代わりに「delete this.x」と記述する。

x;
// x は定義されていないので、実行時エラーが発生する。

void 演算子

 void は単項演算子です。オペランドとしては任意の値が取れます。void 演算子は、あまり使われるものではありません。void 演算子は、オペランド値を廃棄し未定義値を返すという特殊なものだからです。オペランド値を廃棄するので、void 演算子は使って意味のある場合は、オペランドが副作用を持つときだけです。

 実際に void 演算子を使用する場面は、クライアントサイド JavaScript の javascript: URL 中くらいでしょう。式を評価する際の副作用は期待するが、式を評価した結果の値をブラウザが表示するのは望まない場合に使用します。HTML での使用例を以下に紹介しておきます。

<a href="javascript:void window.open();">Open New Window</a>

 HTML では、javascript: URL を使わなくても、onclick イベントハンドラを使えば、もっと明確に記述できます。イベントハンドラを使う場合は、もちろん void 演算子は必要ありません。

カンマ演算子( , )

 カンマ( , )演算子は二項演算子です。オペランドには任意の型の値を指定できます。まず左側のオペランドを評価し、次に右側のオペランドを評価し、最後に右側のオペランドの値を返します。次の例を見てください。

i=0, j=1, k=2;

 この式を評価すると 2 になります。上記のコードは次のように書いても同じです。

i = 0; j = 1; k = 2;

 左側の式は評価されますが、値は捨てられます。つまり、カンマ演算子を使って意味があるのは、左側の式に副作用がある場合だけです。カンマ演算子が使われるのは、for ループで複数のループ変数を使う時が一般的です。例を示します。

// 以下の例の最初のカンマは、var 文の構文の一部。
// 2つ目のカンマがカンマ演算子。カンマ演算子で、2つの式( i++ と j-- )を
// 1つの式しか受け付けない文( for ループ)中に記述。
for(var i=0,j=10; i < j; i++,j--)
  console.log(i+j);