在上一篇博客中,谈及到了原型链共享引用值的问题,其实在原型模式中也存在类似的问题,解决方法一般有以下几种:
- 组合使用构造函数与原型模式
function Person(){
this.friends = ['merry','john'];
}
Person.prototype = {
constructor : Person,
name : "Nicholas",
age : 23,
sayName : function(){
alert(this.name);
}
}
var person1 = new Person();
var person2 = new Person();
person1.friends.push('jack');
alert(person1.friends); //merry,john,jack
alert(person2.friends);//merry,john
- 动态原型模式
function Person(name,age){
this.name = name;
this.age = age;
this.friends = ['merry','john'];
//方法
if(typeof(this.sayName) != 'function'){
Person.prototype.sayName = function(){
alert(this.name);
};
}
}
var person1 = new Person('jack',23);
var person2 = new Person('john',21);
person1.friends.push('haha');
alert(person1.friends);//merry,john,haha
alert(person2.friends);//merry,john
- 寄生构造函数与稳妥构造函数
寄生式与稳妥式大同小异,都实在构造函数内部构造了一个实例。
function Person(name,age)
{
var o = new Object;
o.name = name;
o.age = age;
o.sayName = function (){
alert(this.name);
}
return o;
}
var person1 = new Person('jack',23);
person1.sayName();
稳妥式
比较安全,在方法中不使用this,在调用构造函数时不使用new.
function Person(name,age)
{
var o = new Object;
o.name = name;
o.age = age;
o.sayName = function (){ //只能使用sayName方法访问name,没有其他方法
alert(name);
}
return o;
}
var person1 = Person('jack',23);
person1.sayName();
继承
继承是什么?
当我们想要一个对象能够访问另一个对象的属性,同时,这个对象还能够添加自己新的属性或是覆盖可访问的另一个对象的属性,我们实现这个目标的方式叫做“继承”。一般来讲,继承有以下两种方法。
- 第一种就是上一篇提到的原型链
像是原型模式中的共享实例中的引用值问题,原型链也存在相似的问题。
类比上述解决问题的方法,我们也可以借用构造函数来解决。
function Father(){
this.TshirtColors = ['red','blue','yellow'];
}
function Son(){
Father.call(this);
}
var son1 = new Son();
var son2 = new Son();
son1.TshirtColors.push('black');
alert(son1.TshirtColors); //'red','blue','yelllow','black'
alert(son2.TshirtColors); //'red','blue','yelllow'
事实上,通过这种方法还可以实现参数自下而上的传递。
function Father(){
this.name = name;
}
function Son(){
Father.call(this,'john');
}
var son = new Son();
alert(son.name); //john
- 组合函数
使用原型链和借用构造函数,并且融合了二者的优点。
这种方法的缺点就是会调用两次构造函数。
function Father(){
this.name = name;
this.TshirtColors = ['red','blue','yellow'];
}
Father.prototype.sayName= function(){
alert(this.name);
};
function Son(){
//继承了属性
Father.call('this');
}
//继承了方法
Son.prototype = new Father();
var son1 = new Son();
var son2 = new Son();
son1.TshirtColors.push('black');
alert(son1.TshirtColors); //'red','blue','yelllow','black'
alert(son2.TshirtColors); //'red','blue','yelllow'
- 原型式继承
这种方法的原理就是复制一个目的函数。如:
function object(o){
function F(){}
var F.prototype = o;
return new F();
}
var person = {
name : 'john',
TshirtColors : ['red','blue','yellow']
};
var person1 = object(person);
person1.name = 'merry';
var person2 = object(person);
person2.TshirtColors.push('black');
在ES5中,函数object可被Object.create()取代。
但是这种方法中包含引用值的始终会共享值。
4. 寄生式函数
寄生式函数与原型式紧密相连
function create(o){
var clone = object(o); //这里的object函数即是原型式里自定义的函数
//在这个基础上给clone添加方法或属性
clone.sayName = function(){
alert(this.name);
}
}
- 圣杯模式
当把寄生式和原型式相结合,我们得到一种高效的引用类型的继承范式。
function inherit(Target,Origin){
function F(){ };
F.prototype = Origin.prototype //这一行与下面一行不能颠倒,否则F的原型不能改变。
Target.prototype = new F();
Target.prototype.construct = Target; //完善代码,使Target的构造器指向自己。
Target.prototypr.uber = Origin.prototype //知道真正继承自谁。
}
Father.prototype.lastName = 'xxx';
function Father(){}
function Son(){}
inherit(Son,Father);
var son = new Son();
var father = new Father();
此时赋给son的值不会传到father里。
这种方法最通用的写法如下:
var inherit = (function (){
var = function (){};
return = function (Target,Origin){
F.prototype = Origin.prototype
Target.prototype = new F();
//Target.prototype.construct = Target;
//Target.prototypr.uber = Origin.prototype
}
}());