InfoQ Geekathon 大模型技术应用创新大赛 了解详情
写点什么

dojo 类机制简介

  • 2011-09-12
  • 本文字数:3861 字

    阅读完需:约 13 分钟

随着 AJAX 和 RIA 技术的发展,JavaScript 被广泛的使用,并在开发中发挥着越来越重要的作用。JavaScript 提供了特有的类机制,但是在语法习惯上与传统面向对象的语言有很大的不同,这使得不少的 JavaScript 开发人员感到比较迷惑,而 dojo 作为功能强大的 JavaScript 类库,有功能完整的类机制实现。本文将通过实例介绍 dojo 的类机制,这是 dojo 提供的一种强大和灵活的功能,其 dijit UI 组件框架也是以此为基础实现的。

1. 使用 dojo 定义类

声明 dojo 类是通过 dojo.declare() 方法来实现的,如我们想要定义一个名为 com.levinzhang.Person 的类,该类有 name、age 属性和 getName、getAge 方法:

复制代码
dojo.declare("com.levinzhang.Person", null,{
name:null,
age:null,
constructor: function(name,age){
this.name = name;
this.age = age;
},
getName:function(){
return this.name;
},
getAge:function(){
return this.age;
}
});

除了前面提到的属性的和方法以外,在代码中我们还定义了一个名为 constructor 的方法,这个方法在 dojo 的类机制中至关重要,当我们实例化该类得到对象的时候,该方法将会被调用,从而完成初始化的操作。

dojo 的 declare 接受三个参数,分别为类的名称、要继承的父类以及该类的属性和方法。实例化类的语法也很简洁,与实例化普通的 JavaScript 类并无分别:

复制代码
var person = new com.levinzhang.Person("levinzhang",30);
alert(person.getName());// 将会提示出 levinzhang

2. 实现静态变量

在常见的面向对象语言中,经常会使用到类层次的静态变量,而通过 dojo 定义的类也能实现静态变量的需求,不过静态变量仅限于数组和对象类型。

复制代码
staticInfo:{count:0},
constructor: function(name,age){
this.name = name;
this.age = age;
++this.staticInfo.count;
}

如上所示,如果定义了数组和对象,而没有在构造方法中进行修改的话,这个对象将会成为该类的静态属性,测试代码如下:

复制代码
var person = new com.levinzhang.Person("levinzhang",30);
alert(person.staticInfo.count);// 此时将会提示出 1
var person2 = new com.levinzhang.Person("levin",30);
alert(person2.staticInfo.count);// 此时将会提示出 2

需要注意的两点是:1)对于原始类型的变量如数字、布尔值和字符串,dojo 的类机制并没有提供实现静态属性的功能;2)如果定义的数组或对象属性在 constructor 方法中被重新赋值,那么该属性将不再是静态属性,而是每个实例化对象都持有一份属于自己的备份了。

3. 使用 dojo 实现继承

在 JavaScript 中没有直接实现继承的关键字,因此关于继承有多种的实现方式,代表性的是类式继承原型式继承,但是不管哪种继承方式都需要开发人员对JavaScript 语言本身有着很深厚的了解。dojo 对JavaScript 的继承机制进行了很好的封装,可以实现功能强大的类定义,我们将对一些常见的功能进行介绍。

dojo.declare 方法中的第二个参数,是指明要继承的父类的,该参数可以为 null(要定义的类没有父类)、单个类(要定义的类继承自一个父类)或数组(要定义的类继承自多个父类)。

1) 单继承

我们要定义一个名为 com.levinzhang.Employee 的类,继承自 com.levinzhang.Person,并要添加名为 workExperience 的属性、重写 getName 方法等功能:

复制代码
dojo.declare("com.levinzhang.Employee", com.levinzhang.Person,{
workExperience:null,
constructor: function(name,age,workExperience){
this.workExperience = workExperience;
},
getWorkExperience:function(){
return this.workExperience;
},
getName:function(){
return "Employee:"+this.name;
},
getInput:function(){
return 5000;
}
});

在以上的代码中,我们定义的 com.levinzhang.Employee 继承了 com.levinzhang.Person 并添加了自定义的方法。测试代码如下:

