JavaScript
IE8
ES3

[レガシーJavaScript] ES3環境のブラウザでObject.create(null)相当のオブジェクトを作る

More than 1 year has passed since last update.

今となっては存在価値の無いハックだが、面白かったのでメモに残す。


TL;DR

アイデアの肝の部分のみ載せるとこうなる。(実際はこれだけだと動かない)

document.createElement("iframe").contentWindow.Object.prototype


完全版のコード

function getNoProtoObject() {

var iframe = document.createElement("iframe");
document.body.appendChild(iframe);
var obj = iframe.contentWindow.Object.prototype;
document.body.removeChild(iframe);

// for-inで列挙可能なプロパティを削除する
for (var name in obj) {
delete obj[name];
}

// for-inで列挙不可能な既知のプロパティを削除する
delete obj["constructor"];
delete obj["hasOwnProperty"];
delete obj["isPrototypeOf"];
delete obj["propertyIsEnumerable"];
delete obj["toLocaleString"];
delete obj["toString"];
delete obj["toSource"];
delete obj["valueOf"];
delete obj["watch"];
delete obj["unwatch"];
delete obj["__defineGetter__"];
delete obj["__defineSetter__"];
delete obj["__lookupGetter__"];
delete obj["__lookupSetter__"];
delete obj["__proto__"];

return obj;
}


説明

ECMAScript 3環境において[[Prototype]]内部プロパティがnullであるオブジェクトはObject.prototypeだけであるから、これをObject.create(null)相当のオブジェクトとして扱うほかない。

ところが、Object.prototypeは一つのページにただ一つしか存在しないオブジェクトであるから、Object.create(null)のように量産することができない。

この問題をいかに解決するかが課題となる。

上記の方法は、iframeでページ自体を新しく作ってしまって、そこからObject.prototypeを持ってくることで課題を解決している。

Object.prototypeには組み込みのプロパティがいくつか生えているので、最後の仕上げとしてそれらを削除すれば、まっさらなオブジェクトを得ることができる。


参考リンク

Was there a way to create an object without a prototype prior to ES5?


ところで

言わずもがな、このテクニックはもはや歴史的な意味合いしか持たない。

ECMAScript 3環境のブラウザには、IE 5.5〜8、Netscape 6、Firefox 3.0以前などがあるが、いずれも死んだブラウザである。

IE8ですら、日本標準時で2016年1月13日にサポートが打ち切られている。