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


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を継承してるかどうかは実行環境の実装によるので、気をつけよう。。