Nowadays, every framework is being modularized, even front-end javascript is no exception. Each module is responsible for certain functions, and there are interdependencies between modules. So the question arises: How to implement dependency injection in JavaScript? (Javascript dependency injection, all major frameworks have corresponding implementations, here we only learn the implementation ideas)
The following requirements:
Assume that there is already a defined service module Key-Value collection, func is the new service added, and the parameter list for service dependencies.
var services = { abc : 123, def : 456, ghi : 789 }; // Assume that some Service has been defined
function Service(abc, ghi){ this.write = function(){ console.log(abc); console.log(ghi); } } function Activitor(func){ var obj; // 实现 return obj; }
Solution:
Through some mechanism (reflection?), take out The parameter list defined by the func is assigned values one by one. Then instantiate the func through some mechanism (Activitor?).
Solution:
1. Get the parameter list of func:
How to get the parameter list? The first thing that comes to my mind is the reflection mechanism. So is there reflection in javascript? There should be. Currently, I only know how to use the eval(str) function, but it seems that there is no relevant implementation for obtaining the parameter list. Looking at the func.arguments definition again, this property is only valid when func is called and parameters are passed, and it cannot meet the requirements.
Can we get the parameter list by processing the string after func.toString()?
Let’s try it out:
function getFuncParams(func) { var matches = func.toString().match(/^function\s*[^\(]*\(\s*([^\)]*)\)/m); if (matches && matches.length > 1) return matches[1].replace(/\s*/, '').split(','); return []; };
Now you get the func parameter list array.
2. Find dependencies based on the parameter list:
After getting the parameter list, that is, getting the dependency list, it is very simple to pass in the dependencies as parameters.
var params = getFuncParams(func); for (var i in params) { params[i] = services[params[i]]; }
3. Pass dependency parameters and instantiate:
We know that there is func.constructor in javascript with call(thisArg,[arg[,arg,[arg,[…]]]]) and apply( ThisArg, args...) both functions can implement the instantiation func operation. The first parameter of the call function is this pointer, and the rest is the parameter list. This is suitable for use when the func parameter list is known, but does not meet my needs. Looking at the second apply function, the first parameter is also this pointer, and the second parameter is the parameter array. When it is called, it will automatically assign values to the parameter list of func one by one, which just meets my needs.
The code is roughly as follows:
function Activitor(func){ var obj = {}; func.apply(obj, params); return obj; }
Now we can create an instance of the func and pass the parameters required by the func.
4. Print and test it:
Full code:
var // 假设已定义好某些Service services = { abc: 123, def: 456, ghi: 789 }, // 获取func的参数列表(依赖列表) getFuncParams = function (func) { var matches = func.toString().match(/^function\s*[^\(]*\(\s*([^\)]*)\)/m); if (matches && matches.length > 1) return matches[1].replace(/\s+/, '').split(','); return []; }, // 根据参数列表(依赖列表)填充参数(依赖项) setFuncParams = function (params) { for (var i in params) { params[i] = services[params[i]]; } return params; }; // 激活器 function Activitor(func) { var obj = {}; func.apply(obj, setFuncParams(getFuncParams(func))); return obj; } // 定义新Service function Service(abc, ghi) { this.write = function () { console.log(abc); console.log(ghi); } } // 实例化Service并调用方法 var service = Activitor(Service); service.write();
The console prints successfully!