使用的Object.create方式Tibos不会看起来像它会把传入的对象的所有成员返回的对象的prototype
。
// in firefox firebug running
// an empty page
var Definition = {
name : 'Test1'
};
//doesn't matter where it's defined
Definition.greet=function() {
console.log(this);//<-what is this in Chrome?
};
Definition.arr=[];
// instance of Test1
var test1 = Object.create(Definition);
var test2 = Object.create(Definition);
console.log(test1.greet===test2.greet);//true
delete test2.greet
delete test2.greet
delete test2.greet
delete test2.greet//can't delete it
test2.greet();
console.log(test1.greet===test2.greet);//true
console.log(test1.arr===test2.arr);//true
test1.arr.push(1);
console.log(test2.arr);//=[1]
var things=[];
for(thing in test1){
things.push(thing);
}
console.log("all things in test1:",things);
things=[];
for(thing in test1){
if(test1.hasOwnProperty(thing)){
things.push(thing);
}
}
console.log("instance things in test1:",things);//nothing, no instance variables
[更新]
正如我们从上面的代码看到的Object.create返回具有第一参数的所有成员在其上的原型和第二参数,因为它是实例成员的对象。 (在mccainz的评论中有很长一段时间的回答)增加好处(忽略IE8和多年未更新的浏览器)是可以指定实例成员的枚举,可写和可配置,并且可以创建getter和setter像分配一样工作(instance.someprop = 22实际上可以是instance.someprop(22))。
要指定特定于实例的成员,可以使用多种模式。参数是,当使用这些模式时,你的代码看起来就像使用new关键字一样“丑陋”,甚至更糟糕,但这将是一种个人喜好,并且不会从创建getter和setters或具有额外控制中获益(可枚举,可写和可配置的)。
一个模式将被使用的初始化函数:
var userB = {
init: function(nameParam) {
this.id = MY_GLOBAL.nextId();
this.name = nameParam;
},
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var bob = Object.create(userB).init("Bob");
一个更复杂的一个需要额外控制的优点是这样的:
var Person={
talk:function(){console.log("I'm "+this.name);}
//,other prototype stuff related to Person
};
var userCreator={
processInstanceMembers:function(o,initObj){
this.createName(o,initObj.name);
Object.defineProperty(o,"_name",{writable:true});
o.name=initObj.name;
},
get:function(initObj,inheritFrom){
var ret=Object.create(inheritFrom||Person);
this.processInstanceMembers(ret,initObj);
return ret;
},
createName:function(o){//minimalise closure scope
Object.defineProperty(o,"name",{
get:function(){
return this._name;
},
set:function(val){
if(val.replace(/\s*/gm,"")===""){
throw new Error("Name can't be empty, or only whitespaces");
}
this._name=val;
},
enumerable : true
});
}
};
//when creating an instance you can choose what to inherit from
//leave it out to inherit from Person
var u=userCreator.get({name:"Ben"});
u.talk();
u.name="Benji";
u.talk();
u.name=" ";//error, name can't be empty
创建父的新实例来设置的继承孩子是不需要的,你可以使用Object.create这个或帮助函数:
var Child =function(){
//get Parent's INSTANCE members defined in the
//parent function body with this.parentInstance=...
Parent.apply(this,arguments);
}
Child.prototype=Object.create(Parent.prototype);
Child.prototype.constructor=Child;
Child.prototype.otherFn=function(){};
你可能会发现this有趣,它有一个辅助函数,所以如果你不想使用Object.create,你不需要使用Object.create。
请参阅http://stackoverflow.com/questions/2709612/using-object-create-instead-of-new – mccainz
从技术上讲,测试不是一个对象,因为您从null继承。 JavaScript中的对象预计具有hasOwnProperty,但测试不会。如果其他人使用你的代码,他们可能期望测试是一个JS对象。也许像这样创建它:'test = Object.create(Object.prototype);' – HMR