This is the first step in an Dependency Injection Framework in Javascript:
Now updated to show passing on the registry.
This still needs work. It is OK for the Registry to be a global, but the resolution of an component should be scoped….Like I said, a first step.
#!/usr/bin/rhino var Registry = { factories : {}, instances : {}, register: function(name,factory){ this.factories[name] = factory; this.__defineGetter__(name, function() { if (!this.instances[name]){ this.instances[name] = this.factories[name](this); } return this.instances[name]; }); } } Registry.register("teststring",function(){ return "Injected"; }); Registry.register("testobj",function(registry){ var that = {}; that.string = registry.teststring; that.execute = function(){ print(that.string); } return that; }); Registry.testobj.execute();
Updated: This version would keep a separate instance variable per “request”
#!/usr/bin/rhino var Registry = { factories : {}, keys: [], register: function(name,factory){ this.factories[name] = factory; this.keys.push(name); }, define_getter: function(scope,key){ var facts = this.factories; scope.__defineGetter__(key, function() { var x = key; if (!scope.instances[x]){ scope.instances[x] = facts[x](scope); } return scope.instances[key]; }); }, request_scope: function(){ var scope = {}; scope.instances = {}; var facts = this.factories; for (var i = 0; i < this.keys.length; i +=1){ this.define_getter(scope,this.keys[i]); } return scope; } } Registry.register("teststring",function(scope){ return "Injected"; }); Registry.register("testobj",function(scope){ var that = {}; that.string = scope.teststring; that.execute = function(){ print("executing " + that.string); } return that; }); var scope = Registry.request_scope(); var test_string = scope.teststring; var test_obj = scope.testobj; test_obj.execute();
Interesting. Just getting into node.js for CQRS backed by NoSQL (RavenDB) and was wondering about DI and whether js really needed DI. Doubly so as a coding, Vietnam vet, ex-NH rock climber, and Peregrine monitor out here in Oregon.
I’d say that DI is a good approach for coding in general, and Javascript code would benefit from it. The general rule is “Separate construction from usage.” which really is just a good practice.
Been a while since I’ve been to Smith Rock.
Your codes are so elegant.
I have a question that why updated to the version which keep a separate instance variable per “request”. When do I need two scope like that:
var scope1 = Registry.request_scope();
// scope1 do something
var scope2 = Registry.request_scope();
// scope2 do something
Is there a project for this like “CppInject”?
Thanks.
Coordinate
You wouldn’t do that in the same function call. Instead, in each request, you create a separate instance of the request scope resolver *per* request. It is possible that two requests can come in simultaneously, and they should resolve instances to the appropriate responses, not get crossed.
I wrote similar code for C++ here.
http://adam.younglogic.com/2008/07/dependency-injection-in-c/
Code is on Git Hub, link at the bottom.
This is the Service Locator pattern, not Dependency Injection.
I’d argue that it implements the Dependency Locator in order to perform dependency injection. They are very related patterns.