复制代码
var employee = new com.levinzhang.Employee("levin",30,4);
alert(employee.getName());// 将提示出 Employee:levin
alert(employee.getWorkExperience());// 将提示出 4
alert(employee.getAge());// 将提示出 30

可以看到在 Employee 的实例中,我们能够调用父类中定义的方法。而在类的 constructor 初始化方法中,我们并没有调用父类相关的方法,但是我们成功初始化了 name 和 age 两个属性,这是因为 dojo 会自动调用父类的初始化方法,完成继承要求的相关初始化工作。

2) 多继承

dojo 支持多继承的功能, dojo 实现了被 Python 和很多支持多继承语言使用的 C3 算法。使用 dojo 的多继承功能时,需要注意的是:只有数组中的第一个元素会作为真正的父类,而其它的元素则是通过 mixin 的方式进行属性添加以构建原型链的。

如我们需要定义一个类来表示公司中的股票持有者(com.levinzhang.Shareholder),而公司中的员工可能也会持有股票,于是我们定义一个名为 com.levinzhang.ShareholderEmployee 的类继承自 com.levinzhang.Shareholder 和 com.levinzhang.Employee。

复制代码
dojo.declare("com.levinzhang.Shareholder", com.levinzhang.Person,{
share:null,
constructor: function(args){
this.share = args.share;
},
getShare:function(){
return this.share;
}
});
dojo.declare("com.levinzhang.ShareholderEmployee", [com.levinzhang.Employee,com.levinzhang.Shareholder],{
getInfo:function(){
alert("I'm an Employee with stock.My share is "+this.getShare()+"."+"My name is "+this.getName()+".");
}
});

在以上的代码中,我们调整了原有的初始化传入参数的格式,由传入多个参数改为传入一个简单 JavaScript 字面量对象的方式(原有的代码也要稍作调整),并通过多继承的方式实现了一个类用来描述持有股票的员工。测试代码如下:

复制代码
var shareholderEmployee = new com.levinzhang.ShareholderEmployee({name:"levin",age:30,workExperience:4,share:300});
shareholderEmployee.getInfo();
// 将会提示出“I'm an Employee with stock.My share is 300. My name is Employee:levin.”

关于 dojo 多继承的更多话题,请参考 dojo 的文档资料

3) 调用父类的方法

在编程中,我们经常会遇到在子类的某个方法中需要调用父类的方法来协作完成功能。如我们定义名为 com.levinzhang.Manager 的类,该类继承自 com.levinzhang.Employee 类,并重写 getInput 方法,Manager 的收入分为两部分,一部分是与 com.levinzhang.Employee 相同的固定收入,另一部分是与管理经验相关的其它收入,这样在定义 Manager 的时候,就需要调用父类的方法,实现方式如下:

复制代码
dojo.declare("com.levinzhang.Manager", com.levinzhang.Employee,{
manageExperience:null,
constructor: function(args){
this.manageExperience = args.manageExperience;
},
getInput:function(){
var fromBase = this.inherited(arguments);
return fromBase+1000*this.manageExperience;
}
});

从以上代码可以看到,通过 inherited 方法的使用,使得 Manager 可以调用父类的方法。测试代码如下:

复制代码
var manager = new com.levinzhang.Manager({name:"levin",age:30,workExperience:4,manageExperience:2});
alert(manager.getInput());//7000

在以上的测试代码中,getInput 的返回值为 7000,说明该值为子类和父类方法共同确定的。

除了使用 inherited 来调用父类中的方法以外,从 dojo 的 1.4 版本开始提供了链式调用父类方法的功能,能够通过设置自动调用父类的方法,并且支持类似于 AOP 的 before 或 after 配置(dojo 正在开发中的 1.7 版本,提供了更为丰富的 AOP 功能,我们将会持续关注)。

4. Dojo 类机制的其它功能

除了以上介绍的类定义相关功能以外,dojo 还提供了许多的便利的工具类供使用。

dojo 类所生成对象具有一些特有的属性和方法,常见的如 isInstanceOf 方法和 declaredClass 属性,isInstanceOf 方法判定对象是否为某个类的实例,而 declaredClass 属性则能够表明该对象的声明类是什么。如:

