面向对象原型的七种方法详解(前)

1. 工厂模式
2. 构造函数模式
3. 原型模式
4. 混合构造函数和原型模式
5. 动态原型模式
6. 寄生构造函数模式
7. 稳妥构造函数模式

普通模式
var obj=new Object();
   obj.name="罗桂鑫";
   obj.age=18;
   obj.run=function(){
   return this.name+"+"+this.age+"+"+"100";
   }
   alert(obj.run());

 

 

一。工厂模式

为了解决多个类似对象声明的问题,我们可以使用一种叫做工厂模式的方法,这种方法就是为了解决实例化对象产生大量重复的问题。

function show(name,age){
var obj=new Object();
obj.name=name;
obj.age=age;
obj.run=function(){
return this.name+"+"+this.age+"+"+"100";
};
return obj;
};
var box1=show("罗桂鑫",18);
var box2=show("罗桂鑫",20);
alert(box1.run());
alert(box2.run());
alert(box1.instanceof Object);
alert(box1.instanceof Object);//不管怎样,他们都是Object类型,返回都是true.

问题:工厂模式解决了重复实例化的问题,但还有一个问题,就是识别问题,因为根本无法搞清楚他们到底是哪个对象的实例。

二。构造函数模型

使用构造函数的方法,即解决了重复实例化的问题,又解决了对象识别的问题,但问题
是,这里并没有 new Object(),为什么可以实例化 Box(),这个是哪里来的呢?
使用了构造函数的方法,和使用工厂模式的方法他们不同之处如下:
1.构造函数方法没有显示的创建对象(new Object());
2.直接将属性和方法赋值给 this 对象;
3.没有 renturn 语句。
构造函数的方法有一些规范:
1.函数名和实例化构造名相同且大写,(PS:非强制,但这么写有助于区分构造函数和
普通函数);
2.通过构造函数创建对象,必须使用 new 运算符。

function Show(name,age){
this.name=name;
this.age=age;
this.run=function(){
return this.name+"+"+this.age+"+"+"100";
};
}
function Show2(name,age){
this.name=name;
this.age=age;
this.run=function(){
return this.name+"+"+this.age+"+"+"100";
};
}
var box1=new Show("罗桂鑫",18);//实例化
var box2=new Show2("罗桂鑫",18);//实例化

var box3=new Show2("罗桂鑫",18);//实例化
// alert(box1.run());
// alert(box2.run());
// alert(box1 instanceof Show);//true
// alert(box3 instanceof Show);//false 因为box2是Show2对象的引用,所以返回false
// alert(box1.run()==box2.run());//true //值相同
// alert(box1.run==box2.run); //false //引用地址不同

function Show(name,age){
this.name=name;
this.age=age;
this.run=run;
};
function run(){ //把构造函数内部的方法通过全局来实现引用地址一致,但是外部也可以调用。所以不推荐
return this.name+"+"+this.age+"+"+"100";
};
var box1=new Show("罗桂鑫",18);//实例化
var box2=new Show("罗桂鑫",18);//实例化
alert(box1.run==box2.run);//true

-----------对象冒充的两种方法
function Show(name,age){
this.name=name;
this.age=age;
this.run=function(){
return this.name+this.age+"+"+"100";
};
}
var box1=new Show("罗桂鑫",18);//实例化
alert(box1.run());
var obj=new Object();
Show.call(obj,"lee",100); //使用call对象冒充
alert(obj.run());
Show.apply(obj,["tin",100]); //使用apply对象冒充
alert(obj.run());

三。原型模型

创建的每个函数都有一个 prototype(原型)属性,这个属性是一个对象,它的用途是
包含可以由特定类型的所有实例共享的属性和方法。逻辑上可以这么理解:prototype 通过
调用构造函数而创建的那个对象的原型对象。使用原型的好处可以让所有对象实例共享它所
包含的属性和方法。也就是说,不必在构造函数中定义对象信息,而是可以直接将这些信息
添加到原型中。

原型模式的执行流程:
1.先查找构造函数实例里的属性或方法,如果有,立刻返回,实例属性不会共享;
2.如果构造函数实例里没有,则去它的原型对象里找,如果有,就返回;

function box(){
}
box.prototype.name="罗桂鑫";
box.prototype.age=18;
box.prototype.run=function(){
return this.name+"+"+this.age+"+"+"100";
};
var box1=new box();
var box2=new box();
alert(box1.run());
alert(box1.run==box2.run);//true
//如果是实例方法,不同的 实例化,他们的方法地址是不一样的
//如果是原型方法,地址是共享的

// 判断一个对象是否指向了该构造函数的原型对象,可以使用 isPrototypeOf()方法来测试。
alert(box.prototype.isPrototypeOf(box1)); //只要实例化对象,即都会指向
alert(box1.hasOwnProperty("name"));//判断实例中是否存在制定属性
alert("name" in box1); //无论该属性存在于实例中还是原型中。只要存在就返回true

function isProperty(object, property) { //判断原型中是否存在属性
return !object.hasOwnProperty(property) && (property in object);
}
alert(isProperty(box1, 'name'));

 

字面量创建的方式使用 constructor 属性不会指向实例,而会指向 Object,构造函数创建
的方式则相反。

function Box(){}
//使用字面量的方式创建原型对象,这里{}就是对象,是Object,new Object就相当于{}
Box.prototype={
constructor:Box, //强制指向Box
name:'lee',
age:100,
run:function(){
return this.name+this.age+"运行中...";
}
};

//重写了原型对象
Box.prototype={
age:200 //这里不会保留之前原型的任何信息了,把原来的原型对象和构造函数对象实例之前的关系切断了
};
var box=new Box();
alert(box.name);
alert(box.constructor==Box); //true

原型模式创建对象也有自己的缺点,它省略了构造函数传参初始化这一过程,带来的缺
点就是初始化的值都是一致的。而原型最大的缺点就是它最大的优点,那就是共享。

 

posted @ 2016-12-07 17:51  不再犯错  阅读(1132)  评论(0编辑  收藏  举报