使用 Tibos 的方式使用 Object.create 看起来它会将传入对象的所有成员放入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 和 setter 或拥有额外控制(可枚举、可写和可配置的)。
一种模式是使用 init 函数:
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
不需要创建 Parent 的新实例来设置 Child 的继承,您可以将 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(){};
您可能会觉得这很有趣,它有一个辅助函数,因此如果您不想使用,则不需要使用 Object.create。