Implementing Object.create in the same manner as Tibos does appears to assign all the members of the input object to the prototype
of the resulting object.
// When running in firefox firebug
// on an empty page
var Definition = {
name : 'Test1'
};
// The location of this definition is irrelevant
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
[update]
From the code above, it's clear that using Object.create generates an object with all the properties from the first parameter within its prototype and the second parameter becomes its instance properties. (Answer provided by mccainz in the comments) An additional advantage (excluding older browsers like IE8) is the ability to set enumerable, writable, and configurable flags on instance properties, as well as creating getters and setters for assignment-like behavior (i.e., instance.someprop=22 can be achieved via instance.someprop(22)).
To define specific instance properties, different patterns can be employed. While these patterns may result in code looking "ugly" or even worse than utilizing the new keyword, personal preference plays a role here and doesn't negate the benefits of having control over properties (enumerable, writable, configurable).
One approach involves using the init function:
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");
A more complex pattern that offers greater control looks like this:
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
});
}
};
var u=userCreator.get({name:"Ben"});
u.talk();
u.name="Benji";
u.talk();
u.name=" ";//error, name can't be empty
Creating a new instance of Parent solely for setting inheritance of Child is unnecessary; Object.create can be utilized for this purpose or helper functions:
var Child =function(){
Parent.apply(this,arguments); //get Parent's INSTANCE members defined in the parent function body with this.parentInstance=...
}
Child.prototype=Object.create(Parent.prototype);
Child.prototype.constructor=Child;
Child.prototype.otherFn=function(){};
You might find this link helpful; it includes a helper function so you don't have to use Object.create if desired.