KDE BLOG

Webデザインやコーディングについて書いています

【JavaScript基礎】プリミティブ値の生成方法とラッパーオブジェクトに関して

<目次>

プリミティブ値とは

JavaScriptのデータ型には、現在7つの型が定義されており、大きく分けてプリミティブ型(基本型とも呼ばれる)と参照型と呼ばれるタイプに分類されています。
各データ型は次のように分けることができます。

  • プリミティブ型
    • 文字列(string)
    • 数値(number)
    • 真偽値(boolean)
    • シンボル(symbol)※ES2015からの新機能
    • null
    • undefined
  • 参照型
    • オブジェクト(object)

このように参照型のオブジェクト以外のデータ型はプリミティブ型で、その値のことをプリミティブ値と呼びます。

プリミティブ値の生成方法

プリミティブ値の設定には以下の3つがあります。

リテラルを使う(推奨)

もっとも推奨されている方法がリテラルを使った方法です。

const myString = 'Hello!';
const myNumer = 10;
const myBoolean = true;
const myNull = null;
const myUndefined = undefined;

リテラルとはデータ型に格納できる値そのもの、プログラムに直接記述できる定数値のことをいいます。
※ES2015の新機能として追加された型Symbolはコンストラクタ関数を使って定義できます。

コンストラクタ関数を使う

次にコンストラクタ関数を使った方法です。
String()、Number()、Boolean()のコンストラクタ関数は、new演算子を付けるとオブジェクトを生成しますが、付けずに使用するとプリミティブ値を生成するという特徴があります。 Symbolを定義する以外はあまり使わないかと思います。
※nullとundefinedはコンストラクタを持っていません

const myString = String('Hello!');
const myNumer = Number(10);
const myBoolean = Boolean(true);
const mySymbol = Symbol();

new演算子とコンストラクタ関数を使う(非推奨)

オブジェクト型の生成のようにnew演算子とコンストラクタ関数を使って定義することもできます。

const myString = new String('Hello!');
const myNumber = new Number(10);
const myBoolean = new Boolean(true);

しかしこの方法は後述の理由により非推奨とされています。
むしろ有害となることがありますので通常のコーディングでは使用しない方が良いといわれています。

コードが冗長になる

リテラルでの生成と比べると、記述量が多く書き方が冗長になります。

const myString1 = 'Hello!';
const myString2 = new String('Hello!');

上記の通り、リテラル表記の方が簡潔で直感的な記述に感じます。

返り値がプリミティブ値ではなくオブジェクトになる

一番の有害と言われる理由がこれだと思います。
どういう事かというと実際に試してみると分かります。

const myString1 = 'Hello!';
const myString2 = new String('Hello!');

console.log(myString1); // 出力結果 -> Hello!
console.log(myString2); // 出力結果 -> String {0: "H", 1: "e", 2: "l", 3: "l", 4: "o", 5: "!", length: 6, [[PrimitiveValue]]: "Hello!"} ※出力のされ方は実行環境によって変わる可能性があります

データ型を調べることができるtypeof演算子を使ってみると、もっとわかりやすいです。

console.log(typeof myString1); // 出力結果 -> string
console.log(typeof myString2); // 出力結果 -> object

このことはつまり同値演算(===)ではfalseとなります。
※等価演算(==)ではtrueとなります。

console.log(myString1 === myString2); // 出力結果 -> false
console.log(myString1 == myString2); // 出力結果 -> true

なぜこのようにデータ型が異なるのかというと、new演算子を使ってコンストラクタを呼び出すと、新たに作られたオブジェクト(インスタンス)が返されるからです。
一方リテラル表記の場合は、実は裏ではコンストラクタが実行されるのですが、オブジェクトではなくプリミティブ値が返されます。

このような挙動の違いから、思わぬバグを生む可能性があるためプリミティブ値の生成ではリテラル表記が推奨されているのです。

プリミティブ値もオブジェクトとして扱うとオブジェクトのようにふるまう(ラッパーオブジェクト)

補足すると、プリミティブ値自体もオブジェクトのように扱うと、一時的にラッパーオブジェクトというオブジェクトを生成します。
処理が終わるとこのラッパーオブジェクトは破棄されてプリミティブ値に戻ります。
普段、開発する人がラッパーオブジェクトを意識することはありませんが、このような流れがあるということを知っておくと、「JavaScriptではすべてのものがオブジェクトのようにふるまう」と言われる理由の理解に繋がります。

const myString = 'Hello!';
console.log(myString.length); // 出力結果 -> 6

// 直接リテラルにプロパティを付けても処理できる
console.log('hoge'.length); // 出力 -> 4

参考

開眼!  JavaScript ―言語仕様から学ぶJavaScriptの本質

開眼! JavaScript ―言語仕様から学ぶJavaScriptの本質