【问题标题】:What modernizer scripts exist for the new ECMAScript 5 functions?新的 ECMAScript 5 函数有哪些现代化脚本?
【发布时间】:2010-06-19 11:25:10
【问题描述】:

ECMAScript 5 有很多不错的补充。 John Resig has a good overview here。这是一个很好的ECMAScript 5 compatibility table

对于还不支持这些功能的浏览器来说,很多这些东西可能是“伪造的”。你知道任何可以做到这一点的脚本吗?我对 Object.create 特别感兴趣。

例如,Douglas Crockford's JSON script 在创建 JSON 函数之前检查它们是否存在。

如果有更多类似 JSON 的,我们可以在需要使用新函数时包含它们。

【问题讨论】:

标签: javascript cross-browser backwards-compatibility ecmascript-5


【解决方案1】:

Crockford recommends这种Object.create垫片:

if (typeof Object.create != "function") {
  Object.create = function (o) {
    function F(){}
    F.prototype = o;
    return new F;
  };
}

但是请不要这样做

这种方法的问题在于 ES5 Object.create 具有 2 个参数 的签名:第一个 - 要继承的对象,第二个(可选)- 表示属性的对象(或者更确切地说,描述符)添加到新创建的对象。

Object.create(O[, Properties]); // see 15.2.3.5, ECMA-262 5th ed.

我们所拥有的是一个具有 2 种不同行为的不一致实现。在原生Object.create 的环境中,方法知道如何处理第二个参数;在没有原生 Object.create 的环境中,它不会。

有什么实际意义?

好吧,如果有一些代码(比如第三方脚本)想要使用Object.create,那么该代码这样做是相当合理的:

if (Object.create) {
  var child = Object.create(parent, properties);
}

——基本上假设如果Object.create 存在,它必须符合规范——接受第二个参数并向对象添加相应的属性。

但是,使用上述 shim,第二个参数就被忽略了。甚至没有迹象表明发生了不同的错误。可以说是无声的失败——发现和修复相当痛苦的事情。

我们可以做得更好吗?

嗯,实际上不可能仅使用(标准)ES3 工具来创建完全符合的Object.create shim。最好的解决方案是创建自定义包装方法。

但是,您可以尝试的替代方法(不是最佳)很少:

1) 通知用户无法使用第二个参数

if (!Object.create) {
  Object.create = function (o) {
    if (arguments.length > 1) { 
      throw Error('second argument is not supported'); 
    }
    // ... proceed ...
  };
}

2) 尝试处理第二个参数:

if (!Object.create) {
  Object.create = function (parent, properties) {
    function F(){}
    F.prototype = parent;
    var obj = new F;
    if (properties) {
      // ... augment obj ...
    }
    return obj;
  }; 
}

请注意,“属性”是一个表示属性描述符的对象,而不仅仅是属性名称/值,而且支持起来并不是很简单(有些事情甚至是不可能的,例如控制可枚举性属性):

Object.create(parent, {
  foo: {
    value: 'bar',
    writable: true
  },
  baz: {
    get: function(){ return 'baz getter'; },
    set: function(value){ return 'baz setter'; },
    enumerable: true
  }
});

原始 shim 的另一个不一致之处是它没有处理 父对象为 null

var foo = Object.create(null);

这将创建一个 [[Prototype]] 为 null 的对象;换句话说,不从任何东西继承的对象,甚至不是Object.prototype(ECMAScript 中的所有本机对象都继承自)。

foo.toString; // undefined
foo.constructor; // undefined
// etc.

顺便说一下,这对于在 ECMAScript 中创建“正确的”哈希表很有用。

可以模拟这种行为,但只能使用非标准扩展,例如“神奇的”__proto__ 属性(因此实现不会非常便携或健壮)。此问题的解决方案类似:要么完全模拟 ES5 实现,要么通知不一致/失败。

【讨论】:

  • 我的Xccessors JavaScript library 提供了Object.definePropertyObject.defineProperties 函数,可用于解决方案#2。
  • 这很明显,您对 ES5 的了解显然很扎实,但我认为值得指出的是,Crockford 的代码比 ES5 早了很长一段时间:大约 2006 年的第一个版本和 2008 年初的最新版本。所以它是暗示他“推荐”这个解决方案来填充 ES5 有点不诚实。
  • 我上次看到 Doug 谈论这个 shim 是在 3 个月前 — slideshare.net/douglascrockford/… 那是 ES5 正式标准化后大约 4 个月(12 月 9 日),肯定晚于 2008 年。但我不想责怪任何人(对不起,如果它是这样出来的)。我们都会犯错。我们的想法是反对该方法并解释原因。
  • 那么你推荐你在这里提到的解决方案,还是其他的?
  • @Bob Spryn,解决方案 #1 或 #2 都比原始解决方案更好。您还可以为方法使用不同的名称(例如SomeLibrary.object.create);只要在不同环境中没有不一致的行为。
【解决方案2】:

es5-shim http://github.com/kriskowal/es5-shim/

这是 narwhal 独立 javascript 环境的一部分,但已经独立出来了。它非常成熟和精确。

【讨论】:

    【解决方案3】:

    es5 - JavaScript/EcmaScript 5 in 3 是在 BitBucket 上共享的集合。 Object.create 尤其容易伪造,在by Crockford 等人中很受欢迎,但Justin Love 在此进行了改进,专注于许多 ES5 部分。

    【讨论】:

      【解决方案4】:

      如果您不介意学习该库并自己编写一些代码,您可以在

      找到一些 ECMAScript 5 库的代码实现

      https://developer.mozilla.org/En/JavaScript/ECMAScript_5_support_in_Mozilla

      例如Array.filter的代码

      然后 Crockford 在 json2.js 中有 JSON.parse/stringify

      https://github.com/douglascrockford/JSON-js

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多