javascript面向对象学习笔记(三)——继承

javascript面向对象学习笔记(三)——继承

原型链

原型链是实现继承的主要方法,利用原型让一个引用类型继承另一个引用类型的属性和方法。(然一个原型对象等于另一个类型的实例)
实现原型链的一种基本模式:

function SuperType(){
    this.property=true;
}
SuperType.prototype.getSuperValue=function(){
    return this.property;
}
function SubType(){
    this.subproperty=false;
}
SubType.prototype=new SuperType();
SubType.prototype.getSubValue()=function(){
    return this.subproperty;
};
var instance=new  SubType();
alert(instance.getSuperValue); //true

这里写图片描述
subType继承了SuperType,而继承是通过创建SuperType的实例,并将该实例赋给SubType.property实现。实现的本质是重写原型对象,代之以一个新类型的实例。

在上面的代码中,没有使用SubType默认提供的原型,而是给他换了一个新原型(SuperType的实例),使得新原型不仅具有一个作为SuperType的实例所拥有的全部属性和方法,其内部还有一个指针指向SuperType的原型。
instance.constructor现在指向SuperType,因为SubType.prototype=new SuperType();var instance=new SubType();重写原型导致SubType对象和instance失去了默认的constructor属性,因此搜索到的constructor属性是SuperType()的,因此指向SuperType.

**确定原型和实例的关系:**1、使用instanceof操作符,只要用这个操作符来测试实例与原型链中出现过的构造函数,结果就会返回true。

alert(instance instanceof Object);//true
alert(instance instanceof SuperType);//true
alert(instance instanceof SubType);//true

instance 是Object、SuperType、SubType中任何一个类型的实例。

2、isPrototypeOf()方法,只要是原型链中出现过的原型,都可以说是该原型链所派生的实例的原型。因此isPropertyOf()方法返回true。

alert(Object.protopyte.isPrototypeOf(instance));//true
alert(SuperType.prototype.isPrototypeOf(instance));//true
alert(SubType.prototype.isPrototypeOf(instance));//true

给原型添加方法的代码一定要放在替换原型的语句之后。

function SuperType(){
    this.property=true;
}
SuperType.prototype.getSuperValue=function(){
    return this.property;
}
function SubType(){
    this.subproperty=false;
}
SubType.prototype=new SuperType();
SubType.prototype.getSubValue()=function(){
    return this.subproperty;
};
//重写超类型中的方法
SubType.prototype.getSuperValue=function(){
    return false;
};//此时该方法将屏蔽原来原型链中已存在的getSuperValue()方法;要写在SuperType的实例替换原型之后,即SubType.prototype=new SuperType()之后
var instance=new  SubType();
alert(instance.getSuperValue); //false

通过原型链实现继承时,不能使用对象字面量创建原型方法,因为这样会重写原型链。

function SuperType(){
    this.property=true;
}
SuperType.prototype.getSuperValue=function(){
    return this.property;
}
function SubType(){
    this.subproperty=false;
}
SubType.prototype=new SuperType();
SubType.prototype={
    getSubValue:function(){
        return this.subproperty;
    },
    someOtherMethod:function(){
        return false;
    }
};//使用字面量添加新方法,会导致上一行代码无效,此时原型包含的是Object实例而非SuperType的实例.
var instance=new SubType();
alert(instance.getSuperValue());//error

原型链的问题:主要来自包含引用类型值得原型。在通过原型实现继承时,原型实际上会变成另一个类型的的实例,于是原先的实例属性顺理成章的变成了现在原型的属性。

function SuperType(){   
    this.colors=["red","blue","green"];
}
function SubType(){}
//继承了SuperType
SubType.prototype=new SuperType();
var instance1=new SuperType();
instance1.colors.push("black");
alert(instance1.colors);//red,blue,green,black
var instance2=new SuperType();
alert(instance2.colors);//red,blue,green,black//SubType的所有实例共享这一个colors属性

借用构造函数

基本思想:在子类型构造函数的内部调用超类型构造函数。

function SuperType(){
    this.colors=["red","blue","green"];
}
function SubType(){
    //继承了SuperType
    SuperType.call(this);//借调超类型的构造函数
}
var instance1=new SubType();
instance1.colors.push("black");
alert(instance.colors);//red,blue,green,black

var instance2=new SubType();
alert(instance2.colors);//red,blue,green

与原型链对比的优势:可以在子类型构造函数中向超类型构造函数传递参数.

function SuperType(name){
    this.name=name;
}
function SubType(){
    SuperType.call(this,"Chiaki");//为SubType的实例设置name属性
    this.age=21;
}
var instance=new SubType();
alert(instance.name);//Chiaki
alert(instance.age);//21

