在JavaScript中实现继承的几种方式
文章目录
- 前言
- 继承的几种方式
- 构造方式继承
- 进行测试
- 结论
- 修改原型继承
- 进行测试
- 结论
- (构造函数+修改原型)组合继承
- 进行测试
- 结论
- 基于组合继承的优化
- 测试
- 结论
- 总结
前言
JavaScript作为一门面向对象语言,自然有封装、继承、多态的特性,在其他面向对象语言中(如Java、python等),通过类来实现继承,而JavaScript中没有类的概念,于是JavaScript的继承方式区别于传统的继承方式,且有多种实现
继承的几种方式
以下为JavaScript中常见实现继承的方式,不代表全部。
构造方式继承
function Father() {this.name = "father";this.say = function () {console.log("father say")}
}
Father.prototype.pname = "father prototype";
Father.prototype.run = function () {console.log("father prototype run")
}function Sun() {Father.call(this) //通过call方法将Father函数的this指向//绑定为new Sun()的对象上实现继承
}
进行测试
const sun1 = new Sun();
const sun2 = new Sun();
console.log(sun1.name); //father
sun2.name = "sun2";
console.log(sun1.name); //father
sun1.say(); //father say
console.log(sun1.pname); //报错,未找到该属性
sun1.run(); //报错,未找到该函数
结论
优点
:简单。sun1
和sun2
对象继承了Father构造函数
中的属性与方法,并且分别维护。
缺点
:只继承了Father构造函数中定义的属性与方法,却没有继承
到Father构造函数的原型对象
中的属性与方法。
修改原型继承
function Father() {this.name = "father";this.say = function () {console.log("father say")}
}
Father.prototype.pname = "father prototype";
Father.prototype.run = function () {console.log("father prototype run")
}function Sun() {}//将Sun构造函数的原型对象修改为
//Father实例对象,则由Sun构造函数
//实例化的对象都将有__proto__指针
//指向这个Father实例对象(原型对象)
Sun.prototype = new Father();//修改原型对象的constructor指向用于
//优化instanceof 判断问题
Sun.prototype.constructor = Sun;
进行测试
const sun1 = new Sun();
const sun2 = new Sun();sun1.say(); //father say
sun1.run(); //father prototype run
console.log(sun1.pname); //father prototype
console.log(sun1.name); //father
console.log(sun2.name); //father
sun1.__proto__.name = "sun1";//修改原型对象上的属性将影响所有实例
console.log(sun1.name); //sun1
console.log(sun2.name); //sun1
结论
优点
:现在由Sun构造函数创建的实例对象可以访问Father构造函数的原型对象了,即形成了一条原型链:null --> Object.prototype --> Father.prototype --> Sun.prototype(Father实例对象)--> sun1
。
缺点
:Father实例上定义的属性是全部实例都可共享
的,这就出现了只要一个实例修改了原型对象上的属性值,将会影响所有的实例
。
(构造函数+修改原型)组合继承
只要将上面两种继承的方式合并一下
,即可把各自的缺点给弥补
function Father() {this.name = "father";this.say = function () {console.log("father say")}
}
Father.prototype.pname = "father prototype";
Father.prototype.run = function () {console.log("father prototype run")
}function Sun() {Father.call(this) //构造继承
}
Sun.prototype = new Father(); //修改原型对象
Sun.prototype.constructor = Sun; //优化instanceof判断问题
进行测试
const sun1 = new Sun();
const sun2 = new Sun();sun1.say(); //father say
sun1.run(); //father prototype run
console.log(sun1.pname); //father prototype
console.log(sun1.name); //father
console.log(sun2.name); //father
sun1.__proto__.name = "sun1";
sun1.name = "sun1";
console.log(sun1.name); //sun1
console.log(sun2.name); //father
结论
优点
:现在每个实例对象都维护自身的属性了,修改自身属性及原型对象上的属性均不会影响其他实例,而且形成了一条原型链,可访问原型链中所有属性及方法。
缺点
:由于我们使用了call函数
使得每个实例上都存在与Sun原型对象同名的属性及方法
,所以Sun原型对象
上的属性及方法皆可不要,因为增加了内存开销
。
基于组合继承的优化
基于上一个继承方式的情况,我们可以很自然的得出一个解决方案:将Sun构造函数的原型对象,即Father实例对象上的不必要的属性及方法除去
即可。
function Father() {this.name = "father";this.say = function () {console.log("father say")}
}
Father.prototype.pname = "father prototype";
Father.prototype.run = function () {console.log("father prototype run")
}function Sun() {Father.call(this)
}
Sun.prototype = (function () {function Foo() { } // 声明一个空的构造函数//将该函数的原型对象修改为Father构造函数的原型对象Foo.prototype = Father.prototype//返回该函数的实例化对象,此对象为空对象,且__proto__指针//指向Father.prototype。以此做到了在不断掉原型链的情况下//将Sun构造函数的原型对象置为空对象。return new Foo()
})();
Sun.prototype.constructor = Sun;
测试
const sun1 = new Sun();console.log(sun1.__proto__.name); //undefined
sun1.run(); //father prototype run
结论
该方法应该算是JavaScript继承方案中的最优解了,通过babel转译成es5代码时所用的继承方案
总结
以上是个人学习的一些总结,作为记录特此写下这篇博客,日后忘了可回头看看。
在JavaScript中实现继承的几种方式相关推荐
- Django中Model继承的三种方式
Django中Model继承的三种方式 Django中Model的继承有三种: 1.抽象继承 2.多表继承 3.proxy model(代理model) 1.抽象继承 第一种抽象继承,创建一个通用父类 ...
- javaScript中创建数组的3种方式
JS数组定义及详解 javascript如何定义数组? 直接上代码和截图 //javaScript中创建数组的3种方式 //方式1 var names = ["令狐冲", &quo ...
- javascript中定义事件的三种方式
在javascript中,可以为某个元素指定事件,指定的方式有以下三种: 1.在html中,使用onclick属性 2.在javascript中,使用onclick属性 3.在javascipt中,使 ...
- JavaScript笔记 - 对象继承的几种方式
1)对象冒充 2)call方式 3)apply方式 4)原型链 5)混合方式 1)对象冒充 Js代码 function People(name, age) { this.name = name; th ...
- JavaScript中定义对象的几种方式
JavaScript中没有类的概念,只有对象. 在JavaScript中定义对象可以采用以下5种方式(附加改进方式): 1.基于已有对象扩充其属性和方法 2.工厂方式 3.构造函数方式 4.原型(&q ...
- html中数组的定义,javascript中数组定义的几种方式是什么?
javascript中怎么定义数组?下面本篇文章给大家介绍一下javascript数组定义的几种方法.有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助. 1.什么是数组 数组就是一组数据 ...
- 【JS】JavaScript中创建数组的6种方式(代码示例合集)
创建数组的6种方式 <!DOCTYPE html> <html lang="en"><head><meta charset="U ...
- javascript 面向对象(实现继承的几种方式)
欢迎大家关注我的公众号[老周聊架构],Java后端主流技术栈的原理.源码分析.架构以及各种互联网高并发.高性能.高可用的解决方案. 1.原型链继承 核心: 将父类的实例作为子类的原型 缺点: 父类新增 ...
- JavaScript(js)实现继承的几种方式
1.原型链继承 核心:将父类的实例做为子类的原型对象 //动物类function Animal(name,sex) {this.name = name || 'Animal';this.sex = s ...
- javascript中清空数组的两种方式
1,length赋0 var a=new Array(); a.length=0; 2 [] var a=new Array(); a=[];
最新文章
- 理科生用创意毁灭世界,爆笑!
- Nature子刊:干旱条件下土壤细菌网络的稳定性不如真菌网络
- WAL streaming (max_wal_senders 0) requires wal_level replica or logical
- IIS 6.0支持.SHTML
- 我们只知大势将至,却不知未来已来
- linux监控任务跑满,Linux服务器带宽和CPU跑满或跑高排查
- python职业发展规划书范文_职业生涯规划书范文 3篇
- java常用算法整理
- 会计与计算机融合的会计论文,管理会计与财务会计融合浅析论文
- Vue组件动态(异步)传值
- shader之——shadowGun代码分析
- 中国菜刀使用与原理分析
- 三菱FX5U控制10轴伺服的设备成套电气图纸
- 解决Mac上用spotlight搜索输入几个字母后闪退
- 程序linux培训,马哥-51CTO-Linux培训-0910-程序包管理
- 物质模拟器3.0版,变得彩色
- 自学系列外星人入侵2
- 微软所有正版软件下载网站ITELLYOU_我是亲民_新浪博客
- Android GPU呈现模式分析功能,手机流畅度。仅供参考
- 【python 题练】
热门文章
- 建议IPC采用RTMP(server+rtmppush)的流媒体框架。
- Wap模拟器,pc端浏览器,手机wap网站,web项目
- 城通网盘文件过期自动提醒
- Fastjson存在0day漏洞
- 等差素数列 蓝桥杯 python
- 使用instsrv.exe+srvany.exe将应用程序安装为windows服务的方法
- HTML5+CSS大作业 网页制作代码_大学生网页制作作业代码——年会抽奖网页设计(1页)
- Android,App 常用图标尺寸规范
- 计算机找不到链接打印机主机,电脑连接打印机厂商型号没有怎么办
- 工业数据采集网关的特点及应用场景