【笔记】【Javascript】javascript实现继承

前言

  • 之前写过关于面向对象编程的文章,通过阅读别人的博客了解了一下Javascript实现继承的方法,并且使用图画的形式帮助了解,图是自己做的,若有偏差请读者帮忙指出,谢谢。
  • 笔记中有些个人理解后整理的笔记,可能有所偏差,也恳请读者帮忙指出,谢谢。

免责声明

  • 为了方便,本文中使用的部分图片来自于网络,如有侵权,请联系博主进行删除,感谢其他博主提供的图床。
  • 此笔记用于记录本人对于该知识的汇总。以方便日后的工作与学习。
  • 如有侵权请告知,马上删除。

javascript如何实现继承?

【什么是继承?】

  • 子类拥有父类的特征行为

    • 特征==属性
    • 行为==方法

【怎么做?】

//父类
function Person(name){//给构造函数添加了参数this.name = name;this.msg = function(){alert(this.name);}
}
Person.prototype.age = 10;//给构造函数添加了原型属性

方法一:原型链继承

步骤1:创建一个子类,并把子类的原型对象指向父类的实例**(关键点)**

//创建子类
function Sub(){this.name = 'roy';
}
//子类的原型对象指向父类实例
Sub.prototype = new Person();

步骤2:创建子类实例,此时子类实例已经完成继承

var sub1 = new Sub();

步骤3:验证是否继承成功(其实真正实现继承仅上面两步即可,这一步属于调用父类,检验是否继承成功)

console.log(sub1.age);//10
//instanceof 判断元素是否在另一个元素的原型链上
//sub1继承了Person的属性,返回true
console.log(sub1 instanceof Person);//true

【分析】

  • 优点
    • 实现了继承
      • √ 实例的构造函数的属性(即子类的构造函数属性)
      • √ 父类的构造函数的属性
      • √ 父类原型的属性
  • 缺点
    • 新实例无法向父类构造函数传参
      • 【原因】步骤二时,是通过子类来创建新实例,而不是通过父类创建实例
    • 继承单一
      • 【原因】如图(1)一个子类仅继承一个父类
    • 修改子类实例的属性会改到父类的属性。
      • 【原因】如图(1)

方法二:构造函数继承

步骤1:在子类构造函数内回调父类构造函数(关键点)

function Sub(){Person.call(this,'roy');this.age = 12;
}

步骤2:创建子类实例

var sub1 = new Sub();

步骤3:检验是否继承成功

console.log(sub1.name);//roy
console.log(sub1.age);//12
console.log(sub1 instanceof Person);//false

【分析】

  • 优点
    • 实现了继承:
      • √ 继承父类构造函数的属性
      • ✕ 继承父类原型上的属性(如图(3))
    • 可以向父类构造函数传参
  • 缺点
    • 无法实现父类构造函数的复用
      • 【原因】用一次,重新调用父类构造函数一次
    • 每个新实例都有父类构造函数的副本,臃肿
      • 【原因】子类构造函数中产生了闭包,闭包导致内存泄露
    • 无法继承父类原型上的属性
      • 【原因】如图(3)

方法三:组合式继承

步骤1:在子类构造函数内回调父类构造函数**(关键点)**

function Sub(name){Person.call(this,name);//构造函数继承
}

步骤2:创建一个子类,并把子类的原型对象指向父类的实例**(关键点)**

Sub.prototype = new Person();//原型链继承

步骤3:创建子类实例,检验是否继承成功

var sub = new Sub('roy');
console.log(sub.name);//roy 继承了构造函数属性
console.log(sub.age);//10 继承了父类原型的属性

【分析】

  • 优点:
    • 实现了继承:
      • √ 继承父类原型上的属性
    • 可以传参,复用
    • 每个新实例引入的构造函数属性是私有的
      • 【原因】步骤1产生了闭包
  • 缺点:
    • 调用了两次父类构造函数,耗内存
    • 子类构造函数会代替原型上的父类的构造函数(不懂的点,欢迎小伙伴在评论区讨论一下)

方法四:ES6 Class类继承

为了统一使用ES6格式父类也进行改动一下(不改动直接用前面的父类也行)

//父类
class Person {//给构造函数添加constructor(name) {this.name = name;}msg() {alert(this.name);}
}
Person.prototype.age = 10;//给构造函数添加了原型属性

步骤1:使用关键字extends继承父类方法和属性,关键字super继承父类构造函数属性(关键点)

class Sub extends Person {  //继承父类方法constructor(name) {super(name);        //继承父类构造函数属性this.sex = 'boy';}
}

步骤2:创建子类实例,检验是否继承成功

const sub = new Sub('lao');
console.log(sub.age);    	//10	//证明继承父类构造函数原型属性
console.log(sub.name);   	//lao
console.log(sub.sex); 		//boy
console.log(sub.msg());
console.log(sub instanceof Person);   //true

【分析】

  • 优点:

    • 实现继承
      • √ 继承父类原型上的属性
      • √ 继承父类构造函数的属性
    • 写法更加的简洁
  • 缺点:

    • 函数申明不能自动提升(必须先声明再使用)

      【示例】

      let sub1 = new Sub()	//报错ReferenceError
      class Sub{}
      

