JavaScript实现继承的几种方式详解(代码可本地运行便于理解)


前言

大家好我是前端新手小猿同学:
这篇文章主要给大家简单介绍一下JavaScript实现继承的几种方式及实现原理的简单分析希望对大家的学习进步有所帮助,当然文章中可能存在理解不正确的地方希望大家可在评论区相互讨教,共同进步。。


一、继承是什么?

继承:(百度百科定义)
继承(英语:inheritance)是面向对象软件技术当中的一个概念。这种技术使得复用以前的代码非常容易,能够大大缩短开发周期,降低开发费用。
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的属性和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
Java继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。
子类的创建可以增加新数据、新功能,可以继承父类全部的功能,但是不能选择性的继承父类的部分功能。继承是类与类之间的关系,不是对象与对象之间的关系。
其实总结就是一句话
子类自动拥有父类的属性和方法,继承可以提高代码的复用性,并且子类还可以新增属性和方法

二、JavaScript实现继承的几种方式

1.原型链继承

代码如下(示例):

//定义一个动物类,它有两个属性name和id
function Animal (newName,newId){
    this.name = newName
    this.id = newId
}
// 再为动物类定义几个方法
Animal.prototype.eat = function(){
    console.log('我是动物类吃的方法')
}
Animal.prototype.run = function(){
    console.log('我是动物类跑的方法')
}
// 定义一个人类
function Person(newAge){
    this.age = newAge
}
// 人类继承于动物类
Person.prototype = new Animal("小明",'12')
// 注意:子类只有继承完父类的属性和方法之后才能设置自生的属性和方法
// 设置人类的自有方法
Person.prototype.useTools = function(){
    console.log('我是人类使用工具的方法')
}
// 设置人类的自有属性
var Xiaoming = new Person('18岁')
console.log(Xiaoming.name)
console.log(Xiaoming.id)
console.log(Xiaoming.age)
Xiaoming.eat()
Xiaoming.run()
Xiaoming.useTools()
//输出:
小明
12
18岁
我是动物类吃的方法
我是动物类跑的方法
我是人类使用工具的方法

缺点:

1.被继承的类型(父类)的属性中包含引用类型时它会被所有的实例共享
2.创建子类实例化对象的时候不能改变继承父类时实例化对象的初始值
就是不能改变这个初始值Person.prototype = new Animal("小明",'12')

Javascript的原型链就是这样形成的,我们上面的例子只是一简单的父子继承,如果牵扯到多级继承,那么函数对象的prototype之间会形成一个链式的调用:

孙子类的prototype->父类的_proto_
父类的prototype->爷爷类的_proto_
以此类推出现多级继承这样就会形成一个原型链

如图:
在这里插入图片描述

2.利用函数对象call和apply实现继承(call和apply只是传参格式上有区别)

代码如下(示例):

function Person (name,age){
    this.name = name
    this.age = age
}
// 定义人类的方法
Person.prototype.eat = function(){
    console.log('我是人类吃饭的方法')
}
Person.prototype.love = '感情'
// 定义子类学生类
function Student (name,age,score){
    // 继承父类的两个属性
    Person.call(this,name,age)
    // 自定义自己的属性
    this.score = score
}
// 实例化对象
// 改变了原型链继承的缺点可以在实例化的时候自定义初始值
var s = new Student('小明','13岁','98分')
console.log(s.name,s.age,s.score)
//输出:
小明 1398

缺点:

1.子类不能继承父类prototype中的属性和方法
处理方法:
将父类prototype中的方法写到父类的构造函数中,
但是也有一个缺点,就是每次实例化一个对象都会创建这个方法,
不管子类是否使用,会浪费内存,造成性能损耗。
function Person (name,age){
    this.name = name
    this.age = age
    this.eat = function eat(){
        console.log('父类的prototype方法')
    }
    
}
Person.prototype.love = '感情'
// 定义子类学生类
function Student (name,age,score){
    // 继承父类的两个属性
    Person.apply(this,[name,age])
    // 自定义自己的属性
    this.score = score
}
// 实例化对象
// 改变了原型链继承的缺点可以在实例化的时候自定义初始值
var s = new Student('小明','13岁','98分')
// s.prototype.eat = Person.prototype.eat()
console.log(s.name,s.age,s.score)
s.eat()

3.混合继承(call、apply和原型继承混合)

特点:
完美规避了原型继承和call、apply继承中出现的缺点,
是一种较为完美的实现继承的方案。
// 创建父类以及自身的属性
function Person(newId,newName){
    this.id  = newId
    this.name = newName
}
// 自定义prototype方法
Person.prototype.eat = function(){
    console.log('父类的方法')
}
// 创建子类

function Student(newId,newName,newScore){
    // 继承父类的id和name属性
    Person.call(this,newId,newName)
    // 定义自身的Score属性
    this.Score = newScore
}
// 利用prototype继承父类prototype中的方法和属性
Student.prototype = new Person()
var s = new Student('001','小明','98分')
console.log(s.id,s.name,s.Score)
s.eat()
//输出:
001 小明 98分
父类的方法

4.ES6 Class关键字继承

// ES6 新增关键字
class Person{
    // 构造函数,自定义自身属性
    constructor(newName,newId){
        this.name = newName
        this.id = newId
    }
    // 自定一方法
    eat(){
        console.log('父类的方法')
    }
}

class Student extends Person{
    constructor(newName,newId,newScore){
        // 使用super关键字来继承父类的属性,
        //必须要写在子类的属性前面
        super(newName,newId)
        this.score = newScore
    }
    run(){
        console.log('子类的方法')
    }
}
let s = new Student('001','小明','98分')
console.log(s.name,s.id,s.score)
s.run()
s.eat()
//输出
001 小明 98分
子类的方法
父类的方法

总结

这篇文章主要通过四种不同的方式实现js中的继承,继承在js面试题中也算是一大难点,看完我这篇文章希望对大家深入理解js继承机制有所帮助。
🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇
☞关注博主不迷路,博主带你上高速,希望大家可以共同进步。淦👊

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值