浅谈JavaScript的几种继承实现方式

 更新时间:2023年04月23日 09:09:47   作者:tsja  
本文主要介绍了浅谈JavaScript的几种继承实现方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

当前需求: 实现 Student 继承自 Person

如果手动实现继承效果, Person和Student分别写自己的属性和方法, 两个构造函数之间没有任何关联

  • 代码编写繁琐
  • 可维护性低

构造函数Person

function Person(name, age, height, address) {
	this.age = age
	this.height = height
	this.address = address
}

Person.prototype.running = function() {
	console.log("running~")
}

Person.prototype.eating = function() {
	console.log("eating~")
}

构造函数Student

function Student(name, age, height, address, sno, score) {
	this.age = age
	this.height = height
	this.address = address
	this.sno = sno
	this.score = score
}

Student.prototype.running = function() {
	console.log("running~")
}
Student.prototype.eating = function() {
	console.log("eating~")
}
Student.prototype.studying = function() {
	console.log("studying~")
}

内存图

Pasted image 20230419141544.png

希望满足的条件功能

Student构造函数满足以下条件

  • 能够重写继承的方法, 但不修改Person原型上的方法.
  • 能够增加方法, 但不会影响Person原型上的方法.

Student构建出的实例对象满足以下条件

  • 有name, age, height, address属性, 并且扩充sno和score. 作为自己独立的属性.
  • 继承running, eating方法, 和Person实例对象的方法有相同的引用.

利用原形链实现方法的继承

方式1: 子类原型指向父类原型

function Student(age, height, address, sno, score) {
	this.age = age
	this.height = height
	this.address = address
	this.sno = sno
	this.score = score
}

+ Stuednt.prototype = Person.prototype

内存图

Pasted image 20230419142001.png

缺点

父类和子类共享通一个原型对象, 修改了任意一个, 另外一个也被修改

方式2 子类原型指向父类实例对象

function Student(sno, score) {
	this.sno = sno
	this.score = score
}
+ var p = new Person()
+ Student.prototype = p

内存图

Pasted image 20230419142506.png

缺点

  • 属性放在了原型上, 无法通过打印查看.
  • 创建的多个实例对象, 继承的属性不互相独立, 一个实例对象修改属性影响其他的实例对象
  • 要new一个实例, 怪怪怪怪怪怪

借用构造函数继承

方式3 组合继承

function Person(name, age, height, address) {
	this.name = name
	this.age = age
	this.height = height
	this.address = address
}
Person.prototype.running = ...

function Student(age, height, address, sno, score) {
+   Person.call(this, age, height, address)
	this.sno = sno
	this.score = score
}

Student.prototype = new Person()

内存图

Pasted image 20230419165358.png

优点

解决之前的硬性问题, 实例对象属性独立, 属性放在对象内而不是原型上.

缺点

  • 调用两次父类的构造方法, 性能浪费
    • Student.prototype = new Person()第一次
    • Person.call(this)第二次
  • 调用两次构造方法, 导致子类创建的实例对象上, 保留了两份父类的属性
    • 一份在实例对象的__proto__上, new时产生的
    • 一份在实例对象上, 通过借用构造方法call得到

寄生式继承

思路

属性的继承已经解决, 通过Person.call(this) 解决.

方法的继承未解决, 需要找到 Student.prototype = new Person() 的替代方案

思路1

var obj = {}
obj.__proto__ = Person.prototype
Student.prototype = obj

// __proto__为浏览器增加的属性, 解决浏览器兼容性问题可以改为
var obj = {}
Object.setPrototypeOf(obj, Person.prototype)
Student.prototype = obj

思路2

兼容所有浏览器 解决老版本浏览器不支持setPrototypeOf

function F() {}
F.prototype = Person.prototype
Student.prototype = new F()

思路3

Object.create() 传入一个对象作为参数, 并返回一个对象, 返回的对象的原型为传入对象

var obj = Object.create(Person.prototype)
Student.prototype = obj 

最终 方式4: 寄生组合式继承

// 工具函数
// 创建对象的过程
function createObject(proto) {
	function F() {}
	F.prototype = proto 
	return new F()
}

