ボックス化について

はいどーもこんにちは、自分をニートだと思いこんでいるニートです。
「そういやボックス化について、軽く触れたことはあっても真正面からは書いたことねえなあ」と思ったので、本日はボックス化について書いていこうと思いますよ。
ツクラー向けにJavaScriptを基準に書いていきますが、C#でもボックス化はあります(と言うかボックス化を意識するのはC#のが強い?)。

ボックス化のサンプル

ボックス化を説明するには実例を見てもらった方が早いと思うので、まずは以下のコードをご覧ください。

何の変哲もないコードに見えますね。
文字列’string’にtoUpperCaseメソッドを適用し、結果として「STRING」と出力するだけのコードです。

しかしこのコードには一点だけ不思議な部分があります。
それは、プリミティブ型である’string’という文字列に対し、toUpperCaseというメソッドを呼び出していることです。
言い換えるなら、オブジェクト(クラスのインスタンス)ではないただの値に対し「このメソッドを呼び出してね」とお願いしていることになります。

これは通常であればあり得ないことです。
なぜなら、プリミティブ型はオブジェクトではなく、オブジェクトでなければ関数(メソッド)を保持することはできないはずだからです。

toUpperCaseメソッドについて考える

toUpperCaseメソッドについて考えてみましょう。
toUpperCaseメソッドは、ビルトインオブジェクトであるStringオブジェクトのprototypeプロパティに定義されています。
つまり、StringオブジェクトのインスタンスであればtoUpperCaseメソッドを使用できる、というわけです。

しかし最初にも書いたように、‘string’はStringオブジェクトのインスタンスではありません。
ただのプリミティブ型です。

ではなぜStringオブジェクトのprototypeプロパティに定義されているメソッドを使用できるのでしょうか?
この理由がズバリ、ボックス化です。

ボックス化の仕組み

最初に示したコードをもう一度見てください。

本来であれば’string’に対してtoUpperCaseメソッドを呼び出すことはできません。
しかしこのコードは問題なく動きます。
であるならば、‘string’というプリミティブな値は何らかの方法でString型のインスタンスに変換され、そのインスタンスが代わりにtoUpperCaseメソッドを呼び出していることにはならないでしょうか?

まさにこの挙動がボックス化の仕組みです。

詳しく見てみる

ボックス化の流れを見ていきましょう。

プリミティブな値’string’に対して「toUpperCaseメソッドを呼び出せ」と命令すると、JavaScriptの内部では暗黙的にString型のインスタンスが作成されます。
このインスタンスは’string’というプリミティブな値を内部に保持(ラップ)しています。
ここまでがボックス化です。

そしてこの暗黙的に作成されたString型のインスタンスがtoUpperCaseメソッドを実行します。
メソッド実行が終了すると、暗黙的に作成されたString型のインスタンスは破棄され、結果として’string’というプリミティブな値に対してメソッドを実行できたかのように振る舞うことが可能となるのです。

他のプリミティブな値

今回は文字列のみを扱いましたが、他のプリミティブ型の値も事情は同じです。
数字ならNumber型のインスタンスが作成されますし、真偽値ならBoolean型のインスタンスが作られます。

注*ただしnullおよびundefinedはラッパーオブジェクトを持っていないので、このような変換はおこなわれません。

以上のことをまとめると「プリミティブ型をオブジェクトのように扱うと、オブジェクトのように振る舞う。ただしプリミティブ型はオブジェクトではない。ボックス化がおこなわれているだけである」と言えますね。

おまけでC#

C#では値型と参照型は明確に区別されるべきものです。
しかし値型も参照型もObject型を親に持つため、参照型であるObject型に値型を代入することができます。
これがボックス化ですね。
具体的なコードだと、こんな感じ。

値型であるsampleを参照型であるobに代入しています。
このとき、値型をそのまま参照型に代入するわけにはいかないので、ボックス化がおこなわれます。
つまりObject型であるobは内部で100という値を保持するために、値を新しいオブジェクトにコピーします。

これは単に値を保持させるプロセスよりも負荷の大きいプロセスとなります。
あまり闇雲にボックス化をさせない方がよいらしいですが、ボックス化を連発する書き方ってどういう場面で起きるんでしょうね?
よくわかりません。

ちなみにボックス化解除のコードはこんな感じ。

おわりに

本日はボックス化について書きました。
ボックス化を理解するには、まずは値型(プリミティブ型)と参照型(オブジェクト)の違いを把握しておく必要があります。
「よくわからんべー」という方は、まずそちらをググってみてはいかがでしょーか。

ほなそんな感じでまた。

フォローする