JavaScriptのデータ型は、プリミティブ型とオブジェクト型に分けられます。
プリミティブ型の文字列や数値はオブジェクトではありませんが、ラッパーオブジェクトという仕組みによって、オブジェクトのように扱うことができます。
今回は、プリミティブ型とラッパーオブジェクトについて解説していきます。
プリミティブ型
プリミティブ型は、次の7種類あります。
- 数値(Number)
- 文字列(String)
- 長整数(BigInt)
- 論理値(Boolean)
- null
- undefined
- シンボル(Symbol)
次のコードでは、文字列リテラルを使って文字列を定義しています。
let str = 'string';
str
に対して、toUpperCase
メソッドを使ってみます。
let str = 'string';
console.log(str.toUpperCase()); // "STRING"
すると、大文字で”STRING”と出力されます。
しかし、なぜプリミティブ型の文字列str
がtoUpperCase
メソッドを呼び出せるのでしょうか。
それは、プリミティブ型の値に対応する特別なオブジェクトが作られるためです。
詳しく見ていきましょう。
ラッパーオブジェクト
プリミティブ型の中でnullとundefinedを除いたものは、それぞれに対応するラッパーオブジェクトが存在します。
プリミティブ型 | ラッパーオブジェクト |
---|---|
数値 | Number |
文字列 | String |
長整数 | BigInt |
論理値 | Boolean |
シンボル | Symbol |
new
演算子を使って、各ラッパーオブジェクトのインスタンスを作成することができます。
例えば、文字列に対応するString
オブジェクトのインスタンスを作成するには、このように書くことができます。
// Stringオブジェクトのインスタンスを作成
let str = new String('string');
// Stringオブジェクトのメソッドを呼び出す
console.log(str.toUpperCase()); // "STRING"
String
オブジェクトは、'string'
という文字列の値を包んでいるように例えられます。
そのため、このようなオブジェクトのことを、プリミティブ型の値に対するラッパーオブジェクトと呼びます。
プリミティブ型の値は、変数宣言した段階ではその値に対する型のままです。
しかし、ラッパーオブジェクトを作成すると、その型はオブジェクトとなります。
let str = 'string';
console.log(typeof str); // "string"
let wrapperStr = new String('string');
console.log(typeof wrapperStr); // "object"
let num = 5;
console.log(typeof num); // "number"
let wrapperNum = new Number(5);
console.log(typeof wrapperNum); // "object"
このように、オブジェクトに型が変わるため、それに付随するメソッドが使えるようになるというわけです。
ラッパーオブジェクトの自動変換
new
演算子を使ってラッパーオブジェクトを作成することによって、そのオブジェクトが持つメソッドが呼び出せることが分かりました。
冒頭にも出てきた次のコードは、インスタンスの作成は行なっていませんが、String
オブジェクトのインスタンスメソッドtoUpperCase()
を呼び出せています。
let str = 'string';
console.log(str.toUpperCase()); // "STRING"
これは、プリミティブの値に対してプロパティにアクセスした瞬間に、自動的にラッパーオブジェクトに変換されているからです。
そのため、new String()
でラッパーオブジェクトを作成するのと同じ現象が起きています。
// 1と2は同じ
// 1. 文字列型の値に対してメソッドの呼び出しを行う
let str = 'string';
str.toUpperCase();
// 2. ラッパーオブジェクトを作成してからメソッドの呼び出しを行う
let wrapperStr = new String('string');
wrapperStr.toUpperCase();
通常、プリミティブ型のデータにはリテラルを使った方が良いとされています。
// 推奨:リテラルを使う
let str = 'string';
let num = 5;
// 非推奨:ラッパーオブジェクトを使う
let wrapperStr = new String('string');
let wrapperNum = new Number(5);
その理由としては、プリミティブの値に対して必要な時のみメソッドを使うことで、自動的にラッパーオブジェクトに変換されるからです。つまり、はじめからラッパーオブジェクトを作成する必要がないということです。
また、リテラルを使ったプリミティブ型の値とラッパーオブジェクトを使った値は、異なる型を示すため、混乱を生む可能性があります。(例:typeof演算子を使うと、文字列型は’string’, ラッパーオブジェクトは’object’となる)
そのような理由から、プリミティブ型のデータに対してはほとんどの場合リテラルが使われています。
まとめ
今回は、プリミティブ型とラッパーオブジェクトについて解説しました。
// ポイント
* プリミティブ型の値には、nullとundefinedを除いて、それぞれ対応するラッパーオブジェクトが存在する
* new演算子を使ってラッパーオブジェクトのインスタンスを作成できる
* プリミティブの値に対してプロパティにアクセスすると、自動的にラッパーオブジェクトに変換される
* よって、各ラッパーオブジェクトのメソッドを呼び出すことができる
JavaScriptがオブジェクト指向と表現されるように、プリミティブ型の値でもオブジェクトのように扱えることが分かりました。
BigInt と Symbol は プリミティブ型ではありますが、 new演算子でインスタンスを作成することはできないのではないでしょうか?