プリミティブ型の操作をより便利の為に提供している3種類の特殊なオブジェクト:Boolean、Number、String。これがプリミティブ型のラッパーオブジェクト(以下ラッパーオブジェクトと略する)です。
これらラッパーオブジェクトが普通のオブジェクトと同様な機能を持つ上にプリミティブ型の機能も備わっている。
###暗黙のラッパーオブジェクトへの変換
let s1 = "str";
let s2 = s1.substring(1); //tr
console.log(typeof s1); //string
s1は「str」という文字列を持つプリミティブ型の変数です。だが変数なのにオブジェクトのように直接substring()関数を呼び出している。プリミティブ型はオブジェクトではないので、メソッドとかは持っていないはずなのですが、実際はsubstringの呼び出しが正しく動いていました。その原因は言語の内部でそれを実現できるように以下の三つの処理を追加しているからです。
- Stringオブジェクトのインスタンスを作成
- インスタンスの特定な関数を呼び出す
- このインスタンスを削除
この三つの処理をプログラムに書き換えると以下になります。
let s1 = new String("str");
let s2 = s1.substring(1);
s1 = null;
「プログラム_1」を実行する際は言語の内部では「プログラム_3」の感じになっているかもしれません。
let s1 = "str";
let s2 = (new String(s1)).substring(1); //tr
console.log(typeof s1); //string
上記のプログラム_1では暗黙的に文字列変数「s1」をラッパーオブジェクトの「String」に変換されている、プログラム_2とプログラム_3は明示的ラッパーオブジェクトへの変換を行われていると理解した方が分かりやすいかもしれません。
このような動きは「true,false,数字」の場合も発生する、単に利用されるラッパーオブジェクトがBooleanとNumberに変わるだけ。
###明示ラッパーと暗黙ラッパー変換の違い
明示ラッパーと暗黙ラッパー変換の違いは生成されたインスタンスのライフサイクルです(アクセスできるスコープとも言える)。
明示ラッパーで生成されたオブジェクトのインスタンスは生成されたスコープ内で利用可能、自動的に作られたラッパーオブジェクトのインスタンスは作られた時のみ利用可能です。
let s1 = "str";
s1.name = "wrapper object";
console.log(s1.name); //undefined;
プログラム_4の2行目でラッパーオブジェクトが作れて、nameプロパティを追加して値を設定する。実行が終わったら、そのラッパーオブジェクトが削除される。3行目はまたラッパーオブジェクトが作られてnameプロパティをアクセスする、だが今回のラッパーオブジェクトにはnameプロパティを設定していないので出力結果がundefinedになります。
ここの2行目と3行目は二つのラッパーオブジェクトを作られていて、それぞれ別のラッパーオブジェクトを利用しているので例のプログラムのような問題が発生する原因です。
明示的にnewでラッパーオブジェクトのインスタンスを作って、違いを見ってみましょう。
let s2 = new String("str");
s2.name = "wrapper object";
console.log(s2.name); //wrapper object
###Objectコンストラクタ
Objectコンストラクタはパラメータのデータ型によって対応のラッパーオブジェクトのインスタンスを作成することはできる。
let strObj = new Object("string");
console.log(strObj instanceof String); //true
let boolObj = new Object(true);
console.log(boolObj instanceof Boolean); //true
let numObj = new Object(1);
console.log(numObj instanceof Number); //true
###Boolean
Booleanは「true,false」のラッパーオブジェクトです。Booleanラッパーオブジェクトのインスタンスを作るにはBooleanのコンストラクタを利用して、パラメータに「true,false」を設定する
let boolObj = new Boolean(true);
```
BooleanのインスタンスはvalueOf()とtoString()関数をオーバライドする、前者はtrue又はfalseを返す、後者では文字列の"true"又は"false"を返す。
Booleanラッパーオブジェクトに関する例を見てみましょう
```javascript:プログラム_8
let falseObj = new Boolean(false);
console.log(falseObj && true); //true 説明:※1参照
let falseValue = false;
console.log(falseValue && true); //false 説明:※2参照
falseObj == falseValue; //true 説明:※3参照
falseObj === falseValue; //false 説明:※4参照
falseObj.valueOf() == falseValue; //true 説明:※5参照
console.log(typeof falseObj); //object
console.log(typeof falseValue); //boolean
console.log(falseObj instanceof Boolean); // true
console.log(falseValue instanceof Boolean); //false
```
説明:
※1:[論理積(&&)のルール](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Logical_AND)では、左側がtrueの場合は右側を返す、この例のラッパーオブジェクトのインスタンスがobjectなので、[boolean変換のルール](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Boolean)によってnull以外のobjectはtrueに変換される、よって結果は右側のtrueになります。
※2:falseValueはプリミティブ値なので、そのままの結果になります
※3:等価演算子の計算ルールによってfalseObjがvalueOf()を呼び出され「false」になる、falseValueが「0」に変換されてから等価計されるので、結果的に「false == 0」の計算になります[等価演算子の詳細はここから参照](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Equality)
※4:厳密等価計算になるので、オペラントの型が違ったらfalseになる[厳密等価演算子の詳細はここから参照](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Strict_equality)
※5:前述のようにfalseObj.valueOf()の結果はプリミティブのfalseになる為、falseValueと同じになる
これを見たらBooleanラッパーオブジェクトが誤解しやすく、ややこしいことがわかるでしょう、なので利用するのを避けた方が良いと思う。
###Number
Numberは数字のラッパーオブジェクトです。Numberラッパーオブジェクトのインスタンスを作るにはNumberのコンストラクタを利用して、パラメータに数字を設定する
```javascript:プログラム_9
let numObj = new Number(10);
```
NumberのインスタンスもBooleanと同様にvalueOf()、toString()とtoLocaleString()関数をオーバライドしている、前者は元のプリミティブ数字を返す、後の二つは数字の文字列を返す。
###まとめ
明示的にString、BooleanとNumberコンストラクタを利用してプリミティブ値のラッパーオブジェクトを作成できるのですが、でも本当に必要な時以外は利用しない方が良い、プリミティブ値なのかラッパーオブジェクトなのか区別出来なくなるかもしれません。
明示的ラッパーオブジェクトの利用がお勧めしないが、プリミティブ値とラッパーオブジェクトの違いはとても重要なので理解していた方が良いと思う。