自学实现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 相关文章推荐
采用CSS和JS,刚好我最近有个站点要用到下拉菜单!
Jun 26 Javascript
js 判断checkbox是否选中的操作方法
Nov 09 Javascript
jQuery 淡出一个图像到另一个图像的实现代码
Jun 12 Javascript
js点击出现悬浮窗效果不使用JQuery插件
Jan 20 Javascript
jQuery中阻止冒泡事件的方法介绍
Apr 12 Javascript
jquery获取及设置outerhtml的方法
Mar 09 Javascript
详解angular路由高亮之RouterLinkActive
Apr 28 Javascript
AngularJS中ng-options实现下拉列表的数据绑定方法
Aug 13 Javascript
AngularJS实现与后台服务器进行交互的示例讲解
Aug 13 Javascript
vue-cli脚手架build目录下utils.js工具配置文件详解
Sep 14 Javascript
Vue插件之滑动验证码用法详解
Apr 05 Javascript
TypeScript 运行时类型检查补充工具
Sep 28 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
2014最热门的24个php类库汇总
2014/12/18 PHP
深入探究PHP的多进程编程方法
2015/08/18 PHP
JavaScript(JS) 压缩 / 混淆 / 格式化 批处理工具
2010/12/10 Javascript
HTML DOM的nodeType值介绍
2011/03/31 Javascript
漂亮的jquery提示效果(仿腾讯弹出层)
2013/02/05 Javascript
node.js中的events.emitter.listeners方法使用说明
2014/12/10 Javascript
js判断子窗体是否关闭的方法
2015/08/11 Javascript
js实现的tab标签切换效果代码分享
2015/08/25 Javascript
详解JavaScript中的4种类型识别方法
2015/09/14 Javascript
AngularJS中如何使用$parse或$eval在运行时对Scope变量赋值
2016/01/25 Javascript
ionic2 tabs 图标自定义实例
2017/03/08 Javascript
js is_valid_filename验证文件名的函数
2017/07/19 Javascript
JS倒计时实例_天时分秒
2017/08/22 Javascript
JQuery搜索框自动补全(模糊匹配)功能实现示例
2019/01/08 jQuery
vue keep-alive 动态删除组件缓存的例子
2019/11/04 Javascript
javascript单张多张图无缝滚动实例代码
2020/05/10 Javascript
vue 中的动态传参和query传参操作
2020/11/09 Javascript
js 数据类型判断的方法
2020/12/03 Javascript
[05:28]刀塔密之一:团结则存
2014/07/03 DOTA
[01:56]生活中的妖精之七夕特别档
2016/08/09 DOTA
web.py中调用文件夹内模板的方法
2014/08/26 Python
python对数组进行反转的方法
2015/05/20 Python
python 查找字符串是否存在实例详解
2017/01/20 Python
Python小游戏之300行代码实现俄罗斯方块
2019/01/04 Python
利用css3实现的简单的鼠标悬停按钮
2014/11/04 HTML / CSS
GNC健安喜官方海外旗舰店:美国著名保健品牌
2017/01/04 全球购物
澳大利亚香水在线:Price Rite Mart
2017/12/28 全球购物
Hotels.com越南:酒店预订
2019/10/29 全球购物
Java中有几种类型的流?JDK为每种类型的流提供了一些抽象类以供继承,请说出他们分别是哪些类?
2012/05/30 面试题
法定代表人授权委托书
2014/04/04 职场文书
医德医风演讲稿
2014/05/20 职场文书
交通事故委托书范本精选
2014/10/04 职场文书
2015毕业生实习工作总结
2014/12/12 职场文书
mysql 8.0.24版本安装配置方法图文教程
2021/05/12 MySQL
详解PHP用mb_string处理windows中文字符
2021/05/26 PHP
pytorch 如何把图像数据集进行划分成train,test和val
2021/05/31 Python