惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

The GitHub Blog
The GitHub Blog
S
SegmentFault 最新的问题
MyScale Blog
MyScale Blog
有赞技术团队
有赞技术团队
V
Visual Studio Blog
T
The Blog of Author Tim Ferriss
爱范儿
爱范儿
Vercel News
Vercel News
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Y
Y Combinator Blog
Blog — PlanetScale
Blog — PlanetScale
D
DataBreaches.Net
美团技术团队
Microsoft Security Blog
Microsoft Security Blog
大猫的无限游戏
大猫的无限游戏
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
酷 壳 – CoolShell
酷 壳 – CoolShell
GbyAI
GbyAI
A
About on SuperTechFans
云风的 BLOG
云风的 BLOG
The Cloudflare Blog
宝玉的分享
宝玉的分享
V
V2EX
Microsoft Azure Blog
Microsoft Azure Blog

Yusuf Aytas

When Code Is Cheap, Does Quality Still Matter? Why Crouching Tiger, Hidden Dragon Is a Masterpiece Why We Ignore Advice The Mirror Is Part of the Machine When Too Many Maps Overlap on One Person The Work Runs on Different Maps Your Work Introduces You Trial By Fire The Dude Why Headcount Math Lies Capacity Is the Roadmap The Roadmap Is Not the System Torres del Paine W Trek Escaping Status Theater Incentives Drive Everything Scaling Culture Without Dilution What Good Looks Like Why Airport Security Feels Random Why Politics Appear How to Work with Me The Janus Protocol Multi-Horizon Delivery Framework What Good Execution Looks Like Managing Your Manager Why Kingdom of Heaven’s Director’s Cut Is Better AI Broke Interviews Most of What We Call Progress Managers Have Been Vibe Coding All Along Stop Wasting Brainpower Why Over-Engineering Happens
Dependency Injection in JavaScript
Yusuf Aytas · 2013-05-22 · via Yusuf Aytas

Published · 4 min read

Dependency injection is about removing the hard coded dependencies and providing way of changing dependencies in compile-time or run-time. This pattern has been exercised in several frameworks like Spring(Java). It is also becoming popular in JavaScript community. There are libraries that support dependency injection like Angular.js, Require.js, Inject.js and more. Following recent developments, we will present what is dependency injection, its advantages and simple implementation of this pattern in JavaScript. Dependency injection is to ask for instance of the classes you need and somebody(injector or factory) provides those instances to you in either compile-time or run-time. There are 3 types of dependency injection : setter, constructor and interface injection. For any of those injection types, one needs a container or injector which can provide dependencies we need. Containers or injectors provides those dependencies by using configuration, types and qualifiers. Now, let's have a look at the uml diagram below. In this diagram ItemController uses a logger to log its events and it may use one of those Logger implementations. Having configured which one to use, Injector injects instance of Logger to the ItemController.

Dependency injection class diagramDependency injection class diagram

Having presented dependency injection, let's observe why we need this. There can be two main reason to favor dependency injection : first is to improve maintainability of the code, second is to make it easy to test the code. Besides, writing code through an interface is always preferable in terms of abstraction and reusability. By having interfaces instead of implementation, one can change the implementation and remain the rest untouched. This provides you to replace actual implementation with the mock implementation for testing purposes. Furthermore, you can replace implementation of your interface whenever you want by just configuration. Now, let's see how we implement dependency injection in JavaScript.

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. To figure out, how we use above implementation, we give an example as follows.

var Logger = {
   log : function(log) {}
};
var SimpleLogger = function() {};
var FancyLogger = function(){};

SimpleLogger.prototype = Object.create(Logger);
FancyLogger.prototype = Object.create(Logger);

SimpleLogger.prototype.log = function(log){
   console.log(log);
}

FancyLogger.prototype.log = function(log){
   var now = new Date();
   console.log(now.toString("dd/MM/yyyy HH:mm:ss fff") + " : "+ log);
}

var ItemController = function(logger){
   this.logger = logger;
};
ItemController.prototype.add = function(item) {
   this.logger.log("Item\["+item.id+"\] is added!");
};
Injector.add("logger", new FancyLogger());
var itemController = Injector.get(ItemController);
itemController.add({id : 5});

Above, we have defined an interface(you can quickly look at how to define interfaces from here) as Logger and implemented Logger with FancyLogger and SimpleLogger. We added instance of FancyLogger to the Injector. After that, we tried to get instance of ItemController via get method of Injector. In this post, we have tried to give some insight about dependency injection; however, there is a lot left to talk like dependency graph. As this is an introduction for dependency injection concept, we did not go into much detail. You can read source code of angular.js or require.js to find out how there are doing the staff. Consequently, we have tried to explain what is dependency injection and advantages of it as well as implementation of a simple inversion of control container.