文章目录

  • 前言
  • 继承的几种方式
    • 构造方式继承
      • 进行测试
      • 结论
    • 修改原型继承
      • 进行测试
      • 结论
    • (构造函数+修改原型)组合继承
      • 进行测试
      • 结论
    • 基于组合继承的优化
      • 测试
      • 结论
  • 总结

前言

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(); //报错,未找到该函数

结论

优点:简单。sun1sun2对象继承了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中实现继承的几种方式相关推荐

  1. Django中Model继承的三种方式

    Django中Model继承的三种方式 Django中Model的继承有三种: 1.抽象继承 2.多表继承 3.proxy model(代理model) 1.抽象继承 第一种抽象继承,创建一个通用父类 ...

  2. javaScript中创建数组的3种方式

    JS数组定义及详解 javascript如何定义数组? 直接上代码和截图 //javaScript中创建数组的3种方式 //方式1 var names = ["令狐冲", &quo ...

  3. javascript中定义事件的三种方式

    在javascript中,可以为某个元素指定事件,指定的方式有以下三种: 1.在html中,使用onclick属性 2.在javascript中,使用onclick属性 3.在javascipt中,使 ...

  4. JavaScript笔记 - 对象继承的几种方式

    1)对象冒充 2)call方式 3)apply方式 4)原型链 5)混合方式 1)对象冒充 Js代码 function People(name, age) { this.name = name; th ...

  5. JavaScript中定义对象的几种方式

    JavaScript中没有类的概念,只有对象. 在JavaScript中定义对象可以采用以下5种方式(附加改进方式): 1.基于已有对象扩充其属性和方法 2.工厂方式 3.构造函数方式 4.原型(&q ...

  6. html中数组的定义,javascript中数组定义的几种方式是什么?

    javascript中怎么定义数组?下面本篇文章给大家介绍一下javascript数组定义的几种方法.有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助. 1.什么是数组 数组就是一组数据 ...

  7. 【JS】JavaScript中创建数组的6种方式(代码示例合集)

    创建数组的6种方式 <!DOCTYPE html> <html lang="en"><head><meta charset="U ...

  8. javascript 面向对象(实现继承的几种方式)

    欢迎大家关注我的公众号[老周聊架构],Java后端主流技术栈的原理.源码分析.架构以及各种互联网高并发.高性能.高可用的解决方案. 1.原型链继承 核心: 将父类的实例作为子类的原型 缺点: 父类新增 ...

  9. JavaScript(js)实现继承的几种方式

    1.原型链继承 核心:将父类的实例做为子类的原型对象 //动物类function Animal(name,sex) {this.name = name || 'Animal';this.sex = s ...

  10. javascript中清空数组的两种方式

    1,length赋0 var a=new Array(); a.length=0; 2 [] var a=new Array(); a=[];

最新文章

  1. 理科生用创意毁灭世界,爆笑!
  2. Nature子刊:干旱条件下土壤细菌网络的稳定性不如真菌网络
  3. WAL streaming (max_wal_senders 0) requires wal_level replica or logical
  4. IIS 6.0支持.SHTML
  5. 我们只知大势将至,却不知未来已来
  6. linux监控任务跑满,Linux服务器带宽和CPU跑满或跑高排查
  7. python职业发展规划书范文_职业生涯规划书范文 3篇
  8. java常用算法整理
  9. 会计与计算机融合的会计论文,管理会计与财务会计融合浅析论文
  10. Vue组件动态(异步)传值
  11. shader之——shadowGun代码分析
  12. 中国菜刀使用与原理分析
  13. 三菱FX5U控制10轴伺服的设备成套电气图纸
  14. 解决Mac上用spotlight搜索输入几个字母后闪退
  15. 程序linux培训,马哥-51CTO-Linux培训-0910-程序包管理
  16. 物质模拟器3.0版,变得彩色
  17. 自学系列外星人入侵2
  18. 微软所有正版软件下载网站ITELLYOU_我是亲民_新浪博客
  19. Android GPU呈现模式分析功能,手机流畅度。仅供参考
  20. 【python 题练】

热门文章

  1. 建议IPC采用RTMP(server+rtmppush)的流媒体框架。
  2. Wap模拟器,pc端浏览器,手机wap网站,web项目
  3. 城通网盘文件过期自动提醒
  4. Fastjson存在0day漏洞
  5. 等差素数列 蓝桥杯 python
  6. 使用instsrv.exe+srvany.exe将应用程序安装为windows服务的方法
  7. HTML5+CSS大作业 网页制作代码_大学生网页制作作业代码——年会抽奖网页设计(1页)
  8. Android,App 常用图标尺寸规范
  9. 计算机找不到链接打印机主机,电脑连接打印机厂商型号没有怎么办
  10. 工业数据采集网关的特点及应用场景