
(photo by Dmitry Baranovskiy :: the JavaScript Code)
JavaScriptでオブジェクトをつくる
JavaScriptで、Arrayなどのクラスのオブジェクトを作りたい場合、以下のようにすればよい。
var array1 = new Array(1, 2, 3);
var array2 = Array(4, 5, 6);
var array3 = [7, 8, 9];
[array1, array2, array3].forEach(function(obj) {
console.log("" + obj.toString() + " : " + typeof obj);
});
/*
* outputs
* 1,2,3 : object
* 4,5,6 : object
* 7,8,9 : object
*/
なんら問題はない。ここで注目すべきは、1行目のようにnewをつけても、2行目のようにnewをつけなくても、ちゃんとオブジェクトが生成されていることだ。
じゃあImageオブジェクトもいけるよね!
画像を表すImageオブジェクトも同じように作れるはずである。
var image1 = new Image();
var image2 = Image();
image1.src = "http://example.com/image1.png";
image2.src = "http://example.com/image2.jpg";
[image1, image2].forEach(function(obj) {
console.log("" + obj.src + " : " + typeof obj);
});
/*
* outputs
* http://example.com/image1.png : object
* http://example.com/image2.jpg : object
*/
さて、このコードをブラウザで実行してみよう。まずはFirefox。いける。

次はChrome。

怒られた。Uncaught TypeError: DOM object constructor cannot be called as a function.というエラーメッセージから察するに、ChromeではDOMオブジェクトを作るときは、ちゃんとnewしてあげないといけないらしい。
ブラウザによる挙動の差異の恐怖
Imageオブジェクトにまつわる挙動の違いを以下にまとめる。◯がnewなしでもImageオブジェクトを作れるブラウザ、×がnewなしではImageオブジェクトを作れないブラウザである。IE9以外は全部Mac上のブラウザである。IE9はWindows 7。
◯: Firefox 19.0
◯: Opera 12.14
◯: Internet Explorer 9
×: Chrome 25.0.1364.99
×: Safari 6.0.2
webkitを使ったブラウザはnew必須のようだ。webkit以外の実装が正しいのかwebkitが正しいのかはわからないが、とにかくそうなっている。
new演算子をつけたほうが安全
この結果から、組み込みのクラスオブジェクトを作るときは、newをつけたほうが互換性を確保できるといえる。推測であるが、おそらくグローバルオブジェクト(グローバルスコープでthisキーワードでアクセスできるオブジェクト)にImage()メソッドが定義されていないのだろう。
ちなみに、Dateだともっとややこしい。
var date1 = new Date();
var date2 = Date();
[date1, date2].forEach(function(obj) {
console.log("" + obj.toString() + " : " + typeof obj);
});
/*
* outputs
* Fri Mar 01 2013 14:49:24 GMT+0900 (JST) : object
* Fri Mar 01 2013 14:49:24 GMT+0900 (JST) : string
*/
newをつけるとDateオブジェクトが、newをつけないと文字列が返るようだ。便宜上、グローバルオブジェクトが持つDate()メソッドの戻り値をDateオブジェクトではなく、あえて文字列を返すように定義しているのだろう。
わたしはRubyやC#に慣れているため、特段の理由がない限りあえてnewを省略することはないが、ややこしい振る舞いをするものである。やはりJavaScript(特に非CoffeeScript)は好きになれない。