Was there a way to create an object without a prototype prior to ES5?
i.e. something like Object.create(null)
(ES5)
I thought something like this might work, but the final statement unexpectedly returns true
:
function withPrototype(p) {
function temp(){}
temp.prototype = p;
return new temp();
}
Object.getPrototypeOf(withPrototype(null)) === Object.prototype; // true
Object.getPrototypeOf
is ES5. I use it here for exposition.
As @Oriol has shown, there was no "official" (spec-compliant) way to do this.
However, there was indeed an object that had no prototype - Object.prototype
itself.
15.2.4 Properties of the Object Prototype Object
The value of the internal
[[Prototype]]
property of the Object prototype object isnull
and the value of the internal[[Class]]
property is"Object"
.
You could potentially "create" such an object by instantiating a new environment ("realm" in ES6 terms), e.g. via an <iframe>
, capturing its Object.prototype
, stripping it of its properties and voilá - you've got a new empty object.
function getNoProtoObject(callback) {
var iframe = document.createElement('iframe');
iframe.onload = function() {
var obj = iframe.contentWindow.Object.prototype;
document.body.removeChild(iframe);
// Remove all built-in enumerable properties.
for (var name in obj) {
delete obj[name];
}
// Remove known built-in non-enumerable properties, which may vary.
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__'];
callback(obj);
};
iframe.src = 'about:blank';
iframe.style.display = 'none';
document.body.appendChild(iframe);
}
getNoProtoObject(function(o) {
console.log(o); // Object { }
console.log(Object.getPrototypeOf(o)); // null
console.log(o.__proto__); // undefined
});