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实现,要么通知有关不一致/失败的问题.