Our Global Presence
Canada
57 Sherway St,
Stoney Creek, ON
L8J 0J3
India
606, Suvas Scala,
S P Ring Road, Nikol,
Ahmedabad 380049
USA
1131 Baycrest Drive,
Wesley Chapel,
FL 33544
Dependency Injection (DI), sometimes referred to as ‘Inversion of Control’, is when an object receives other objects or functions it depends on for part of its functionality. This can be achieved by passing an object through object instantiation with a constructor or with a property setting. This is very common in the world of statically typed languages like Java or C#. There are many popular frameworks built specifically for managing dependencies in the statically typed object-oriented world.
DI allows specific functionality to be loaded at runtime. One of the advantages of being able to change the functionality of an object at runtime is to provide greater flexibility and make our applications more loosely coupled. A very common use case is using mocking during testing. There are some great libraries in Node.js like Sinon that make mocking very easy, but we can accomplish the same task by using DI.
It is very common with testing to substitute code that communicates with a database or a network request with a mock or fake. This is because in a lot of CI/CD workflows the build or testing server may not have access to a database server or a network needed for the actual service. This is an excellent use case for DI to substitute an actual service with a mock or fake service.
There are many different reasons to use DI, but testing is one of the most common reasons.
We have a technique that We have used throughout the years for configuring DI in my applications whether they are statically typed or duct-typed like JavaScript that We like to call ‘Poor Mans Dependency Injection’. With this technique, We usually create default dependent objects if a required object is not passed in on object instantiation.
Lets’ say we have a cart object that needs to calculate a tax rate for a certain location. In a lot of e-commerce systems that kind of data has to be calculated based on the location of the user, with the sales tax being different for every location. We can create a factory function that creates a shopping cart with an injectable function for calculating the tax.
function createCart(settings) { const { taxrepository } = settings; let items = []; function addItemToCart(item) { items.push(item); } function removeItemFromCart(removeThisItem) { items = items.filter((item, index, arr) => { return item.sku !== removeThisItem.sku }); } function getSubTotal() { return items.map(item => item.price * item.quantity) .reduce((accum, item) => accum + item, 0); } function getTotal() { return taxrepository(getSubTotal()) + getSubTotal(); } function getTaxes() { return taxrepository(getSubTotal()); } return Object.freeze({ addItemToCart, removeItemFromCart, getSubTotal, getTotal, getTaxes }); }
If we look at the following example, we are creating an object with functions for adding items to the cart and calculating the totals and subtotals. We have a function that we can pass into our settings constructor object called taxrepository
. We will use this function to calculate our taxes.
Lets’ create a test function for calculating our taxes. We will make this a pure function without any side effects.
function calculateMyTax(subtotal) { return subtotal * 0.11; }
When we instantiate this object with our factory function, we can just pass it into our settings object;
const cart = createCart({ taxrepository: calculateMyTax }); myCart.addItemToCart({ sku: 'DEF456', price: 2.00, quantity: 2 }); myCart.addItemToCart({ sku: 'HIG789', price: 6.00, quantity: 1 }); myCart.addItemToCart({ sku: 'ABC123', price: 12.00, quantity: 1 });
We can now get the subtotal and calculate the taxes.
console.log(`subtotal: ${myCart.getSubTotal()}`); // subtotal: 22 console.log(`taxes: ${myCart.getTaxes()}`); // taxes: 2.42 console.log(`total: ${myCart.getTotal()}`); // total: 24.42
All of the objects that We define, We try to create defaults for whenever an injectable behavior is not included in the constructor. That way if someone is using my object without passing in the needed objects, it will either get an error or a default function if it is missing from the constructor. We can modify the factory function to use a default if no taxrepository
is passed in the settings object.
We also might want to have our factory function fail if the developer calling our function forgets to pass the taxrepository
into the constructor.
if (!settings.hasOwnProperty('taxrepository')) { throw Error(`This function requires a 'taxrepository' to be passed into the contructor!`) }
DI frameworks are extremely popular in the statically typed object-oriented world of Java and .NET development, but there are DI frameworks you can use for JavaScript. One of the frameworks is called di4js, and will work with either Node.js or plain old JavaScript in the browser. Here is an example from the di4js readme;
var Car = function (engine, year) { this.engine = engine; this.year = year; }; Car.prototype.start = function () { this.engine.start(); }; var DieselEngine = function () { this.hp = 0; }; DieselEngine.prototype.start = function () { console.log("Diesel engine with " + this.hp + " hp has been started..."); }; di .autowired(false) .register('dieselEngine') .as(DieselEngine) .withProperties() .prop('hp').val(42); .register('car') .as(Car) .withConstructor() .param().ref('dieselEngine') .param().val(1976); var car = di.resolve('car'); car.start(); // Diesel engine with 42 hp has been started...
This example is from the di4js Github repo
For more information and to develop your web app using front-end technology, Hire Front-End Developer from us as we give you a high-quality solution by utilizing all the latest tools and advanced technology. E-mail us any clock at – hello@hkinfosoft.com or Skype us: “hkinfosoft“.
To develop your custom website using JS, please visit our technology page.
Content Source:
57 Sherway St,
Stoney Creek, ON
L8J 0J3
606, Suvas Scala,
S P Ring Road, Nikol,
Ahmedabad 380049
1131 Baycrest Drive,
Wesley Chapel,
FL 33544
57 Sherway St,
Stoney Creek, ON
L8J 0J3
606, Suvas Scala,
S P Ring Road, Nikol,
Ahmedabad 380049
1131 Baycrest Drive,
Wesley Chapel,
FL 33544
© 2024 — HK Infosoft. All Rights Reserved.
© 2024 — HK Infosoft. All Rights Reserved.
T&C | Privacy Policy | Sitemap