自学实现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 相关文章推荐
取得传值的函数
Oct 27 Javascript
JQuery 学习笔记 element属性控制
Jul 23 Javascript
jQuery获得页面元素的绝对/相对位置即绝对X,Y坐标
Mar 06 Javascript
Jquery性能优化详解
May 15 Javascript
JavaScript中使用concat()方法拼接字符串的教程
Jun 06 Javascript
jquery ajaxfileupload异步上传插件
Nov 21 jQuery
微信小程序如何修改本地缓存key中单个数据的详解
Apr 26 Javascript
vue组件化中slot的基本使用方法
May 01 Javascript
微信小程序实现吸顶效果
Jan 08 Javascript
jQuery 判断元素是否存在然后按需加载内容的实现代码
Jan 16 jQuery
jquery简易手风琴插件的封装
Oct 13 jQuery
vantUI 获得piker选中值的自定义ID操作
Nov 04 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
input file获得文件根目录简单实现
2013/04/26 PHP
php-cli简介(不会Shell语言一样用Shell)
2013/06/03 PHP
PHP Global定义全局变量使用说明
2013/08/15 PHP
PHP获取不了React Native Fecth参数的解决办法
2016/08/26 PHP
php文件上传及下载附带显示文件及目录功能
2017/04/27 PHP
javascript dom代码应用 简单的相册[firefox only]
2010/06/12 Javascript
javascript是怎么继承的介绍
2012/01/05 Javascript
javacript使用break内层跳出外层循环分析
2015/01/12 Javascript
js调用百度地图及调用百度地图的搜索功能
2015/09/07 Javascript
Javascript随机标签云代码实例
2016/06/21 Javascript
针对后台列表table拖拽比较实用的jquery拖动排序
2016/10/10 Javascript
AngularJS入门教程之路由机制ngRoute实例分析
2016/12/13 Javascript
Angularjs通过指令监听ng-repeat渲染完成后执行脚本的方法
2016/12/31 Javascript
jQuery加密密码到cookie的实现代码
2017/04/18 jQuery
vue自定义底部导航栏Tabbar的实现代码
2018/09/03 Javascript
Vue 刷新当前路由的实现代码
2019/09/26 Javascript
解决vue一个页面中复用同一个echarts组件的问题
2020/07/19 Javascript
[41:52]DOTA2-DPC中国联赛 正赛 CDEC vs Dynasty BO3 第二场 2月22日
2021/03/11 DOTA
老生常谈Python基础之字符编码
2017/06/14 Python
Python 3.6 性能测试框架Locust安装及使用方法(详解)
2017/10/11 Python
分享vim python缩进等一些配置
2018/07/02 Python
使用Python实现租车计费系统的两种方法
2018/09/29 Python
python实现对输入的密文加密
2019/03/20 Python
Python检测端口IP字符串是否合法
2020/06/05 Python
学python爬虫能做什么
2020/07/29 Python
Python使用windows设置定时执行脚本
2020/11/12 Python
python3通过subprocess模块调用脚本并和脚本交互的操作
2020/12/05 Python
美国零售商店:Blue&Cream
2017/04/07 全球购物
阿里健康官方海外旗舰店:阿里健康国际自营
2017/11/24 全球购物
大学生个人推荐信范文
2013/11/25 职场文书
战略合作协议书范本
2014/04/18 职场文书
介绍信的写法
2015/01/31 职场文书
学习保证书100字
2015/02/26 职场文书
学习保证书怎么写
2015/02/26 职场文书
长辈生日祝福语大全(72句)
2019/08/09 职场文书
python开发实时可视化仪表盘的示例
2021/05/07 Python