Dependency Injection with Javascript


An Illustrated Guide
(in 10 minutes or less)


by Mike Geyser


Developer User Group

08 July 2014

Overview

  • Introduction
  • Components of a hand rolled injection
  • What makes it tick?
  • How angular does it

Dependency Injection

  • Easier to test/mock Easier to test/mocklame..
  • Isolate behaviour
  • Configure at runtime
  • Object creation responsibility

The rest are awesome!

In Javascript? Why?

  • It's become a 'real' language
  • Patterns solve problems
  • Rapidly growing adoption - Angular + RequireJs

Disclaimer:

The content of this talk is shamelessly ripped off of Angular.


No original thought was harmed in the making of this presentation.

Angular style injection



    var Controller = function(Greeter) {

        /*Greeter is 'constructor' injected*/
        Greeter.greet()
    };

					    

Container has three responsibilities


    var Dependency = {

        register: function(name, dependency){

		},

        resolve: function(name) {
	        
        },

        inject: function(target){

        }
    };
					    

Registration


    var Greeter = {
        greet: function(){
            Alert("Hello Developer User Group!");
        }
    };
                            
    Dependency.register("Greeter", Greeter);
					    

Inject by key, because JS has no 'interfaces'

Registration


    var Dependency = {
        dependencies: {}, // Simple object hash
        register: function(name, dependency){
            this.dependencies[name] = dependency;
        }
    };
					    

Resolution


    var greeter = Dependency.resolve("Greeter");
    greeter.Greet();
					    

Resolution


    var Dependency = {
        resolve: function(name){
            return this.dependencies[name];
		}
    };
					    

Easy.
But not what we're after..

Constructor Injection

(Where the real money is)


                                     
    var Controller = function(Greeter) {
        Greeter.greet()
    };
                                
    Dependency.inject(Controller);

					    

Magic strings

  • We want to deal in objects, but resolution is by key.
  • Simple string representation of the object.

    Controller.toString();

    /*
         "function (Greeter){
            Greeter.greet();
		 }"
    */					    

Magic strings

Relax.
Embrace it.
The feeling of discomfort will pass.

Magic strings

The incantation:


    var regex = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;

    var arguments = Controller.toString()
                              .match(regex)[1]
                              .split(',');

                        

Injection


    var Dependency = {
        inject: function(target){

            var regex = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
            var arguments = target.toString()
                                  .match(regex)[1]
                                  .split(',');
            var self = this;
            var dependencies = arguments.map(function(key){
                return self.resolve(key);
            });

            target.apply(target, dependencies);
        }
    };
                        

The whole picture


    var Dependency = {
        dependencies: {},
        register: function(name, dependency){
            this.dependencies[name] = dependency;
        },
        resolve: function(name){
            return this.dependencies[name];
		},
        inject: function(target){
            var regex = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
            var arguments = target.toString()
                                  .match(regex)[1]
                                  .split(',');
            var self = this;
            var dependencies = arguments.map(function(key){
                return self.resolve(key);
            });
            target.apply(target, dependencies);
        }
    };
                        

How Angular wires it up


    

    

Ng hides the injection behind Controller injection.

(Much like ASP.NET MVC)

Summary

  • Simple registration / resolution
  • Reflection and 'magic strings'
  • Spirit of the law (or pattern) vs. letter of the law



Questions?

@mikegeyser