javascript继承的几种方式

前言

继承的目的其实就是改变原型链

比如说,继承之前的原型链是 son -> Son.prototype -> Object.prototype -> null

而继承之后的原型链是 son -> Son.prototype -> Father.prototype -> Object.prototype -> null

一、原型继承

实现方式:把父类的实例作为子类的原型

缺点:子类的实例中共享了父类原型上的引用属性

// 字面量方式
var father = {
    data: [1, 2]
}

var son = Object.create(father)
son.data.push(3)
console.log(son.data)      // [1,2,3]
console.log(father.data)   // [1,2,3]


// 构造函数方式
function Father() {
    this.data = {
        name: 'zs'
    }
}

function Son() {}
var father = new Father()
Son.prototype = father
var son = new Son()
son.data.name = 'ls'
console.log(son.data)     // { name: 'ls' }
console.log(father.data)  // { name: 'ls' }

二、构造函数继承

实现方式:调用父类的构造函数,改变this的指向,指向子类

缺点:只能继承父类的属性,不能继承父类的方法

function Father(age) {
    this.info = {
        name: 'zs'
    }
    this.age = age
}

Father.prototype.getName = function () {
    console.log(this.info.name)
}

function Son(age) {
    Father.call(this, age)
}

var father = new Father(18)
var son = new Son(20)
son.info.name = 'ls'
console.log(father.info)  // { name: 'zs' }
console.log(father.age)   // 18
father.getName()          // zs

console.log(son.info)     // { name: ''ls }
console.log(son.age)      // 20
son.getName()             // son.getName is not a function

三、组合继承

实现方式:构造函数继承 + 原型继承

缺点:调用父类的构造函数两次,造成消耗

function Father(age) {
    this.info = {
        name: 'zs'
    }
    this.age = age
}

Father.prototype.getName = function () {
    console.log(this.info.name)
}

function Son(age) {
    // 第一次调用父类的构造函数
    Father.call(this, age)   // 构造函数继承
}

// 第二次调用父类的构造函数
Son.prototype = new Father()     // 原型继承
Son.prototype.constructor = Son  // 修复子类构造函数的指向

var father = new Father(18)
var son = new Son(20)
son.info.name = 'ls'
console.log(father.info)  // { name: 'zs' }
console.log(father.age)   // 18
father.getName()          // zs

console.log(son.info)     // { name: ''ls }
console.log(son.age)      // 20
son.getName()             // ls

四、寄生组合式继承

实现方式: 构造函数继承 + 原型继承,原型继承的方式调整,不继承父类的属性

function Father(age) {
    this.info = {
        name: 'zs'
    }
    this.age = age
}

Father.prototype.getName = function () {
    console.log(this.info.name)
}

function Son(age) {
    // 第一次调用父类的构造函数
    Father.call(this, age)   // 构造函数继承
}

// 第二次调用父类的构造函数
Son.prototype = Object.create(Father.prototype)     // 原型继承
Son.prototype.constructor = Son  // 修复子类构造函数的指向

var father = new Father(18)
var son = new Son(20)
son.info.name = 'ls'
console.log(father.info)  // { name: 'zs' }
console.log(father.age)   // 18
father.getName()          // zs

console.log(son.info)     // { name: ''ls }
console.log(son.age)      // 20
son.getName()             // ls

五、ES6 extends继承

class Father{
    constructor(name){
        this.name = name
    }
}
 
// extends相当于 Son.prototype.__proto__ = Father.prototype
class Son extends Father{
    // 若写了 constructor 则必须要写 super
    constructor(){
        // super相当于 Father.call(this)
        super()
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浅墨、离殇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值