借用构造函数的问题:方法都在构造函数中定义,缺少函数的复用;且在超类型的原型中定义的方法,对子类型不可见

组合继承

将原型链和借用构造函数的技术组合到一起,使用原型链实现原型属性和方法的基础,通过借用构造函数来实现对实例属性的基础。

function SuperType(){
    this.name=name;
    this.colors=["red","blue","green"];
}
SuperType.prototype.sayName=function(){
    alert(this.name);
};
function SubType(name,age){
    SuperType.call(this.name);//调用SuperType构造函数时传入name参数
    this.age=age;
}
SubType.prototype=new SuperType();
SubType.prototype.sayAge=function(){    
    alert(this.age);
}
var instance1=new SubType("Chiaki",21);
instance1.colors.push("black");
alert(instance1.color);//red,blue,green,black
instance1.sayName();//Chiaki
instance1.sayAge();//21

var instance2=new SubType("Wu",20);
alert(instance2.color);//red,blue,green
instance2.sayName();//Wu
instance2.sayAge();//20

原型式继承

借助原型可以基于已有对象创建新对象,同时还不必因此创建自定类型。

function object(o){
    funtion F(){
        F.prototype=o;
        return new F();
    }
}

在object()函数内部,先创建了一个临时性的构造函数,然后将传入的对象作为这个构造函数的原型,最后返回这个临时类型的一个新实例.。从本质上讲,object()对传入其中的对象执行了一次浅复制.

var person={
    name:"Chiaki",
    friends:["lola","cherry","van"]
};
var anotherPerson=object(person);
anotherPerson.name="Greg";
anotherPerson.friends.push("Rob");

var yetAnotherPerson=object(person);
yetAnotherPerson.name="linda";
yetAnotherPerson.friends.push("Barbie");
alert(person.friends);

原型模式继承要求必须要有一个对象作为另一个对象的基础,把它传递给object()函数,然后再根据具体需求对得到的对象加以修改即可。
Object.create()方法规范化了原型式继承。该方法接收了两个参数:一个用作新对象原型的对象和一个作为新对象而外属性的对象。适用于IE9+,Firefox4+,Safari 5+,Opera 12+,Chrome

var anotherPerson=Object.create(person,{
    name:{
        value:"Chiaki"
    }
});

寄生式继承

创建一个仅用于封装仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真的是它做了所有工作一样返回对象。以下代码示范了寄生式继承模式:

function createAnother(original){
    var clone=object(original);//通过调用函数创建一个新对象
    clone,sayHi=function(){//以某种方式来增强这个对象
        alert("hi");
    };
    return clone;//返回这个对象
}

可以像下面那样使用createAnother()函数。

var person={
    name:"Chiaki",
    friends:["lola","cherry"]
};
var anothePerson=createPerson(person);
anotherPerson.sayHi();//hi

主要考虑对象而不是自定义类型和构造函数的情况下,寄生式继承也是一种有用的模式。

寄生组合式继承

组合继承的问题:无论什么情况下,都会调用两次超类型构造函数:一次是在创建子类型原型的时候,另一次是在子类型构造函数内部。

function SuperType(name){
    this.name=name;
    this.colors=["red","blue","green"];
}
SuperType.prototype.sayName=function(){
    alert(this.name);
}
function SubType(name,age){
    SuperType.call(this.name);//第二次调用SuperType()
    this.age=age;
}
SubType.prototype=new SuperType();//第二次调用SuperType()
SubType.prototype.constructor=SubType;
SubType.prototype.sayAge=function(){
    alert(this.age);
}

寄生式组合继承:通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。基本模式如下:

function inheritPrototype(subType,superType){
    var prototype=object(superType.prototype);//创建对象
prototype.constructor=subType;//增强对象//弥补因重写原型二失去的默认的constructor属性
subType.prototype=prototype;    //指定对象
}

inheritPrototype()函数接收两个参数:子类型构造函数和超类型构造函数。

function SuperType(name){
    this.name=name;
    this.colors=["red","blue","green"];
}
SuperType.prototype.sayName=function(){
    alert(this.name);
}
function SubType(name,age){
    SuperType.call(this.name);
    this.age=age;
}
inheritPrototype(subType,SuperType);
SubType.prototype.sayAge=function(){
    alert(this.age);
}

这里写图片描述
使用inheritPrototype()只调用了一次SuperType构造函数,提高了效率

【参考自《javascript高级程序设计(第三版)》】

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值