Skip to content

Instantly share code, notes, and snippets.

@skrat
Forked from jankuca/injector.js
Created August 31, 2012 11:17
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save skrat/3551592 to your computer and use it in GitHub Desktop.
Save skrat/3551592 to your computer and use it in GitHub Desktop.
Injector.js
/**
* @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