欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JavaScript实现继承(七种)

程序员文章站 2022-06-19 17:17:48
Js继承在学习继承前希望读者先去学习下js原型和原型对象的知识。对于js原型和原型对象的理解原型链继承让一个函数的原型指向另一个引用类型的对象,这样子这个原型对象中就有一个指针是指向另一个函数的原型的,这个原型中又有一个指针是指向另一个函数的构造函数的。function Animal(){ this.name='动物'}Animal.prototype.say=function(){ return this.name}function Cat(){ this.nam...

Js继承

在学习继承前希望读者先去学习下js原型和原型对象的知识。
对于js原型和原型对象的理解

原型链继承

让一个函数的原型指向另一个引用类型的对象,这个对象中又有指针是指向另一个引用类型的原型对象的,原型对象也可以继续指下去,直到原型链的末端

function Animal(){
    this.name='动物'
}
Animal.prototype.say=function(){
    return this.name
}
function Cat(){
    this.name='猫'
}
Cat.prototype=new Animal()
let c=new Cat()
c.say()   //猫
//可以看到Cat继承了say这个方法

这里的Cat的prototype指向了Animal的实例,而Animal的实例的属性_proto_指向了Animal.prototype,Animal.prototype的constructor又指向了Animal构造函数,这就是构成了一条原型链,原型链到这里其实还没有结束,因为我们知道所有的对象都是继承Object的,所以

Animal.prototype._proto_==Object.prototype //true
Object.prototype._proto_==Object  //true

这样就构成了一个完整的原型链,这边要注意的是所有函数的原始原型对象都是指向Object原型对象的。原型链的末端就是Object.prototype
如图所示:
红色线条就构成了一条原型链
JavaScript实现继承(七种)

原型链的特点就是它既是子类的实例也是父类的实例,且如果继承的对象中是个引用类型的,那么这将会被所有实例全部引用一个引用类型的数据,原型链继承一般也很少使用。

c instanceof Animal //true
c instanceof Cat    //true

构造函数继承

这个方法其实很简单,就是通过call或者是apply在一个构造函数中执行一下另一个构造函数即可。

function Animal(){
    this.type=['狗','猪']
}
function Cat(){
    Animal.call(this)
}
let c=new Cat()
c.type.push('猫')
c.type //['狗','猪','猫']
//可以看到Cat继承了Animal的type属性。

构造函数继承中不存在函数复用,所有都是借用构造函数来初始化的,所以我们也很少用

组合继承

组合继承顾名思义,就是将原型链继承和构造函数继承放在一块来实现。

function Animal(name){
    this.name=name
}
Animal.prototype.say=function(){
    console.log('--动物--')
}
function Cat(name){
    Animal.call(this,name)
}
Cat.prototype=new Animal()
Cat.prototype.constructor=Cat
let c=new Cat('猫')
c.name//猫
c.say() //--动物--

组合继承最大的缺点就是它会调用两次父类的构造函数。

原型式继承

最开始原型式的继承提出方案是这个样子的

function object(obj){
    function f(){}
    f.prototype=obj
    let F=new f()
    return F
}
let people={name:'姓名'}
let p=new object(people)
p.name //姓名

object函数接受一个对象 然后在函数里面声明一个局部的构造函数,让其原型指向传过来的参数,然后实例化并返回就可

ECMAScript5规范化了原型式继承,即Object.create接收两个参数,一个是用作新对象原型的对象和一个新对象作为额外的属性

let Animal={name:'动物'}
let Cat=Object.create(Animal)
Cat.name //动物

只是一个对象要类似于另一个对象,这是完全可以胜任的,要注意的就是引用类型的继承还是会共享相应的值。

寄生式继承

与原型式基本类似,只不过函数中创建对象的方式不同 ,他只考虑最基本的

function create(obj){
    let clone=object(obj)  //调用原型式的函数
    clone.say=function(){
        console.log('说话')
    }
    return clone
}
let p={name:'姓名'}
let o=create(p)
o.name// 姓名
o.say// 说话

如果只考虑最基本的对象而不考虑通过构造函数来生成对象的话,寄生式继承也是一种好的方式

寄生组合继承

在介绍寄生组合前我们先来看下组合继承的两次生成实例。

function Animal(){
    this.name='动物'
}
function Cat(){
    Animal.call(this) //第二次调用
}
Cat.prototype=new Animal() //第一次调用
Cat.Prototype.constructor=Cat
let c=new Cat()  

我们可以看到组合继承调用了两次父类的构造函数,第二次调用会使得原型中的属性被实例中的同名属性所覆盖,因此要解决这个问题,就有了寄生组合继承,其实就是在定义子类的原型时不去new父类,我们只要一开始的时候获取到父类的原型对象的副本即可

function Animal(){
    this.name='动物'
}
function Cat(){
    Animal.call(this) //只有这一次执行
}
let o=Object.create(Animal.prototype)//获取一个父类原型的副本
Cat.prototype=o
Cat.prototype.constructor=Cat
let c=new Cat()
c.name //动物

es6中的继承

es6中新增了class extends关键字,让js具有了与其他OO语言一样的对象写法

class A{
    constructor(){
        console.log('aaa')
        this.a='a'
    }
}
class B extends A{
    constructor(){
        super()
        console.log('bbb')
        this.b='b'
    }
}
let b=new B()
b.a //'a'
b.b //'b'

本文地址:https://blog.csdn.net/qq_40026070/article/details/107543389

相关标签: JavaScript js