Nowadays, all frameworks are modular, and even front-end javascript is no exception. Each module is responsible for certain functions, and there is interdependence between modules. So the question is: How to implement dependency injection in javascript? (Javascript's dependency injection, major frameworks have corresponding implementations, only implementation ideas are learned here)
The following requirements:
Assume that there is already a defined service module Key-Value collection, func is the added new service, and the parameter list is the service dependency.
The code copy is as follows:
var services = { abc : 123, def : 456, ghi : 789 }; // Assume that some services are defined
function Service(abc, ghi){
this.write = function(){
console.log(abc);
console.log(ghi);
}
}
function Activitor(func){
var obj;
// accomplish
return obj;
}
Solution:
Through some mechanism (reflection?), take out the parameter list defined by the func and assign values one by one. Then, through some mechanism (Activitor?), the func is instantiated.
Solution:
1. Get the parameter list of func:
How to get the parameter list? The first thing that comes to mind is the reflection mechanism. So is there any reflection in JavaScript? It should be there. I only know how to use the eval(str) function at the moment, but it seems that there is no relevant implementation for obtaining the parameter list. Let’s look at the func.arguments definition. This property is only valid when calling func and passing parameters, and cannot meet the needs.
So can we get the parameter list by processing the string after func.toString()?
Let's try it:
The code copy is as follows:
function getFuncParams(func) {
var matches = func.toString().match(/^function/s*[^/(]*/(/s*([^/)]*)/)/m);
if (matches && matches.length > 1)
return matches[1].replace(//s*/, '').split(',');
return [];
};
Here we get the func parameter list array.
2. Find dependencies based on the parameter list:
After getting the parameter list, that is, the dependency list is obtained. It is very simple to pass the dependency into it as a parameter.
The code copy is as follows:
var params = getFuncParams(func);
for (var i in params) {
params[i] = services[params[i]];
}
3. Pass the dependency parameters and instantiate them:
We know that JavaScript has func.constructor, which has two functions: call(thisArg,[arg[,arg,[arg,[…]]]]) and apply(thisArg,args…) and can implement instantiation func operations. The first parameter of the call function is this pointer, and the rest is a parameter list. This is suitable for use when a func parameter list is known and cannot meet my needs. Let’s look at the second apply function. The first parameter is also this pointer, and the second parameter is a parameter array. When called, it will automatically assign values to the func parameter list one by one, which just meets my needs.
The code is roughly as follows:
The code copy is as follows:
function Activitor(func){
var obj = {};
func.apply(obj, params);
return obj;
}
At this point, we can create an instance of this func and pass the parameters required by this func.
4. Print and test it:
Complete code:
The code copy is as follows:
var
// Assume that some Services are defined
services = { abc: 123, def: 456, ghi: 789 },
// Get the parameter list of func (dependency list)
getFuncParams = function (func) {
var matches = func.toString().match(/^function/s*[^/(]*/(/s*([^/)]*)/)/m);
if (matches && matches.length > 1)
return matches[1].replace(//s+/, '').split(',');
return [];
},
//Fill parameters (dependencies) according to parameter list (dependencies)
setFuncParams = function (params) {
for (var i in params) {
params[i] = services[params[i]];
}
return params;
};
// Activator
function Activitor(func) {
var obj = {};
func.apply(obj, setFuncParams(getFuncParams(func)));
return obj;
}
// Define a new service
function Service(abc, ghi) {
this.write = function () {
console.log(abc);
console.log(ghi);
}
}
// Instantiate the Service and call the method
var service = Activator(Service);
service.write();
The console was successfully printed!