= 値と変数 = == 値の型 == 他の多くの言語がそうであるように、 !JavaScript にも値の'''型'''が存在します。 しかし、各言語が作られた目的やフィールドの違いに由来し、型の意味合いも言語毎に大きく異なります。古典的には、型と言えば精度の異なる複数の整数型と実数型を指すものでした。これは CPU が直接に理解できるマシン語の世界観に相当するものですが、この概念自体は古典的な多くの言語においてそのまま踏襲されます。 FORTRAN 然り、 PASCAL 然り、 BASIC 然り、 C 然り。 その後、 LISP を筆頭とする高級言語が台頭するのを皮切りに、こうした物理的な型の区別に加え、より観念的な、あるいは実務的な型の概念が採用されるようになってゆきました。 文字列、ポインタや参照、列挙値、配列や構造体、共用体、未定義値、そしてオブジェクトや関数などです。 !JavaScript の型概念は、物理的な数値の区別は一切排除し、その一方でオブジェクトのクラスの違いを型とは別の次元で区別するルールを採用しています。まずは、 !JavaScript にどのような型が用意されているのかを、一通り見てみることにしましょう。 === 数値 === !JavaScript には整数と実数の区別がありません。もちろん、整数の精度毎の区別もありません。数値として扱う値はすべて、数値型の値として扱われます。 {{{ // 以下はすべて数値型の値 var a = 0; var b = 20100802144236; var c = -12.3456; var d = 1.73e-11; var e = Infinity; // 無限大 var f = NaN; // 非数 }}} 上記で変数 d に代入している値は、数学的には「1.73×10^^-11^^」という意味です。 Infinity は無限大を表す定数です。任意の値を 0 で割った場合にもこの値を得られます。 Infinity で掛けた数値はどんな数値でも Infinity になり、 Infinity で割った数値はどんな数値でも 0 になります。 NaN は非数を表す定数です。例えば負の値の平方根を求めようとしたりすると、この値を得られます。数値型ではありますが、数値ではありませんので、他のどの数値とどのような演算を行っても結果は NaN になります。 数値型の値には、さまざまな数値演算を適用することができます。また、数値同士の足し算は、通常の数値の足し算として計算した結果が得られます。 {{{ var a = 12.3 + 45.6; // 57.9 var b = 8901 - 2345 / 67; // 8866 var c = 650 % 7; // 6 }}} 数値型の値と文字列型の値の足し算を行った場合、数値を数字の文字列に置き換えた上で、連結された文字列が結果として得られます。 {{{ var d = 12.3 + "45.6"; // "12.345.6" var e = "社員数: " + 1; // "社員数: 1" var f = "1 + 1 = " + 1 + 1; // "1 + 1 = 11" }}} 上記の変数 f に代入する例はよくある間違いで、恐らく本来意図した通りの動作ではないでしょう。足し算は数値の足し算でも文字列の連結でも左から順に行うので、このケースでは数値の足し算を括弧で括る必要があります。 {{{ var f = "1 + 1 = " + (1 + 1); // "1 + 1 = 2" }}} === 文字列 === ダブルクォーテーションマーク '"'~'"'、およびシングルクォーテーションマーク "'"~"'" で括った文字列は、文字列値として扱われます。 {{{ var a = "Hello, World!!"; var b = 'Goodbye, dream...'; }}} 文字列は足し算演算子で連結が可能です。文字列と数値の足し算もまた、数値をその数字の文字列として扱った上で連結されます。 {{{ var c = "T.MURACHI は " + 1978 + "年 " + 2 + "月 " + 7 + "日生まれの " + 32 + "歳です。"; }}} 文字列中に、 C 言語ライクな'''エスケープ文字'''を含めることもできます。 {{{ var d = "いろはにほへと\nちりぬるをわか\nよたれそつねな\n" + // \n は改行文字 "らむうゐのおく\nやまけふこえて\nあさきゆめみし\nゑひもせすん"; var e = "氏名:\t村山 俊之\n年齢:\t32\n性別:\t男性"; // \t はタブ文字 var f = "-?(?:\\d+\\.?|\\d*\\.\\d+)(?:e[\\+\\-]?\\d+)?"; // \\ は \ そのもの }}} === 真偽値 === 比較演算の結果が正しいか否かを示す値です。真を表す true と、偽を表す false の 2通りのみを取ります。 {{{ var a = true; // 真 var b = false; // 偽 var c = 1 + 2 == 3; // true var d = 4 * 5 < 6; // false }}} 実際には比較演算のみならず、関数の処理が成功したかどうかを表す戻り値や、フラグとして表現されるべきステータス全般などにおいて、広く用いられています。 === 未定義値 === 識別子 undefined で表されるこの値は、変数に値が定義されていないことを表すものです。値なのに値が定義されていないとはこれ如何に。 {{{ var a = undefined; }}} 上記は以下と完全に同義です。 {{{ var a; // 初期値を指定しない変数には undefined が入っている…!! }}} === 関数 === 関数は値である、といわれても、感覚的にはぴんと来ないかも知れません。しかし、関数を変数に代入しておいたり、関数の処理内容を動的に作り出したりできる仕組みは、慣れるとなかなかに便利なものです。 まず、 function 宣言によって定義された関数は、そのままその名前の変数として振る舞います。 {{{ function a() { /* 処理... */ } var b = a; // 変数 b に関数 a を代入 }}} このとき、以下のように記述することで、変数 b から関数を実行することができます。 {{{ b(); // a(); と等価の処理を実行する }}} なお、一度定義した関数の処理内容を直接変更することはできません。別の関数を代入して上書きすることはできますが…。 名前をつけてちゃんと定義した関数ではなく、無名の関数をその場で変数に代入することもできます。 {{{ var c = function() { /* 処理... */ }; c(); // もちろん、こう書けば処理を実行できる }}} このような関数定義の書き方は'''無名関数'''などと呼ばれたりしています。 関数呼び出しの前に '''new''' 命令を挿入すると、その関数をコンストラクタとしたオブジェクトの生成ができるのですが (詳細は後ほど…)、無名関数でもオブジェクトの生成はもちろん可能です。 {{{ var X = function() { this.name = "unknown"; this.mask = "secret"; }; var x = new X(); // オブジェクト生成 var y = new (function() { /* ... */ })(); // こんな書き方も一応可能 }}} === オブジェクト === !JavaScript はオブジェクト指向的な性格の強い言語ですので、未定義値を除くすべての型で、その値にオブジェクトとしての性格を持っています。例えば数値型の値には toFixed() メソッドを適用することで、指定した精度の少数を表す文字列を得ることができますし、 {{{ var root2 = 1.41421356; alert(root2.toFixed(3)); // "1.414" と表示 }}} 文字列型の値には substr() メソッドを適用することで、指定した位置の文字列を切り出すことができたりします。 {{{ var text = "Hello World."; alert(text.substr(6, 5)); // "World" と表示 }}} しかし、より自由に、プログラム側から'''メンバ'''に新しい値を代入し、それをメンバフィールドやメンバメソッドとして活用することのできる型は、2種類しか存在しません。ひとつは関数型、そしてもう一つがオブジェクト型です。 オブジェクト型の値を生成する方法は以下の 2通りです。 {{{ var a = { "foo": 1, "bar": "hoge", "baz": true, "showAll": function() { alert("foo: " + this.foo + ", bar: " + this.bar + ", baz: " + this.baz); } }; var b = new Object(); }}} 変数 a に代入している方は、最も手軽にオブジェクト型の値を生成する方法です。全体をブレース "{" ~ "}" でくくり、「"メンバ名": 値」の組み合わせをカンマ "," で区切って記述します。すると、指定したメンバ名の値を持つオブジェクトが生成されます。 変数 b に代入している方は、関数呼び出しをコンストラクタとして利用することにより、オブジェクトを生成する方法です。 "Object" というのは、実は !JavaScript に最初から定義されている関数名ですが、自分で定義した関数をコンストラクタに用いることももちろんできます。 {{{ // コンストラクタ function X() { this.foo = 1; this.bar = "hoge"; this.baz = true; this.showAll = function() { alert("foo: " + this.foo + ", bar: " + this.bar + ", baz: " + this.baz); }; } // オブジェクトを生成 var x = new X(); }}} ここで、変数 x に代入されたオブジェクトと、先ほどの例で変数 a に代入されたオブジェクトは、内容的には等価です。オブジェクトのメンバには、ドット "." に続いてメンバ名を指定することにより参照することができます。 {{{ alert(a.foo); // "1" を表示 alert(a.bar); // "hoge" を表示 alert(a.baz); // "true" を表示 a.showAll(); // "foo: 1, bar: hoge, baz: true" を表示 alert(x.foo); // "1" を表示 alert(x.bar); // "hoge" を表示 alert(x.baz); // "true" を表示 x.showAll(); // "foo: 1, bar: hoge, baz: true" を表示 }}} === 型を調べる === ある変数に代入されている値がどの型なのかに応じて、処理を振り分けたい場合があります。そのようなときには、値の型を調べる必要があります。型を調べるには、 '''typeof 演算子'''を利用します。 {{{ var type = typeof x; // 変数 x に代入されている値の型を調べる }}} ここで、上記の変数 type に代入される値は、以下のいずれかの文字列です。 * "number" ... 数値 * "string" ... 文字列 * "boolean" ... 真偽値 * "undefined" ... 未定義値 * "function" ... 関数 * "object" ... オブジェクト === null という値 === ところで、 !JavaScript には、 '''null''' という名前の値が存在します。他の言語を既に習得されている方にとっては非常に馴染みのある単語かと思われますが、 !JavaScript においても、未定義値である undefined と非常によく似た性質を持つ値で、オブジェクトを返す関数が、オブジェクトを返せないことを表すために、代わりに返す値としてよく使われます。 null は undefined と似ているので、等価演算子で比較すると、真を返します。しかし、厳密には違う値なので、厳密等価演算子で比較すると、偽を返します。 {{{ // この if-else 文は "null == undefined is TRUE!!" を表示 if (null == undefined) alert("null == undefined is TRUE!!"); else alert("null == undefined is FALSE!!"); // この if-else 文は "null === undefined is FALSE!!" を表示 if (null === undefined) alert("null === undefined is TRUE!!"); else alert("null === undefined is FALSE!!"); }}} また、 null は undefined によく似ていますが、これでも立派なオブジェクト型の値です。 {{{ var a = typeof null; // "object" }}} ただ、オブジェクト型であるにも関わらず、 undefined との近似性を表したいのか、メンバに値を代入しようとしたりすると、エラーになります (例外を送出する)。 {{{ null.hoge = "fuga"; // エラー! var b = null.toString(); // これもエラー!! }}}