欢迎转载opendevkit文章, 文章原始地址: http://www.opendevkit.com/?e=57

declare接口是dojo定义类系统的关键函数, 类系统就是抽象,封装,继承.dojo用javascript的prototype实现继承, 用mixin实现派生, javascript一切都是函数, 这本身就是高度抽象.巧妙的地方在于: 对于一个类, 有构造函数和类名字, 实际上构造函数是用户自定义的函数, 类名字也是用户自定的, 怎么实现用户使用new操作符的时候, 构造整个对象呢?

1. 对象从哪来

比如, Dialog.js里声明了一个dijit.Dialog, 这是一个var,还是一个函数?实际上, 在declare接口里:

817         // add name if specified
 818         if(className){
 819             proto.declaredClass = className;                                                                                               
 820             lang.setObject(className, ctor);
 821         }
红 字部分, 把dijit.Dialog声明成了一个对象, 并且赋值为ctor, 实际上ctor是一个函数, 马上就说会说到. 当new操作的时候, 实际上调用的是ctor这个函数, 这个函数并不是dijit.Dialog里constructor(继承_Widget.js).

2. 关联类名字的函数ctor

declare接口里:

768                 // chain in new constructor                                                                                                
 769                 ctor = new Function;
 770                 ctor.superclass = superclass;
 771                 ctor.prototype = proto;
 772                 superclass = proto.constructor = ctor;
ctor首先是一个匿名函数, 接下来的

799         bases[0] = ctor = (chains && chains.constructor === "manual") ? simpleConstructor(bases) :
 800             (bases.length == 1 ? singleConstructor(props.constructor, t) : chainedConstructor(bases, t));
实际上给ctor赋值了simpleConstructor或者chainedConstructor的返回值, 而比如

simpleConstructor的返回值是个函数:

441     // plain vanilla constructor (can use inherited() to call its base constructor)
 442     function simpleConstructor(bases){
 443         return function(){
 444             var a = arguments, i = 0, f, m;
 445
 446             if(!(this instanceof a.callee)){
 447                 // not called via new, so force it
 448                 return applyNew(a);
 449             }
 450
 451             //this._inherited = {};
 452             // perform the shaman's rituals of the original declare()
 453             // 1) do not call the preamble
 454             // 2) call the top constructor (it can use this.inherited())
 455             for(; f = bases[i]; ++i){ // intentional assignment
 456                 m = f._meta;
 457                 f = m ? m.ctor : f;
 458                 if(f){
 459                     f.apply(this, a);
 460                     break;
 461                 }
 462             }
 463             // 3) call the postscript
 464             f = this.postscript;
 465             if(f){
 466                 f.apply(this, a);
 467             }
 468         };
 469     }
也就是ctor =  441     // plain vanilla constructor (can use inherited() to call its base constructor)
 442     function simpleConstructor(bases){
 443         return function(){
 444             var a = arguments, i = 0, f, m;
 445
 446             if(!(this instanceof a.callee)){
 447                 // not called via new, so force it
 448                 return applyNew(a);
 449             }
 450
 451             //this._inherited = {};
 452             // perform the shaman's rituals of the original declare()
 453             // 1) do not call the preamble
 454             // 2) call the top constructor (it can use this.inherited())
 455             for(; f = bases[i]; ++i){ // intentional assignment
 456                 m = f._meta;
 457                 f = m ? m.ctor : f;
 458                 if(f){
 459                     f.apply(this, a);
 460                     break;
 461                 }
 462             }
 463             // 3) call the postscript
 464             f = this.postscript;
 465             if(f){
 466                 f.apply(this, a);
 467             }
 468         };
 469     }
也就是ctor是一个函数, 函数体里 :

