Home  >  Article  >  Web Front-end  >  JS reflection and dependency injection use case analysis

JS reflection and dependency injection use case analysis

php中世界最好的语言
php中世界最好的语言Original
2018-05-31 14:37:521486browse

This time I will bring you JS reflection and Dependency injectionUse case analysis, what are the Notes when using JS reflection and dependency injection, the following is a practical case, let’s take a look one time.

The understanding of reflection in javascript has always been that using an array to save the callback function, and then using the call or apply method at the appropriate moment , just call the callback. Generally, the operation is as follows:

First define two methods:

var service = function() {
  return { name: 'Service' };
}
var router = function() {
  return { name: 'Router' };
}

We have another function that needs to use these two modules.

var doSomething = function(other) {
  var s = service();
  var r = router();
};

Of course, we hope to be able to use dependency injection to do it and give the control to the computer instead of manually calling the following:

var doSomething = injector.resolve('router,,service', function(a, b, c) {
  expect(a().name).to.be('Router');
  expect(b).to.be('Other');
  expect(c().name).to.be('Service');
});
doSomething("Other");

Then we can create Create a reflection method as follows:

var injector ={
    dependencies: {},
    register: function(key, value) {
      this.dependencies[key] = value;
    },
    resolve:function(deps, func, scope) {
      var args = [];
      for(var i=0; i<deps.length, d=deps[i]; i++) {
        if(this.dependencies[d]) {
          args.push(this.dependencies[d]);
        } else {
          throw new Error('Can\'t resolve ' + d);
        }
      }
      return function() {
        func.apply(scope || {}, args.concat(Array.prototype.slice.call(arguments, 0)));
      }
    }
};

As shown in the above code, dependencies are used to save the callback function collection, and resolve is used to call it.

This can be considered a relatively mature and ok idea.

But there are still several problems:

1 When calling resolve, the order of the deps parameter list must be consistent.

2 This is a bit far-fetched, but it counts. When calling, you need to enter the formal parameters again and cannot call it directly.

In order to solve the above problems, the following solutions are given:

var injector ={
    dependencies: {},
    register: function(key, value) {
      this.dependencies[key] = value;
    },
    resolve: function() {
      var func, deps, scope, args = [], self = this;
      if(typeof arguments[0] === 'string') {
        func = arguments[1];
        deps = arguments[0].replace(/ /g, '').split(',');
        scope = arguments[2] || {};
      } else {
        func = arguments[0];
        deps = func.toString().match(/^function\s*[^]*\(\s*([^]*\(\s*([^]*)\)/m)[1].replace(/ /g, '').split(',');
        scope = arguments[1] || {};
      }
      return function() {
        var a = Array.prototype.slice.call(arguments, 0);
        for(var i=0; i<deps.length; i++) {
          var d = deps[i];
          args.push(self.dependencies[d] && d != '' ? self.dependencies[d] : a.shift());
        }
        func.apply(scope || {}, args);
      }
    }
};

Use regular rules to parse the code, parse out the function list parameters, and then automatically match and pass values ​​one by one, then you can To solve the problem, the order must always be maintained. Of course, this is also the approach taken by the hottest mvvm framework AngularJs.

The calling method can be as follows:

injector.resolve(['service,,router', function(service, router) {
}]);

You may notice that there are two commas after the first parameter-note that

This is not a typo. The null value actually represents the "Other" parameter (placeholder). This shows how we control the order of arguments.

Finally, there is another way to directly inject the scope, that is, directly inject the scope. Then the scope is injected, and the above-mentioned parameter order problem does not exist

Because there is no need to pass parameters , directly accessible from the scope.

var injector = {
  dependencies: {},
  register: function(key, value) {
    this.dependencies[key] = value;
  },
  resolve: function(deps, func, scope) {
    var args = [];
    scope = scope || {};
    for(var i=0; i<deps.length, d=deps[i]; i++) {
      if(this.dependencies[d]) {
        scope[d] = this.dependencies[d];
      } else {
        throw new Error('Can\'t resolve ' + d);
      }
    }
    return function() {
      func.apply(scope || {}, Array.prototype.slice.call(arguments, 0));
    }
  }
}
var doSomething = injector.resolve(['service', 'router'], function(other) {
  expect(this.service().name).to.be('Service');
  expect(this.router().name).to.be('Router');
  expect(other).to.be('Other');
});
doSomething("Other");

I believe you have mastered the method after reading the case in this article. For more exciting information, please pay attention to other related articles on the php Chinese website!

Recommended reading:

How to develop the verification code password input box function in the WeChat applet

How to use js statistics Number of page tags

The above is the detailed content of JS reflection and dependency injection use case analysis. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn