自学实现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 相关文章推荐
基于jquery的复制网页内容到WORD的实现代码
Feb 16 Javascript
Ext JS 4实现带week(星期)的日期选择控件(实战一)
Aug 21 Javascript
js生成随机数的方法实例
Oct 16 Javascript
Node.js操作Firebird数据库教程
Mar 04 Javascript
浅谈js内置对象Math的属性和方法(推荐)
Sep 19 Javascript
Bootstrap页面缩小变形的快速解决办法
Feb 03 Javascript
js实现类bootstrap模态框动画
Feb 07 Javascript
基于vue实现圆形菜单栏组件
Jul 05 Javascript
JavaScript实现五子棋游戏的方法详解
Jul 08 Javascript
jQuery实现的记住帐号密码功能完整示例
Aug 03 jQuery
jQuery使用jsonp实现百度搜索的示例代码
Jul 08 jQuery
js正则匹配markdown里的图片标签的实现
Mar 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
新版PHP极大的增强功能和性能
2006/10/09 PHP
PHP中预定义的6种接口介绍
2015/05/12 PHP
JQuery 国际象棋棋盘 实现代码
2009/06/26 Javascript
js去除重复字符串两种实现方法
2013/01/09 Javascript
深入document.write()与HTML4.01的非成对标签的详解
2013/05/08 Javascript
多种方法实现360浏览器下禁止自动填写用户名密码
2014/06/16 Javascript
node.js中的emitter.emit方法使用说明
2014/12/10 Javascript
简介JavaScript中toTimeString()方法的使用
2015/06/12 Javascript
jQuery+css3实现Ajax点击后动态删除功能的方法
2015/08/10 Javascript
JavaScript实现的多个图片广告交替显示效果代码
2015/09/04 Javascript
仅9张思维导图帮你轻松学习Javascript 就这么简单
2016/06/01 Javascript
JS扩展类,克隆对象与混合类实例分析
2016/11/26 Javascript
Angular中自定义Debounce Click指令防止重复点击
2017/07/26 Javascript
vue 运用mock数据的示例代码
2017/11/07 Javascript
详解Node.js模板引擎Jade入门
2018/01/19 Javascript
web3.js增加eth.getRawTransactionByHash(txhash)方法步骤
2018/03/15 Javascript
Javascript格式化并高亮xml字符串的方法及注意事项
2018/08/13 Javascript
如何为你的JavaScript代码日志着色详解
2019/04/08 Javascript
ES6 Promise对象的含义和基本用法分析
2019/06/14 Javascript
webpack常用构建优化策略小结
2019/11/21 Javascript
JS前端面试必备——基本排序算法原理与实现方法详解【插入/选择/归并/冒泡/快速排序】
2020/02/24 Javascript
jquery实现简易验证插件封装
2020/09/13 jQuery
将Emacs打造成强大的Python代码编辑工具
2015/11/20 Python
python单线程文件传输的实例(C/S)
2019/02/13 Python
图文详解python安装Scrapy框架步骤
2019/05/20 Python
Python微信操控itchat的方法
2019/05/31 Python
python flask框架实现重定向功能示例
2019/07/02 Python
浅谈matplotlib 绘制梯度下降求解过程
2020/07/12 Python
通过实例了解python__slots__使用方法
2020/09/14 Python
CK加拿大官网:Calvin Klein加拿大
2020/03/14 全球购物
房地产销售大学生自我评价分享
2013/11/11 职场文书
个人对照检查材料思想汇报(四风问题)
2014/09/25 职场文书
处级领导班子全部召开专题民主生活会情况汇报
2014/09/27 职场文书
客户答谢会致辞
2015/07/30 职场文书
python中opencv实现图片文本倾斜校正
2021/06/11 Python
Linux磁盘管理方法介绍
2022/06/01 Servers