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也是使用寄生组合继承原理

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

相关推荐
Csvn21 小时前
`??` 和 `||` 搞混,线上用户头像全挂了
前端
kyriewen21 小时前
白宫前脚下了限制令,OpenAI 后脚就把 GPT-5.6 发了
前端·gpt·openai
用户40269244819081 天前
CRMEB Pro 新增后台接口全链路:路由、权限、验证器、返回格式一次讲清
前端·后端
泉城老铁1 天前
springboot+vue+ ffmpeg 实现视频的拉流播放
前端
PedroQue991 天前
uni-router v1.8.0新增冷启动守卫补执行
前端·uni-app
xiaok1 天前
部署之后,本地浏览器还在读取旧缓存导致页面一直显示loading中
前端
用户059540174461 天前
Redis缓存一致性踩坑实录:线上故障排查6小时,我用pytest+内存快照把它永久关进了笼子
前端·css
星栈1 天前
我用 Rust + Dioxus 做了个全栈跨平台笔记应用:第一版先把列表和详情跑通
前端·rust·前端框架
用户1733598075371 天前
Vue 3 SPA 首屏优化:从 3s 到 1.2s 的 5 个实践
前端·vue.js
咖啡无伴侣1 天前
基础骨架:30 分钟搭好 pnpm workspace,完成双项目 Monorepo 迁入
前端