设计工工厂模式
工厂模式是一种创建类型的模式,目的是为简化创建对象的流程,它把对象实例化简单封装在一个函数中,然后通过函数调用,实现快速、批量生产对象。
function createCar(sColor,iDoors,iMpg){
var oTempCar=new Object;
oTempCar.color=sColor;
oTempCar.doors=iDoors;
oTempCar.mpg=iMpg;
oTempCar.showColor=function(){
alert(this.color);
};
return oTempCar;
}
var oCar1=createCar("red",4,23);
var oCar2=createCar("blue",3,26);
oCar1.showColor(); //red
oCar2.showColor(); //blue
function showColor(){
alert(this.color);
}
function createCar(sColor,iDoors,iMpg){
var oTempCar=new Object;
oTempCar.color=sColor;
oTempCar.doors=iDoors;
oTempCar.mpg=iMpg;
oTempCar.showColor=showColor;
return oTempCar;
}
var oCar1=createCar("red",4,23);
var oCar2=createCar("blue",3,26);
oCar1.showColor(); //red
oCar2.showColor(); //blue
设计类继承
类继承设计方法:在子类中执行父类的构造函数。在JavaScript中实现类的继承,需要考虑和设置下面3点:
- 在构造函数B的结构体内,使用call()函数调用构造函数A,把B的参数x传递给调用函数。让B能够继承A的所有属性和方法,即A.call(this.,x);语句行。
- 在构造函数A和B之间建立原型链,即B.prototype=new A();语句行。
- 恢复B原型对象的构造函数,即B.prototype.constructor=B;语句行。
function A(x){
this.get1=function(){
return x;
}
}
A.prototype.has=function(){//原型方法
return ! (this.get1()==0);
}
function B(){
var a=[];
a=Array.apply(a,arguments);
A.call(this,a.length);
this.add=function(){
return a.push.apply(a,arguments);
}
this.geta=function(){
return a;
}
}
B.prototype=new A();//设置B类的原型为A类的实例,从而创建原型链
B.prototype.constructor=B;//恢复B类原型对象的构造器
B.prototype.str=function(){
return this.geta().toLocaleString();
}
function C(){
B.apply(this,arguments);
this.sort=function(){
var a=this.geta();
a.sort.apply(a,arguments);
}
}
C.prototype=new B();
C.prototype.constructor=C;
var b=new B(1,2,3,4);
alert(b.get1()); //4
alert(b.has());//true
var c=new C(30,10,20,40);
c.add(6,5);
alert(c.geta()); //30,10,20,40,6,5
c.sort();
alert(c.geta());//10,20,30,40,5,6
alert(c.get1());//4
alert(c.has());//true
alert(c.str());//10,20,30,40,5,6
把类继承封装起来。
定义封装函数。
function extend(Sub,Sup){//类继承封装函数
//其中参数Sub表示子类,Sup表示超类
}
恢复子类原型的构造器子类自己。
function extend(Sub,Sup){//类继承封装函数
//其中参数Sub表示子类,Sup表示超类
var F=function(){};//定义一个空函数
F.prototype=Sup.prototype;//设置空函数F的原型为超类的原型
Sub.prototype=new F();//实例化空函数,并把超类原型引用传递给子类
Sub.prototype.constructor=Sub;//恢复子类原型的构造器为子类自身
Sub.sup=Sup.prototype;//为子类定义一个本地属性存储超类原型
if(Sup.prototype.constructor==Object.prototype.constructor){
//检测超类原型构造器是否为自身
Sup.prototype.constructor=Sup;//类封装函数
}
}
设计构造原型模式
原型模式存在两个问题
- 由于构造函数事先声明,而原型属性在类结构声明之后才被定义,因此无法通过构造函数参数向原型属性动态传递值。这样该类实例化所有对象都是一个模样,没有个性。要改变原型属性值,则所有实例都受到干扰。
- 当原型属性的值为引用类型数据,如果在一个对象实例中修改该属性值,将会影响所有的实例。
function Book(title,pages){
this.title=title;
this.pages=pages;
}
Book.prototype.what=function(){
alert(this.title+this.pages);
};
var book1=new Book("javascript程序设计",160);
var book2=new Book("C程序设计",240);
alert(book1.title); //javascript程序设计
alert(book2.title); //C程序设计*/
定义两个类并绑定为继承关系。
function A(x){
this.x=x;
this.get=function(){
return this.x;
}
}
A.prototype.add=function(){
return this.x+this.x;
}
A.prototype.mul=function(){
return this.x*this.x;
}
function B(x){
A.call(this,x);
}
extend(B,A);
var f=new B(5);
alert(f.get()); //5
alert(f.add()); //10
alert(f.mul()); //25
设计动态原型模式
根据面向对象设计原则,所有成员应该都被封装在类结构体内。
function Book(title,pages){
this.title=title;
this.pages=pages;
if(typeof Book.isLock=="undefined"){ //创建原型方法的锁,如果不存在则创建
Book.prototype.what=function(){
alert(this.title+this.pages);
};
Book.isLock=true; //创建原型方法后,把锁锁上,避免重复创建
}
}
var book1=new Book("javascript程序设计",160);
var book2=new Book("C程序设计",240);
alert(book1.title); //javascript程序设计
alert(book2.title); //C程序设计
动态原型模式与构造函数原型模式在性能上是等价的,用户可以自由选择,不够构造函数原型模式应用比较广泛。
设计实例继承
类继承和原型继承在客户端中是无法继承DOM对象的,同时他们也不支持继承系统对象和方法。
使用类继承法继承Date对象。
function D(){
Date.apply(this.arguments);
}
var d=new D();
alert(d.toLocaleString());
使用原型继承法继承Date对象。
function D(){
var d=new Date();
d.get=function(){
alert(d.toLocaleString());
}
return d;
}
var d=new D();
d.get();
使用实例继承法能够实现对所有对象的继承,包括自定义类、核心对象和DOM对象等。不够实例继承不是真正的继承机制,仅是一种模拟方法。
- 实例继承法无法传递动态参数。
- 实例继承只能返回一个对象,与原型继承一样,不支持多重继承。
- 由于通过封装的方法把对象实例化,以及初始化操作都被封装在一个函数体内,最后通过对封装函数执行实例化操作来获取继承的对象。但是这种做法无法真正实现继承对象是封装类的实例,它仍然保持与原对象的实例关系。
惰性实例化
惰性如果在页面中没有使用这个实例化的对象,实例化所要解决的问题是:避免了在页面中JavaScript初始化执行的时候就实例化类,就会造成了一定内存浪费和性能消耗。如果能够将一些类的实例化推迟到需要使用它的时候才开始去实例化,就可以避免资源过早损耗,做到“按需供应”。
var myNamespace2=function(){
var Configure=function(){
var privateName="someone's name";
var privateReturnName=function(){
return privateName;
}
var privateSetName=function(name){
privateName=name;
}
return {
setName:function(name){
privateSetName(name);
},
getName:function(){
return privateReturnName();
}
}
}
var instance;
return {
init:function(){
if(!instance){
instance=Configure();
}
for(var key in instance){
if(instance.hasOwnProperty(key)){
this[key]=instance[key];
}
}
this.init=null;
return this;
}
}
}();
myNamespace2.init();
myNamespace2.getName();
安全构造对象
构造函数其实是一个使用new运算符的函数。当使用new调用时,构造函数的内部用到的this对象会指向新创建的实例。
function Person(name.age,jog){
this.name=name;
this.age=age;
this.job=job;
}
var person=new Person("Nicholas",34,'software engineer');
function Person(name.age,jog){
if(this instanceof Person){
this.name=name;
this.age=age;
this.job=job;
}else{
return new Person(name,age,job);
}
}
如果使用的构造函数获取继承且不使用原型链,那么这个继承可能就被破坏。
function Polygon(sides){
if(this instanceof Polygon){
this.sides=sides;
this.getArea=function(){
return 0;
}
}else{
return new Polygon(sides);
}
}
function Rectangle(width,height){
Polygon.call(this,2);
this.width=width;
this.height=height;
this.getArea=function(){
return this.width*this.height;
}
}
Rectangle.prototype = new Polygon(); //使用原型链
var rect=new Rectangle(5,10);
alert(rect.sides); //2