`
子衿青青
  • 浏览: 111036 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Dojo面向对象机制深入剖析

 
阅读更多

Dojo是一个基于javascript语言的web控件库,要了解dojo的面向对象机制,我们可以首先来回顾一下javascript本身的基本面向对象机制:

首先,javascript主要通过函数来模拟面向对象机制,如:

function func1(){};

func1(); //函数调用

new func1(); //实例化的对象

上述两种方式其函数内部的this对象也是不一样的。

再者,关于javascript的最基本的继承方式主要有两种,(当然还有更复杂的,这里只列出最基本的两种方式)

1. 对象冒充方式:

function ClassA(sColor) {
this.color = sColor;
this.xxx = xxx;
......
}

function ClassB(sColor, name) {
this.newMethod = ClassA;
this.newMethod(sColor);
delete this.newMethod;
......
}

或者:(这里ClassA同上)

function ClassB(sColor, sName) {
ClassA.call(this, sColor); //或者apply

this.name = sName;
this.sayName = function() {
alert(this.name);
};
}

2. 原型链式继承:

//基类

function ClassA() { }
ClassA.... = .....;
//子类
function ClassB() { }
//通过修改prototype来达到继承目的
ClassB.prototype = new ClassA();

//定义新属性与方法
ClassB.... = .....;

//保证constructor的一致性(修改prototype后其constructor变为ClassA,应该是ClassB)

ClassB.prototype.constructor = ClassB;

上述两种方法各有优缺点:对象冒充方式效率低,而且必须使用构造函数方式但是能支持多继承,而prototype方式很灵活但不支持多继承。于是有了如下混合方式:

function ClassA(sColor) { }
ClassA.... = ..... //设置属性

function ClassB() {
ClassA.call(this, sColor); //对象冒充方式 继承属性
this.name = sName;
}
ClassB.prototype = new ClassA(); //原型链方式 继承方法
ClassB.prototype.sayName = function() {
alert(this.name);
}

下面我们来看看dojo是如何实现继承机制的:

下面是dojo中声明类和使用类的一个简单示例,可以看出,其核心在一个dojo.declare函数上:

我们来看看dojo.declare函数:

1> 先看第一个参数:className参数,可以见如下相关代码:

......

// add name if specified
if(className){
proto.declaredClass = className;
d.setObject(className, ctor);
}

......

其中ctor是在该方法内构造的一个函数,其实是该声明类的定义,其本身是一个函数对象,里面有很多成员:包括属性定义,函数定义,关于这个的详细介绍这个后面会涉及到。这里主要通过dojo.setObject将该构造的函数对象赋给名为className的变量,如dijit.WidgetSet.

所以这里相当于这样写:

ctor = function(){....};

Dijit.WidgetSet = ctor;

另外强调一下,这里的proto就是ctor的prototype.

2> 我们再来看看第三个参数:props,可以见如下代码:(具体可见加粗的字体说明)

............

proto = {};


//复制一份类的定义对象的内容,见上面Dijit.Calendar的templateString, value, buildRendering等等属性和方法.
safeMixin(proto, props);



// 开始构造ctor,即构造类的定义,可以看到里面还有很多dojo自己添加的属性
t = !chains || !chains.hasOwnProperty(cname);

//以下三个对象singleConstructor/simpleConstructor/chainedConstructor 都是 是一个函数对象,其返回值也是一个函数对像,这些返回的函数对象内部,都会包含一些默认操作,包括初始化,调用ctor及其基类的ctor等等,具体细节可以参见上述三个函数的定义,可以看出模拟dojo的类的函数在初始化时都做了些什么,很值得研究,为了是篇幅不要太长,这里暂时不做过于细致的深入。
bases[0] = ctor = (chains && chains.constructor === "manual") ? simpleConstructor(bases) :
(bases.length == 1 ? singleConstructor(props.constructor, t) : chainedConstructor(bases, t));

// add meta information to the constructor

//这里的ctor属性很关键,在上面提到的 singleConstructor/simpleConstructor/chainedConstructor函数里面会调用到,这也是为什么dojo.declare的“类”在初始化时(new操作)会自动调用constructor方法的原因!!!
ctor._meta = {bases: bases, hidden: props, chains: chains,
parents: parents, ctor: props.constructor };
ctor.superclass = superclass && superclass.prototype;
ctor.extend = extend;

//这里是比较关键的操作了,将定义的属性全部作为prototype的属性,注意我们这里先不谈继承,而且这里不是在继承,请和前面的javascript继承区分开

ctor.prototype = proto;

//由于prototype被修改,所以需要重新赋值以保持prototype的constructor一致性
proto.constructor = ctor;

// 添加dojo里面比较常用的方法,注意:这些方法被直接加到了prototype中!
proto.getInherited = getInherited;
proto.inherited = inherited;
proto.isInstanceOf = isInstanceOf;

............


//最后将构造好的类对象ctor(本质上是一个函数对象)赋值给我们声明的类名
dojo.setObject(className, ctor)

.............

所以这里其实可以知道,在dojo中declare的类,其本质是函数对象,其实他就是如下代码:

ctor = function(){};

ctor.prototype = props 属性定义.....

类名变量{eval(className)} = ctor;

3> 下面我们来看一看第二个参数,关系着dojo的继承机制:(具体可见加粗的字体说明)

..................

if(opts.call(superclass) == "[object Array]"){
//多个基类时,整理基类数组
bases = c3mro(superclass);
t = bases[0];
mixins = bases.length - t;

//基类数组里的第一个对象
superclass = bases[mixins];
}else{

//只有一个基类的情况
bases = [0];
if(superclass){
if(opts.call(superclass) == "[object Function]"){
t = superclass._meta;
bases = bases.concat(t ? t.bases : superclass);
}else{
err("base class is not a callable constructor.");
}
}else if(superclass !== null){
err("unknown base class. Did you use dojo.require to pull it in?")
}
}

//开始构造基类属性,合并他们的prototype内容
if(superclass){
for(i = mixins - 1;; --i){

//拷贝prototypesuperclass为基类数组里的第一个函数对象,forceNew之后变成含有superclass的prototype 属性的一个对象
proto = forceNew(superclass);
if(!i){
// stop if nothing to add (the last base)
break;
}
// mix in properties
t = bases[i];

//合并所有基类的prototype,作为后面子类的prototype,实现属性共享
(t._meta ? mixOwn : mix)(proto, t.prototype);
//构造 基于合并prototype的基类临时函数对象
ctor = new Function;
ctor.superclass = superclass;
ctor.prototype = proto;


superclass = proto.constructor = ctor;

//如上这行代码用于调整所构造的ctor的constructor,保持一致性,然后修改superclass用于后续迭代,其实将这一行写成如下两行更通俗易懂:

// ctor.prototype.constructor = ctor;

// superclass = ctor;


}
}else{
proto = {};
}

.................

这里我们只是粗略的把dojo.declare的主线路大致过了一遍,后面附上了dojo.declare的源代码(基于dojo1.5),大家可以参考一下。关于dojo.declare的实现细节还有很多很多值得讨论的地方,但是这里由于篇幅过长,所以关于dojo的面向对象机制的详细实现我们以后再继续讨论,这里就不做详细说明了。

dojo.declare 是和 dojo.require(类似java的import) 以及 dojo.provide 联合起来一起使用的,主要由这3个函数将javascript封装成了一个接近面向对象的dojo语言模式,这也是dojo比起其他web控件库比较独到的一大特点。

另外强调一点:在dojo.declare方法里还实现了一种比较有用的链式机制,通过定义“-chains-”变量来使用,有兴趣可以研究一下,这里不做过多说明。

附上dojo.declare源代码:(dojo1.5)

d.declare = function(className, superclass, props){
// crack parameters
if(typeof className != "string"){
props = superclass;
superclass = className;
className = "";
}
props = props || {};

var proto, i, t, ctor, name, bases, chains, mixins = 1, parents = superclass;

// build a prototype
if(opts.call(superclass) == "[object Array]"){
// C3 MRO
bases = c3mro(superclass);
t = bases[0];
mixins = bases.length - t;
superclass = bases[mixins];
}else{
bases = [0];
if(superclass){
if(opts.call(superclass) == "[object Function]"){
t = superclass._meta;
bases = bases.concat(t ? t.bases : superclass);
}else{
err("base class is not a callable constructor.");
}
}else if(superclass !== null){
err("unknown base class. Did you use dojo.require to pull it in?")
}
}
if(superclass){
for(i = mixins - 1;; --i){
proto = forceNew(superclass);
if(!i){
// stop if nothing to add (the last base)
break;
}
// mix in properties
t = bases[i];
(t._meta ? mixOwn : mix)(proto, t.prototype);
// chain in new constructor
ctor = new Function;
ctor.superclass = superclass;
ctor.prototype = proto;
superclass = proto.constructor = ctor;
}
}else{
proto = {};
}
// add all properties
safeMixin(proto, props);
// add constructor
t = props.constructor;
if(t !== op.constructor){
t.nom = cname;
proto.constructor = t;
}

// collect chains and flags
for(i = mixins - 1; i; --i){ // intentional assignment
t = bases[i]._meta;
if(t && t.chains){
chains = mix(chains || {}, t.chains);
}
}
if(proto["-chains-"]){
chains = mix(chains || {}, proto["-chains-"]);
}

// build ctor
t = !chains || !chains.hasOwnProperty(cname);
bases[0] = ctor = (chains && chains.constructor === "manual") ? simpleConstructor(bases) :
(bases.length == 1 ? singleConstructor(props.constructor, t) : chainedConstructor(bases, t));

// add meta information to the constructor
ctor._meta = {bases: bases, hidden: props, chains: chains,
parents: parents, ctor: props.constructor};
ctor.superclass = superclass && superclass.prototype;
ctor.extend = extend;
ctor.prototype = proto;
proto.constructor = ctor;

// add "standard" methods to the prototype
proto.getInherited = getInherited;
proto.inherited = inherited;
proto.isInstanceOf = isInstanceOf;

// add name if specified
if(className){
proto.declaredClass = className;
d.setObject(className, ctor);
}

// build chains and add them to the prototype
if(chains){
for(name in chains){
if(proto[name] && typeof chains[name] == "string" && name != cname){
t = proto[name] = chain(name, bases, chains[name] === "after");
t.nom = name;
}
}
}
// chained methods do not return values
// no need to chain "invisible" functions

return ctor; // Function
};

分享到:
评论

相关推荐

    dojo的包加载机制

    这里我们将深入探讨Dojo的包加载机制,并结合提供的源代码和文档进行分析。 首先,Dojo的包加载机制基于AMD(Asynchronous Module Definition)规范,这允许异步加载和定义模块,确保代码的并行加载和延迟加载,...

    dojo类机制实现原理分析

    本文旨在深入探讨Dojo类机制背后的实现原理,包括其类声明方式、继承机制、以及多重继承中涉及的C3父类线性化算法等关键技术点。 #### 二、Dojo类声明 Dojo的类声明主要通过`dojo.declare`方法来实现。该方法接收...

    dojo dojo实例 dojo例子 dojo资料 dojo项目 dojo实战 dojo模块 dojo编程

    7. **dojo/aspect**:提供面向切面编程(AOP)的支持,允许在方法调用前、后或替代方法执行插入额外的功能。 8. **dojo/data**:提供了一种数据模型接口,用于与各种数据源进行交互,比如从服务器获取数据。 9. **...

    DOJO 学习笔记 dojo

    Dojo 是一个功能丰富的 JavaScript 库,它提供了一系列模块化、面向对象的工具,用于构建高性能的 Web 应用程序。在 Dojo 中,模块和包的概念是核心组成部分,它们帮助开发者组织和管理代码,使其更易于维护和重用。...

    精通Dojo by Dojo之父

    Dojo是一个非常强大的、面向对象的、开源的JavaScript工具箱,它为开发富客户端Ajax应用提供了一套完整的小部件和一些特效操作。曾经有人这样说:“对于一个Web开发者而言,如果没有Dojo,他将是一个“残废”的...

    dojo中文文档-dojo手册

    《dojo中文文档-dojo手册》提供了全面而深入的Dojo框架知识,这是一份非常有价值的资源,对于想要理解和掌握Dojo JavaScript库的开发者来说至关重要。Dojo是一个强大的JavaScript工具包,它提供了丰富的功能,包括...

    Dojo 入门 + Dojo 工具包系列 + Dojo 使用技巧 ......

    Dojo 是一个强大的JavaScript工具包,它为富互联网应用程序(RIA)开发提供了丰富的功能和组件。...通过深入理解Dojo的体系架构、类系统、对象和函数的使用,开发者能够更高效地利用Dojo进行RIA开发。

    RFT识别疑难dojo对象自动化脚本

    1. **定制识别规则**:由于RFT的标准识别机制可能无法很好地匹配Dojo对象,我们需要编写自定义识别规则。这通常涉及编写Java或.NET插件,这些插件扩展了RFT的能力,使其能够识别Dojo组件。这些插件可以通过分析DOM...

    dojo文档 dojo文档 dojo文档

    dojo文档 dojo文档 dojo文档 dojo文档 dojo文档 dojo文档 dojo文档 dojo文档 dojo文档 dojo文档 dojo文档 dojo文档

    DOJO权威指南+DOJO1.1源码

    - **dojo/_base**: 包含了DOJO的基础功能,如事件处理、对象继承、数组操作等。 - **dojo/dom**: 提供DOM操作的API,包括查找、操作和监听DOM元素。 - **dojo/domReady**: 一个确保DOM完全加载后的回调函数,常...

    dojo官网的源码dojo官网的源码

    3. **对象和类**:Dojo提供了一套面向对象的编程模型,包括`dojo/_base/lang`中的函数增强、对象创建和继承。`dojo/_base/declare`用于创建类,支持多重继承。 4. **DOM操作**:`dojo/dom`和`dojo/query`模块提供了...

    精通Dojo(中文版)

    在动画和效果部分,书中将深入剖析dojo.fx和dojox.fx模块,这些工具提供了丰富的动画效果和组合方法,使开发者能够轻松创建出流畅的用户体验。例如,淡入淡出、滑动、旋转等常见动画效果的实现,以及如何使用动画链...

    dojo js dojo js

    dojo js dojo js dojo js dojo js dojo js dojo js dojo js

    dojo学习...........

    在深入学习Dojo之前,了解JavaScript的基础知识,尤其是面向对象编程的概念,是非常重要的,因为这将有助于更好地理解和使用Dojo的高级特性。 首先,让我们从基础开始,探讨Dojo的核心概念——模块和包。Dojo的模块...

    dojo事件处理框架

    这个系统深受面向切面编程(AOP)思想的影响,尤其是其advice机制,允许开发者在不干扰原有代码结构的情况下添加、修改或控制事件处理。 1. **基本事件绑定**: Dojo Event System使得绑定事件处理函数变得简单。...

    Dojo 1.10版离线参考手册

    在Dojo 1.10版离线参考手册中,我们可以深入了解到这个版本的详细信息和使用方法。 1. **Dojo核心模块**: - `dojo/_base`:包含Dojo的基本功能,如事件处理、对象创建、数组操作等。 - `dojo/dom`:提供了操作...

    DOJO中文手册【出自dojo中国】

    Dojo的包加载机制允许动态加载所需模块,为用户提供高度的灵活性来扩展和定制工具包。 在技术特性上,Dojo的文件结构包括一个核心代码文件(Dojo.js)和多个JavaScript文件,按照功能不同分为多个版本,如AJAX版、...

    精通Dojo 中文版PDF版(高清)

    Doio是一个功能强大的面向对象开源JavaScript工具包,它为开发新一代Web程序提供了一套完整的小部件和一些特效,得到了IBM、Sun、Zend等公司的大力支持。 本书是Dojo之父Alex Russell与人编著的一部Dojo权威之作,...

    dojo 离线API

    Dojo的核心特性之一是它的模块系统,称为AMD(Asynchronous Module Definition),这是一种异步模块加载机制,允许开发者按需加载和组织代码,提高页面性能。AMD通过`require`和`define`函数来实现模块的定义和依赖...

    dojo相关详细资料

    Dojo采用模块化设计,通过AMD(Asynchronous Module Definition)加载机制,可以异步地加载所需模块,提高了页面性能。此外,Dojo还支持模块的依赖管理和命名空间,使得代码组织更加清晰。 5. Dojo MHT 文件: `....

Global site tag (gtag.js) - Google Analytics