写点什么

dojo 类机制简介

  • 2011 年 9 月 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 中文站用户讨论组中与我们的编辑和其他读者朋友交流。

2011 年 9 月 12 日 00:005880

评论

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

基于 BDD 理论的 Nebula 集成测试框架重构(下篇)

Nebula Graph

分布式数据库 测试 图数据库 BDD

密码学系列之:twofish对称密钥分组算法

程序那些事

加密解密 密码学 程序那些事

【源码篇】Flutter Provider的另一面(万字图文+插件)

小呆呆666

flutter ios android 前端

Dapr:我不是Service Mesh!我只是长得很像

中原银行

Service Mesh istio Multi-Architecture 云原生架构 dapr

浪潮云说丨浪潮云智能对话,想你所想,无限畅聊

浪潮云

【全球软件大会】华为前端工程师分享:华为云官网的智能化实践

华为云开发者社区

算法 智能化 华为云官网 全球软件大会 内容分发

内蒙古公安重点人员管控研判平台建设方案

13823153121

如果非要在多线程中使用 ArrayList 会发生什么?(第二篇)

看山

Java 并发编程

毕业论文被不小心删除了,有什么方法可以恢复?

淋雨

EasyRecovery 文件恢复 硬盘数据恢复

百度关于EMP的探索:落地生产可用的微前端架构

百度Geek说

【TcaplusDB】世界青年联欢节| 让世界看到我们的光彩!

TcaplusDB

nosql tencentdb TcaplusDB

[译] R8 优化: Lambda Groups

Antway

6月日更

项目案例--吃货联盟

加百利

Java 项目 案例 6月日更

[TcaplusDB知识库]查看TcaplusDB集群状态

TcaplusDB

nosql tencentdb TcaplusDB database

Linux之less命令

入门小站

Linux

谈一谈Java的网络编程

CodeWithBuff

Java 网络io

过一过Java“锁”事

CodeWithBuff

Java 并发 同步

趣谈Java类加载器

程序猿阿星

Java ClassLoader 类加载器

测量电压调节器输出纹波和开关瞬变的方法

不脱发的程序猿

硬件研发 输出纹波测量 开关瞬变测量 电源测试 测量电压调节器

成为你想要看到的改变,首先就是让正确的事情持续的发生。

叶小鍵

Rust从0到1-函数式编程-迭代器

rust 函数式编程 Iterator 迭代器

【源码篇】Flutter Bloc背后的思想,一篇纠结的文章

小呆呆666

flutter ios android 前端

推荐一个MySQL宝藏网站

Simon

MySQL 网站

OnlyOffice基本组成及工作原理

一个需求

onlyoffice

研发管理工具 ONES 完成3亿人民币 B1 B2 轮融资,继续领跑研发管理赛道

万事ONES

项目管理 融资 研发管理工具 ONES

数据结构——顺序栈

若尘

数据结构 6月日更

react native实践总结与思考

碗盆

android 跨平台 React Native

anyRTC视频连麦demo上线啦!

anyRTC开发者

音视频 WebRTC 直播 视频直播 直播连麦

扩展ADO.net实现对象化CRUD(.net core/framework)

Spook

.net ORM ado

[TcaplusDB]世界青年联欢节, 让世界看到我们的光彩!

数据人er

数据库 nosql tencentdb TcaplusDB

我看 JAVA 之 线程同步(下)

awen

Java synchronized JOL 锁升级

基于英特尔x86平台构建AI软件生态系统

基于英特尔x86平台构建AI软件生态系统

dojo类机制简介-InfoQ