方法五:原型式继承

步骤1:通过一个函数来模拟子类构造函数(关键点)

function content(obj){function F(){};			//模拟子类的构造函数F.prototype = obj;	//将子类构造函数原型对象设为父类实例return new F();			//创建子类构造函数实例
}

步骤2:创建父类的实例

var person = new Person();

步骤3:调用模拟子类构造函数来模拟创建子类实例

var sub1 = content(person);

步骤4:检验是否继承成功

console.log(sub1.age);//10 继承了父类函数的属性

【分析】

  • 优点:
    • 无需定义子类,反而使用一个现成的类直接继承。
  • 缺点:
    • 所有实例都会继承父类原型上的属性(如图(4)所示)
    • 无法实现复用(新实例属性都是后面添加的)

PS:Object.create()的原理就是通过原型式继承实现的

【简写】上述原型式继承可如下简写

var person = new Person();
var sub1 = Object.create(person);
console.log(sub1.age);//10 继承了父类函数的属性

方法六:寄生式继承

步骤1:通过一个函数来模拟子类构造函数(关键点)

function content(obj){function F(){};F.prototype = obj;//继承了传入的参数return new F();//返回函数对象
}

步骤2:创建父类实例

var person = new Person();

步骤3:创建一个仅用于封装继承过程的函数,函数的内部以某种方式来继承父类

function subObject(obj){var sub = content(obj);//通过调用函数sub.name = 'roy';//以某种方式来增强这个对象sub.sayHi=function(){console.log('hello');}return sub;//返回子类
}

步骤4:调用函数来模拟创建子类实例

var sub1 = subObject(person);

步骤5:

console.log(typeof subObject);//function
console.log(typeof sub1);//object
console.log(sub1.name);//'roy' 返回了个sub对象,继承了sub的属性
sub1.sayHi();	//'hello'

【分析】

  • 优点:
    • 为对象添加函数
  • 缺点:
    • 效率低
      • 【原因】不能做到函数复用

方法七:寄生组合继承

步骤1:创建父类,给父类添加方法

function Parent6() {this.name = 'parent6';this.play = [1, 2, 3];
}
Parent6.prototype.getName = function () {return this.name;
}

步骤2:创建子类,回调继承父类属性(关键点)

function Child6() {Parent6.call(this);	//继承服父类的属性this.friends = 'child6';
}

步骤3:借助函数,父子类关联(关键点)

function clone(parent, child) {// 这里改用 Object.create 就可以减少组合继承中多进行一次构造的过程child.prototype = Object.create(parent.prototype);child.prototype.constructor = child;
}clone(Parent6, Child6);

PS:子类构造器等于父类对象

【证明】

console.log(child.prototype.constructor == parent); //true

步骤4:给子类追加方法

Child6.prototype.getFriends = function () {return this.friends;
}

步骤5:验证继承

let person6 = new Child6();
console.log(person6);	//输出:带有父类属性的对象>>>>>>证明:实现子类继承父类属性
console.log(person6.getName());	//输出:parent6>>>>证明:实现子类继承父类的方法
console.log(person6.getFriends());//输出:child6>>>证明:子类可以追加方法

文献参考

[1] 贪吃的猫,《JS继承》,稀土掘金,2021-04-29

[2] 小小操作手,《js继承》,稀土掘金,2020-06-13

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/255394.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

linux条件变量知识点总结

与条件变量相关API 条件变量是线程另一可用的同步机制。条件变量给多个线程提供了一个会合的场所。条件变量与互斥量一起使用时,允许线程以无竞争的方式等待特定的条件发生。 条件本身是由互斥量保护的。线程在改变条件状态前必须首先锁住互斥量,其他线程…

chatgpt赋能python:Python中的平均值及其计算方式

Python中的平均值及其计算方式 Python是广泛使用的编程语言之一,它拥有强大而且易于使用的数据处理和分析功能。在数据分析领域,计算平均值是非常常见的操作之一。Python中有多种方法可以计算平均值,包括使用内置的函数和使用第三方库。本文…

实用网址资源集锦 -- 收集

http://tongji.baidu.com/data/browser 百度统计研究院 http://www.php-internals.com/book/?pchapt01/01-01-php-env-building 深入理解PHP内核 http://www.219.me/ 不错的博客 https://github.com/humiaozuzu/dot-vimrc 给力的vim配置 http://www.alloyteam.com/ 腾讯前端给…

IOS 加密、解密

首先罗列一些知识点: 1.加密算法通常分为对称性加密算法和非对称性加密算法:对于对称性加密算法,信息接收双方都需事先知道密匙和加解密算法且其密匙是相同的,之后便是对数据进行 加解密了。非对称算法与之不同,发送双…

iOS7以后,我们如何统计和跟踪用户

设备唯一标示,在App中,常用来统计和跟踪用户的行为。自从苹果在iOS5之后废弃掉了UDID后,找到一个稳定可用的设备标识一时成了业界棘手的问题,我们先看看目前的几种方案。 1 UDID UIDevice.uniqueIdentifier 接口在iOS 5.0被废弃 …

