在一些浏览器中,例如IE8、Opera v11.5和Konq4.3等版本,Object.create还没有被标准化。对于这些浏览器,你可以使用Douglas Crockford的版本来代替Object.create,但这个版本不包括CMS答案中使用的第二个“初始化对象”参数。
为了实现跨浏览器代码,可以暂时修改Crockford的Object.create方法以实现对象初始化。以下是一种方法:
Object.build = function(o) {
var initArgs = Array.prototype.slice.call(arguments,1)
function F() {
if((typeof o.init === 'function') && initArgs.length) {
o.init.apply(this,initArgs)
}
}
F.prototype = o
return new F()
}
这个方法维护了 Crockford 的原型继承,并且还会检查对象中是否存在任何 init 方法,然后使用参数运行它,例如 new man('John','Smith')。您的代码将变成:
MY_GLOBAL = {i: 1, nextId: function(){return this.i++}}
var userB = {
init: function(nameParam) {
this.id = MY_GLOBAL.nextId();
this.name = nameParam;
},
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var bob = Object.build(userB, 'Bob');
bob.sayHello();
因此,Bob继承了sayHello方法,并具有自己的属性id=1和name='Bob'。当然,这些属性都是可写和可枚举的。如果您不关心可写、可枚举和可配置属性,这也比ECMA Object.create更简单的初始化方式。
对于没有init方法的初始化,可以使用以下Crockford模式:-
Object.gen = function(o) {
var makeArgs = arguments
function F() {
var prop, i=1, arg, val
for(prop in o) {
if(!o.hasOwnProperty(prop)) continue
val = o[prop]
arg = makeArgs[i++]
if(typeof arg === 'undefined') break
this[prop] = arg
}
}
F.prototype = o
return new F()
}
这会按照从左到右的顺序使用Object.gen参数填充userB自己的属性,紧随其后的是userB参数。它使用for(prop in o)循环,因此根据ECMA标准,属性枚举的顺序不能保证与属性定义的顺序相同。然而,通过在使用hasOwnProperty过滤器的情况下进行测试,甚至有时即使没有使用该过滤器,几个测试过的主流浏览器的代码示例显示它们是相同的。
MY_GLOBAL = {i: 1, nextId: function(){return this.i++}};
var userB = {
name: null,
id: null,
sayHello: function() {
console.log('Hello '+ this.name);
}
}
var bob = Object.gen(userB, 'Bob', MY_GLOBAL.nextId());
相较于Object.build方法,我认为这种方法更简单,因为userB不需要init方法。同时,userB不是特别的构造函数,它看起来像一个普通的单例对象。因此,使用这种方法你可以从普通的纯对象中构建和初始化对象。
Object.create
来获得与new UserA('bob')
相同的单步功能。 - Rick Jollynew
从未得到广泛采纳。 - Andy