在用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>

谢谢大家!

angularjs 依赖注入原理与实现的更多相关文章

  1. AngularJS依赖注入

    <html> <head> <meta charset="utf-8"> <title>AngularJS 依赖注入</tit ...

  2. AngularJS 依赖注入

        依赖注入(Dependency Injection,简称DI)是一种软件设计模式,在这种模式下,一个或更多的依赖(或服务)被注入(或者通过引用传递)到一个独立的对象(或客户端)中,然后成为了该 ...

  3. 关于angularjs依赖注入的整理

    初学angularjs阶段,刚刚看到菜鸟教程的angularjs依赖注入.现在整理一下: 1.含义:一个或更多的依赖(可以理解为模块关系依赖)或服务(分为内建服务[例如$http,$tiomeout等 ...

  4. PHP依赖注入原理与用法分析

    https://www.jb51.net/article/146025.htm 本文实例讲述了PHP依赖注入原理与用法.分享给大家供大家参考,具体如下: 引言 依然是来自到喜啦的一道面试题,你知道什么 ...

  5. Spring依赖注入原理分析

    在分析原理之前我们先回顾下依赖注入的概念: 我们常提起的依赖注入(Dependency Injection)和控制反转(Inversion of Control)是同一个概念.具体含义是:当某个角色( ...

  6. 【串线篇】spring泛型依赖注入原理

    spring泛型依赖注入原理 不管三七二十一 servlet :加注解@servlet service:加注解@service dao:加注解@Repository 这相当于在容器中注册这些个类

  7. angularjs 依赖注入--自己学着实现

    在用angular依赖注入时,感觉很好用,他的出现是 为了"削减计算机程序的耦合问题" ,我怀着敬畏与好奇的心情,轻轻的走进了angular源码,看看他到底是怎么实现的,我也想写个 ...

  8. 30行代码让你理解angular依赖注入:angular 依赖注入原理

    依赖注入(Dependency Injection,简称DI)是像C#,java等典型的面向对象语言框架设计原则控制反转的一种典型的一种实现方式,angular把它引入到js中,介绍angular依赖 ...

  9. angular 依赖注入原理

    依赖注入(Dependency Injection,简称DI)是像C#,java等典型的面向对象语言框架设计原则控制反转的一种典型的一种实现方式,angular把它引入到js中,介绍angular依赖 ...

随机推荐

  1. Asp.net MVC + Redis(Linux安装Redis)

    最近有幸在工作中用到了redis,玩的还算开心.但是发现Redis在Windows上并不是满血状态的,所以决定安装一个Linux的虚拟机,让Redis在Linux上运行. 虚拟环境 虚拟机,我已经玩了 ...

  2. 终结篇:RemoteWebDriver与Grid简介-----Selenium快速入门(十五)

    Selenium的基本使用,已经介绍得差不多了,今天来简单说说RemoteWebDriver与Grid,也是本系列的最后一篇. 还记得本系列第一章(Selenium简介与环境搭配)的配置中,提到我们下 ...

  3. 【C#进阶】委托那些事儿(一)

    一.简单的委托 1.1 委托的声明: C#当中,委托(delegate)是一种方法封装,也即委托对象可以作为一种传递方法的变量来使用. 委托也算是一种类,与类是平级的存在.在类中写delegate对象 ...

  4. 第五章 ReentrantLock源码解析1--获得非公平锁与公平锁lock()

    最常用的方式: int a = 12; //注意:通常情况下,这个会设置成一个类变量,比如说Segement中的段锁与copyOnWriteArrayList中的全局锁 final Reentrant ...

  5. hdoj1575 Tr A(矩阵快速幂)

    简单的矩阵快速幂.最后求矩阵的秩. #include<iostream> #include<cstring> using namespace std; ; int n,k; s ...

  6. redis集群配置及运行命令(windows和centos)附Python测试范例代码

    表示配置主服务器器的IP和端口 slaveof <masterip> <masterport> # 设置slave是否是只读的.从2.6版起,slave默认是只读的. slav ...

  7. deepin安装Mariadb后,登录时出现ERROR 1045 (28000): Access denied for user 'root'@'localhost'

    安装Mariadb的时候设置了root密码,但是登录的时候出现了这样的提示 这里记录下我的处理方法.我是用的如果重置root密码的套路. 首先,在/etc/mysql/mariadb.conf.d/5 ...

  8. Netty核心概念(10)之内存管理

    1.前言 之前的章节已经将启动demo中能看见的内容都分析完了,Netty的一个整体样貌都在第8节线程模型最后给的图画出来了.这些内容解释了Netty为什么是一个异步事件驱动的程序,也解释了Netty ...

  9. MyEclipse:详细使用教程

    http://www.56.com/u18/v_MTQwNzY1MTU5.html?fromvsogou=1

  10. Spring Security构建Rest服务-1203-Spring Security OAuth开发APP认证框架之短信验证码登录

    浏览器模式下验证码存储策略 浏览器模式下,生成的短信验证码或者图形验证码是存在session里的,用户接收到验证码后携带过来做校验. APP模式下验证码存储策略 在app场景下里是没有cookie信息 ...