自学实现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 相关文章推荐
永不消失的title提示代码
Feb 15 Javascript
JS 遮照层实现代码
Mar 31 Javascript
jQuery学习总结之元素的相对定位和选择器(持续更新)
Apr 26 Javascript
jquery自动填充勾选框即把勾选框打上true
Mar 24 Javascript
jquery选择器排除某个DOM元素的方法(实例演示)
Apr 25 Javascript
jQuery实现菜单感应鼠标滑动动画效果的方法
Feb 28 Javascript
jQuery实现新消息闪烁标题提示的方法
Mar 11 Javascript
jQuery获取上传文件的名称的正则表达式
May 21 Javascript
javascript判断并获取注册表中可信任站点的方法
Jun 01 Javascript
jQuery.uploadify文件上传组件实例讲解
Sep 23 Javascript
jquery.flot.js简单绘制折线图用法示例
Mar 13 Javascript
Vue源码解读之Component组件注册的实现
Aug 24 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
JAVA/JSP学习系列之六
2006/10/09 PHP
php中socket通信机制实例详解
2015/01/03 PHP
Yii快速入门经典教程
2015/12/28 PHP
php实现图片以base64显示的方法
2016/10/13 PHP
PHP实现限制IP访问的方法
2017/04/20 PHP
js 数组操作代码集锦
2009/04/28 Javascript
javascript oop开发滑动(slide)菜单控件
2010/08/25 Javascript
Javascript中的for in循环和hasOwnProperty结合使用
2013/06/05 Javascript
js获取多个tagname的节点数组
2013/09/22 Javascript
浅析jquery ajax异步调用方法中不能给全局变量赋值的原因及解决方法
2014/01/10 Javascript
javascript中attachEvent用法实例分析
2015/05/14 Javascript
解读Bootstrap v4 sass设计
2016/05/29 Javascript
JavaScript事件学习小结(五)js中事件类型之鼠标事件
2016/06/09 Javascript
前端弹出对话框 js实现ajax交互
2016/09/09 Javascript
vue多级多选菜单组件开发
2020/09/08 Javascript
使用AngularJS编写多选按钮选中时触发指定方法的指令代码详解
2017/07/24 Javascript
jquery使用FormData实现异步上传文件
2018/10/25 jQuery
php结合js实现多条件组合查询
2019/05/28 Javascript
在Node.js中将SVG图像转换为PNG,JPEG,TIFF,WEBP和HEIF格式的方法
2019/08/22 Javascript
vuex存值与取值的实例
2019/11/06 Javascript
javascript 对象 与 prototype 原型用法实例分析
2019/11/11 Javascript
Python os模块介绍
2014/11/30 Python
从零开始学Python第八周:详解网络编程基础(socket)
2016/12/14 Python
python3监控CentOS磁盘空间脚本
2018/06/21 Python
Python判断以什么结尾以什么开头的实例
2018/10/27 Python
python3实现字符串操作的实例代码
2019/04/16 Python
Python生命游戏实现原理及过程解析(附源代码)
2019/08/01 Python
Python基本类型的连接组合和互相转换方式(13种)
2019/12/16 Python
深入浅析css3 border-image边框图像详解
2015/11/24 HTML / CSS
英国在线珠宝店:The Jewel Hut
2017/03/20 全球购物
物理力学求职信
2014/02/18 职场文书
自主招生推荐信范文
2014/05/10 职场文书
未婚证明格式
2015/06/15 职场文书
《比的意义》教学反思
2016/02/18 职场文书
教你用Python写一个植物大战僵尸小游戏
2021/04/25 Python
如何在Python项目中引入日志
2021/05/31 Python