Since Base
is a constructor function, if you want a single object that uses Base.prototype
as its base, as Brian Peacock points out below you can just use the constructor:
var concrete2 = new Base();
concrete2.notify(); // Works
If you want to add further features to the concrete2
instance, you can do that directly:
concrete2.doSomethingElse = function() { /* ... */ };
That works because you already have a constructor function, so the simplest way to create a single object backed by that constructor's prototype is to use the new
operator.
Sometimes, though, you want to use an object when either it's not associated with a constructor function, or you have a reason for not wanting to call that constructor function. In those situations (I'll give an example of one below), you can use Object.create
, which is in ES5 and which can be partially shimmed in older browsers:
// Creates an object backed by Base.prototype without calling Base
var concrete2 = Object.create(Base.prototype);
concrete2.notify(); // Works
Object.create
creates a new object directly, setting its prototype to the object you pass into it. The single-argument version of it can be shimmed on older browsers, which is also useful for knowing what it does:
if (!Object.create) {
Object.create = function(proto, props) {
if (typeof props !== "undefined") {
throw "The two-argument version of Object.create cannot be shimmed.";
}
function ctor() { }
ctor.prototype = proto;
return new ctor();
};
}
One use of this is exemplified by flagging up an issue with some of the other code in the question, which uses a common, but not ideal, means of setting up inheritance between Concrete1
and Base
. This is the problematic line:
Concrete1.prototype = new Base(); // Not ideal
The issue is: What if Base
does something that should only be instance-specific? For instance, suppose it accepts instance-specific arguments? (Which is one, but only one, way Base
could have instance-specific code in it.) Calling Base
is almost never the correct way to set up the prototype for a "subclass" of it. Instead, you use Object.create
:
Concrete1.prototype = Object.create(Base.prototype); // Better
...usually followed by:
Concrete1.prototype.constructor = Concrete1;
...just because that's how the spec defines the prototype property of function instances (it says constructor
will be the function, but then never actually uses constructor
for anything).
Then you call Base
from the Concrete1
function when its creating an actual instance:
function Concrete1(any, necessary, args) {
Base.call(this, any, necessary); // For example
this.args = args; // For example
}
Complete example:
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
Person.prototype.getFullName = function() {
return this.firstName + " " + this.lastName;
};
/* ...further Person-specific functions put on Person.prototype here...*/
function Employee(firstName, lastName, jobTitle) {
Person.call(this, firstName, lastName);
this.jobTitle = jobTitle;
}
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
/* ...Employee-specific functions put on Employee.prototype here...*/
function Manager(firstName, lastName, jobTitle) {
Employee.call(this, firstName, lastName);
this.jobTitle = jobTitle;
}
Manager.prototype = Object.create(Employee.prototype);
Manager.prototype.constructor = Manager;
/* ...Manager-specific functions put on Manager.prototype here...*/
...and so on. (Or use a helper script like my Lineage
script, which also helps with supercalls and simplifies things a fair bit.)