// 将Subtype和Supertype联系在一起
// 寄生式函数
function inherit(Subtype, Supertype) {
	Subtype.prototype = createObject(Supertype.prototype)
	Object.defineProperty(Subtype.prototype, "constructor", {
		enumerable: false,
		configurable: true,
		writable: true,
		value: Subtype
	})
}

function Student(age, height, sno, score) {
	Person.call(this, age, height)
	this.sno = sno
	this.score = score
}

+ inherit(Student, Person)

// 使用方法
Student.prototype.studying = function() {
	console.log("studying")
}

💡 使用Person.call实现属性的继承

💡 使用inherit实现方法的继承

  • createObject 使Student.prototype指向Person的prototype, 但中间多一个构造函数F(), 解决方式1 的问题
  • Object.defineProperty 实现 Student.prototypeconstructor 属性指回Student构造函数.内存图

image.png

附: 扩充createObject

最初的设计思想, 是为了实现对象的继承, 所以有了以下的代码

createObject只能够做到构造一个有原型的空对象, 现在想要让构造的对象也有属性

createInfo(proto, age, height) {
	const newObj = this.createObject(proto)
	newObj.age = age
	newObj.height = height
	return newObj
}

到此这篇关于浅谈JavaScript的几种继承实现方式的文章就介绍到这了,更多相关JavaScrip 继承内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • JavaScript详细分析数据类型和运算符

    JavaScript详细分析数据类型和运算符

    这篇文章主要介绍了JavaScript数据类型和运算符案例,结合实例形式分析了JavaScript数据类型和运算符特性与相关操作技巧,需要的朋友可以参考下
    2022-07-07
  • 使用JavaScript实现随机曲线之间进行平滑切换

    使用JavaScript实现随机曲线之间进行平滑切换

    今天,我运用拉格朗日插值法绘制了一条曲线,然而,我并未止步于静态展示,而是引入了一个定时器,每隔一段时间便对曲线上的点进行动态更新,从而赋予曲线生命般的动态变化,本文介绍了使用JavaScript实现随机曲线之间进行平滑切换,感兴趣的朋友可以参考下
    2024-11-11
  • Webpack介绍和基本使用指南

    Webpack介绍和基本使用指南

    Webpack 本身功能比较少,只能处理 js 资源,一旦遇到 css 等其他资源就会报错,本文给大家讲解Webpack介绍和基本使用指南,感兴趣的朋友一起看看吧
    2024-02-02
  • JS中null和undefined的区别

    JS中null和undefined的区别

    在JavaScript中,null和undefined是两个常见的数据类型,本文就详细的介绍了JS中null和undefined的区别,感兴趣的可以了解一下
    2023-05-05
  • JS生成不重复的随机数组的简单实例

    JS生成不重复的随机数组的简单实例

    下面小编就为大家带来一篇JS生成不重复的随机数组的简单实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-07-07
  • js判断请求的url是否可访问,支持跨域判断的实现方法

    js判断请求的url是否可访问,支持跨域判断的实现方法

    下面小编就为大家带来一篇js判断请求的url是否可访问,支持跨域判断的实现方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-09-09
  • 一文详解HTML中script 标签的属性

    一文详解HTML中script 标签的属性

    在HTML中,<script>标签用于嵌入或引用JavaScript代码,在HTML中,<script>标签用于嵌入或引用JavaScript代码,本文将详细的而介绍这两个标签,感兴趣的同学可以参考一下
    2023-04-04
  • javascript while语句和do while语句的区别分析

    javascript while语句和do while语句的区别分析

    这篇文章通过实例代码较详细的给大家介绍了javascript while语句和do while语句的区别,感兴趣的朋友一起看看吧
    2007-12-12
  • jQuery中deferred对象使用方法详解

    jQuery中deferred对象使用方法详解

    这篇文章主要为大家详细介绍了jQuery中deferred对象使用方法,也就是延迟对象的使用方法,感兴趣的小伙伴们可以参考一下
    2016-07-07
  • 详解JavaScript原生封装ajax请求和Jquery中的ajax请求

    详解JavaScript原生封装ajax请求和Jquery中的ajax请求

    在本篇文章中我们总结了关于JavaScript原生封装ajax请求和Jquery中的ajax请求的知识点内容,需要的朋友们学习参考下。
    2019-02-02

最新评论