新的ECMAScript 5函数有哪些现代化程序脚本?

and*_*yuk 16 javascript cross-browser backwards-compatibility ecmascript-5

ECMAScript 5有很多不错的补充.John Resig在这里有一个很好的概述.这是一个很好的ECMAScript 5兼容性表.

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

例如,Douglas Crockford的JSON脚本在创建JSON函数之前检查它们是否存在.

如果有更多像JSON那样我们可以在需要使用新函数时包含它们.

kan*_*gax 40

Crockford推荐这种Object.create垫片:

if (typeof Object.create != "function") {
  Object.create = function (o) {
    function F(){}
    F.prototype = o;
    return new F;
  };
}
Run Code Online (Sandbox Code Playgroud)

但请不要这样做.

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

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

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

有什么实际意义?

好吧,如果有一些想要使用的代码(比如第三方脚本),Object.create那么代码执行此操作是相当合理的:

if (Object.create) {
  var child = Object.create(parent, properties);
}
Run Code Online (Sandbox Code Playgroud)

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

但是,对于上述垫片,第二个论点被忽略了.甚至没有迹象表明事情会发生错误不同.可以说是一种无声的失败 - 一种在检测和修复方面相当痛苦的事情.

我们可以做得更好吗?

嗯,实际上不可能Object.create仅使用(标准)ES3设施来创建完全符合要求的垫片.最好的解决方案是创建自定义包装器方法.

但是,您可以尝试很少的替代(不太理想)的事情:

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

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

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

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

请注意,"properties"是一个表示属性描述符的对象,而不仅仅是属性名称/值,并且是一些不太容易支持的东西(有些东西甚至不可能,例如控制属性的可枚举性):

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

原始垫片中的另一个不一致是它不处理父对象null.

var foo = Object.create(null);
Run Code Online (Sandbox Code Playgroud)

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

foo.toString; // undefined
foo.constructor; // undefined
// etc.
Run Code Online (Sandbox Code Playgroud)

顺便说一句,这对于在ECMAScript中创建"适当的"哈希表很有用.

可以模拟这种行为,但仅使用非标准扩展,例如"魔法" __proto__属性(因此实现将不是非常便携或健壮).此问题的解决方案类似:要么完全模拟ES5实现,要么通知有关不一致/失败的问题.

  • 这一点非常明显,你对ES5的了解显然是可靠的,但我认为值得指出的是,Crockford的代码早于ES5已经有一段时间了:大约是2006年的第一版和2008年初的最新版本.所以有点不诚实地建议他'推荐'这个解决方案来重新调整ES5. (10认同)
  • 上次我看到Doug谈论这个垫片是在3个月前 - http://www.slideshare.net/douglascrockford/javascript-the-good-parts-3292746/36这是ES5正式标准化后约4个月(在12月09)并且肯定比2008年晚.但我不想责怪任何人(抱歉,如果它出来的话).我们都会犯错.这个想法是建议反对**方法**并解释原因. (7认同)

Sea*_*lan 8

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

这是独角鲸独立的javascript环境的一部分,但它已经自行分解.它非常成熟和精确.