热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

AngularJs依赖注入的研究

为什么80%的码农都做不了架构师?声明,这篇文章是我在网上搜索并根据自己的理解写的,第一次发文章,还请多多指教。什么是

为什么80%的码农都做不了架构师?>>>   hot3.png

声明,这篇文章是我在网上搜索并根据自己的理解写的,第一次发文章,还请多多指教。

什么是依赖注入呢,我的理解,简单点就是说我的东西我自己并不像来拿着,我想要我依赖的那个人来帮我拿着,当我需要的时候,他给我就行了。当然这只是简单的理解,还是用代码解释比较清楚一些。

这里有一个function,很简单。

var a = function(name){console.log(name);}

我们调用它:

a('abc');//abc

那么,就像我上面说的,我能不能自己不传参数呢,例如:

a();//undefined

如何才能实现让别人帮我们注入这个参数呢:

var inject = function(name,callback){return function(){callback(name);}}

像这样,我们在定义参数的时候这样传:

a = inject('abc',a)

我们再调用a方法:

a();//abc

这其实就是最简单的依赖注入了,当然这么简单是不行的,其实这是很无意义的,下面我们来看一下高深的angularjs:

var MyController = function($scope){$scope.test = 1;}

上面这段代码定义了angularjs的controller里面用到了scope,这样还看不出问题,在看下面:

var MyController = function($scope,$http){$scope.test = 1;$http.get('');}

上面这段代码在原来的基础上增加了http,那么问题就来了,angular在调用controller的时候怎么知道我需要scope还是http还是两个都需要呢,这就牵着到了angular里的依赖注入,那么我们来模拟一下。

假设没有angular的情况下,我们:

var MyController = function($scope,$http){$scope.test = 1;$http.get('');}MyController();//undefined

肯定会报错的,然后我们来修改下我们的inject:

var inject &#61; {dependencies: {},register: function(key, value) {this.dependencies[key] &#61; value;},resolve: function(deps, func, scope) {var arr &#61; [];for (var i &#61; 0 ; i < deps.length ; i&#43;&#43;) {if (this.dependencies.hasOwnProperty(deps[i])) {arr.push(this.dependencies[deps[i]])}}console.log(arr);return function(){func.apply(scope || {}, arr);}}}

这里解释一下&#xff0c;我们用了dependencies来存储所有的依赖&#xff0c;register来实现注册依赖&#xff0c;resolve方法来实现注入。

然后我们模仿angular来预先注册几个模块&#xff1a;

