自学实现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 相关文章推荐
区分JS中的undefined,null,&quot;&quot;,0和false
Mar 08 Javascript
基础的prototype.js常用函数及其用法
Mar 10 Javascript
利用javascript移动div层-javascript 拖动层
Mar 22 Javascript
js 兼容多浏览器的回车和鼠标焦点事件代码(IE6/7/8,firefox,chrome)
Apr 14 Javascript
js用Date对象处理时间实现思路及代码
Jan 31 Javascript
JavaScript实现GriwView单列全选(自写代码)
May 13 Javascript
js Math 对象的方法
Sep 01 Javascript
Javascript遍历table中的元素示例代码
Jul 08 Javascript
js实现简单的省市县三级联动效果实例
Feb 18 Javascript
使用bootstrapValidator插件进行动态添加表单元素并校验
Sep 28 Javascript
Vuejs实现带样式的单文件组件新方法
May 02 Javascript
ES6基础之字符串和函数的拓展详解
Aug 22 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
微信公众号开发之通过接口删除菜单
2017/02/20 PHP
flash javascript之间的通讯方法小结
2008/12/20 Javascript
使用js检测浏览器的实现代码
2013/05/14 Javascript
javascript实现在下拉列表中显示多级树形菜单的方法
2015/08/12 Javascript
Javascript中replace()小结
2015/09/30 Javascript
jQuery实现表格隔行及滑动,点击时变色的方法【测试可用】
2016/08/20 Javascript
jQuery实现可拖拽的许愿墙效果【附demo源码下载】
2016/09/14 Javascript
jQuery解析返回的xml和json方法详解
2017/01/05 Javascript
js实现图片放大展示效果
2017/08/30 Javascript
axios向后台传递数组作为参数的方法
2018/08/11 Javascript
详解vue 自定义marquee无缝滚动组件
2019/04/09 Javascript
echarts统计x轴区间的数值实例代码详解
2019/07/07 Javascript
微信小程序开发摇一摇功能
2019/11/22 Javascript
在项目vue中使用echarts的操作步骤
2020/09/07 Javascript
如何在JavaScript中正确处理变量
2020/12/25 Javascript
python计算最小优先级队列代码分享
2013/12/18 Python
Python实现基于二叉树存储结构的堆排序算法示例
2017/12/08 Python
2018年Python值得关注的开源库、工具和开发者(总结篇)
2018/01/04 Python
Python中的 enum 模块源码详析
2019/01/09 Python
用python打印1~20的整数实例讲解
2019/07/01 Python
Python及Pycharm安装方法图文教程
2019/08/05 Python
python被修饰的函数消失问题解决(基于wraps函数)
2019/11/04 Python
Python模块zipfile原理及使用方法详解
2020/08/04 Python
Pycharm学生免费专业版安装教程的方法步骤
2020/09/24 Python
HTML5 canvas绘制的玫瑰花效果
2014/05/29 HTML / CSS
在职研究生自我鉴定
2013/10/16 职场文书
超市总经理岗位职责
2014/02/02 职场文书
市场营销求职信范文
2014/02/21 职场文书
人事部专员岗位职责
2014/03/04 职场文书
酒店采购员岗位职责
2014/03/14 职场文书
学前班语言教学计划
2015/01/20 职场文书
中学生运动会广播稿
2015/08/19 职场文书
2015年挂职锻炼个人总结
2015/10/22 职场文书
教育教学工作反思
2016/02/24 职场文书
如何理解Vue前后端数据交互与显示
2021/05/10 Vue.js
星际争霸:毕姥爷vs解冻01
2022/04/01 星际争霸