Edited at

すべてのオブジェクトがObjectを継承している訳じゃない

More than 5 years have passed since last update.

MDNいわく


JavaScript におけるすべてのオブジェクトは Object に由来します。 すべてのオブジェクトは Object.prototype からメソッドとプロパティを継承しています が、それらは上書きされている可能性があります。


らしい、だけどオブジェクトの中にはObjectを継承していないものがある。

追記

優しい人に教えてもらったのだけど、IE8およびIE7はじゃなくてJavaScriptじゃなくてJScriptというJavaScript互換言語でスクリプトを実行している。なのでMDNに書かれていることは正しい。紛らわしいこと書いてごめんなさい。

追記終わり。

JScriptのオブジェクトの中にはObjectを継承していないものがある。

具体例を出すとIE7でのwindowオブジェクトやDOM Events。

さらにIE7でのwindow.toStringFunctionを継承していない。

alert(window instanceof Object); // IE7ではfalse

alert(window.toString instanceof Function); // IE7ではfalse

以下、どうしてこんなことになっているか調べた。


native object, built-in object, host object

JScriptの標準言語仕様であるECMAScriptによると、オブジェクトは3つに分類できる。


  • native object

ホスト環境(つまりブラウザとかNode)から独立したオブジェクト。後述のbuilt-in objectと自分で作った(ユーザ定義した)オブジェクトがこれにあたる。


  • built-in object

ECMASciriptで定義されているオブジェクト。すべてのbuilt-in objectはnative objectでもある。ObjectFunctionDateなどおなじみのオブジェクトがこれ。


  • host object

ホスト環境から提供されるオブジェクト。ブラウザでいうwindowやDOM、Nodeでいうrequireなどがこれにあたる。


Objectの継承について

ECMAScript5.1によると


Unless otherwise specified every built-in prototype object has the Object prototype object, which is the initial value of the expression Object.prototype (15.2.4), as the value of its [[Prototype]] internal property, except the Object prototype object itself.


(てきとうな意訳)特に断りのない場合、すべてのbuilt-in prototype objectの[[Prototype]]内部プロパティはObject.prototypeを初期値として持っている、とある。

つまり基本的に built-in objectObjectをプロトタイプ継承しているよ、ということだ。

でも、逆にbuilt-in object以外についてはObjectを継承する、ということが明記されていない。


つまり?

built-in object以外はObjectを継承していなくても、ECMAScriptの仕様上間違いではないので host object であるwindowなどはObjectを継承していなくてもよい。

すべてのオブジェクトがObjectを継承しているだろうと思って、うっかりIE7で

// IE7

document.getElementById('btn').attachEvent('onclick', function (e) {
if (e.hasOwnProperty('target')) {
// 処理
}
});

とかやってしまうと、エラーになる(host objectであるEventObjectを継承しておらずObject.prototype.hasOwnpropertyを参照しないため)。

関数についても同様のことがいえるので、IE7だと下記がエラーになる。

var obj = {};

window.toString.call(obj); // Functionを継承していないのでFunction.prototype.callを使えない


まとめ

host objectがObjectを継承してるかどうかは実行環境の実装によるので、気をつけよう。。