455             for(; f = bases[i]; ++i){ // intentional assignment
 456                 m = f._meta;
 457                 f = m ? m.ctor : f;
 458                 if(f){
 459                     f.apply(this, a);
 460                     break;

也就是当new调用这个对应dijit.Dialog的ctor的时候, 会执行_meta.ctor, 实际就是声明里边的constructor, 之后又调用:

463             // 3) call the postscript
 464             f = this.postscript;
 465             if(f){
 466                 f.apply(this, a);
 467             }

3. 总结

declare接口, 声明一个类, 实际上就是定一个了一个xxxx.xxxx.xxx这样的名字的一个函数, 名字就是类名, 函数就是调用constructor和postscript两个回调的ctor.

当, new的时候, xxx.xxx.xxx被调用, 近而调用了constructor和postscript函数.


需要理解具体的构造过程的话, 需要关注 : simpleConstructor和chainedConstructor.

dojo分析之declare接口的更多相关文章

  1. Dojo的declare接口

    declare(classname,[],{}) declare的第一个参数是可选的,代表类的名称 declare的第二个参数代表类的继承关系,比如继承哪一个父类,可以看到:第二个参数是一个数组,所以 ...

  2. mybatis源码分析之04Mapper接口的动态代理

    在工作中,使用mybatis操作数据库,只需要提供一个接口类,定义一些方法,然后调用接口里面的方法就可以CRUD,感觉是牛了一逼! 该篇就是记录一下,mybatis是如何完成这波骚操作的,即分析我们测 ...

  3. MyBatis 源码分析——生成Statement接口实例

    JDBC的知识对于JAVA开发人员来讲在简单不过的知识了.PreparedStatement的作用更是胸有成竹.我们最常见用到有俩个方法:executeQuery方法和executeUpdate方法. ...

  4. 【spring源码分析】BeanDefinitionRegistryPostProcessor接口可自定义bean加入IOC

    自定义BeanDefinitionRegistryPostProcessor BeanDefinitionRegistryPostProcessor继承自BeanFactoryPostProcesso ...

  5. 后端程序员之路 33、Index搜索引擎实现分析2-对外接口和大体流程

    # index_manager的单例是index server对外的唯一接口,part_indexer是index搜索的核心部分,index_manager持有了一组part_indexer. typ ...

  6. Dojo Data Store——统一数据访问接口

    原文地址:http://www.infoq.com/cn/articles/wq-dojo-data-store 无论在传统的桌面应用还是在主流的互联网应用中,数据始终占据着软件应用中的核心地位.当下 ...

  7. List 接口以及实现类和相关类源码分析

    List 接口以及实现类和相关类源码分析 List接口分析 接口描述 用户可以对列表进行随机的读取(get),插入(add),删除(remove),修改(set),也可批量增加(addAll),删除( ...

  8. Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6642463 在前面几篇文章中,我们详细介绍了A ...

  9. 【Spring源码分析系列】ApplicationContext 相关接口架构分析

    [原创文章,转载请注明出处][本文地址]http://www.cnblogs.com/zffenger/p/5813470.html 在使用Spring的时候,我们经常需要先得到一个Applicati ...

随机推荐

  1. C#ActiveX控件开发学习

    一:C#ActiveX控件开发注意事项   1:C#开发的ActiveX控件只可在装有Framework的系统上才能用. 2:只有IE浏览器支持. 3:初次安装需要导入代码签名证书及其证书链的方式, ...

  2. JavaWeb 学习007-4个页面,5条sql语句(添加、查看、修改、删除)2016-12-2

    需要复习的知识: 关联查询 =================================================================================班级模块学 ...

  3. C++基础-01

    指针 - 指针的基本操作间接引用指针所指向的对象 - 机器一般按字节寻址,所以能够独立分配的最小空间是1字节,也就是说指针指向的 最小空间为1字节.特别地,对于bool变量,虽然实际需要的是1bit, ...

  4. 使用spring-data-redis做缓存

    说到缓存,首先肯定是spring-cache了. spring-cache使用一个CacheManager来进行管理缓存,为了使用我们的redis作为缓存源,需要向spring注册一个CacheMan ...

  5. [转]C#在创建完项目后如何重命名项目名称。

    今天写了个C#的小测试程序,一开始使用的默认命名WindowsFormsApplication2,写完后觉得名字不好看,于是想改个名字,但是试了一下,想完整的改名还挺复杂,不但要改解决方案名,项目名, ...

  6. 【Java】:压缩成多个压缩卷

    Java自带的库不支持压缩成多个压缩卷,找到了一个开源库 zip4j ,发现更好用 so easy package com.jws.common.mail; import java.io.File; ...

  7. 一 java线程的等待/通知模型

    java 中线程之间的通信问题,有这么一个模型:一个线程修改了一个对象的值,而另一个线程感知到了变化,然后进行相应的操作,整个过程开始于一个线程,而最终执行又是另一个线程.前者是生产者,后者就是消费者 ...

  8. Ext JS

    官網:http://www.sencha.com/products/extjs/

  9. fatal error: call to undefined function imagettftext

    参照:http://stackoverflow.com/questions/7290958/php-fatal-error-call-to-undefined-function-imagettftex ...

  10. SpringMVC 的RequestMapping

    Spring MVC之@RequestMapping 详解 2013-10-13 23:39 150698人阅读 评论(6) 收藏 举报  分类: Java 精华文章(161)    目录(?)[+] ...