inject.register(&#39;$http&#39;, {&#39;get&#39;:function(){console.log(&#39;get&#39;)}});inject.register(&#39;$scope&#39;, {&#39;test&#39;:&#39;&#39;});inject.register(&#39;$location&#39;, {&#39;hash&#39;:function(){console.log(&#39;hash&#39;)}});

然后我们就可以注入了&#xff1a;

MyController &#61; inject.resolve([&#39;$http&#39;,&#39;$scope&#39;],MyController)&#xff1b;MyController();

我们只需要http和scope&#xff0c;所以我们只传了两个&#xff0c;虽然这样看似解决了依赖注入&#xff0c;但是还有很多问题&#xff0c;比如我要交换两个参数的位置就不行了。

于是翻看了angularjs的源码&#xff0c;找到了&#xff1a;

var FN_ARGS &#61; /^function\s*[^\(]*\(\s*([^\)]*)\)/m;var STRIP_COMMENTS &#61; /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;.....function annotate(fn) {.....fnText &#61; fn.toString().replace(STRIP_COMMENTS, &#39;&#39;);argDecl &#61; fnText.match(FN_ARGS);.....}

我们忽略掉一些细节代码&#xff0c;只看我们需要的。annotate方法和我们的resolve方法很像。它转换传递过去的func为字符串&#xff0c;删除掉注释代码&#xff0c;然后抽取其中的参数。让我们看下它的执行结果&#xff0c;修改一下resolve方法&#xff1a;

resolve: function(deps, func, scope) {var FN_ARGS &#61; /^function\s*[^\(]*\(\s*([^\)]*)\)/m;var STRIP_COMMENTS &#61; /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;var fnText &#61; func.toString().replace(STRIP_COMMENTS, &#39;&#39;);var argDecl &#61; fnText.match(FN_ARGS);console.log(argDecl);}

打印出argDecl&#xff1a;

["function ($scope,$http)", "$scope,$http", index: 0, input: "function ($scope,$http){↵                $scope.test &#61; 1;↵                $http.get(&#39;&#39;);↵        }"]

可以看到&#xff0c;这个数组拿到了func的参数&#xff0c;argDecl&#xff3b;1&#xff3d; &#61; “$scope,$http”;

根据这个&#xff0c;我们来修改resolve&#xff1a;

resolve: function(func, scope) {var FN_ARGS &#61; /^function\s*[^\(]*\(\s*([^\)]*)\)/m;var STRIP_COMMENTS &#61; /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;var fnText &#61; func.toString().replace(STRIP_COMMENTS, &#39;&#39;);var argDecl &#61; fnText.match(FN_ARGS);console.log(argDecl);var deps &#61; argDecl[1].split(&#39;,&#39;);var arr &#61; [];for (var i &#61; 0 ; i < deps.length ; i&#43;&#43;) {if (this.dependencies.hasOwnProperty(deps[i])) {arr.push(this.dependencies[deps[i]])}}return function(){func.apply(scope || {}, arr);}}

OK&#xff0c;这次我们不用在意参数的顺序了&#xff0c;但是angular远比我们要想的多&#xff0c;大多数情况下&#xff0c;我们的js都是要压缩的&#xff0c;所以function的实参会被替换&#xff0c;如果是那样的话&#xff0c;我们这个方法的argDecl&#xff3b;1&#xff3d; &#61; “$scope,$http”;就会是argDecl&#xff3b;1&#xff3d; &#61; “r,t”;类似这样的变量&#xff0c;那么又该怎么解决呢&#xff1f;

angular官方有这样的解释&#xff1a;

为了克服压缩引起的问题&#xff0c;只要在控制器函数里面给$inject属性赋值一个依赖服务标识符的数组&#xff0c;就像&#xff1a;

var MyController &#61; [&#39;$scope&#39;, &#39;$http&#39;, function($scope, $http) {  }];

那么&#xff0c;用到我们这个方法里面又该怎么实现呢&#xff1f;那我们在看看angular的源码吧&#xff1a;

....} else if (isArray(fn)) {last &#61; fn.length - 1;assertArgFn(fn[last], &#39;fn&#39;)$inject &#61; fn.slice(0, last);} else {....

看到了吧&#xff0c;之所以用到数组也是有原因的&#xff0c;把需要的依赖写在方法的前面&#xff0c;于是&#xff0c;应用到我们的reslove方法&#xff1a;

resolve: function(func, scope) {if (isArray(func)) {var last &#61; func.length - 1;var deps &#61; func.slice(0, last);func &#61; func[last]} else {var FN_ARGS &#61; /^function\s*[^\(]*\(\s*([^\)]*)\)/m;var STRIP_COMMENTS &#61; /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;var fnText &#61; func.toString().replace(STRIP_COMMENTS, &#39;&#39;);var argDecl &#61; fnText.match(FN_ARGS);var deps &#61; argDecl[1].split(&#39;,&#39;);}var arr &#61; [];for (var i &#61; 0 ; i < deps.length ; i&#43;&#43;) {if (this.dependencies.hasOwnProperty(deps[i])) {arr.push(this.dependencies[deps[i]])}}return function(){func.apply(scope || {}, arr);}}

OK&#xff0c;到这里&#xff0c;便可以用我们的inject来模拟angular的依赖注入了&#xff0c;当然&#xff0c;真正angular的依赖注入还有很多东西&#xff0c;这里就不在详细描述了。



转载于:https://my.oschina.net/hxwny/blog/352436


推荐阅读
  • 本文总结了在编写JS代码时,不同浏览器间的兼容性差异,并提供了相应的解决方法。其中包括阻止默认事件的代码示例和猎取兄弟节点的函数。这些方法可以帮助开发者在不同浏览器上实现一致的功能。 ... [详细]
  • 本文介绍了闭包的定义和运转机制,重点解释了闭包如何能够接触外部函数的作用域中的变量。通过词法作用域的查找规则,闭包可以访问外部函数的作用域。同时还提到了闭包的作用和影响。 ... [详细]
  • IjustinheritedsomewebpageswhichusesMooTools.IneverusedMooTools.NowIneedtoaddsomef ... [详细]
  • 本文介绍了在wepy中运用小顺序页面受权的计划,包含了用户点击作废后的从新受权计划。 ... [详细]
  • 本文讨论了编写可保护的代码的重要性,包括提高代码的可读性、可调试性和直观性。同时介绍了优化代码的方法,如代码格式化、解释函数和提炼函数等。还提到了一些常见的坏代码味道,如不规范的命名、重复代码、过长的函数和参数列表等。最后,介绍了如何处理数据泥团和进行函数重构,以提高代码质量和可维护性。 ... [详细]
  • 小程序wxs中的时间格式化以及格式化时间和date时间互转
    本文介绍了在小程序wxs中进行时间格式化操作的问题,并提供了解决方法。同时还介绍了格式化时间和date时间的互相转换的方法。 ... [详细]
  • 本文介绍了在go语言中利用(*interface{})(nil)传递参数类型的原理及应用。通过分析Martini框架中的injector类型的声明,解释了values映射表的作用以及parent Injector的含义。同时,讨论了该技术在实际开发中的应用场景。 ... [详细]
  • 本文介绍了使用readlink命令获取文件的完整路径的简单方法,并提供了一个示例命令来打印文件的完整路径。共有28种解决方案可供选择。 ... [详细]
  • 【爬虫】关于企业信用信息公示系统加速乐最新反爬虫机制
    ( ̄▽ ̄)~又得半夜修仙了,作为一个爬虫小白,花了3天时间写好的程序,才跑了一个月目标网站就更新了,是有点悲催,还是要只有一天的时间重构。升级后网站的层次结构并没有太多变化,表面上 ... [详细]
  • 一、什么是闭包?有什么作用什么是闭包闭包是定义在一个函数内部的函数,它可以访问父级函数的内部变量。当一个闭包被创建时,会关联一个作用域—— ... [详细]
  • EPPlus绘制刻度线的方法及示例代码
    本文介绍了使用EPPlus绘制刻度线的方法,并提供了示例代码。通过ExcelPackage类和List对象,可以实现在Excel中绘制刻度线的功能。具体的方法和示例代码在文章中进行了详细的介绍和演示。 ... [详细]
  • 单页面应用 VS 多页面应用的区别和适用场景
    本文主要介绍了单页面应用(SPA)和多页面应用(MPA)的区别和适用场景。单页面应用只有一个主页面,所有内容都包含在主页面中,页面切换快但需要做相关的调优;多页面应用有多个独立的页面,每个页面都要加载相关资源,页面切换慢但适用于对SEO要求较高的应用。文章还提到了两者在资源加载、过渡动画、路由模式和数据传递方面的差异。 ... [详细]
  • Hibernate延迟加载深入分析-集合属性的延迟加载策略
    本文深入分析了Hibernate延迟加载的机制,特别是集合属性的延迟加载策略。通过延迟加载,可以降低系统的内存开销,提高Hibernate的运行性能。对于集合属性,推荐使用延迟加载策略,即在系统需要使用集合属性时才从数据库装载关联的数据,避免一次加载所有集合属性导致性能下降。 ... [详细]
  • 1简介本文结合数字信号处理课程和Matlab程序设计课程的相关知识,给出了基于Matlab的音乐播放器的总体设计方案,介绍了播放器主要模块的功能,设计与实现方法.我们将该设 ... [详细]
  • 工作经验谈之-让百度地图API调用数据库内容 及详解
    这段时间,所在项目中要用到的一个模块,就是让数据库中的内容在百度地图上展现出来,如经纬度。主要实现以下几点功能:1.读取数据库中的经纬度值在百度上标注出来。2.点击标注弹出对应信息。3 ... [详细]
author-avatar
weibophp
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有