在Dojo工具箱中,dojo/_base/declare模块是创建类的基础。declare允许开发者实现类多继承,从而创建有弹性的(灵活的)代码, 避免写重复的代码。 Dojo, Digit, Dojox模块都使用了declare。
1 语法
declare(className,superclass,props);
参数 | 类型 | 描述 |
---|---|---|
className | string | 可选参数。存储在已创建原型中的“declaredClass”属性中的构造函数的可选名称(松散地说,“类”)。它将用作创建的构造函数的全局名称。 |
superclass | Function | Function[] | 可以是null、函数或函数数组。这个参数指定了一个基类列表(列表的第一个类将是新创建类的原型)。 |
props | Object | 将其属性复制到创建的原型的对象。通过将实例初始化函数设置为一个名为“构造函数”的属性来添加实例初始化函数。 |
注:
- 如果一个新类要继承多个类,即superclass参数包含多个基类,那么在列表的第一个类将是新创建类的原型,剩下的被认为为”多态”(复制它们的属性和方法到新类)。
- 如果一个属性或者方法在多个被继承的类中,新的类会从左到右继承父类的属性和方法。 后面类的属性和方法具有最高的优先权,即最后一个类的属性或者方法会被使用。
- 如果props 参数提供的属性或方法如果跟被继承的类的属性或方法同名,那么会重写同名的方法或属性。
2 示例
//定义基类Person
declare("Person", null,{
name:null,
age:null,
constructor: function(args){
this.name = args.name;
this.age = args.age;
},
getName:function(){
return this.name;
},
getAge:function(){
console.log(this.age);
}
});
})
2.1 单继承
下面定义了Employee
类和Shareholder
类,它们都继承于Person
类。Employee
类添加了workExperience
属性,并重写了Person
类中的getName
方法,同时添加了getWorkExperience
和getInput
方法。
Shareholder
类添加了share
属性,并添加了getShare:function
方法。
//下面定义了类Employee,其继承于Person类
declare("Employee", Person,{
workExperience:null,
constructor: function(args){
this.workExperience = args.workExperience;
},
getWorkExperience:function(){
console.log(this.workExperience);
},
getName:function(){
return "Employee:"+this.name;
},
getSalary:function(){
return 5000;
}
})
var employee1 = new Employee({name:"peter",age:"27",workExperience:"4"});
employee1.getWorkExperience(); //4
employee1.getName(); //Employee:peter
employee1.getAge(); //27 调用父类中的方法
可以看到在Employee
的实例中,我们能够调用父类中定义的方法。而在类的constructor
初始化方法中,我们并没有调用父类相关的方法,但是我们成功初始化了name
和age
两个属性,这是因为dojo会自动调用父类的初始化方法,完成继承要求的相关初始化工作。
2.2 多继承
dojo支持多继承的功。使用dojo的多继承功能时,需要注意的是:只有数组中的第一个元素会作为真正的父类,而其它的元素则是通过mixin的方式进行属性添加以构建原型链的。
例如,这里定义了一个类表示股票持有者,而公司中的员工也可能会持有股票,因此定义了一个ShareholderEmployee
来表示这个群体,该类继承于Shareholder
类和Employee
类。
//下面定义了Shareholder类,继承于Person类
declare("Shareholder", Person,{
share:null,
constructor: function(args){
this.share = args.share;
},
getShare:function(){
return this.share;
}
});
//下面定义了类ShareholderEmployee,其继承于Employee和Shareholder类
declare("ShareholderEmployee", [Employee,Shareholder],{
getInfo:function(){
console.log("I'm an Employee with stock.My share is "+this.getShare()+"."+"My name is "+this.getName()+".");
}
});
var shareholderEmployee1 = new ShareholderEmployee({name:"levin",age:30,workExperience:4,share:300});
shareholderEmployee1.getInfo(); //I'm an Employee with stock.My share is 300.My name is Employee:levin.
至此,我们通过多继承的方式实现了一个类用来描述持有股票的员工。
2.3 调用父类方法
在编程中,我们经常会遇到在子类的某个方法中需要调用父类的方法来协作完成功能。例如,我们又定义了一个名为Manager
的类,该类继承自Employee
类,并重写getInput
方法,Manager
的收入分为两部分,一部分是与 Employee
相同的固定收入,另一部分是与管理经验相关的其它收入,这样在定义Manager
的时候,就需要调用父类的方法。可以使用this.inherited(arguments)
语句调用父类的同名方法。例如:
declare("Manager", Employee,{
manageExperience:null,
constructor: function(args){
this.manageExperience = args.manageExperience;
},
getSalary:function(){
var fromBase = this.inherited(arguments);
return fromBase+1000*this.manageExperience;
}
})
var manager = new Manager({name:"levin",age:30,workExperience:4,manageExperience:2});
console.log(manager.getSalary()); //7000
从以上代码可以看到,通过inherited
方法的使用,使得Manager
可以调用父类的方法。
3 关于原型继承
类声明中可以给原始类型(number, string, boolean) 定义默认的值, 然后在实例对像中可以直接修改。 但是,如果你给原型上的属性分配的是一个对象(Object, Array), 那么每一个实例会共享同一个值。在实例中修改会在原型中体现出来。
例如,定义了一个Student
类:
declare("Student",null,{
name:"jack",
age:"13",
favoriteColor:["red","black","green"]
})
该类中包含了三个属性,两个原始类型属性:name(string类型)
、age(number类型)
,一个对象类型:favoriteColor(array类型)
。
var stu1 = new Student();
var stu2 = new Student();
console.log(stu1.name===stu2.name); //true
stu2.name = 'rose';
console.log(stu1.name===stu2.name); //false
console.log(stu1.age===stu2.age); //true
console.log(stu1.age); // 13
对Student类实例化得到两个对象stu1
和stu2
,可以对实例对象中基本类型的属性进行修改,而这并不会影响到原型对象。
而当我们在实例中对对象类型的属性进行修改时,这会修改原型中的属性:
console.log(stu1.favoriteColor===stu2.favoriteColor); //true
stu2.favoriteColor.push("yellow","blue");
console.log(stu1.favoriteColor===stu2.favoriteColor); //true
console.log(stu1.favoriteColor); //["red", "black", "green", "yellow", "blue"]
console.log(stu2.favoriteColor); //["red", "black", "green", "yellow", "blue"]
可以看到此时的原型中favorite
属性已被修改:
为了避免非故意的修改共享的数组或者对象, 对象的属性应该声名为null 然后在构造函数中对它初始化。
declare("Student",null,{
name:null,
age:null,
favoriteColor:null,
score:null,
constructor:function(name,age){
this.name = name;
this.age = age;
this.favoriteColor = [];
this.score = {};
}
})
stu3 = new Student("Rose","12")
stu3.favoriteColor = ["red","black","green"];
stu3.score = {"语文":90,"数学":93}
console.log(stu3);
输出结果: