自学实现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 相关文章推荐
Javascript创建Silverlight Plugin以及自定义nonSilverlight和lowSilverlight样式
Jun 28 Javascript
jquery让返回的内容显示在特定div里(代码少而精悍)
Jun 23 Javascript
JavaScript中document.forms[0]与getElementByName区别
Jan 21 Javascript
JavaScript表单验证开发
Nov 23 Javascript
原生Javascript插件开发实践
Jan 09 Javascript
jQuery选取所有复选框被选中的值并用Ajax异步提交数据的实例
Aug 04 jQuery
Angular实现下拉框模糊查询功能示例
Jan 03 Javascript
关于vue3默认把所有onSomething当作v-on事件绑定的思考
May 15 Javascript
js实现点击按钮随机生成背景颜色
Sep 05 Javascript
vue动态合并单元格并添加小计合计功能示例
Nov 26 Vue.js
js实现复制粘贴的两种方法
Dec 04 Javascript
vue报错function () { [native code] },无法出现我们想要的内容 Unknown custom element
Apr 11 Vue.js
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
php4的彩蛋
2006/10/09 PHP
修改Zend引擎实现PHP源码加密的原理及实践
2008/04/14 PHP
javascript支持firefox,ie7页面布局拖拽效果代码
2007/12/20 Javascript
jquery中ajax学习笔记4
2011/10/16 Javascript
javascript生成随机颜色示例代码
2014/05/05 Javascript
node.js中的fs.existsSync方法使用说明
2014/12/17 Javascript
setinterval()与clearInterval()JS函数的调用方法
2015/01/21 Javascript
解决jQuery uploadify在非IE核心浏览器下无法上传
2015/08/05 Javascript
Bootstrap插件全集
2016/07/18 Javascript
JS获取字符串实际长度(包含汉字)的简单方法
2016/08/11 Javascript
Vue.js每天必学之表单控件绑定
2016/09/05 Javascript
JavaScript队列、优先队列与循环队列
2016/11/14 Javascript
canvas绘制一个常用的emoji表情
2017/03/30 Javascript
nodejs服务搭建教程 nodejs访问本地站点文件
2017/04/07 NodeJs
移动端效果之IndexList详解
2017/10/20 Javascript
微信小程序实现点击按钮移动view标签的位置功能示例【附demo源码下载】
2017/12/06 Javascript
jQuery实现的回车触发按钮事件功能示例
2018/03/25 jQuery
js 将多个对象合并成一个对象 assign方法的实现
2020/09/24 Javascript
python解析xml文件实例分享
2013/12/04 Python
Python实现监控程序执行时间并将其写入日志的方法
2015/06/30 Python
用pandas按列合并两个文件的实例
2018/04/12 Python
对python产生随机的二维数组实例详解
2018/12/13 Python
keras-siamese用自己的数据集实现详解
2020/06/10 Python
Django多个app urls配置代码实例
2020/11/26 Python
Canvas与Image互相转换示例代码
2013/08/09 HTML / CSS
div或img图片高度随宽度自适应的方法
2020/02/06 HTML / CSS
video.js支持m3u8格式直播的实现示例
2020/05/20 HTML / CSS
美国最大的香水连锁店官网:Perfumania
2016/08/15 全球购物
工作时间上网检讨书
2014/02/03 职场文书
运动会口号8字
2014/06/07 职场文书
2014年政协委员工作总结
2014/12/01 职场文书
我们的节日端午节活动总结
2015/02/11 职场文书
地球一小时活动总结
2015/02/27 职场文书
先进个人自荐书
2015/03/06 职场文书
公司表扬信格式
2015/05/04 职场文书
详解jQuery的核心函数和事件处理
2022/02/18 jQuery