-
-
Save skrat/3551592 to your computer and use it in GitHub Desktop.
Injector.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @constructor | |
*/ | |
function Injector() { | |
/** | |
* @type {!Object.<string, function(Injector=): !Object>} | |
*/ | |
this.factories = {}; | |
/** | |
* @type {!Object.<string, !Object>} | |
*/ | |
this.services = { | |
'$injector': this | |
}; | |
/** | |
* @type {Number} | |
*/ | |
this.idcount = 0; | |
} | |
/** | |
* Adds a service factory. | |
* @param {string|Function} key A service key. | |
* @param {function(Injector=): !Object} factory A service factory. | |
*/ | |
Injector.prototype.addService = function(key, factory) { | |
var nkey = this.normalize(key); | |
if (!factory) { | |
factory = function() { | |
return this.create(key); | |
}.bind(this); | |
} | |
this.factories[nkey] = factory; | |
}; | |
/** | |
* Returns a service by its key. | |
* @param {string|Function} key The key of the service to get. | |
* @return {!Object} The service. | |
*/ | |
Injector.prototype.getService = function(key) { | |
var nkey = this.normalize(key); | |
var service = this.services[nkey]; | |
if (!service) { | |
if (!(nkey in this.factories)) | |
throw "uknown service: " + (key.name || key); | |
service = this.factories[nkey](); | |
this.services[nkey] = service; | |
} | |
return service; | |
}; | |
/** | |
* Instantiates the given constructor providing it with its dependencies. | |
* @param {Function} Constructor The constructor function to use. | |
* @return {!Object} An instance of the constructor. | |
*/ | |
Injector.prototype.create = function(Constructor) { | |
var Dependant = function() {}; | |
Dependant.prototype = Constructor.prototype; | |
var instance = new Dependant(); | |
this.inject(Constructor, instance); | |
return instance; | |
}; | |
/** | |
* Injects dependencies to a constructor in the context of the given instance. | |
* @param {Function} Constructor The constructor function to use. | |
* @param {!Object} instance The instance to use. | |
*/ | |
Injector.prototype.inject = function(Constructor, instance) { | |
var keys = Constructor.prototype.$deps || []; | |
var deps = keys.map(this.getService, this); | |
Constructor.apply(instance, deps); | |
}; | |
Injector.prototype.normalize = function(key) { | |
if (typeof key === 'function') { | |
if (!key.__injectorId) | |
key.__injectorId = ++this.idcount; | |
return key.__injectorId; | |
} | |
return key; | |
}; | |
// --- define it | |
function Renderer(backend) { | |
console.log('@Renderer ctor - ' + backend.draw()); | |
} | |
Renderer.prototype.$deps = [Backend]; | |
function Backend(ponny) { | |
console.log('@Backend ctor - ' + ponny.speak()); | |
} | |
Backend.prototype.$deps = [Ponny]; | |
Backend.prototype.draw = function() { | |
return "drawn"; | |
}; | |
function Ponny(no) { | |
console.log('@Ponny ctor - ' + no); | |
} | |
Ponny.prototype.speak = function() { | |
return "moooo..."; | |
}; | |
// --- configure it | |
var injector = new Injector(); | |
injector.addService(Backend); | |
injector.addService(Ponny, function() { | |
return new Ponny(123); | |
}); | |
// -- run it | |
var renderer = injector.create(Renderer); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment