欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

自学实现angularjs依赖注入

程序员文章站 2022-04-06 14:27:30
    在用angular依赖注入时,感觉很好用,他的出现是 为了“削减计算机程序的耦合问题” ,我怀着敬畏与好奇的心情,轻轻的走进了angu...

    在用angular依赖注入时,感觉很好用,他的出现是 为了“削减计算机程序的耦合问题” ,我怀着敬畏与好奇的心情,轻轻的走进了angular源码,看看他到底是怎么实现的,我也想写个这么牛逼的功能。于是就模仿着写了一个,如果有什么不对,请大家批评指正。

     其实刚开始的时候我也不知道怎么下手,源码中有些确实晦涩难懂,到现在我也没有看明白,于是我就静下心想一想,他是怎么用的,如下所示:

angular.module(/*省略*/)
 .factory("xxxservice", ['xx',function (xx) {
  return {
    //省略
  }
 }])
 .controller('iicontroller',['xxxservice',function(xxxservice){
  //省略
 }]);
/*...方法省略..*/

    看看上面严格模式下的使用方式,先不去看源码,如何实现service重用,controller不重用呢? 我就按照自己的想法创建一个cache用于保存service,controller 只运行一次,不保存到cache中。

有了点思路,就把该有的东西先写了,

(function (global) {
 function createinjector(cache){
  this.cache=cache;//用于保存service的cache
 }
 function angular(){}
 angular.module=function(){
  var moduleobj={};
  return {
   injector:new createinjector(moduleobj),
   factory:function(name,fn){
   },
   controller:function(name,fn){
   }
  }
 };
 global.angular = angular;
})(window);

    上面两个构造函数,一个是创建构造器,一个是angular 的静态module(不用创建直接用 "构造函数名.方法名",这里就是想模仿angular.module())方法,这里angular module 的方法我简写了,他也有依赖注入,但是我能力有限,先研究了controller和service的注入。上面的方法名字都是我copy于源码中的,这里我就不解释他们的具体意义了。

由于我们研究的是依赖注入,真正的核心代码如下:

var arrow_arg = /^([^\(]+?)=>/;
var fn_args = /^[^\(]*\(\s*([^\)]*)\)/m;
var strip_comments = /((\/\/.*$)|(\/\*[\s\s]*?\*\/))/mg;
function isarray(obj){
 return object.prototype.tostring.call(obj) === '[object array]';
}
function stringifyfn(fn) {
 return fn.tostring();
}

function extractargs(fn) {
 var fntext = stringifyfn(fn).replace(strip_comments, ''),
 args= fntext.match(arrow_arg) || fntext.match(fn_args);
 return args[1].split(',');
}
function createinjector(cache){
 this.cache=cache;
}
createinjector.prototype={
 constructor:createinjector,
 invoke:function(fn,self){
  var argsname= extractargs(fn),argsfn=[];
  argsname.foreach(function(arg){
   argsfn.push(this.cache[arg]);
  },this);
  if(isarray(fn)){
   return fn[fn.length-1].apply(self,argsfn);
  }else{
   return fn.apply(self,argsfn);
  }
 }
};

其中上面的正则表达式是复制于源码中的,代码原理是:

   (1)把传来的function tostring(),然后用正则match出所传参数名,用split把参数分割成参数数组;

   (2)循环参数数组,在cache中找到此参数名下的函数,push到一个函数数组中;

   (3)利用apply,把函数数组当成参数,去执行函数;

对于所传的fn, 判断是数组格式,还是普通的,如果是数组就apply最后的一个值,也就是函数,否则就是fn自己。

   上面的我没有做错误处理,比如注入的找不到等等一些问题,有兴趣自己加上吧。

最后所有代码如下,大家可以复制运行:

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>angular injector demo</title>
</head>
<body>
<script>
(function (global) {
  var arrow_arg = /^([^\(]+?)=>/;
  var fn_args = /^[^\(]*\(\s*([^\)]*)\)/m;
  var strip_comments = /((\/\/.*$)|(\/\*[\s\s]*?\*\/))/mg;
  function isarray(obj){
    return object.prototype.tostring.call(obj) === '[object array]';
  }
  function stringifyfn(fn) {
    return fn.tostring();
  }

  function extractargs(fn) {
    var fntext = stringifyfn(fn).replace(strip_comments, ''),
    args= fntext.match(arrow_arg) || fntext.match(fn_args);
    return args[1].split(',');
  }
  function createinjector(cache){
    this.cache=cache;
  }
  createinjector.prototype={
    constructor:createinjector,
    invoke:function(fn,self){
      var argsname= extractargs(fn),argsfn=[];
      argsname.foreach(function(arg){
        argsfn.push(this.cache[arg]);
      },this);
      if(isarray(fn)){
        return fn[fn.length-1].apply(self,argsfn);
      }else{
        return fn.apply(self,argsfn);
      }
    }
  };
  function angular(){}
  angular.module=function(){
    var moduleobj={};
     return {
       injector:new createinjector(moduleobj),
       factory:function(name,fn){
         moduleobj[name]=this.injector.invoke(fn);
         return this;
       },
       controller:function(name,fn){
         this.injector.invoke(fn);
         return this;
       }
     }
  };
  global.angular = angular;
})(window);


angular.module()
  .factory('cacheservice',[function(){
    return {};
  }])
  .factory("userinfoservice", ['cacheservice',function (cacheservice) {
    return {
      getuserinfo:function(){
        return cacheservice.userinfo;
      },
      setuserinfo:function(value){
        cacheservice.userinfo=value;
      }
    }
  }])
  .controller('usercontroller',['userinfoservice',function(userinfoservice){
    userinfoservice.setuserinfo({id:'qqqq11234',name:'zhanglearing'});
    console.log(userinfoservice.getuserinfo());
  }]);
</script>
</body>
</html>

谢谢大家!

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。