动手实现你的依赖注入

首先咱们用大白话来理解一次,依赖注入就是我有一个东西,我平时不用,我把这个东西放在你那里,在我用的时候你拿给我。数组

这个时候咱们已经初步有了概念,咱们在用代码来消化这个概念bash

首先咱们来先建立一个inject的对象,对象下有个三个属性分别为app

  • dependencies这个为一个数组,用来存放咱们全部的依赖
  • register 这个为一个函数,用来注册咱们的依赖
  • resolve 这个用来注入(提取)咱们的依赖
    const inject = {
    dependencies: {},
    register: function(key, value) {
      this.dependencies[key] = value;
    },
    resolve: function(deps, func, scope){
      let arr = [];
      for (let i = 0 ; i < deps.length ; i++) {
           if (this.dependencies.hasOwnProperty(deps[i])) {
              arr.push(this.dependencies[deps[i]])
           }
      }
      return function(){
        func.apply(scope||{},arr);
      }
    },
    }复制代码
    嗯, 大概就是这个,即然已经把初步的想法实现,咱们如今就来试试到底可不能够注入

首先实现我有一个东西,而且把这个东西存在你那,那么咱们用register方法来注册两个函数

inject.register('$http', {
  'get': function() {
    return '我是依赖注入的$http下的一个函数';
  }
});
inject.register('$scope', {
  'test': ''
});复制代码

这个时候我须要用到我前面存放在你那里东西,你得拿给我ui

let MyController = function($scope,$http){
  console.log(`MyController-result:${$http.get()}`)
}
MyController = inject.resolve(['$scope','$http'],MyController)
MyController(); // MyController-result:我是依赖注入的$http下的一个函数复制代码

嗯,完美,这样就简单的实现咱们的注入,但咱们仔细一下,若是这个时候咱们把这个依赖注入的顺序变换一下是报错的,由于他们是一一对应的,因此咱们还得来改造一下resolve这个方法,this

resolve: function(func, scope){
  let arr = [];
  // 这些正则是在angular的源码里找来的
  // 首先把这个函数toString,而后FN_ARGS匹配出来函数的参数,这个参数就是咱们依赖的表
  // 那么这个时候咱们已经拿到依赖的表了,咱们按照这个表里取出相对应的函数体给他就完了
  let FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
  let STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
  let fnText = func.toString().replace(STRIP_COMMENTS, '');
  let argDecl = fnText.match(FN_ARGS);
  let deps = argDecl[1].split(',');
  for (let i = 0 ; i < deps.length ; i++) {
       if (this.dependencies.hasOwnProperty(deps[i])) {
          arr.push(this.dependencies[deps[i]])
       }
  }
  return function(){
    func.apply(scope||{},arr);
  }
}复制代码

固然使用的时候也得改一下spa

let MyController = function($scope,$http){
  console.log(`MyController-result:${$http.get()}`)
}
MyController = inject.resolve(MyController)
MyController(); // MyController-result:我是依赖注入的$http下的一个函数复制代码

看上去有点像模样了,这时候我以为应该有人会提出问题,嗯,对,就是还有问题,咱们知道上线前咱们通常会把项目静态资源打包,function($scope,$http)会打成相似于function(a,b)这种,那么这个时候还怎么去打到对应的函数体呢 ? 咱们再来改写一下resolve方法code

resolve: function(func, scope) {
  let deps;
  // 若是传入的函数是一个数组,大概长这样[a,b,function(a,b){}],那么咱们删掉function(){}这部分,只留下咱们的依赖部分,这样就解决了打包压缩时的问题
  if (isArray(func)) {
    let last = func.length - 1;
    deps = func.slice(0, last);
    func = func[last]
  } else {
    let FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
    let STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
    let fnText = func.toString().replace(STRIP_COMMENTS, '');
    let argDecl = fnText.match(FN_ARGS);
    deps = argDecl[1].split(',');
  }
  let arr = [];
  for (let i = 0; i < deps.length; i++) {
    if (this.dependencies.hasOwnProperty(deps[i])) {
      arr.push(this.dependencies[deps[i]])
    }
  }
  return function() {
    func.apply(scope || {}, arr);
  }
}复制代码

固然使用的时候仍是得改改对象

let MyController = ['$scope', '$http', function($scope, $http) {
  console.log(`MyController-result:${$http.get()}`)
}];
MyController = inject.resolve(MyController)
MyController(); // MyController-result:我是依赖注入的$http下的一个函数复制代码

这样咱们一个简易的dependencies inject就完成了,angular的实现思路也是如此ci

相关文章
相关标签/搜索