ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

继承

2021-11-29 20:00:26  阅读:191  来源: 互联网

标签:function 父类 sub 继承 SubClass SuperClass prototype


类式继承

// 声明父类
function SuperClass() {
    this.superValue = true
}
// 为父类添加共有方法
SuperClass.prototype.getSuperValue = function () {
    return this.superValue
}
// 声明子类
function SubClass() {
    this.subValue = false
}

继承的是父类的实例对象

// 继承父类
SubClass.prototype = new SuperClass()
// 为子类添加共有方法
SubClass.prototype.getSubValue = function () {
    return this.subValue
}

实例化子类看看结果

const sub = new SubClass()
sub.getSuperValue()    // true
sub.getSubValue()      // false

通过instanceOf测试一下

// instanceof通过判断原型链来确定对象是否是某个类的实例,而不关心对象与类自身的结构
sub instanceof SuperClass   // true
sub instanceof SubClass   // true
// 注意,它并不表示继承,而是判断前面是否是后面的实例
SubClass instanceof SuperClass   // false
SubClass.prototype instanceof SuperClass   // true

 看起来挺不错,好像继承就应该是这样,子类可以使用父类的属性和方法,那么这样做是否有什么缺点呢?我们再测试一下

function SuperClass() {
    this.books=["1","2","3"]
}
function SubClass() {}
SubClass.prototype= new SuperClass()
const sub1 = new SubClass()
const sub2 = new SubClass()
sub2.books     // [ '1', '2', '3' ]
sub1.books.push("4")
sub2.books     // [ '1', '2', '3', '4' ]

 出现问题了,我们改动了一个实例sub1中的数组,但sub2实例中的数组也发生了变化,为什么会这样?

其实不难想到,出现这种情况的根本原因肯定是sub1直接改动了原型中的数据,因为sub1中没有books属性,就去自己的原型中找,在SuperClass中找到了,但是由于父类是个实例对象,所以其引用类型数据会被子类共用,导致所有子类都出现了问题,这个是很不安全的,那么如何避免这个问题呢?往下看

构造函数式继承

通过使用call的方法,

// 声明父类
function SuperClass(id) {
    this.books=["1","2","3"]
    this.id = id
}
// 父类声明原型方法
SuperClass.prototype.showBooks = function () {
    console.log(this.books)
}
// 声明子类
function SubClass(id) {
    SuperClass.call(this, id)
}

 检测引用类型,发现解决了问题

const sub_1 = new SubClass(12)
const sub_2 = new SubClass(20)
sub_1.books.push("4")
sub_1.books   // [ '1', '2', '3', '4' ]
sub_1.id      // 12
sub_2.books   // [ '1', '2', '3' ]
sub_2.id      // 20
sub_1.showBooks() // sub_1.showBooks is not a function

但是又出现了新的问题,showBooks is not a function,不能查找到原型链中的showBooks方法

因为call相当于直接把父类构造函数中的属性和方法复制了一份给子类,因为没有涉及prototype,所以父类的原型子类无法继承

组合式继承

 那是不是说,把构造函数式继承和类式继承一起使用就可以避免这个问题了呢

function SuperClass(name) {
    this.name = name
    this.books = [ '1', '2', '3' ]
}
SuperClass.prototype.getName = function () {
    console.log(this.name)
}
function SubClass(name, time) {
    // 构造函数继承
    SuperClass.call(this, name)
    this.time = time
}
// 类式继承
SubClass.prototype = new SuperClass4()
SubClass.prototype.getTime = function () {
    console.log(this.time)
}

测试结果发现,果然,问题都解决了

const sub_1 = new SubClass("vue", 2021)
sub_1.books.push("4")
console.log(sub_1.books)   // [ '1', '2', '3', '4' ]
sub_1.getName()            // vue
sub_1.getTime()            // 2021

const sub_2 = new SubClass("react", 1998)
console.log(sub_2.books)   // [ '1', '2', '3']
sub_2.getName()            // react
sub_2.getTime()            // 1998

但是又出现了新的问题,因为call()在对象自身复制了一份原型共有属性,但原型中也有一份父类共有属性,父类的构造函数实际调用了两遍

 寄生式组合继承

创建一个过渡类,传入父类的prototype,将父类掏空,同时继承父类的原型链,返回一个过渡类的实例对象

然后创建寄生组合式继承方法,此处因为修改prototype后,子类 __proto__中的constructor会被覆盖丢失,所以重新修正一下其constructor

// 创建一个空的过渡类,减小构造函数的开销
function inheritObject(o) {
    // 创建一个过渡类
    function F() {}
    F.prototype = o
    return new F()
}
// 寄生组合式继承
function inheritPrototype(subClass, superClass) {
    // 复制一份父类的原型副本保存在变量中
    const p = inheritObject(superClass.prototype)
    // 继承
    subClass.prototype = p
    // 重新修正constructor
    p.constructor = subClass
}

测试一下

// 定义父类
function SuperClass5(name) {
    this.name = name
    this.colors = ["red", "blue", "green"]
}
// 定义父类原型方法
SuperClass5.prototype.getName = function () {
    console.log(this.name)
}
// 定义子类
function SubClass5(name, time) {
    // 构造函数继承
    SuperClass5.call(this, name)
    // 子类新增属性
    this.time = time
}
// 寄生组合式继承
inheritPrototype(SubClass5, SuperClass5)
SubClass5.prototype.getTime = function () {
    console.log(this.time)
}

这回都没有问题了

const test1 = new SubClass5("vue", 20)
const test2 = new SubClass5("react", 10)
test2.colors    // ['red', 'blue', 'green']
test1.colors.push("blue")
test2.colors    // ['red', 'blue', 'green']
test1.getName() // vue    

其实在ES5中提供了上述inheritObject创建过渡类的方法,即

Object.create(superClass.prototype)

在ES6中更是提供了寄生组合式继承的方法,即

Object.setPrototypeOf(SubClass.prototype, SuperClass.prototype)

 

标签:function,父类,sub,继承,SubClass,SuperClass,prototype
来源: https://www.cnblogs.com/xt112233/p/15621038.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有