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

推荐订阅源

量子位
云风的 BLOG
云风的 BLOG
小众软件
小众软件
IT之家
IT之家
T
Tailwind CSS Blog
WordPress大学
WordPress大学
S
SegmentFault 最新的问题
美团技术团队
博客园 - 叶小钗
V
V2EX
博客园 - Franky
大猫的无限游戏
大猫的无限游戏
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
阮一峰的网络日志
阮一峰的网络日志
博客园 - 【当耐特】
罗磊的独立博客
博客园_首页
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
爱范儿
爱范儿
宝玉的分享
宝玉的分享
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Jina AI
Jina AI
月光博客
月光博客
有赞技术团队
有赞技术团队

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.