面向对象类型系统
•合理使用面向对象编程
–提高复用性,提高可维护性,etc.
–并非提高软件质量的保证
•可以使用各种成熟的设计方式
–模式,etc
•不拘泥于使用OO方式扩展对象
–结合JavaScript的动态特性
–下一次课程
命名空间
•合理的组织大量的类型
–使开发人员能够方便地找到他们所需要的类型
–并非仅仅为了避免命名冲突
•可重复注册
–每个独立的脚本模块前都要注册命名空间以保证命名空间存在
Type.registerNamespace(“MyNamespace”);
类
•定义步骤:
–定义构造函数
–定义成员(方法、属性、事件)
–注册类
类–构造函数
•类的构造函数即为function定义
•通常用于初始化域变量
•私有成员使用下划线开头(无法真正封装)
–this._myPrivateField;
–this._myPrivateMethod();
类–构造函数
Type.registerNamespace("MyNamespace");
MyNamespace.MyClass= function(param1, ...){
this._myField= null;
...
}
类–定义方法
•基于prototype定义
MyNamespace.MyClass.prototype = {
myMethod1 : function() { ... },
myMethod2 : function(){
this.myMethod1(); // this保留字不可少
}
}
类–定义属性
•Microsoft AJAX Library的面向对象类型系统将add_和set_开头的方法认作属性
•避免定义只写属性,使用某个方法替代
类–定义属性
MyNamespace.MyClass = function(param1, ...) {
this._myProperty = null;
}
MyNamespace.MyClass.prototype = {
get_myProperty : function(){
return this._myProperty;
},
set_myProperty : function(value){
this._myProperty = value;
}
}
类–注册类
MyNamespace.MyClass = function(param1, ...) {
// …
}
MyNamespace.MyClass.prototype = {
// …
}
MyNamespace.MyClass.registerClass(
'MyNamespace.MyClass');
定义及使用类
<
form id
=
"
form1
"
runat
=
"
server
"
>
<
asp:ScriptManager ID
=
"
ScriptManager1
"
runat
=
"
server
"
ScriptMode
=
"
Debug
"
>
<
Scripts
>
<
asp:ScriptReference Path
=
"
Employee.js
"
/>
</
Scripts
>
</
asp:ScriptManager
>
<
div id
=
"
info
"
></
div
>
<
script language
=
"
javascript
"
type
=
"
text/javascript
"
>
function display(text)
{
document.getElementById(
"
info
"
).innerHTML
+=
(text
+
"
<br />
"
);
}
var jeffz
=
new
MyNamespace.Intern(
"
Jeffrey Zhao
"
);
jeffz.set_year(
3
);
display(jeffz.getDescription());
var tom
=
new
MyNamespace.Vendor(
"
Tom
"
);
tom.set_year(
3
);
display(tom.getDescription());
var jerry
=
new
MyNamespace.FulltimeEmployee(
"
Jerry
"
);
jerry.set_year(
5
);
display(jerry.getDescription());
display(
"
jeffz implements 'IEmployee' interface:
"
+
MyNamespace.IEmployee.isImplementedBy(jeffz));
var type
=
MyNamespace.EmployeeType.toString(tom.get_type());
display(String.format(
"
{0} is a {1}.
"
, tom.get_name(), type));
var all
=
MyNamespace.MyFlags.All;
display(MyNamespace.MyFlags.toString(all));
display(MyNamespace.MyFlags.parse(
"
Item1, Item3
"
));
</
script
>
</
form
>
Employee.js
Type.registerNamespace(
"
MyNamespace
"
);
MyNamespace.EmployeeType
=
function()
{
throw
Error.notImploemented();
}
MyNamespace.EmployeeType.prototype
=
{
Intern :
0
,
Vendor :
1
,
FulltimeEmployee :
2
}
MyNamespace.EmployeeType.registerEnum(
"
MyNamespace.EmployeeType
"
);
MyNamespace.IEmployee
=
function()
{
throw
Error.notImplemented();
}
MyNamespace.IEmployee.prototype
=
{
calcaulateSalary : function()
{
throw
Error.notImplemented();
},
get_type : function()
{
throw
Error.notImplemented();
}
}
MyNamespace.IEmployee.registerInterface(
"
MyNamespace.IEmployee
"
);
MyNamespace.Employee
=
function(name)
{
this
._name
=
name
?
name :
"
[Anonymous]
"
;
this
._year
=
0
;
}
MyNamespace.Employee.prototype
=
{
get_name : function()
{
return
this
._name;
},
get_year : function()
{
return
this
._year;
},
set_year : function(value)
{
this
._year
=
value;
},
calculateSalary : function()
{
throw
Error.notImplemented();
},
getDescription : function()
{
return
String.format(
"
{0} gets {1} yuan per month.
"
,
this
._name,
this
.calculateSalary());
}
}
MyNamespace.Employee.registerClass(
"
MyNamespace.Employee
"
,
null
,
MyNamespace.IEmployee);
MyNamespace.Intern
=
function(name)
{
MyNamespace.Intern.initializeBase(
this
, [name]);
}
MyNamespace.Intern.prototype
=
{
calculateSalary : function()
{
return
2000
;
},
getDescription : function()
{
var description
=
MyNamespace.Intern.callBaseMethod(
this
,
"
getDescription
"
);
return
description
+
"
What a poor intern!
"
;
},
get_type : function()
{
return
MyNamespace.EmployeeType.Intern;
}
}
MyNamespace.Intern.registerClass(
"
MyNamespace.Intern
"
, MyNamespace.Employee);
MyNamespace.Vendor
=
function(name)
{
MyNamespace.Vendor.initializeBase(
this
, [name]);
}
MyNamespace.Vendor.prototype
=
{
calculateSalary : function()
{
return
5000
+
1000
*
(
this
.get_year()
-
1
);
},
get_type : function()
{
return
MyNamespace.EmployeeType.Vendor;
}
}
MyNamespace.Vendor.registerClass(
"
MyNamespace.Vendor
"
, MyNamespace.Employee);
MyNamespace.FulltimeEmployee
=
function(name)
{
MyNamespace.FulltimeEmployee.initializeBase(
this
, [name]);
}
MyNamespace.FulltimeEmployee.prototype
=
{
calculateSalary : function()
{
return
15000
+
2000
*
(
this
.get_year()
-
1
);
},
get_type : function()
{
return
MyNamespace.EmployeeType.FulltimeEmployee;
}
}
MyNamespace.FulltimeEmployee.registerClass(
"
MyNamespace.FulltimeEmployee
"
, MyNamespace.Employee);
///////////////////////////////////////
MyNamespace.MyFlags
=
function()
{
throw
Error.notImplemented();
}
MyNamespace.MyFlags.prototype
=
{
Item1 :
1
,
Item2 :
2
,
Item3 :
4
,
None :
0
,
All :
7
}
MyNamespace.MyFlags.registerEnum(
"
MyNamespace.MyFlags
"
,
true
);
//
Item1 + Item3
//
Item1 | Item3 (preferred)