JavaScript

ラッパーオブジェクト

 JavaScript のオブジェクトは複合型の値です。つまり、プロパティ(名前付きの値)の集合体です。プロパティの値を参照するときは、「 . 」を使って表記します。プロパティが関数の場合は、メソッドと呼びます。オブジェクト o のメソッド m を呼び出すときは、o.m() と記述します。

 すでに前頁で紹介したように文字列は、プロパティとメソッドを持ちます。

var s = "hello world!";
// 文字列。

var word = s.substring(s.indexOf(" ")+1, s.length);
// 文字列のプロパティを使う。

 しかし、文字列はオブジェクトではありません。では、なぜプロパティがあるのでしょうか。文字列 s のプロパティを参照すると、JavaScript は文字列値をオブジェクトに変換します。new String(s) を呼び出したのと同じ変換をします。このオブジェクトは、文字列用のメソッドを継承するので、このオブジェクトを使ってプロパティを参照できます。プロパティがアクセスできたら、新たに生成されたオブジェクトは廃棄されます(なお、JavaScript インタプリタは、実際にこのようなオブジェクトを作成したり、廃棄したりしなければならないわけではありません。あくまで、ここで紹介したような振る舞いをしなければならないということです)。

 文字列と同じような理由で、数値や論理値もメソッドを持ちます。一時的なオブジェクトが、Number() コンストラクタや Boolean() コンストラクタを使って生成されます。この一時的なオブジェクトを使ってメソッドが呼び出されます。null 値や undefined 値のプロパティにアクセスしようとすると、TypeError が発生します。

 次のコードが実行されると、どのようなことが起きるのかを考えてみましょう。

var s = "test";
// 文字列値のサンプル。

s.len = 4;
// 文字列に対してプロパティを設定する。

var t = s.len;
// 設定したプロパティを読み出す。

 このコードを実行すると、t の値は undefined になります。先ほどのコードの 2行目では、一時的に String オブジェクトが生成され、このオブジェクトの len プロパティに 4 を設定しています。しかし、このオブジェクトは廃棄されます。3行目では、元の(変更されていない)文字列値から新たに String オブジェクトが生成され、len プロパティを読み出します。このプロパティは存在しないので、読み出した値は undefined になります。このコード例からわかるように、文字列や数値、論理値は、プロパティ(メソッド)の値を読み出すとオブジェクトのように振る舞います。しかし、プロパティに値を設定する場合は、単に無視されるだけです。値の変更は、一時的に生成されるオブジェクトに対して行われ、すぐに捨てられてしまうからです。

 このように、文字列や数値、論理値のプロパティにアクセスするときに生成される一時的なオブジェクトのことをラッパーオブジェクトと呼びます。文字列値と String オブジェクト、数値と Number オブジェクト、論理値と Boolean オブジェクトを区別しなければならない場合も確かにあります。しかし、普通は、ラッパーオブジェクトは処理上の問題ですので、あまり深く気にする必要はありません。文字列や数値、論理値は、通常のオブジェクトと異なり、プロパティは読み出しのみであり、新たなプロパティも定義できないと覚えておけば十分です。

 あまり必要となる場面もなく、便利でもありませんが、明示的にラッパーオブジェクトを生成することもできます。String()Number()Boolean() コンストラクタを以下の例のように呼び出します。

var S = new String(s);
// String オブジェクト。

var N = new Number(n);
// Number オブジェクト。

var B = new Boolean(b);
// Boolean オブジェクト。

 JavaScript は、ラッパーオブジェクトを必要に応じて、元の基本型に変換します。つまり、先ほどのコードの例では、SNB は、snb と同じ振る舞いをします。例えば、等値演算子 == で比較すると、元の値とラッパーオブジェクトは同じ値であると判定されます。ただし、一部例外もあります。例えば、同値演算子 === で比較した場合は、異なる値と判定されます。typeof 演算子を使った場合も、基本型値とラッパーオブジェクトでは結果が異なります。