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

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

相关推荐
Rubin935 分钟前
判断元素在可视区域?用于滚动加载,数据埋点等
前端
爱学习的茄子6 分钟前
AI驱动的单词学习应用:从图片识别到语音合成的完整实现
前端·深度学习·react.js
用户3802258598246 分钟前
使用three.js实现3D地球
前端·three.js
程序无bug8 分钟前
Spring 面向切面编程AOP 详细讲解
java·前端
zhanshuo9 分钟前
鸿蒙UI开发全解:JS与Java双引擎实战指南
前端·javascript·harmonyos
JohnYan9 分钟前
模板+数据的文档生成技术方案设计和实现
javascript·后端·架构
撰卢32 分钟前
如何提高网站加载速度速度
前端·javascript·css·html
10年前端老司机38 分钟前
在React项目中如何封装一个可扩展,复用性强的组件
前端·javascript·react.js
Struggler28140 分钟前
解决setTimeout/setInterval计时不准确问题的方案
前端
sophie旭1 小时前
《深入浅出react开发指南》总结之 10.1 React运行时总览
前端·react.js·源码阅读