自学实现angularjs依赖注入


Posted in Javascript onDecember 20, 2016

    在用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>

谢谢大家!

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

Javascript 相关文章推荐
javascript中获取下个月一号,是星期几
Jun 01 Javascript
js校验表单后提交表单的三种方法总结
Feb 28 Javascript
Javascript中的默认参数详解
Oct 22 Javascript
ExpressJS入门实例
Jan 14 Javascript
第八篇Bootstrap下拉菜单实例代码
Jun 21 Javascript
Google 地图获取API Key详细教程
Aug 06 Javascript
js中获取jsp表单中radio类型的值简单实例
Aug 15 Javascript
浅谈javascript中的事件冒泡和事件捕获
Dec 28 Javascript
JS实现动态修改table及合并单元格的方法示例
Feb 20 Javascript
bootstrap栅格系统示例代码分享
May 22 Javascript
vue 开发之路由配置方法详解
Dec 02 Javascript
js实现适配移动端的拖动效果
Jan 13 Javascript
JS多物体实现缓冲运动效果示例
Dec 20 #Javascript
详解js中Number()、parseInt()和parseFloat()的区别
Dec 20 #Javascript
JavaScript 限制文本框不可输入英文单双引号的方法
Dec 20 #Javascript
用jQuery.ajaxSetup实现对请求和响应数据的过滤
Dec 20 #Javascript
NPM 安装cordova时警告:npm WARN deprecated minimatch@2.0.10: Please update to minimatch 3.0.2 or higher to
Dec 20 #Javascript
js多个物体运动功能实例分析
Dec 20 #Javascript
JS高级运动实例分析
Dec 20 #Javascript
You might like
PHP基于mssql扩展远程连接MSSQL的简单实现方法
2016/10/08 PHP
Laravel框架处理用户的请求操作详解
2019/12/20 PHP
限制文本字节数js代码
2007/03/06 Javascript
javascript for循环设法提高性能
2010/02/24 Javascript
jquery validation验证身份证号,护照,电话号码,email(实例代码)
2013/11/06 Javascript
JS仿Windows开机启动Loading进度条的方法
2015/02/26 Javascript
JQuery中层次选择器用法实例详解
2015/05/18 Javascript
Jquery easyui开启行编辑模式增删改操作
2016/01/14 Javascript
JS函数arguments数组获得实际传参数个数的实现方法
2016/05/28 Javascript
js和C# 时间日期格式转换的简单实例
2016/05/28 Javascript
Node.js发送HTTP客户端请求并显示响应结果的方法示例
2017/04/12 Javascript
es6中的解构赋值、扩展运算符和rest参数使用详解
2017/09/28 Javascript
Vue 自定义动态组件实例详解
2018/03/28 Javascript
200行HTML+JavaScript实现年会抽奖程序
2019/01/22 Javascript
微信小程序的授权实现过程解析
2019/08/02 Javascript
Python人脸识别初探
2017/12/21 Python
python如何在列表、字典中筛选数据
2018/03/19 Python
python 通过 socket 发送文件的实例代码
2018/08/14 Python
使用Python实现一个栈判断括号是否平衡
2018/08/23 Python
wxPython实现画图板
2020/08/27 Python
Python Numpy中数据的常用保存与读取方法
2020/04/01 Python
python使用梯度下降和牛顿法寻找Rosenbrock函数最小值实例
2020/04/02 Python
基于Python把网站域名解析成ip地址
2020/05/25 Python
在keras里面实现计算f1-score的代码
2020/06/15 Python
Python调用C语言程序方法解析
2020/07/07 Python
Linux中如何用命令创建目录
2015/01/12 面试题
自我评价怎么写好呢?
2013/12/05 职场文书
文明倡议书范文
2014/04/15 职场文书
个人作风纪律整顿整改措施
2014/10/25 职场文书
总经理检讨书范文
2015/02/16 职场文书
自主招生自荐信格式
2015/03/04 职场文书
2015年学校禁毒工作总结
2015/05/27 职场文书
幼儿园开学家长寄语(2015秋季)
2015/05/27 职场文书
毕业生学校组织意见
2015/06/04 职场文书
爱国主义教育基地观后感
2015/06/18 职场文书
《雪域豹影》读后感:父爱的伟大
2019/12/23 职场文书