1、创建原型访问prototype有两种方法
(1)构造函数实例方法创建
构造函数:在对象创建或者实例化时候被调用的方法。通常使用该方法来初始化数据成员和所需资源。
构造器Constructor不能被继承,因此不能重写Overriding,但可以被重载Overloading
function Box(){
...
}
a、对象名访问prototype;
var box=new Box();
//alert(box.prototype); //使用对象实例无法访问到prototype
alert(box.__proto__); //使用对象实例访问prototype指针;
alert(Box.prototype);
//使用构造函数(对象名)访问prototype
b、box.constructor
Box.prototype.name='Lee';
Box.prototype.age=21;
Box.prototype.run=function(){
return this.name+this.age+'运行中..';
};
var box=new Box();
alert(box.constructor);
//结果:function Box(){}
alert(box.constructor==Object); //false
alert(box.constructor==Box); //true;
(2)使用字面量方式创建
其中的方括号就是创建了一个新对象
a、创建一个原型对象
Box.prototype={
name:'Lee';
age:21;
run:function(){
return this.name+this.age+'运行中...';
}
};
b、重写prototype原型
重写后,之前的将不再存在,即覆盖
Box.prototype={
age:22; //这里不会保留之前的任何信息;
};
c、box.prototype
var box=new Box();
//alert(box.run)
alert(box.constructor==Object); //true;
alert(box.constructor==Box); //true;
区别——
第一种构造函数的方法不可以指向Object,只能指向Box函数
第二种字面量方法既可以指向Box原型,又可以指向Object,(由于字面量花括号{}即表示的为新的 对象)
(2)通过原型prototype创建内置引用扩展(以sort排序为例)
a、sort()最简单的排序——采用数组方式
var box=[2,1,3,6,0,9];
alert(box.sort());
结果:0 1 2 3 6 9
b、查看sort是否为Array原型对象的方法
alert(Array.prototype.sort);
alert(String.prototype.substring);
c、内置引用类型扩展;
String.prototype.addstring=function(){
return this+'被添加了';
};
alert('Lee'.addstring()); //Lee被添加了;
注意:不推荐用上述扩展对象办法,会导致命名冲突。
(3)原型优缺点
(1)即“共享”
(2)无法保持独立性
若引用类型时,添加或修改实例化都会发生冲突。
2、原型prototype
(1)全部在原型prototype中定义函数
function Box(){
}
Box.prototype={
constructor:Box,
name:'Lee',
age:21,
family:['哥哥','姐姐','妹妹'],
run:function(){
return this.name+this.age+'运行中';
}
};
var box1=new Box();
alert(box1.family);
box1.family.push('弟弟');
//在第一个实例修改后引用类型,保持了共享;
var box2=new Box();
alert(box2.family);
//共享了box1添加后的引用类型的原型;
结果:(1)哥哥、姐姐、妹妹
(2)哥哥、姐姐、妹妹、弟弟
(3)哥哥、姐姐、妹妹、弟弟(共享)
上述案例中,由于原型的共享性,导致相互独立性与共享之间的属性无法区分开来,
为了解决这个问题,推荐使用混合模式,即“构造函数+原型模式”,见案例(2)
(2)构造函数+原型模式
要点:在共享的时候选择原型,在独立时选择构造函数;
分析:(1)由于name、age相对独立,使用构造函数模式
(2)run方法是一致的,采用原型共享的模式
//1.保持独立的用构造函数
function Box(name,age){
this.name=name;
this.age=age;
this.family=['哥哥','姐姐','妹妹'];
}
//2.保持共享的用原型;
Box.prototype={
constructor:Box,
run:function(){
return this.name+this.age+'进行中';
}
};
var box1=new Box('Lee',21);
alert(box1.family);
box1.family.push('弟弟');
alert(box1.family);
var box2=new Box('Jack',22);
alert(box2.family);
结果:(1)哥哥、姐姐、妹妹
(2)哥哥、姐姐、妹妹、弟弟
(3)哥哥、姐姐、妹妹
注意:(1)引用类型没有使用原型,所以没有共享;
(2)对于原型模式而言,不管是否调用了原型中的共享方法,他都会初始化原型中的方法,
最好的方式将原型与构造函数封装在一起,即“动态原型模式”,见案例(3)
(3)动态原型模式(封装)
要点:a、将构造函数、原型模式封装在一起,实现了资源的高效性,同时减少内存;
b、采用typeof关键字、if语句判断减少了初始化的次数,实现了效率的高效性。
//动态原型模式
function Box(name,age){
this.name=name;
this.age=age;
this.family=['哥哥','姐姐','妹妹'];
//判断this.run是否存在;
if(typeof this.run!='function'){
alert('原型初始化开始');
Box.prototype.run=function(){
return this.name+this.age+'运行中';
};
alert('原型初始化结束');
}
}
//原型的初始化,只要第一次初始化即可,没必要每次多初始化,采用if语句判断;
var box1=new Box('Lee',10);
var box2=new Box('Jack',20);
结果:(1)原型初始化开始 原型初始化结束
(2)原型初始化开始 原型初始化结束(只执行了两次)
注意:使用动态原型模式,注意不可以再用字面量方式重写原型,会切断实例和新原型之间的联系
(4)寄生构造模式=工厂模式+构造函数
工厂模式——即先创建一个对象object,再返回这个对象,同时为该对添加属性和方法;
function Box(name,age){
var obj=new Object();
obj.name=name;
obj.age=age;
obj.run=function(){
return this.name+this.age+'运行中...';
};
return obj;
}
var box1=new Box('Lee',21);
alert(box1.run());
(5)稳妥构造模式
与寄生构造模式唯一不同点是:稳妥构造模式不适用new关键字
var box1=Box('Lee',21);
alert(box1.run());