ES5中的Object.defineProperty是什么?

8

我看到有关于一个“新”的Object.create的帖子,它使枚举可配置。但是,它依赖于Object.defineProperty方法。我找不到这个方法的跨浏览器实现。

我们是否只能使用旧版的Object.create?我不能写那些在IE6/7中无法工作的代码。

3个回答

14

在 ECMAScript 3 环境中,有一些东西是无法从 ECMAScript 5 的 Object.create 方法中模拟出来的。

正如你所看到的,由于 E3 实现中没有办法更改属性特性,因此属性参数会给你带来问题。

@Raynos 提到的 Object.defineProperty 方法在 IE8 中可以使用,但只能在 DOM 元素中部分地使用。

另外,访问器属性也会给你带来问题。它们可以使用广泛支持的非标准方法(如__defineGetter__/__defineSetter__)进行模拟,但同样地,你无法更改属性特性

除了属性描述符之外,另一个问题是 Object.create 方法可以接受 null 作为参数,以创建一个不从任何对象继承的对象。

这不能用Crockford's Object.create shim来模拟,因为当使用具有包含null 或其他非对象值的 prototype 属性的构造函数与 new 运算符一起创建新对象时,新创建的对象将默认继承自 Object.prototype

在一些实现中(如 V8、Spidermonkey、Rhino 等),它们有一个可设置的__proto__ 属性,可以用于设置一个 null [[Prototype]],但同样地,这是非标准的,并且肯定永远不会在 IE 上工作。

如果你想要针对旧浏览器,请勿使用那些特性,因为在这些环境中无法使它们正常工作。

如果你仍然想要使用 Object.create 而不使用 properties 参数,你可以,但我建议你检测哪些东西无法模拟。

以下是Crockford's Object.create shim的一个更安全版本:

if (typeof Object.create != 'function') {
  (function () {
    var F = function () {};
    Object.create = function (o) {
      if (arguments.length > 1) { throw Error('Second argument not supported');}
      if (o === null) { throw Error('Cannot set a null [[Prototype]]');}
      if (typeof o != 'object') { throw TypeError('Argument must be an object');}
      F.prototype = o;
      return new F;
    };
  })();
}

无论如何,要小心使用它。


4
如果你想要一个良好的defineProperty()实现,请查看https://github.com/kriskowal/es5-shim 不幸的是,在ES3环境中,您无法使枚举可配置。这个shim将允许您在任一环境中调用API,但在ES3下属性仍将是可枚举的。

2

值得一提的是,Object.defineProperty 在ie8和FF4中可用。

这意味着在有用的地方进行功能嗅探并实现它是值得的,因为您希望从ie 6/7升级到8/9将在未来几年内发生。

还要注意的另一件事是,dontEnum属性在JScript中存在错误。

您将不得不解决在IE中使用dontEnum属性的方式。

[编辑]:

这里是Internet explorer的文档和ES5规范链接(第122页,15.2.3.6)。


很高兴知道它在IE8中存在,我看到了可能是实现的一瞥。所以,我的问题仍然是是否有defineProperty的已发布实现? - Drew
很抱歉,对于IE6/7,目前还没有相应的实现。 - Raynos
4
@Drew说:Object.defineProperty在IE8上只能部分使用,只能用于DOM元素。我在答案中简要地说了一下:你不能这么做。属性描述符无法在基于ECMAScript 3的实现中定义... - Christian C. Salvadó
我甚至没有注意到它只适用于DOM元素。感谢您指出这一点。 - Raynos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接