6時だョ!!全員集合!!

Rails・JavaScrictを中心にアウトプットします。

2021年12月13日 JavaScript (JS Primer) ラッパーオブジェクト

JavaScriptでは、プリミティブ型の値に対してプロパティアクセスするとき、自動で対応するラッパーオブジェクトに変換されます。

const str = "string";
// プリミティブ型の値に対してメソッド呼び出しを行う
str.toUpperCase();
// `str`へアクセスする際に"string"がラッパーオブジェクトへ変換され、
// ラッパーオブジェクトはStringのインスタンスなのでメソッドを呼び出せる
// つまり、上のコードは下のコードと同じ意味である
(new String(str)).toUpperCase();

明示的に作成したラッパーオブジェクトからプリミティブ型の値を取り出すこともできます。

const stringWrapper = new String("文字列");
// プリミティブ型の値を取得する
console.log(typeof stringWrapper);
console.log(stringWrapper.valueOf()); // => "文字列"

- 検証 -
const str = stringWrapper.valueOf()
console.log(typeof str); // => string

JavaScriptには、リテラルを使ったプリミティブ型の文字列とラッパーオブジェクトを使った文字列オブジェクトがあります。

  • プリミティブ型の値からラッパーオブジェクトへの変換は自動的に行われるため、基本的はプリミティブ型のデータにはリテラルを使います。

プリミティブ型の値がなぜメソッド呼び出しできるのか

それはJavaScriptではプリミティブ型に対応したラッパーオブジェクトというものが存在しているためです。 プリミティブ型の値のプロパティへアクセスする際に、自動的にラッパーオブジェクトへ変換されることでメソッド呼び出しなどが可能となっています。

プリミティブ型に対してメソッドを使える事にはこういった背景があるという認識だけを持ち、普段コードを書くときには、リテラルを使うと良いでしょう。

検証(インスタンスであるか)

instanceof演算子は、オブジェクトがどのコンストラクタから生成されたかを判別することが出来ます。

// プリミティブの文字列は"string"型
const str = "文字列";
console.log(typeof str); // => "string"

console.log(str instanceof String); // => false

上記で見る限り、プリミティブな文字列はインスタンスではないことが分かります。

次のコードではnew演算子を用いた場合の実行結果です。

const str = new String("文字列");
console.log(typeof str); // => "object"

console.log(str instanceof Object); // => "true"

以上の結果からnew演算子を用いた場合、インスタンスが生成されているという認識が正しいと言えます。

オブジェクトがどのオブジェクトか知りたいときの検証方法

Object.prototype.toString.call(new String("文字列")); // => [object String]

// 省略してこのようにも書けます。
toString.call(new String("文字列")); // => [object String]

上記のようにObject.prototype.toString.call(検証対象);又は、toString(検証対象)とすると検証できます。

以下はNumberを扱った場合の例です。

const yano = 1;
console.log(typeof yano); // => "number"

console.log(yano instanceof Number);

toString.call(yano);

出力結果
number
false
[object Number]
  • yanoに数値を代入します。
  • typeof演算子で見るとnumberと出力されます。これはデータ型がnumberのプリミティブな値であるということを意味しています。
  • instanceof Numberではfalseと出力されます。このように出力されるのは上の説明の通りNumberのインスタンスではなく、yanoはただのプリミティブな数値であるからです。
  • 最後のcallでNumberとして返り値が出力されるのは一時的に生成されたラッパーオブジェクトが呼び出されているためです。

ラッパーオブジェクトというのはstring, number, booleanの3つのプリミティブな値に対してメソッドを呼び出した際に、メソッド実行用に一時的に生成されるオブジェクトです。その為、コンストラクタを使わずにtoStringを呼び出す事が出来ます。

豆知識

このようなプリミティブ型からオブジェクト型への変換はボックス化(ボクシング)、逆にオブジェクト型からプリミティブ型への変換はボックス化解除(アンボクシング)と呼ばれます。

JavaScriptはすべてがオブジェクトである」と言われることがあります。 プリミティブ型はオブジェクトではありませんが、プリミティブ型に対応したラッパーオブジェクトが用意されています(nullとundefinedを除く)。 そのため、「すべてがオブジェクトのように見える」というのが正しい認識となるでしょう。

結論

長々と深堀りしましたが、結論は プリミティブ型のデータにはリテラルを使ってもラッパーオブジェクトへの変換が自動的に行われることで、メソッドが使えるため、基本的にはnew演算子は使用せずリテラルを使えば良いでしょう。

参考

JavaScript Primerプリミティブ型とラッパーオブジェクト

JavaScriptの「型」の判定について