JS基础⚡️ 探究JS的六种继承

JavaScript中,相比于传统的面向对象编程语言使用类(class)来实现继承关系,JS的做法是利用原型对象(prototype)来实现继承。虽然在 ES6 中引入了class语法,但实质上该语法仍然基于原型继承实现(语法糖)。

今天让我们来学习下六种继承的方式

第一种 原型链的继承

js 复制代码
function Person() {
  this.name = 'Person'
}
Person.prototype.eating = function () {
  console.log(this.name + 'eating~')
}
// 子类:特有属性和方法
function Student() {
  this.sno = 111
}
const p = new Person()
Student.prototype = p
Student.prototype.studying = function () {
  console.log(this.name + ' studying~')
}
const stu = new Student()
console.log(stu.name) // Person
stu.eating() // Person eating~
stu.studying() // Person studying~

弊端有很多

1.第一个弊端:打印stu对象,继承的属性是看不到的

2.直接修改对象上的属性,是给本对象添加了一个新属性 获取引用,修改引用中的值,会相互影响

3.第三个弊端:在前面实现类的过程中都没有传递参数

第二种 借用构造函数继承

js 复制代码
function Person(name, age, friends) {
  this.name = name
  this.age = age
  this.friends = friends
}
Person.prototype.eating = function () {
  console.log(this.name + ' eating~')
}
function Student(name, age, friends, sno) {
  Person.call(this, name, age, friends)
  this.sno = 111
}
const p = new Person()
Student.prototype = p
Student.prototype.studying = function () {
  console.log(this.name + ' studying~')
}
const stu = new Student('Student', 18, ['kobe'], 111)
console.log(stu.name)  // Student
stu.eating() // Student studying~
stu.studying()//Student eating~

原型链继承的弊端基本解决

但是借用构造函数也会有自己的弊端:

1.第一个弊端: Person函数至少被调用了两次

2.第二个弊端: stu的原型对象上会多出一些属性, 但是这些属性是没有存在的必要

第三种 组合继承

js 复制代码
function Person(name, age, friends) {
  this.name = name
  this.age = age
  this.friends = friends
}
Person.prototype.eating = function () {
  console.log(this.name + ' eating~')
}
//子类
function Student(name, age, friends, sno) {
  Person.call(this, name, age, friends)
  this.sno = 111
}
// 直接将父类的原型赋值给子类, 作为子类的原型
// 直接将 Person.prototype 赋值给 Student.prototype 会导致 Student.prototype 和 Person.prototype 指向同一个对象,因此对 Student.prototype 的修改也会影响到 Person.prototype,因此使用`Object.create` 来创建一个新的对象,并将其赋值给 `Student.prototype`,以保持继承关系的正确性
Student.prototype = Object.create(Person.prototype)
Student.prototype.studying = function () {
  console.log(this.name + ' studying~')
}
const stu = new Student('student', 18, ['friend'], 111)
console.log(stu) // Person { name: 'student', age: 18, friends: [ 'friend' ], sno: 111 }
stu.eating() // student eating~

组合继承结合了原型链继承和构造函数继承的优点。首先使用构造函数继承来继承父对象的属性,然后将父对象的原型赋值给子对象的原型,实现对父对象原型上方法的继承。

第四种 原型式继承

js 复制代码
let obj = {
  name: 'why',
  age: 18
}
let info = Object.create(obj)
console.log(info)
console.log(info.__proto__)

弊端

1.原型链继承多个实例的引用类型属性指向相同。修改引用中的值,会相互影响。

2.无法传递参数

第五种 寄生式继承

js 复制代码
let personObj = {
  running: function () {
    console.log('running')
  }
}
function createStudent(name) {
  let stu = Object.create(personObj)
  stu.name = name
  stu.studying = function () {
    console.log('studying~')
  }
  return stu
}

let stuObj = createStudent('why')
let stuObj1 = createStudent('kobe')
let stuObj2 = createStudent('james')

弊端与原型式继承一样

1.原型链继承多个实例的引用类型属性指向相同。修改引用中的值,会相互影响。

2.无法传递参数

第六种 寄生组合式继承

js 复制代码
//将SubType的原型对象指向SuperType的原型对象
function inheritPrototype(SubType, SuperType) {
  SubType.prototype = Object.create(SuperType.prototype)
// 重新定义 SubType 的 constructor 属性
 Object.defineProperty(SubType.prototype,'constructor',{
    enumerable: false,
    configurable: true,
    writable: true,
    value: SubType
  })
}
function Person(name, age, friends) {
  this.name = name
  this.age = age
  this.friends = friends
}
Person.prototype.running = function () {
  console.log('running~')
}
function Student(name, age, friends, sno, score) {
  Person.call(this, name, age, friends)
  this.sno = sno
  this.score = score
}
inheritPrototype(Student, Person)
Student.prototype.studying = function () {
  console.log('studying~')
}
let stu = new Student('student', 18, ['xiaoming'], 111, 100)
console.log(stu)
stu.studying()
stu.running()
console.log(stu.constructor.name)

这个方法比较成熟 前面继承方式弊端基本解决 只调用一次父类构造函数 Child可以向Parent传参 父类方法可以复用 父类的引用属性不会被共享 ES6中的类继承extends也是使用寄生组合继承原理

文章更多作为个人学习,有错欢迎指出,也希望对你有所帮助

相关推荐
林太白19 分钟前
npm多组件发布Vue3+TS版本,快来像Antd一样搭建属于你的UI库吧
前端·javascript·node.js
Juchecar27 分钟前
如何避免Node.js项目node_modules重复占用空间
前端
百罹鸟38 分钟前
nestjs 从零开始 一步一步实践
前端·node.js·nestjs
袁煦丞1 小时前
Wiki.js团队知识大脑/个人笔记管家:cpolar内网穿透实验室第496个成功挑战
前端·程序员·远程工作
Alporal1 小时前
【前端学习】背闭包快疯了?我用实际场景搞懂了!
javascript
维他AD钙1 小时前
2025 年前端性能优化实战:从加载到渲染的全链路优化指南
前端
大米饭消灭者1 小时前
markdown-it是怎么将markdown转为html的
前端·面试
1024小神2 小时前
在vue/react项目中单独引入一个js文件,在js文件中使用DOMContentLoaded函数querySelectorAll为空数组解决办法
前端
moyu842 小时前
前端请求封装实战解析:基于Axios的封装技巧
前端