今となっては存在価値の無いハックだが、面白かったのでメモに残す。
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日にサポートが打ち切られている。