ECMAScript 5增加了不少好的特性。 John Resig在这里有一个很好的概述。 这是一个ECMAScript 5兼容性表。
对于那些还没有支持这些函数的浏览器,很多功能都可以“模拟”。你知道有哪些脚本可以实现这一点吗?我特别感兴趣的是Object.create。
例如,Douglas Crockford的JSON脚本会在创建函数之前检查JSON函数是否存在。
如果还有像JSON这样的东西,我们在需要使用新功能时就可以把它们包含进来。
ECMAScript 5增加了不少好的特性。 John Resig在这里有一个很好的概述。 这是一个ECMAScript 5兼容性表。
对于那些还没有支持这些函数的浏览器,很多功能都可以“模拟”。你知道有哪些脚本可以实现这一点吗?我特别感兴趣的是Object.create。
例如,Douglas Crockford的JSON脚本会在创建函数之前检查JSON函数是否存在。
如果还有像JSON这样的东西,我们在需要使用新功能时就可以把它们包含进来。
Crockford推荐使用这种Object.create
的垫片:
if (typeof Object.create != "function") {
Object.create = function (o) {
function F(){}
F.prototype = o;
return new F;
};
}
但是请不要这样做。
这种方法的问题在于ES5的Object.create
有一个签名含有两个参数:第一个是继承自的对象,第二个(可选)是一个表示要添加到新创建的对象中的属性(或者说描述符)的对象。
Object.create(O[, Properties]); // see 15.2.3.5, ECMA-262 5th ed.
我们所拥有的是一个实现不一致且存在两种不同行为的问题。在拥有本地 Object.create
的环境中,该方法知道如何处理第二个参数;而在没有本地 Object.create
的环境中,它则无法处理。
这会有什么实际影响呢?
嗯,如果有一些代码(比如第三方脚本)想要使用 Object.create
,那么代码通常会这样做:
if (Object.create) {
var child = Object.create(parent, properties);
}
基本上假设Object.create
存在,它必须符合规范 - 接受第二个参数并将相应的属性添加到对象中。
但是,使用上述补丁时,第二个参数被简单地忽略了。甚至没有任何指示表明出现了不同的情况。可以说是无声的失败 - 这种情况很难检测和修复。
我们能做得更好吗?
实际上,只使用(标准)ES3设施是不可能创建一个完全符合规范的Object.create
补丁。最好的解决方案是创建一个自定义包装方法。
然而,还有一些其他的(次优的)方法可供尝试:
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;
};
}
请注意,“properties”是表示属性描述符的对象,而不仅仅是属性名称/值,并且这是一些不太容易支持的内容(有些事情甚至是不可能的,例如控制属性的可枚举性):Object.create(parent, {
foo: {
value: 'bar',
writable: true
},
baz: {
get: function(){ return 'baz getter'; },
set: function(value){ return 'baz setter'; },
enumerable: true
}
});
原始的垫片中存在另一个不一致之处,即它未考虑父级对象为null
的情况。
var foo = Object.create(null);
这将创建一个 null
原型的对象;换句话说,该对象不继承任何东西,甚至不继承 Object.prototype
(ECMAScript中所有原生对象的继承者)。
foo.toString; // undefined
foo.constructor; // undefined
// etc.
顺便说一下,这对于在ECMAScript中创建“proper”哈希表是有用的。
虽然可以使用非标准扩展(例如“magical”__proto__
属性)来模拟此行为,但只能如此(因此实现可能不太可移植或健壮)。解决此问题的方法类似:要么完全模拟ES5实现,要么通知存在不一致/失败。
SomeLibrary.object.create
),只要在不同环境中不存在不一致的行为即可。 - kangaxes5-shim http://github.com/kriskowal/es5-shim/
这是 narwhal 独立的 JavaScript 环境的一部分,但已经被单独分离出来。它非常成熟和精确。
ES5 - JavaScript/EcmaScript 5 in 3 是在BitBucket上分享的一个集合。特别是Object.create
是一个容易“伪造”的方法,由Crockford等人广泛使用,但这里由Justin Love改进,专注于许多ES5部分。
如果您不介意学习库并自己编写一些代码,您可以在以下网址找到ECMAScript 5库的一些代码实现:
https://developer.mozilla.org/En/JavaScript/ECMAScript_5_support_in_Mozilla
例如,Array.filter 的代码
然后 Crockford 在 json2.js 中有 JSON.parse/stringify