首先是生成对象的模式:
1工厂模式:
用函数封装特定接口创建对象的细节:
function createPerson(name,age,job){
var o=new Object();
o.name=name;
.....
return o;
}
var person1= createPerson(.....);
var person2= createPerson(......);
缺点:未解决对象识别的问题(怎样知道一个对象的类型)。
2构造函数模式:
创建自定义的构造函数。
function Person(name,age,job){
this.name=name;
this.sayname=new Function("alert(this.name)");
....
}
var person1=new Person(...........);
var person2=new Person(...........);
Person方法与工厂模式的createPerson方法不同之处:没显式地创建对象。直接将属性和方法赋给this对象。没有return语句.
对比工厂模式,构造函数模式创建自定义的构造函数意味着将来可以将它的实力标识为一种特定类型。
缺点:每个在构造函数里边的方法在每个实例上都要重新创造一遍。Function实例也是对象。person1的sayname和person2的sayname是不一样的。
如果将this.sayname=sayname;
在构造函数外声明:
function sayname(){
alert(...);
}
虽然sayname此时指向同一个函数的指针。但是全局作用域的函数怎么只能让某一个对象调用呢?此外,如果有很多这样的方法,在全局内就要定义很多。毫无封装性可言。
3原型模式
function person(){}
person.prototype.name="........";
......
......
var person1=new person();
可以用对象字面量来重写整个原型对象:
person.prototype={
name:"........",
.........
}
也会存在问题,如果属性里边的值是引用类型的话,那么修改的后果的波及范围是很大的。比如说属性的值是数组。。。
解决方案:组合使用构造函数模式和原型模式。
构造函数模式用于定义实例属性,而原型模式用于定义方法和共享属性。这样,每个实例都会有自己的一份实例属性的副本,同时共享对方法的引用。节省了内存。
function Person(name,age,job)
{
this.name=name;
.........................
}
Person.prototype={
constructor:Person,
sayName:function(){
.............};
}
在前几种模式都不适用的情况下可以使用寄生构造函数模式(其实和工厂模式差别就在于有个new)。
例子:
function Person(name,age,job){
var o=new Object();
o.name=name;
.....
return o;
}
var person1=new Person(.....);
var person2=new Person(......);
以及稳妥构造函数模式,稳妥与寄生大体相似.但有两点不同,一是新创建对象的实力方法不引用this,二是不实用new来调用构造函数。
继承:
原型链
关键在于:
SubType.prototype=new SuperType();
谨记!在通过原型链实现继承是,不能使用对象字面量创建原型方法!否则会重写原型链。
原型链一样也会出属性值是引用类型的问题。第二个问题:创建子类型的实力时,不能向超类构造函数传递参数。
借用构造函数(有时候叫做伪造对象或者经典继承)。
思想非常简单:在子类型构造函数的内部调用超类型的构造函数。
function supertype(name)
{
this.color=["red","green"];
this.name=name;
}
function subtype()
{
supertype.call(this,"nicholas");
}
var a=new subtype();
var b=new subtype();
这样,引用类型值得数组就不是共享的了。而是两份副本。而且也可以传递参数了。
缺点:方法都在构造函数都定义好,函数的复用就无从谈起了。单独使用就少了。
组合继承(伪经典继承)
指将原型链和借用构造函数的技术组合到一块。原型链实现对原型属性和方法的继承,二通过借用构造函数来实现对实力属性的继承。见书169页!!!虽然组合继承是javascript最常见的继承模式,但是无论什么情况下都会调用超类型的构造函数两次!!!一次是在call的时候一次是在原型继承的时候。这时候实例属性就会屏蔽原型中的同名属性。
那么寄生组合模式是最理想的继承范式。
function inheritPrototype()
{
var prototype=object(superType.protype); 创建对象
prototype.constructor=subType;
subType.prototype=prototype
}
用这个方法来代替对原型赋值的语句。