オブジェクトとプリミティブ

前にJavaScriptのオブジェクトとプリミティブの話が出ていたので、もう1つ面白い話を。

JavaScriptはオブジェクト毎にメソッドを設定したり上書きできるので…、

var obj = {};

alert(obj.toString());   // "[object Object]" と表示される

obj.toString = function() { return "じゃばすくりぷと"; }

alert(obj.toString());   // "じゃばすくりぷと" と表示される

オブジェクト単位でメソッドの挙動を変更できます。

しかしstringに対して行うと、

var str = "Java";

alert(str.toString());   // "Java"と表示される

str.toString = function() { return this.valueOf() + "Script"; }

alert(str.toString());   // "Java"と表示される

変わりません…。

これはstrがStringオブジェクトではなく、Stringプリミティブであるためです。

Stringプリミティブに対してメソッドを呼び出したりプロパティにアクセスすると、その処理中だけStringプリミティブはStringオブジェクトに変化し、完了するとプリミティブに戻ります。

プリミティブに対してメソッドを変更した場合、その変更は一瞬だけ変化したオブジェクトに対する変更となり、元に戻ると同時にオブジェクトは破棄され、メソッド変更もなかった事になってしまいます。

Stringオブジェクトならば

var str = new String("Java");

alert(str.toString());   // "Java"と表示される

str.toString = function() { return this.valueOf() + "Script"; }

alert(str.toString());   // "JavaScript"と表示される

メソッドをオーバーライドできます*1

*1:この場合は、prototypeのメソッドを上書きしているわけではなく隠しているので、オーバーライドではなくシャドウと呼ぶのが正しい