BLOG.QuelLENcode

by Moza USANE (a.k.a. Mozamimy)

Recent Tweets @Mozamimy

image
(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。いける。

image

次はChrome。

image

怒られた。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)は好きになれない。