ES6-Class类的继承

ES5实现类的继承

实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面,Parent.apply(this)

function Phone(brand, price) {
    this.brand = brand
    this.price = price
}
Phone.prototype.makePhone = function () {
    console.log('我可以打电话!')
}

function SmartPhone(brand, price, color) {
    Phone.call(this, brand, price)
    this.color = color
}
SmartPhone.prototype = new Phone
SmartPhone.prototype.constructor = SmartPhone

var sp = new SmartPhone('华为', 4999, '黑色')
console.log(sp.brand) // '华为'
console.log(sp.price) // 4999
console.log(sp.color) // 黑色
sp.makePhone() // 我可以打电话!

sp instanceof Phone // true
sp instanceof SmartPhone // true

Class类实现继承

Class可以通过extends关键字实现继承,比ES5实现继承的方式要清晰和方便很多。
实质是先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this

constructor和super函数

  • constructor中调用super以后,相当于深拷贝了一份this对象,子类修改成员变量也会影响super的调用结果
class Phone {
    constructor(brand, price) {
        this.brand = brand
        this.price = price
    }

    makePhone () {
        console.log('我可以打电话')
    }

    printBrand () {
        console.log(`手机品牌:${this.brand}`)
    }
}
class SmartPhone extends Phone {
    constructor(brand, price, color) {
        super(brand, price)
        this.color = color
    }

    makePhone () {
        console.log('---升级前---')
        super.makePhone()
        console.log('---升级后---')
        console.log('我可以打视频电话')
    }

    changeBrand (brand) {
        super.printBrand()
        this.brand = brand
        super.printBrand()
    }
}

var sp = new SmartPhone('小米', 2199, '黑色')
console.log(sp) // {brand: "小米", color: "黑色", price: 2199}

sp.changeBrand('华为') 
// 手机品牌:小米 
// 手机品牌:华为

sp.makePhone()
// ---升级前---
// 我可以打电
// ---升级后---
// 我可以打视频电话

sp instanceof Phone // true
sp instanceof SmartPhone // true
  • 子类必须在constructor方法中调用super方法,通过父类得到this对象,而且this只能在super调用后使用
class Phone {
    constructor() {}
}

// 必须在constructor中调用super函数,否则会报错
class ESPhone extends Phone {
    constructor() {
        // Must call super constructor in derived class before accessing 'this' or returning from derived constructor
    }
}
var esp = new ESPhone('小米', 2199, '黑色')
  • 如果子类中没有显示定义constructor函数,会默认添加,并将所有的参数通过rest操作符传入
class Phone {
    constructor(brand, price) {
        this.brand = brand
        this.price = price
    }

    makePhone () {
        console.log('我可以打电话')
    }
}

class SmartPhone extends Phone {}
// 等同于
// class SmartPhone extends Phone {
//     constructor (...argus) {
//         super(...argus)
//     }
// }

var sp = new SmartPhone('小米', 2199, '黑色') // success

Class类静态方法的继承

静态方法只能继承静态方法 而且必须通过super()来调用 此时super指向构造函数本身

class Phone {
    static systemName = '安卓'
    static version = '12.0.1'

    static aboutPhone() {
        console.log(`系统:${this.systemName};版本:${this.version}`)
    }
}

class SmartPhone extends Phone {
    static printAbout() {
        super.aboutPhone()
    }
}
SmartPhone.printAbout() // 系统:安卓;版本:12.0.1

Object.getPrototypeOf()

可以使用这个方法判断,一个类是否继承了另一个类

class Phone {}
class SmartPhone extends Phone {}

var parent = Object.getPrototypeOf(SmartPhone)
console.log(parent === Phone) // true

super关键字

super函数调用

super作为函数调用的时候,代表父类的构造函数,ES6规定了,子类的构造函数必须执行一次super函数;
必须显式指定是作为函数、还是作为对象使用,否则会报错;
由于对象总是继承其他对象的,所以可以在任意一个对象中,使用super关键字;

  • super()函数内部this指向的是子类
class Phone {
    constructor(brand, price) {
        this.brand = brand
        this.price = price
        console.log(new.target.name)
    }
}
class SmartPhone extends Phone {
    constructor(brand, price, color) {
        super(brand, name)
        // 相当于 Phone.prototype.constructor.call(this, brand, price)
        this.color = color
    }
}
var sp = new SmartPhone('华为', 4999, 'black') // SmartPhone
  • 只能在子类的构造函数中调用super函数,否则会报错
class Phone {}
class SmartPhone extends Phone {
    makePhone() {
        super() // Uncaught SyntaxError: 'super' keyword unexpected here
    }
}

Super对象使用

super作为对象使用的时候,在普通方法中,指向父类的原型对象,在静态方法中使用,指向父类本身;

class Phone {
    makePhone() {
        console.log('我可以打电话!')
    }

    static aboutPhone() {
        console.log('关于本机')
    }
}

class SmartPhone extends Phone{
    constructor() {
        super()
        super.makePhone()
        // console.log(super) // error 报错
    }

    static aboutPhone() {
        super.aboutPhone()
    }
}
var sp = new SmartPhone() // 我可以打电话!
SmartPhone.aboutPhone() // 关于本机
  • super指向父类的原型对象时,无法通过super调用父类实例上的方法或者属性
class Phone {
    constructor (brand) {
        this.brand = brand
    }
}

class SmartPhone extends Phone {
    constructor (brand) {
        super(brand)
    }

    printBrand() {
        console.log(`手机品牌:${super.brand}`)
    }
}

var sp = new SmartPhone('华为') // 华为
sp.printBrand() // 手机品牌:undefined
  • 在子类普通方法中通过super调用父类的方法时,方法内部的this指向当前的子类实例,静态方法内部的this指向当前的子类,而不是子类的实例
class Phone {
    static color = '黑色'
    constructor (brand) {
        this.brand = brand
    }

    printBrand() {
        console.log(`手机品牌:${this.brand}`)
    }
}

class SmartPhone extends Phone {
    constructor (brand) {
        super(brand)
        super.printBrand()
        super.brand = '苹果'
        super.printBrand()
    }   

    printColor () {
        console.log(super.color)
    }
}

var p = new Phone('小米')
var sp = new SmartPhone('华为') // 华为; 苹果
sp.printColor() // 黑色

类的prototype属性和__proto__属性

Class作为构造函数的语法糖,同时有prototype属性和__proto__属性,因此同时存在两条继承链
(函数也同时拥有prototype__proto__两个属性,因为函数也是对象的一种,被称为函数对象)

子类的__proto__属性,表示构造函数的继承,总是指向父类
子类prototype属性的__proto__属性,表示方法的继承,总是指向父类的prototype属性

class phone {}
class SmartPhone extends Phone {}
console.log(SmartPhone.__proto__ === Phone) // true
console.log(SmartPhone.prototype.__proto__ === Phone.prototype) // true

// 实现模式
// B 的实例继承 A 的实例
// Object.setPrototypeOf(B.prototype, A.prototype);
// B 继承 A 的静态属性
// Object.setPrototypeOf(B, A);

// Object.setPrototypeOf方法的实现
// Object.setPrototypeOf = function(obj, proto) {
//  obj.__proto__ = proto
//  return obj;
// }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值