document.writeln(e1[i].ID);
}
document.write("
")
注意:
这种表达形式是对象数组的JSON表达
∙通过函数定义来创建一个类定义
functionEmployee(id,name,email){
this.ID=id;
this.Name=name;
this.Email=email;
}
varo4=newEmployee(4,"Jerry4","jerry4@");
document.writeln("o4:
"+o4.ID+","+o4.Name+","+o4.Email+"
");
Employee函数实际上也是Emplyee类的构造函数
类成员的可访问性
案例代码:
03accessibility.html
∙this关键字:
在某个函数中使用this时,this代表调用该函数的对象实例
∙在类的构造函数中,this同样代表正在创建的对象实例
functionEmployee(id,name,email){
this.ID=id;
this.Name=name;
this.Email=email;
}
在构造函数中,因为没有使用var定义变量,因此ID,Name,Email都是全局上下文变量,可以从Employee外部代码中访问,即它们都是"公有成员"
∙公有成员变量可以通过对象实例直接访问:
varo1=newEmployee(1,"Jerry1","jerry1@");
document.writeln("o1:
"+o1.ID+","+o1.Name+","+o1.Email+"
");
∙如果在Employee类中定义了函数,则该函数是"私有成员",不可从外部访问
functionEmployee(id,name,email){
this.ID=id;
this.Name=name;
this.Email=email;
functionHello(){
}
}
函数Hello无法从Employee类外部访问。
∙如果希望数据成员是"私有"的,必须采用var来声明该成员
functionEmployee2(id,name,email){
varID=id;
varName=name;
varEmail=email;
}
此时将不能再通过对象来直接访问ID等属性
类成员函数
案例代码:
04method.html
∙除了定义成员变量,也可以在类中定义函数
functionEmployee(id,name,email){
varID=id;
varName=name;
varEmail=email;
//hello被定义在全局上下文中,它也并不属于类Employee
hello=function(){
document.writeln("Hello");
// 尽管此处也能访问ID,Name等,但因为没有关联的对象实例,因此没有意义
}
// 加上this前缀后,display被视为当前employee对象实例的一个"成员函数"
// 它并不属于全局名字空间
this.display=function(){
// 不能通过this.ID来访问成员变量。
因为varID只是一个局部变量,并不是this对象的属性。
document.writeln(ID+","+Name+","+Email);
}
// 如果定义 vardisplay=function()..., 那么display将变成"私有函数"
}
∙如果希望函数是公有的,那么可以采用this.myfunction=function(){…}方式
∙如果函数私有,那么采用 varmyfunction=function(){…}. 但是这种方法不常用
∙如果没有任何修饰,直接定义函数(如例子中的hello),那么hello会被定义在全局上下文中,不是类Employee的成员函数
∙函数的多个"实例"问题
varo1=newEmployee(1,"Jerry1","jerry1@");
varo2=newEmployee(2,"Jerry2","jerry2@");
∙o1对象创建时,除了ID,Name和Email外,display函数也会被"实例化"
∙o2对象创建时,display函数会被再次实例化
∙因此,有多少个对象实例,就会有多少个display函数的实例。
这一点与Java等语言有着重大不同
在类外定义函数
案例代码:
05outsidemethod.html
∙如上节所述,类内部的函数定义会随着对象实例化被多次实例化。
为解决这一问题,可以尝试在类外部定义函数:
functionEmployee(id,name,email){
this.ID=id;
this.Name=name;
this.Email=email;
// 使display指向外部的一个函数
this.display=displayEmployee;
}
functiondisplayEmployee(){
//this代表调用该函数的对象实例
// 因此后面的o1.display代码意味着:
this代表o1对象
document.writeln(this.ID+","+this.Name+","+this.Email+"
");
}
∙类成员函数display指向类外部定义的函数displayEmployee
∙无论创建多少个Employee对象实例,它们的display函数都指向同一个的displayEmployee
∙在类外函数中访问私有成员
o类外函数不能访问类中的私有成员,因此必须为私有成员创建公有访问器
functionEmployee2(id,name,email){
varID=id;
varName=name;
varEmail=email;
this.getID=function(){returnID;}
this.getName=function(){returnName;}
this.getEmail=function(){returnEmail;}
}
o这样就可以从类外函数调用公有访问器了
functiondisplayEmployee2(){
//this代表调用此函数的对象实例
// 本函数不能直接访问私有成员,必须借助属性访问器
document.writeln(this.getID()+","+this.getName()+","+this.getEmail()+"
");
Prototype
代码案例:
06prototype.html
∙JavaScript为每个类型提供了prototype,以代表该类型的"原型"
∙任何类型只有一个原型,在原型中定义的函数,被所有对象实例共享。
因此使用原型也可以非常方便的定义类成员函数
functionEmployee(id,name,email){
this.ID=id;
this.Name=name;
this.Email=email;
}
Employee.prototype.display=function(){
//this代表调用该函数的对象实例
document.writeln(this.ID+","+this.Name+","+this.Email+"
");
}
∙使用prototype后,display函数不用定义在类中,可以在类外直接定义
∙如果要访问私有变量,还是需要通过公有访问器
functionEmployee2(id,name,email){
varID=id;
varName=name;
varEmail=email;
// 定义公有属性访问器
this.getID=function(){returnID;}
this.getName=function(){returnName;}
this.getEmail=function(){returnEmail;}
}
Employee2.prototype.display=function(){
//this代表调用此函数的对象实例
// 本函数不能直接访问私有成员(即使通过prototype),必须借助属性访问器
document.writeln(this.getID()+","+this.getName()+","+this.getEmail()+"
");
}
名字空间
案例代码:
07namespace.html
∙默认情况下只有一个名字空间:
全局名字空间
o所有变量、函数都在全局名字空间中存在(通过var在函数中声明的内容除外)
o一个网页上很可能包含多个JS文件,这些JS文件中定义的类、函数、变量等也都处于全局名字空间中
o这样就很可能造成名字冲突。
因此有必要定义子名字空间
∙定义子名字空间:
varmyApp={}; //myApp作为子名字空间定义在全局名字空间中
myApp.i=1; //i不在全局名字空间中
//Employee是定义在myApp名字空间中的
myApp.Employee=function(id,name,email){
this.ID=id;
this.Name=name;
this.Email=email;
}
myApp.Employee.prototype.display=function(){
document.writeln(this.ID+","+this.Name+","+this.Email+"
");
}
∙名字空间有点类似于Java中的Package名或C#中的namespace
多个名字空间
案例代码:
08multiplenamespace.html,scripts/08namespace1.js,scripts/08namespace2.js, scripts/08namespace3.js,
∙在多个JS文件中,可以定义相同或不同的名字空间
o定义不同的名字空间,可以防止类名的冲突
o如果希望在不同JS文件中定义相同名字空间,那么应该采用下列代码:
varns=ns||{}
上面代码表明:
如果ns曾经定义过,那么继续沿用;如果没定义过,那么创建一个新名字空间"{}"
∙08namespace1.js
varsales=sales||{};
sales.Product=function(id,name,price){
this.ID=id;
this.Name=name;
this.Price=price;
}
sales.Product.prototype.display=function(){
document.writeln("SalesProduct:
ID="+this.ID+",Name="+
this.Name+",Price="+this.Price+"
");
}
∙定义了sales名字空间,及其内部的Product类
∙08namespace2.js
varsales=sales||{};
sales.Customer=function(id,name,address){
this.ID=id;
this.Name=name;
this.Address=address;
}
sales.Customer.prototype.display=function(){
document.writeln("SalesProduct:
ID="+this.ID+",Name="+
this.Name+",Address="+this.Address+"
");
}
∙同样适用sales名字空间,并且定义了Customer类
∙现在Product和Customer类都属于sales名字空间
∙08namespace3.js
varstock=stock||{};
stock.Product=function(id,name,quantity){
this.ID=id;
this.Name=name;
this.Quantity=quantity;
}
stock.Product.prototype.display=function(){
document.writeln("StockProduct:
ID="+this.ID+",Name="+
this.Name+",Quantity="+this.Quantity+"
");
}
∙定义了stock名字空间及其内部的Product类
∙不同名字空间中的同名类不会发生名字冲突:
varp1=newsales.Product(101,"MK101型自行车",1999.0);
vars1=newstock.Product(101,"MK101型自行车",10);
立即自行执行的函数
案例代码:
09IIFE.html, 09IIFE.js
∙如果希望某个函数在定义后立即执行一次,可以使用IIFE函数(ImmediatelyInvokdedFunctionExpression)
varresult1=(function(){
return"HelloIIFE!
";
})();
∙上述函数将立即执行,将结果返回给result1
∙IIFE函数是匿名函数
∙IIFE函数仅执行一次
∙也可以使用带参数的IIFE
varresult2=(function(num){
vartotal=0;
for(vari=1;i<=num;i++){
total+=i;
}
returntotal;
})(10);
∙实际参数(10)将被传递给形式参数(num)
∙如需带多个参数,可用逗号隔开
∙可以通过IIFE来定义一个类
varPeople=(function(){
functionPeople(name,birthday){
this.Name=name;
this.Birthday=birthday;
}
People.prototype.display=function(){
document.writeln("姓名:
"+this.Name+", 出生日期:
"+this.Birthday.toLocaleDateString());
}
returnPeople;
})();
∙在IIFE内部定义类,然后返回该类定义
∙"="左边的People就代表了IIFE函数内部的People类定义(请注意,该People不是对象实例,而是类定义)
∙在JS文件中使用IIFE(09IIFE.js文件)
(function(){
//Employee类定义是私有的
varEmployee=function(id,name,email){
this.ID=id;
this.Name=name;
this.Email=email;
}
Employee.prototype.display=function(){
document.writeln(this.ID+","+this.Name+","+t