I am new at JavaScript. I wonder how dependency injection is being implemented in JavaScript? I searched the internet but couldn't find anything.
-
@qwertynl: As you can see from Yusufaytas' answer, the mechanics of how to auto-wire dependencies differs completely from doing this in .NET. With .NET you have to reflect over the type system and we inject types based on the type of the parameter. With Javascript you have to 'reflect' over the names of the arguments, since there are no (discoverable) types in javascript. – Steven Nov 19 '13 at 09:19
12 Answers
var Injector = {
dependencies: {},
add : function(qualifier, obj){
this.dependencies[qualifier] = obj;
},
get : function(func){
var obj = new func;
var dependencies = this.resolveDependencies(func);
func.apply(obj, dependencies);
return obj;
},
resolveDependencies : function(func) {
var args = this.getArguments(func);
var dependencies = [];
for ( var i = 0; i < args.length; i++) {
dependencies.push(this.dependencies[args[i]]);
}
return dependencies;
},
getArguments : function(func) {
//This regex is from require.js
var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
var args = func.toString().match(FN_ARGS)[1].split(',');
return args;
}
};
The first thing we need a configuration to provide necessary dependencies with qualifiers. To do that, we define a dependency set as dependencies in the Injector class. We use dependency set as our container which will take care of our object instances mapped to qualifiers. In order to add new instance with a qualifier to dependency set, we define an add method. Following that, we define get method to retrieve our instance. In this method, we first find the arguments array and then map those arguments to dependencies. After that, we just construct the object with our dependencies and return it. For more information and examples, please see the post on my blog.

- 39,603
- 20
- 94
- 123

