在 ES5 之前,有没有办法在没有原型的情况下创建对象?

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

有没有办法在 ES5 之前创建一个没有原型的对象?

即像 Object.create(null) (ES5)

我以为这样的事情可能会奏效,但最后的声明出人意料returns true:

function withPrototype(p) {
  function temp(){}
  temp.prototype = p;
  return new temp();
}

Object.getPrototypeOf(withPrototype(null)) === Object.prototype; // true

Object.getPrototypeOf 是 ES5。我在这里用它来说明。

没有。在 ES3 spec 中搜索 [[Prototype]] 表明将 [[Prototype]] 更改为任意给定值的唯一方法是通过 [[Construct]].

但是,只有当该值是一个对象时它才有效。如果不是(包括null),[[Prototype]]将被设置为Object.prototype的初始值。

13.2.2 [[Construct]]

When the [[Construct]] property for a Function object F is called, the following steps are taken:

  1. Create a new native ECMAScript object.
  2. Set the [[Class]] property of Result(1) to "Object".
  3. Get the value of the prototype property of the F.
  4. If Result(3) is an object, set the [[Prototype]] property of Result(1) to Result(3).
  5. 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.
  6. 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.
  7. If Type(Result(6)) is Object then return Result(6).
  8. Return Result(1).

如@Oriol 所示,没有"official"(符合规范的)方法来做到这一点。

然而,确实存在一个没有原型的对象 - Object.prototype 本身。

15.2.4 Properties of the Object Prototype Object

The value of the internal [[Prototype]] property of the Object prototype object is null and the value of the internal [[Class]] property is "Object".

您可以通过实例化一个新环境("realm" 在 ES6 术语中)潜在地 "create" 这样一个对象,例如通过 <iframe>,捕获它的 Object.prototype,剥离它的属性,瞧瞧——你得到了一个新的空对象。

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
});