一、概述
AngularJS有一经典之处就是依赖注入,对于什么是依赖注入,熟悉spring的同学应该都非常了解了,但,对于前端而言,还是比较新颖的。
依赖注入,简而言之,就是解除硬编码,达到解偶的目的。
下面,我们看看AngularJS中常用的实现方式。
方法一:推断式注入声明,假定参数名称就是依赖的名称。因此,它会在内部调用函数对象的toString()方法,分析并提取出函数参数列表,然后通过$injector将这些参数注入进对象实例。
如下:
//方法一:推断式注入声明,假定参数名称就是依赖的名称。 //因此,它会在内部调用函数对象的toString()方法,分析并提取出函数参数列表, //然后通过$injector将这些参数注入进对象实例 injector.invoke(function($http, $timeout){ //TODO });
方法二:行内注入声明,允许我们在函数定义时,直接传入一个参数数组,数组包含了字符串和函数,其中,字符串代表依赖名,函数代表目标函数对象。
如下:
//方法二:行内注入声明,允许我们在函数定义时,直接传入一个参数数组, //数组包含了字符串和函数,其中,字符串代表依赖名,函数代表目标函数对象。 module.controller('name', ['$http', '$timeout', function($http, $timeout){ //TODO }]);
看了上述代码,心中有一疑问,这些是怎么实现的呢?
哈哈,下面,我们就来一起模拟一下这些依赖注入方式,从而了解它们。
二、搭建基本骨架
依赖注入的获取过程就是,通过字段映射,从而获取到相应的方法。
故而,要实现一个基本的依赖注入,我们需要一个存储空间(dependencies),存储所需键值(key/value);一个注册方法(register),用于新增键值对到存储空间中;还有一个就是核心实现方法(resolve),通过相关参数,到存储空间中获得对应的映射结果。
So,基本骨架如下:
var injector = { dependencies: {}, register: function(key, value){ this.dependencies[key] = value; return this; }, resolve: function(){ } };
三、完善核心方法resolve
从我们搭建的基本骨架中,可以发现,重点其实resolve方法,用于实现我们具体形式的依赖注入需求。
首先,我们来实现,如下形式的依赖注入:推断式注入声明。
如下:
injector.resolve(function(Monkey, Dorie){ Monkey(); Dorie(); });
要实现上述效果,我们可以利用函数的toString()方法,我们可以将函数转换成字符串,从而通过正则表达式获得参数名,即key值。 然后通过key值,在存储空间dependencies找value值,没找到对应值,则报错。
实现如下:
var injector = { dependencies: {}, register: function(key, value){ this.dependencies[key] = value; return this; }, resolve: function(){ var func, deps, args = [], scope = null; func = arguments[0]; //获取函数的参数名 deps = func.toString().match(/^function\s*[^\(]*\(\s*([^\)]*)\)/m)[1].replace(/ /g, '').split(','); scope = arguments[1] || {}; for(var i = 0, len = deps.length; i < len, d = deps[i]; i++){ if(this.dependencies[d]){ args.push(this.dependencies[d]); }else{ throw new Error('Can\'t find ' + d); } } func.apply(scope, args); } };
测试代码,如下:
<!DOCTYPE html> <head> <meta charset="utf-8"/> </head> <body> <script> var injector = { dependencies: {}, register: function(key, value){ this.dependencies[key] = value; return this; }, resolve: function(){ var func, deps, args = [], scope = null; func = arguments[0]; //获取函数的参数名 deps = func.toString().match(/^function\s*[^\(]*\(\s*([^\)]*)\)/m)[1].replace(/ /g, '').split(','); scope = arguments[1] || {}; for(var i = 0, len = deps.length; i < len, d = deps[i]; i++){ if(this.dependencies[d]){ args.push(this.dependencies[d]); }else{ throw new Error('Can\'t find ' + d); } } func.apply(scope, args); } }; //测试代码 injector.register('Monkey', function(){ console.log('Monkey'); }).register('Dorie', function(){ console.log('Dorie'); }); injector.resolve(function(Monkey, Dorie){ Monkey(); Dorie(); console.log('-.-'); }); </script> </body> </html>
推断式注入声明,有个缺点,就是不能利用压缩工具压缩,因为我们是通过函数的参数作为依赖的,当我们压缩时,会将参数名改掉,参数名都变了,那肯定扑街咯。
那么下面,我们就看看行内注入声明,它可以弥补这缺点。
实现行内注入声明,如下:
injector.resolve(['Monkey', 'Dorie', function(M, D){ M(); D(); }]);
利用typeof判断arguments[0]的类型可以辨别并获得依赖参数和函数。
实现如下:
var injector = { dependencies: {}, register: function(key, value){ this.dependencies[key] = value; return this; }, resolve: function(){ var firstParams, func, deps = [], scope = null, args = []; firstParams = arguments[0]; scope = arguments[1] || {}; //获得依赖参数 for(var i = 0, len = firstParams.length; i < len; i++){ var val = firstParams[i], type = typeof val; if(type === 'string'){ deps.push(val); }else if(type === 'function'){ func = val; } } //通过依赖参数,找到关联值 for(i = 0, len = deps.length; i < len, d = deps[i]; i++){ if(this.dependencies[d]){ args.push(this.dependencies[d]); }else{ throw new Error('Can\'t find ' + d); } } func.apply(scope || {}, args); } };
测试代码,如下:
<!DOCTYPE html> <head> <meta charset="utf-8"/> </head> <body> <script> var injector = { dependencies: {}, register: function(key, value){ this.dependencies[key] = value; return this; }, resolve: function(){ var firstParams, func, deps = [], scope = null, args = []; firstParams = arguments[0]; scope = arguments[1] || {}; //获得依赖参数 for(var i = 0, len = firstParams.length; i < len; i++){ var val = firstParams[i], type = typeof val; if(type === 'string'){ deps.push(val); }else if(type === 'function'){ func = val; } } //通过依赖参数,找到关联值 for(i = 0, len = deps.length; i < len, d = deps[i]; i++){ if(this.dependencies[d]){ args.push(this.dependencies[d]); }else{ throw new Error('Can\'t find ' + d); } } func.apply(scope || {}, args); } }; //测试代码 injector.register('Monkey', function(){ console.log('Monkey'); }).register('Dorie', function(){ console.log('Dorie'); }); injector.resolve(['Monkey','Dorie',function(M, D){ M(); D(); console.log('-.-'); }]); </script> </body> </html>
因为行内注入声明,是通过字符串的形式作为依赖参数,so,压缩也不怕咯。
最后,我们将上面实现的两种方法,整合到一起,就可以为所欲为啦。
那,就合并下吧,如下:
var injector = { dependencies: {}, register: function(key, value){ this.dependencies[key] = value; return this; }, resolve: function(){ var firstParams, func, deps = [], scope = null, args = []; firstParams = arguments[0]; scope = arguments[1] || {}; //判断哪种形式的注入 if(typeof firstParams === 'function'){ func = firstParams; deps = func.toString().match(/^function\s*[^\(]*\(\s*([^\)]*)\)/m)[1].replace(/ /g, '').split(','); }else{ for(var i = 0, len = firstParams.length; i < len; i++){ var val = firstParams[i], type = typeof val; if(type === 'string'){ deps.push(val); }else if(type === 'function'){ func = val; } } } //通过依赖参数,找到关联值 for(i = 0, len = deps.length; i < len, d = deps[i]; i++){ if(this.dependencies[d]){ args.push(this.dependencies[d]); }else{ throw new Error('Can\'t find ' + d); } } func.apply(scope || {}, args); } };
四、花絮—RequireJS之依赖注入
依赖注入并非在AngularJS中有,倘若你使用过RequireJS,那么下面这种形式,不会陌生吧:
require(['Monkey', 'Dorie'], function(M, D){ //TODO });
通过,上面我们一步步的模拟AngularJS依赖注入的实现,想必,看到这,你自己也会豁然开朗,换汤不换药嘛。
模拟实现如下:
var injector = { dependencies: {}, register: function(key, value){ this.dependencies[key] = value; return this; }, resolve: function(deps, func, scope){ var args = []; for(var i = 0, len = deps.length; i < len, d = deps[i]; i++){ if(this.dependencies[d]){ args.push(this.dependencies[d]); }else{ throw new Error('Can\'t resolve ' + d); } } func.apply(scope || {}, args); } };
测试代码如下:
<!DOCTYPE html> <head> <meta charset="utf-8"/> </head> <body> <script> var injector = { dependencies: {}, register: function(key, value){ this.dependencies[key] = value; return this; }, resolve: function(deps, func, scope){ var args = []; for(var i = 0, len = deps.length; i < len, d = deps[i]; i++){ if(this.dependencies[d]){ args.push(this.dependencies[d]); }else{ throw new Error('Can\'t resolve ' + d); } } func.apply(scope || {}, args); } }; //测试代码 injector.register('Monkey', function(){ console.log('Monkey'); }).register('Dorie', function(){ console.log('Dorie'); }); injector.resolve(['Monkey', 'Dorie'], function(M, D){ M(); D(); console.log('-.-'); }); </script> </body> </html>
五、参考
1、AngularJS应用开发思维之3:依赖注入
2、Dependency injection in JavaScript
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
RTX 5090要首发 性能要翻倍!三星展示GDDR7显存
三星在GTC上展示了专为下一代游戏GPU设计的GDDR7内存。
首次推出的GDDR7内存模块密度为16GB,每个模块容量为2GB。其速度预设为32 Gbps(PAM3),但也可以降至28 Gbps,以提高产量和初始阶段的整体性能和成本效益。
据三星表示,GDDR7内存的能效将提高20%,同时工作电压仅为1.1V,低于标准的1.2V。通过采用更新的封装材料和优化的电路设计,使得在高速运行时的发热量降低,GDDR7的热阻比GDDR6降低了70%。
更新日志
- 古典吉他《鲁特琴-BachInspirations巴赫灵感》ThibautGarcia[24Bit/96kHz]
- 刘纬武《睡眠音乐家 缓解疼痛 赫兹白噪音》[320K/MP3][217.2MB]
- 刘纬武《睡眠音乐家 缓解疼痛 赫兹白噪音》[FLAC/分轨][870.69MB]
- 群星1998 《宝丽金最佳电视主题曲》香港首版[WAV+CUE][1.2G]
- 群星1990《群星会·金曲重现》新加坡版[WAV+CUE][1.1G]
- 张惠妹2003《勇敢》[WAV+CUE][1.1G]
- 群星1995《摇滚中国乐势力》首版引进版[WAV+CUE][983M]
- 陈思安《32首酒廊情调》2CD新雅(国际)影碟[WAV+CUE]
- 齐豫潘越云《回声》K2HD[正版原抓WAV+CUE]
- 凤飞飞《我们的主题曲》飞跃制作[正版原抓WAV+CUE]
- 刘嘉亮《亮情歌2》[WAV+CUE][1G]
- 红馆40·谭咏麟《歌者恋歌浓情30年演唱会》3CD[低速原抓WAV+CUE][1.8G]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[320K/MP3][193.25MB]
- 【轻音乐】曼托凡尼乐团《精选辑》2CD.1998[FLAC+CUE整轨]
- 邝美云《心中有爱》1989年香港DMIJP版1MTO东芝首版[WAV+CUE]