javascript的DI

学习AngularJS的原因之一就是觉得他的DI很牛叉,为了更好的学习,在研究源码之前,想自己按照自己的思路先实现个DI,希望这个思路能够对
学习源码有帮助。

 1 (function(){
 2     var config;
 3     var di={};
 4     //用来缓存已经生成的对象
 5     var beans=new Array();
 6     di.config=function(conf){    
 7         this.config=conf;
 8         return di;
 9     };
10     
11     /*获取一个方法的参数列表,要求所有注入的参数都已$开头
12       第二个正则表达是后面的 g 很重要,它表示搜索到第一个之后接着往后搜
13       没有这个g ,就只能match第一个参数。
14       这里的参数列表指的就是代码中写的参数列表,不是带入参数后的参数类表
15       比如有一个方法:
16       function Fn(a,b,c,c1){}
17       参数列表就是一个有四个字符串组成的数组:["a","b","c","c1"]
18       因为需要有参数的名字去匹配参数的类型
19     */
20     var getArguments=function(fun){
21         return fun.toString().match(/\(.*\)/)[0].match(/\$\w+/g);
22     };
23     //核心方法
24     di.getBean=function(beanName){
25         //查看缓存,有的话直接返回
26         if(beans[beanName]!=undefined)
27             return beans[beanName];
2929         var fn=this.config[beanName];
30         if(fn==undefined) return;
31         var args=getArguments(fn);
32         var argss=new Array();
33         var objstr="";
34         var index=0;
35         var obj;
36         for(var i in args){
37             argss[i]=(di.getBean(args[i]));
38             objstr+="argss["+index+"],";
39             index++;
40         }
41         objstr=objstr.substring(0, objstr.length-1);
42         objstr="obj=new (fn)("+objstr+"); ";
43         /*整个DI能够实现就靠这个eval方法了,
44          它接受一个String参数,并把String里面的内容按照Javasript的标准编译并执行
45          最牛叉的是eval里面的变量也遵循Javascript的函数作用域:也就是变量可以定义在eval外面
46          */
47          /*
48          当然这里也可以用apply,或者call,不过总有这样那样的问题,可能是自己对这两个方法不够了解吧
49          先用eval实现了,以后再研究apply 和call
50          */
51         eval(objstr);
52         beans[beanName]=obj;
53         return obj;
54     };
55     window.di=di;
56 })(window);

下面是个例子,

 1 function Person(){
 2     this.name="Mike";
 3     this.address="China";
 4     
 5     this.getName=function(){
 6         return this.name;
 7     };
 8     this.getAddress=function(){
 9         return this .address;
10     };
11 }
12 function Service($person){
13     this.work=function(){
14         return $person.getName()+" is living in "+$person.getAddress();
15     };
16 }
17 
18 function Adaptor($person,$service){
19     this.alertt=function(){
20         var k=$service.work();
21         alert(k);
22     };
23 }

有Person,Service,Adaptor三个类,Service类依赖Person来组装语句,Adaptor类依赖Service类来显示,只要有下面的代码就能运行了

var conf={
        "$person":Person,
        "$adaptor":Adaptor,
        "$service":Service
};
di.config(conf).getBean("$adaptor").alertt();
View Code

 



目前这种DI有个缺陷就是没法再组装时决定类的状态。比如一开始new一个Person时想通过构造方法给name赋值,以上的方式是不能直接做不到的。
只能通过一个间接地方式,如下:

function Person(){
    this.name="Mike";
    this.getName=function(){
        return this.name;
    };
    this.setName=function($name){
        this.name=$name.Name;
    };
}
function Name(){
    this.NAME="Tom";
}
//然后在Service中使用Person前重新给name赋值
function Service($person,$name){
    this.work=function(){
        $person.setName($name.NAME);
        return $person.getName()+" is living in China";   //这里就成了 Tom is living in China
    };
}
View Code

 

posted @ 2014-12-12 21:27  502280728  阅读(561)  评论(0编辑  收藏  举报