JavaScript中的继承方式

原型的概念:每一个javascript对象(除null外)创建的时候,就会与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型中“继承”属性。
原型链的概念:当读取一个对象的属性时,如果找不到,就会查找与对象关联的原型中的属性,如果还查不到,就去找原型的原型,层层向上直到一个对象的原型对象为 null。根据定义,null 没有原型,并作为这个原型链中的最后一个环节。
在这里插入图片描述

// 父类
function Person(name){ //给构造函数添加了参数 
    this.name = name || "父类"
    this.sum=function(){
        console.log(this.name)
    }
}
Person.prototype.age=26 // 给构造函数添加了原型属性

一、 原型链继承

让父类中的属性和方法在子类实例的原型链上

function Per(){
    this.name = "子类per"
}
Per.prototype = new Person() // 重点 就是让新实例的原型等于父类的实例
let per1 = new Per()
console.log(per1.name)
// instanceof 判断元素是否在另一个元素的原型链上
// per1 继承了Person的属性,返回true
console.log(per1 instanceof Person)

特点:
1、实例(per1)可继承的属性有:实例的构造函数的属性,父类构造函数的属性,父类原型的属性(新实例不会继承父类实例的属性)
2、子类可以重写父类上的方法(这样会导致父类其他的实例也受到影响)
3、父类中私有或者共有的属性方法都会变成子类的共有属性和方法
缺点:
1、创建子类实例时,无法向父构造函数传参
2、继承单一
3、所有新实例都会共享父类实例的属性(原型上的属性是共享的,一个实例修改了原型属性,另一个实例的原型属性也会被修改)

二、构造函数继承

复制父类的实例属性给子类,在子类中把父类当做普通元素执行,让父类的this指向子类的实例

function Animal(name){
	Person.call(this,name) // 重点采用.call()或者.apply()将父类构造函数引入子类函数中(在子类函数中做了父类函数的复制)
}
let dog=new Animal('子类animal传入父类')
console.log(dog.name, dog.age, dog instanceof Person) // 子类animal传入父类 undefined  false

特点:
1、只继承了父类构造函数的属性,没有继承父类原型的属性
2、解决了原型链继承中子类实例共享父类引用属性的问题
3、可以继承多个构造函数属性(call多个父类对象)
4、在子实例中可向父实例传参
缺点:
1、只能继承父类构造函数的属性
2、无法实现构造函数的复用(每次用每次都要重新调用)
3、每个新实例都有父类构造函数的副本,臃肿

三、组合继承(组合原型链继承和构造函数继承) 常用

function SubType(name){
    Person.call(this,name) //借用构造函数模式
}
SubType.prototype=new Person() // 原型链继承
var sub=new SubType("gar")
console.log("继承了构造函数的属性",sub.name)
console.log("继承了父类原型的属性",sub.age)
var sub2 = new SubType("sub222")
console.log("继承了构造函数的属性", sub2.name)
console.log("继承了父类原型的属性", sub2.age)

重点:
结合了两种模式的有点,传参和复用
特点:
1、可以继承父类原型上的属性,可以传参,可以复用
2、每个新实例引入的构造函数属性是私有的
缺点:
调用了两次父类构造函数(耗内存),子类的构造函数会代替原型上的那个父类构造函数

四、原型式继承

// 先封装一个函数容器,用来输出对象和承载继承的原型
function content(obj){
    function F(){}
    F.prototype=obj //继承传入的参数
    return new F() // 返回函数对象
}
var sup=new Person() //拿到了父类的实例
var sup1=content(sup)
console.log("继承了父类函数的属性", sup1.age) 

重点:
用一个函数包装一个对象,然后返回这个函数的调用,这个函数就变成了个可以随意增添属性的实例或对象。object.create()就是这个原理。
特点:类似于复制一个对象,用函数来包装。
缺点:
1、所有实例都会继承原型上的属性。
2、无法实现复用。(新实例属性都是后面添加的)

五、寄生继承

function content(obj){
    function F(){}
    F.prototype=obj //继承了传入的参数
    return new F() //返回函数对象
}
var sup3=new Person()
// 以上是原型式继承,给原型式继承再套个壳子传递参数
function subObject(obj){
    var sub=content(obj)
    sub.name="寄生继承"
    return sub
}
var sup4=subObject(sup3)
// 这个函数经过声明之后就成了可增添属性的对象
console.log("function",typeof subObject)
console.log("object",typeof sup4)
console.log("返回了sub对象,继承了sub属性 寄生继承",sup4.name)

重点:就是给原型式继承外面套了个壳子
优点:没有创建自定义类型,因为只是套了个壳子返回对象(这个),这个函数顺利成章就成了创建的新对象。
缺点:没用到原型,无法复用。

六、寄生组合式继承 常用

寄生:在函数内返回对象然后调用
组合:1、函数的原型等于另一个实例。2、在函数中用apply或者call引入另一个构造函数,可传参

function content(obj){
    function F(){}
    F.prototype=obj
    return new F()
}
// content就是F实例的另一种表示法
var con=content(Person.prototype)
// con实例(F实例)的原型继承了父类函数的原型 上述更像是原型链继承,只不过只继承了原型属性

// 组合
function Sub(){
    Person.call(this) //这个继承了父类构造函数的属性
}
// 解决了组合式两次调用构造函数属性的缺点
// 重点
Sub.prototype=con //继承了con实例
con.constructor=Sub //一定要修复实例
var sub1=new Sub() // Sub的实例就继承了构造函数属性,父类实例,con的函数属性
console.log(sub1.age)

重点:修复了组合继承的问题

七、Es6 class继承机制

先将父类实例 的属性方法加到this上(super),然后再用子类的构造函数修改this,在子类的构造函数中,只有调用super之后才可以使用this 关键字,因为super 之后子类才有了自己的this。

class Animal {
    constructor(name) {
        this.name = name;
    }
}
class Cat extends Animal {
    constructor(name) {
        super(name)
    say() {
        return `Hello, ${this.name}!`
    }
}
// 测试:
var kitty = new Cat('Kitty');
var doraemon = new Cat('哆啦A梦');
if ((new Cat('x') instanceof Animal) && kitty && kitty.name === 'Kitty' && kitty.say && typeof kitty.say === 'function' && kitty.say() === 'Hello, Kitty!' && kitty.say === doraemon.say) {
    console.log('测试通过!');
} else {
    console.log('测试失败!');
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值