Setting the Prototype Constructor in JavaScript
While writing the upcoming Part 2 of my Pluralsight course Building Apps with Angular and Breeze, I found myself wanting to extend a constructor object with another constructor’s members. I had an object called AbstractRepository
that has a set of functions (ex: getAll
, queryFailed
) that could be shared by many repositories. I had a LookupRepository
with its own functions that are very specific to getting “lookups”. The way I settled on was to extend the AbstractRepository
’s functions onto the LookupRepository
by setting the prototype’s constructor. The result is that the LookupRepository
gets all the functions that it has plus the AbstractRepository
’s functions too.
This technique is something Ward Bell and hashed out together during one of our code pairing sessions. It's great what you can achieve when you work together! We adapted this from some ideas from this answer in StackOverflow.
First I create the constructor function for the LookupRepository
.
// LookupRepository function Ctor(mgr) { this.repoName = 'repository.lookup'; this.entityName = 'lookups'; this.manager = mgr; // Exposed data access functions this.getAll = getAll; this.setLookups = setLookups; } AbstractRepository.extend(Ctor); return Ctor;
The AbstractRepository
was injected into LookupRepository
(using Angular’s dependency injection). Notice I extend it by calling a method on the AbstractRepository
and passing in the constructor function for the LookupRepository
.
AbstractRepository.extend(Ctor);
The AbstractRepository
’s extend function set’s the prototype for the LookupRepository
to the AbstractRepository
’s constructor function. This extends the AbstractRepository
’s functions to the LookupRepository
. Then we make sure the LookupRepository
gets back its constructor function. So now the LookupRepository
will have the functions from both repositories.
// AbstractRepository function Ctor() { } Ctor.extend = function (repoCtor) { // Allow this repo to have access to // the Abstract Repo's functions, // then put its own Ctor back on itself. repoCtor.prototype = new Ctor(); repoCtor.prototype.constructor = repoCtor; };
The AbstractRepository
’s function are now accessible from the LookupRepository
. So if the AbstractRepository
has some generic functions like _getAllLocal
which may get all of the data for a given resource, then LookupRepository
can use it.
// AbstractRepository Ctor.prototype._getAllLocal = _getAllLocal; Ctor.prototype._queryFailed = _queryFailed;
This adds value when you have a set of repositories such as LookupRepository
, SessionRepository, SpeakerRepository, AttendeeRepository, and so on where they all can re-use the common functions from AbstractRepository
.
I don’t need this technique often, but it does come in handy.