复制代码
var manager = new com.levinzhang.Manager({name:"levin",age:30,workExperience:4,manageExperience:2});
alert(manager.isInstanceOf(com.levinzhang.Employee));// 提示为 true
alert(manager.isInstanceOf(com.levinzhang.Person));// 提示为 true
alert(manager.declaredClass);// 提示为“com.levinzhang.Manager”

类机制还涉及到的包管理等功能,限于篇幅,不再展开叙述,感兴趣的读者可以参考 dojo 的在线文档或图书。

5. 小结

JavaScript 本身的类机制比较复杂,对开发人员有着较高的要求,而 dojo 提供了功能强大的类功能,有些降低了开发的难度。本文简单介绍了 dojo 类机制的基本功能,包括类定义、继承、静态属性等,这是 dojo 最基础也是最核心的内容之一,dojo 的许多高级功能都是基于此来实现的,因此了解这部分功能的使用方式甚至源码实现对于整体把握 dojo 框架都大有裨益。

参考资料:

关于作者:

张卫滨,关注企业级 Java 开发和 RIA 技术,个人博客: http://lengyun3566.iteye.com


感谢张凯峰对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家加入到 InfoQ 中文站用户讨论组中与我们的编辑和其他读者朋友交流。

活动推荐:

2023年9月3-5日,「QCon全球软件开发大会·北京站」 将在北京•富力万丽酒店举办。此次大会以「启航·AIGC软件工程变革」为主题,策划了大前端融合提效、大模型应用落地、面向 AI 的存储、AIGC 浪潮下的研发效能提升、LLMOps、异构算力、微服务架构治理、业务安全技术、构建未来软件的编程语言、FinOps 等近30个精彩专题。咨询购票可联系票务经理 18514549229(微信同手机号)。

2011-09-12 00:006138

评论

发布
暂无评论
发现更多内容

谁再悄咪咪的吃掉异常,我上去就是一 JIO

楼下小黑哥

Java dubbo 踩坑经历

BIGO全球计算平台的技术挑战

DT极客

最近一周总结

朱月俊

八张图彻底了解JDK8 GC调优秘籍-附PDF下载

程序那些事

JVM jdk8 「Java 25周年」 Java 25 周年 性能调优

【架构师训练营】第三周作业

Mr.hou

极客大学架构师训练营

架构师训练营-第三周作业

清风徐徐

架构训练营第三章课后作业单例模式 组合模式

周冬辉

架构师训练营第三周作业

大丁💸💵💴💶🚀🐟

看完这篇 HashMap,和面试官扯皮就没问题了

cxuan

Java 源码分析

架构师课程第三周作业

杉松壁

架构师训练营 No.3 周作业

连增申

投资人李丰对中国商业模式创新的理解

石云升

投资 零售 模式创新

【架构师训练营】第三周总结

Mr.hou

极客大学架构师训练营

第三周作业

CP

观察者模式详解

Seven七哥

设计模式 观察者模式

为什么建议你使用枚举?

王磊

Java 枚举

架构师训练营 - 第三周 - 作业

韩挺

架构师训练营作业 --Week3

吴炳华

极客大学架构师训练营

架构师训练营作业 -20200621

caibird1984

极客大学架构师训练营

架构师训练营第三章总结

叮叮董董

第三周作业

王鑫龙

极客大学架构师训练营

漫画通信:有了它,终于可以放心买买买了

阿里云Edge Plus

云通信 短信 语音 通信云

Week 03 命题作业

卧石漾溪

极客大学架构师训练营

Zookeeper面试题36问,再和面试官多聊半个点

Java小咖秀

zookeeper 负载均衡 面试 分布式协同 分布式系统

架构师训练营 第三周作业

Glowry

极客大学架构师训练营

分布式时序数据库SilverDB-技术架构1

Hervor。

时序数据库 分布式架构 分布式存储

改变要一点点来

Neco.W

正确阅读 进步

架构师训练营 - 第三周 - 学习总结

韩挺

锦囊篇|一文摸懂Glide

ClericYi

架构师训练营第三章作业

叮叮董董

代码重构:如何充实你的设计工具箱

SkyeDance

极客大学架构师训练营 代码重构

  • 扫码添加小助手
    领取最新资料包
dojo类机制简介_Java_张卫滨_InfoQ精选文章