问题
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.
回答1:
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
});
回答2:
No. Searching [[Prototype]]
in the ES3 spec shows that the only way of changing [[Prototype]] to an arbitrary given value is through [[Construct]].
However, it only works if that value if an object. If it's not (including null), the [[Prototype]] will be set to the initial value of Object.prototype
.
13.2.2 [[Construct]]
When the [[Construct]] property for a Function object F is called, the following steps are taken:
- Create a new native ECMAScript object.
- Set the [[Class]] property of Result(1) to
"Object"
.- Get the value of the
prototype
property of the F.- If Result(3) is an object, set the [[Prototype]] property of Result(1) to Result(3).
- If Result(3) is not an object, set the [[Prototype]] property of Result(1) to the original Object prototype object as described in 15.2.3.1.
- Invoke the [[Call]] property of F, providing Result(1) as the this value and providing the argument list passed into [[Construct]] as the argument values.
- If Type(Result(6)) is Object then return Result(6).
- Return Result(1).
来源:https://stackoverflow.com/questions/36117162/was-there-a-way-to-create-an-object-without-a-prototype-prior-to-es5