仿QQ变声功能的实现

Android ndk开发之QQ变声 要做出QQ变声的效果,用Android系统自带的MediaPlayer是无法实现的,只能另想他法了。听说汤姆猫是用SoundTouch实现的,而QQ是用FMOD实现的,就根据网上的教程,自己捣鼓ndk好几天,终…

iOS - 加解密(对称,非对称)(AES DES base64这里都有),数字签名,cookie

这篇文章不是研究性的东西,主要是简单的一些知识, 开篇如此, 我尽量不让读者失望。 首先罗列一些知识点: 1.加密算法通常分为对称性加密算法和非对称性加密算法:对于对称性加密算法,信息接收双方都需事先知…

ASP留言板(在一页里实现所有功能)

很久没发贴了,因为这些时间又在做ASP的页面,没用dotnet,有时真有点过意不去了。唉!中国现状呀! 发一个ASP留言板,当资料存着&#xff…

使用ffi-napi引入C++的dll

引言 这一篇将介绍如何在node.jselectron环境中, 使用node-ffi/ffi-napi调用C/C编写的动态链接库(即dll), 实现调用C/C代码。 本教程适用于electron 4.x-6.x版本。 如electron 4.2.10版本, electron 5.0.6版本, electron 6.0.10版本。 ffi 实现这个功能, 主要使用的插件是…

iOS各种设备识别码IDFA、UDID、UUID、MAC、OpenUDID、IDFV

今天在app服务端接口文档中看到2个接口名称,是和idfa相关的,就搜索了解了一下,顺便梳理了ios各种设备识别码。 *IDFA英文全称IdentifierforAdvertising,即广告标示符,目前是苹果生态内广告交易的主要标示符&#xff0…

RFID节点的编写

新项目开始咯,其实就是华清项目的换皮,增强了对传感器的控制加了大量的32采集与控制节点,由于时间紧迫先按照节点发布文章。以后有时间会发一些框架和整体数据流向分析的文章。 一、RFID节点框架 我的想法是使用超高频RFID技术,…

(七)DSP28335基础教程——I2C通信实验(OLED显示控制)

0 前言 本期实验目标:采用硬件I2C模块与OLED进行通信,完成显示控制。 目前发现28335比较缺乏关于I2C模块的实用例程,许多新手在配置使用该模块比较难上手,走弯路。那么通过该例程,大家则可以快速学会使用I2C的基本功…

安卓开发淘宝抢购界面!史上最全的Android面试题集锦,附带学习经验

前言 这是“拔剑金九银十”的第二篇文章,本文主要针对3年以上的Android开发者进阶面试中高级开发工程师而整理。 希望可以对你们有所帮助。不多废话,进入正题。 目录: Java中高级 计算机网络 Android高级面试—性能优化 Android优秀第三方…

Linux系统下imx6ull QT编程—— Ubuntu 下编写程序(一)

Linux QT编程 文章目录 Linux QT编程前言一、C简介二、C环境设置1.安装编译 C 语言和 C的环境。2.创建文件编写代码3.编译运行代码 总结 前言 绍在 Ubuntu 在终端窗口下使用 vi/vim 编辑一个 C源文件。通过编写最简单的示例“Hello,World QCX”。 一、C简介 C (c…

0531最后的挣扎结束于传说中的段错误

部署训练后的缺陷检测模型 Linux Ubuntu18.04双机尝试 报错,Linux内核或是编译器版本不匹配,多次尝试更改18.04的gcc,g,gcc-arm-linux,garm-linux的代码,尝试在Makefile文件里更改编译器路径、添加LInux内…

用Python求最大公约数和最小公倍数(51)

小朋友们好,大朋友们好! 我是猫妹,一名爱上Python编程的小学生。 和猫妹学Python,一起趣味学编程。 今日主题 什么是最大公约数? 如何用Python求最大公约数? 什么是最小公倍数? 如何用Pyt…

PDF免费压缩、在线压缩

找了很多个网站,发现说是免费,其实不然。 在线上传,在线压缩,然后直接下载,没有任何套路。 PDF Compressor – Compress PDF Files OnlineThis online PDF compressor allows compressing PDF files without degradi…

PDF文件怎么压缩大小

PDF文件怎么压缩大小?3个办法实现一键压缩 相信大家在工作中,会收到许多的PDF文件,但随着时间的推移,PDF文件便会越积越多,最终导致我们的电脑内存严重不足,这时候只好把一些PDF文件删除,来释放…

【C#图解教程】第四章 类型、存储和变量 学习笔记总结

类型 C#是一组类型声明,这个与第三章:命名空间就是一组类型声明可以一起理解。类型是一个用来创建数据结构的模板: 使用这个模板创建对象的过程叫做实例化,所以创建的对象也叫实例 类型成员 简单类型可能只包含一个数据成员&…

chatgpt赋能python:Python中的%怎么用

Python中的%怎么用 Python中的%是一个非常重要的运算符,也称为格式化运算符。它用于将一个值插入到另一个字符串中。在本文中,我们将深入了解Python中的%运算符的使用。 %运算符的语法 先看下%运算符的语法: string % values其中&#xf…