Welcome

首页 / 脚本样式 / Dojo Toolkit / 掌握Dojo工具包,第7部分: Dojo的扩展

掌握Dojo工具包,第7部分: Dojo的扩展2010-07-04 IBM 谢福生 蒋贤礼 董伟通过对本系列文章的前六个部分的学习,你已经对 Dojo 的强大功能有所了解了。但有时候 Dojo 的一些功能并不能完全满足实际的要求,这时就需要对 Dojo 进行扩展了,比如可以对 Widget 进行扩展,使它以更加符合项目的要求展现或响应行为。本文将详细介绍 Dojo 的面向对象特性,以及如何在这个特性上开发新的 Dojo 模块,创建新的 Dijit,定义自己个性化的 Widget。

Dojo 类定义

JavaScript 基于原型的继承

JavaScript 是一门基于对象的语言,对象可以继承自其它对象,但是 JavaScript 采用的是一种基于原型的 (prototype based) 的继承机制,与开发人员熟知的基于类的 (class based) 继承有很大的差别。在 JavaScript 中,每个函数对象(实际上就是 JavaScript 中 function 定义代码)都有一个属性 prototype,这个属性指向的对象就是这个函数对象的原型对象,这个原型对象也有 prototype 属性,默认指向一个根原型对象。如果以某个特定的对象为原型对象,而这个对象的原型对象又是另一个对象,如此反复将形成一条原型链,原型链的末端是根原型对象。JavaScript 访问一个对象的属性时,首先检查这个对象是否有同名的属性,如果没有则顺着这条继承链往上找,直到在某一个原型对象中找到,而如果到达根原型对象都没有找到则表示对象不具备此属性。这样低层对象仿佛继承了高层对象的某些属性。下面通过一个例子说明基于原型的继承是如何工作的。

清单 1. 基于原型的继承

function Plane(w, s) {
this.weight = w;
this.speed = s;
}
Plane.prototype.name = "";
function JetPlane() {
this.seats = 0;
this.construct = function(name, weight, speed, seats) {
this.name = name;
this.seats = seats;
this.weight = weight;
this.speed = speed;
}
}
JetPlane.prototype.erased = true;
JetPlane.prototype = new Plane();
var p1 = new Plane(2000, 100);
p1.name = "Boeing";
var j1 = new JetPlane(500, 300);
j1.construct("F-22", 500, 500, 2);
console.log("p1.weight:" + p1.weight + ", p1.speed:" + p1.speed + ", p1.name:" +
p1.name);
console.log("j1.name:"+ j1.name + ", j1.weight:"+ j1.weight + ",
j1.speed:"+ j1.speed + ",j1.seats:"+ j1.seats);

在这个例子中声明了两个函数对象 Plane 和 JetPlane,Plane 对象的属性有在构造函数中定义的 weight, speed,也有在 Plane 的 prototype 对象中定义的 name。这些属性在使用的时候没有区别,都可以通过【对象.属性】访问。JetPlane 中定义了两个属性 seats 和 construct,construct 的值是一个函数。JetPlane 的 prototype 对象增加了一个属性 erased,然后把 JetPlane 的 prototype 设为一个 Plane 对象,这样 JetPlane 就拥有了 Plane 的 prototype 对象(注意不是 Plane 对象)中所有的属性。随后的代码是使用 Plane 和 JetPlane 构造函数生成了一些对象,并输出对象的属性值。例子中的对象之间的关系如图 1 所示。

图 1. 对象图

绿颜色框表示的函数对象;蓝颜色框代表的是原型对象,每个函数对象都有一个原型对象,如 Plane 有 PlanPrototype,而 JetPlane 有 JetPlanePrototype。黄颜色框表示的普通对象。每个对象都有一个 Prototype 属性,指向一个原型对象。从图中可以看到各个对象的内部属性是如何分布的,Plane 对象中只有在自己的构造函数中定义的属性 weight,spead,name 存在于 Plane 的原型对象 PlanePrototype 中;p1 拷贝了 Plane 中的属性,而不会拷贝 PlanePrototype 中的属性。访 p1 的 name 属性时,JavaScript 解释器发现 p1 没有 name 属性,它会顺着 prototype 属性所指往上找,然后在 PlanePrototype 中发现了 name,所以实际上访问的是这里的 name。同理 j1 仅拷贝 JetPlane 中的 seats 和 construct,而 j1 的 prototype 有点特别;在语句 JetPlane.prototype = new Plane(); 执行之前,JetPlane 的 prototype 属性是指向 JetPlanePrototype 的,而当此语句执行之后,JetPlane 的 prototype 就被设为一个匿名的 Plane 对象,原来到 JetPlanePrototype 的链条被“剪断”了。访问 j1 的 weight 和 speed 时,实际上访问的是匿名 Plane 对象 [plane] 中的 weight 和 speed。简单的说,JavaScript 会在原型链上查找需要访问的属性,这就是 JavaScript 基于原型的继承的工作原理。