- 1,231
- 13
- 20
-
6Up until now, it was a complete mystery to me how one would get the argument names of a function in javascript. Your answer is scary and cool at the same time :-) – Steven Nov 19 '13 at 09:21
-
Although this is great, the 'get' function is not creating the objects correctly. My objects are being created on the line containing 'var obj = new func' with no arguments passed to them. Pulling out that function into a jsFiddle (http://jsfiddle.net/JJf2M/2/) you can see that code will call the constructor twice. One time with no arguments and one time with arguments. This answer: http://stackoverflow.com/questions/3362471/how-can-i-call-a-javascript-constructor-using-call-or-apply has an alternative strategy and it appears to solve the problem – Bryan Johnson Feb 07 '14 at 16:50
-
Because I needed a simple dependency injection module for a couple of projects I decided to write a simple commonJS module: https://github.com/nerdbeere/simpledi – Julian Hollmann Mar 28 '15 at 12:35
-
2
-
3Most code these days is minified and obfuscated. Since this code is based on argument names, which are a target of minification, this code will not hold up on such post processing practices. – ptoinson Sep 07 '17 at 19:44
Let's learn it doing a super simple real world example :)
The example class I am going to talk about here is a Printer
which needs a driver
to print something. I have demonstrated the advantages of dependency injection design pattern in 4 steps to arrive at the best solution in the end.
Case 1: no dependency injection used:
class Printer {
constructor() {
this.lcd = '';
}
/* umm! Not so flexible! */
print(text) {
this.lcd = 'printing...';
console.log(`This printer prints ${text}!`);
}
}
// Usage:
var printer = new Printer();
printer.print('hello');
Usage is simple, it is easy to make a new printer this way but this printer is not flexible.
Case 2: abstract the functionalities inside the print
method into a new class called Driver
:
class Printer {
constructor() {
this.lcd = '';
this.driver = new Driver();
}
print(text) {
this.lcd = 'printing...';
this.driver.driverPrint(text);
}
}
class Driver {
driverPrint(text) {
console.log(`I will print the ${text}`);
}
}
// Usage:
var printer = new Printer();
printer.print('hello');
So our Printer
class is now more modular, clean and easy to understand but It is not flexible yet again. Any time you use new
keyword you are actually hard-coding something. In this case you are constructing a driver inside your Printer which in real world is an example of a printer that comes with a built-in driver that can never change!
Case 3: inject an already made driver into your printer
A better version is to inject a driver at the time we construct a printer
meaning you can make any type of printer, color or black & white, because this
time the driver is being made in isolation and outside the Printer
class and then
given (INJECTED!) into the Printer
…
class Printer {
constructor(driver) {
this.lcd = '';
this.driver = driver;
}
print(text) {
this.lcd = 'printing...';
this.driver.driverPrint(text);
}
}
class BWDriver {
driverPrint(text) {
console.log(`I will print the ${text} in Black and White.`);
}
}
class ColorDriver {
driverPrint(text) {
console.log(`I will print the ${text} in color.`);
}
}
// Usage:
var bwDriver = new BWDriver();
var printer = new Printer(bwDriver);
printer.print('hello'); // I will print the hello in Black and White.
Usage is now different, as a user, in order to have a printer you need to first
construct (make) a driver (of your choice!) and then pass this driver to your printer. It may seem that end user now needs to know a bit more about the system, however this structure gives them more flexibility. Users can pass ANY driver as long as valid! for example let's say we have a BWDriver
(black & white) type of driver; user can create a new driver of this type and use that to make a new printer that prints black and white.
So far so good! But what you think we can do better and what you think has still some room to address here?! I am sure you can see it too!
We are creating a new printer each time we need our printer to print with
a different driver! That is because we are passing our driver of choice to
the Printer
class at the construction time; if user wants to use another driver they need to create a new Printer with that driver. For example, if now I want to do a color print I need to do:
var cDriver = new ColorDriver();
var printer = new Printer(cDriver); // Yes! This line here is the problem!
printer.print('hello'); // I will print the hello in color.
Case 4: provide a setter function to set the driver of your printer at ANY TIME!
class Printer {
constructor() {
this.lcd = '';
}
setDriver(driver) {
this.driver = driver;
}
print(text) {
this.lcd = 'printing...';
this.driver.driverPrint(text);
}
}
class BWDriver {
driverPrint(text) {
console.log(`I will print the ${text} in Black and White.`);
}
}
class ColorDriver {
driverPrint(text) {
console.log(`I will print the ${text} in color.`);
}
}
// Usage:
var bwDriver = new BWDriver();
var cDriver = new ColorDriver();
var printer = new Printer(); // I am happy to see this line only ONCE!
printer.setDriver(bwDriver);
printer.print('hello'); // I will print the hello in Black and White.
printer.setDriver(cDriver);
printer.print('hello'); // I will print the hello in color.
Dependency Injection is not a really difficult concept to understand. The term may be a bit overloaded but once you have realised its purpose you will find yourself using it most of the time.

- 3,755
- 2
- 14
- 11
-
2You should not use the `code markup` for regular text, this decreases readability. – t.niese Sep 17 '18 at 08:16
-
2
-
4
-
2This answer should be injected as constructor dependency in a `class` called Life :-) – Arjit Sharma Mar 22 '21 at 12:32
-
3one of the best explanations I've ever seen on this subject, thanks. – Vinicius Aquino Jun 24 '21 at 18:08
-
Regarding `Case 3` where we **inject** into the `constructor`. How this different from just saying that we are passing **arguments** into the **constructor**? Is it the simple fact that it's a `class` that makes it **dependency injection?** It's significant because we can create a single **instance** of a **class** and share that same **instance** via **dependency injection**? – CodeFinity Jul 19 '21 at 19:51
-
"One object depends on another object, but the second object does not depend on the first one." - [Maciek Przybylski](https://medium.com/@maciekprzybylski/dependency-injection-in-javascript-74f8791ba7c8) That might be part of the answer I am looking for. – CodeFinity Jul 19 '21 at 19:53
-
1_what_ we are doing in **Case3** is, as you also pointed out, passing an argument into our class but you should know that we are passing an argument into our class as a means to implement the **DI concept**. So it is not right to say that passing an argument into a class (simply because it was a class) is called DI. _passing that driver argument into your class_ implements the **DI concept** because: that driver argument is a piece of logic that we are bringing into our class from somewhere else as an implementation that has been done outside our class. – Nesa Mouzehkesh Jul 20 '21 at 03:36
-
1That piece of logic that your class is now using is decoupled and abstracted from it and then passed to it. **THIS** is why you call it DI. We then compose and build a Printer logic with that driver. This will also help during testing since you can pass a mock version of your driver to your printer. – Nesa Mouzehkesh Jul 20 '21 at 03:36
You can use AngularJS as an example. Whether it is a good thing, you have to decide for yourself. I wrote a week ago an article about demistifying dependency injection in AngularJS. Here you can read the code from the article:
// The following simplified code is partly taken from the AngularJS source code:
// https://github.com/angular/angular.js/blob/master/src/auto/injector.js#L63
function inject(fn, variablesToInject) {
var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
var FN_ARG_SPLIT = /,/;
var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
if (typeof fn === 'function' && fn.length) {
var fnText = fn.toString(); // getting the source code of the function
fnText = fnText.replace(STRIP_COMMENTS, ''); // stripping comments like function(/*string*/ a) {}
var matches = fnText.match(FN_ARGS); // finding arguments
var argNames = matches[1].split(FN_ARG_SPLIT); // finding each argument name
var newArgs = [];
for (var i = 0, l = argNames.length; i < l; i++) {
var argName = argNames[i].trim();
if (!variablesToInject.hasOwnProperty(argName)) {
// the argument cannot be injected
throw new Error("Unknown argument: '" + argName + "'. This cannot be injected.");
}
newArgs.push(variablesToInject[argName]);
}
fn.apply(window, newArgs);
}
}
function sum(x, y) {
console.log(x + y);
}
inject(sum, {
x: 5,
y: 6
}); // should print 11
inject(sum, {
x: 13,
y: 45
}); // should print 58
inject(sum, {
x: 33,
z: 1 // we are missing 'y'
}); // should throw an error: Unknown argument: 'y'. This cannot be injected.

- 233
- 4
- 9
For me yusufaytas answer was exactly what I needed! The only missing features were:
- Getting a dependency with custom parameters.
- Registering dependencies using callbacks.
I wanted to have the ability to do something like this:
Injector.register('someDependency', function () {
return new ConcreteDependency();
});
function SomeViewModel(userId, someDependency) {
this.userId = userId;
this.someDependency = someDependency;
}
var myVm = Injector.get(SomeViewModel, { "userId": "1234" });
So I ended up with the following code:
var Injector = {
factories = {},
singletons = {},
register: function (key, factory) {
this.factories[key] = factory;
},
registerSingle: function (key, instance) {
this.singletons[key] = instance;
},
get: function (CTor, params) {
var dependencies = this.resolveDependencies(CTor, params);
// a workaround to allow calling a constructor through .apply
// see https://stackoverflow.com/questions/1606797/use-of-apply-with-new-operator-is-this-possible
function MiddlemanCTor() {
CTor.apply(this, dependencies);
}
MiddlemanCTor.prototype = CTor.prototype;
return new MiddlemanCTor();
},
resolveDependencies: function(CTor, params) {
params = params || {};
var args = this.getArguments(CTor);
var dependencies = [];
for (var i = 0; i < args.length; i++) {
var paramName = args[i];
var factory = this.factories[paramName];
// resolve dependency using:
// 1. parameters supplied by caller
// 2. registered factories
// 3. registered singletons
var dependency = params[paramName] ||
(typeof factory === "function" ? factory() : undefined) ||
this.singletons[paramName];
dependencies.push(dependency);
}
return dependencies;
}
getArguments: func(func) {
// Regex from require.js
var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
var args = func.toString().match(FN_ARGS)[1].split(',').map(function (str) {
return str.trim();
});
return args;
}
};
Update - 21.5.2018
I've been using this solution for a few years now. As I moved my code base to TypeScript the solution evolved with it to support both TypeScript and JavaScript. After quite a while that the code was running in production I recently (two days ago) published a library based on this solution. Feel free to check it out, open issues, etc.

- 482
- 9
- 10
Take a loot at Flyspeck: https://gist.github.com/elfet/11349215
var c = new Flyspeck();
c.set('name', 'GistHub');
c.set('config', {
server: 'https://gist.github.com'
});
c.set('user', function (c) {
return new User(c.get('name'));
});
c.extend('user', function (user, c) {
return new ProxyUser(user);
});
c.set('app', function (c) {
return new Application(c.get('config'), c.get('user'));
});
var app = c.get('app');

- 339
- 3
- 14
I'd say DI is an out-of-the-box feature of JS/ES2015. :-) Of course, it is not full featured IOC containers but looks useful, doesn't it? Check out an example below!
const one = () => 1;
const two = ({one}) => one + one;
const three = ({one, two}) => one + two;
// IOC container
const decimalNumbers = {
get one() { return one(this); },
get two() { return two(this); },
get three() { return three(this); }
};
const binaryTwo = ({one}) => one + 9;
// child IOC container
const binaryNumbers = Object.create(decimalNumbers, {
two: { get() { return binaryTwo(this); } }
});
console.log(`${decimalNumbers.three} is ${binaryNumbers.three} in binary`);
You can wrap dependencies in _.once
(see underscore or lodash) to turn them into singletons.
const rand = function() {
return (min, max) => min + Math.random() * (max - min) | 0;
};
const pair = function({rand} = this) {
return [rand(10, 100), rand(100, 1000)];
};
// IOC container
const ioc = Object.create({}, {
rand: {get: rand},
pair: {get: _.once(pair)} // singleton
});
console.log(`${[ioc.pair, ioc.pair === ioc.pair]}`);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>

- 3,619
- 1
- 22
- 35
I coded my own JavaScript Dependency Injection Framework called Di-Ninja https://github.com/di-ninja/di-ninja
It's full featured and is currently the only one in javascript, as I know, that implement Composition-Root design pattern, helping you to keep all things decoupled and to wire application components and config at one unique root place. http://blog.ploeh.dk/2011/07/28/CompositionRoot/
It work well with NodeJS and Webpack
Any feedback would be appreciated

- 2,179
- 2
- 21
- 25
-
Correct me if I am wrong but saying that a di container implements composition-root design pattern does not make sense to me. The way you use a di container makes you use or not use the composition root design pattern. – liaguridio Aug 22 '20 at 12:37
-
It's implementing composition root as a config, and this approach allow you to flatten your implementations specifications. It's not just a container, it's a dependencies resolution framework, acting from top to down level, take a look deeper at doc and you'll see the difference with others DiC and how it's dealing with composition root in the most friendly way. Check: https://github.com/di-ninja/di-ninja#3-dependencies-resolution – DevTheJo Aug 22 '20 at 13:10
candiJS is a lightweight implicit dependency injection and object creation library. Have a look
Example:
candi.provider.singleton('ajax', function() {
return {
get: function() { /* some code */ },
put: function() { /* some code */ }
};
});
candi.provider.singleton('carService', function(ajax) {
return {
getSpecs: function(manufacturer, year, model, trim) {
return ajax.get();
}
};
});
var Car = candi.provider.instance('Car', function(carService, year, manufacturer, model, trim) {
this.year = year;
this.manufacturer = manufacturer;
this.model = model;
this.trim = trim;
this.specs = carService.getSpecs(manufacturer, year, model, trim);
});
var car = new Car(2009, 'honda', 'accord', 'lx');

- 6,698
- 20
- 88
- 155
Injecting is a lightweight yet powerful DI container, it can well handle promise injection.
Source Code only 100+ lines.
Test Cases to see its examples.

- 367
- 2
- 4
bubble-di is a lightweight DI container for Javascript and Typescript.
It enables you to register factory methods (callbacks) or instances. Below is a simple example (more examples).
npm install --save bubble-di
var {DiContainer} = require("bubble-di");
// import { DiContainer } from "bubble-di";
DiContainer.setContainer(new DiContainer());
class Bar { sayBar(){ console.log("bar"); } }
class Baz { sayBaz(){ console.log("baz"); } }
class Foo {
constructor (bar, baz)
{
bar.sayBar();
baz.sayBaz();
// ...
}
};
DiContainer.getContainer().registerInstance("bar", new Bar());
DiContainer.getContainer().registerInstance("baz", new Baz());
DiContainer.getContainer().register("foo", {
dependencies: ["bar", "baz"],
factoryMethod: (bar, baz) => new Foo(bar, baz) },
);
const foo = DiContainer.getContainer().resolve("foo"); // will print "bar" and "baz".

- 21
- 4
I am new at JavaScript. I wonder how dependency injection is being implemented in JavaScript? I searched the internet but couldn't find anything.
To be completely honest after working with JavaScript (mainly on the server side) and the whole ecosystem for a few years, I get the feeling that dependency injection (not to mention containers) hasn't really made it into a regular JS programmer's toolbox. That's probably the reason why there's not much information about it out there (it's getting better though).
As opposed to a language such as Java, you cannot rely on static types in JavaScript. This fact alone rules out the traditional way of declaring dependencies via interfaces. You can of course add types to JS (see Flow) but these get elided before the code gets executed. The same applies for TypeScript but I believe there's a way to preserve the types as non enforced metadata. Further, JavaScript doesn't support annotations (although there's a proposal for it).
People have been getting around the limitations in various ways. Some containers parse the function/class definition (as in they call .toString()
on the passed function/class and parse the resulting string) and look for dependencies based on the names, some require functions/classes to provide a property/static method to get the list of dependencies.
I've been working myself on a container called Ashley, which simply asks for the dependencies as part of the binding process. No further inspection required.
container.instance('Client', Client, ['DependencyA', 'DependencyB']);
container.instance('DependencyA', DependencyA, ['DependencyC']);
container.instance('DependencyB', DependencyB, ['DependencyC']);
container.instance('DependencyC', DependencyC, [], {
scope: 'Prototype', // Defaults to Singleton
initialize: true,
deinitialize: true
});
const client = await container.resolve('Client');
More examples on GitHub.

- 14,296
- 2
- 41
- 52
Even though this is an old question I feel the urge. ;)
//dependency injection
class Thing1 {
constructor(aThing){
this.otherThing = aThing;
}
}
class Thing2 {}
const thing = new Thing1(new Thing2())
//dependency inversion
class Thing1 {
constructor({
read = null
} = {}){
if(typeof read !== 'function'){
//establish a simple contract
throw new TypeError(read + ' is not a function.');
}
this._read = read;
//Somewhere an instance of Thing1()
//will call this._read()
}
}
class Thing2 {
read(){
//read something
}
}
const thing2 = new Thing2();
const thing1 = new Thing1({
read(){
//Here is the equivalent to the so called "interface"
return thing2.read();
}
});

- 2,744
- 1
- 20
- 33