手把手教你如何实现继承

本文将从最简单的例子开始,从零讲解在 JavaScript 中如何实现继承。


小例子

现在有个需求,需要实现 Cat 继承 Animal ,构造函数如下:

function Animal(name){this.name = name
}function Cat(name){this.name = name
}
复制代码

注:如对继承相关的 prototype、constructor、__proto__、new 等内容不太熟悉,可以先查看这篇文章:理性分析 JavaScript 中的原型


继承

在实现这个需求之前,我们先谈谈继承的意义。继承本质上为了提高代码的复用性。

对于 JavaScript 来说,继承有两个要点:

  1. 复用父构造函数中的代码
  2. 复用父原型中的代码

下面的内容将围绕这两个要点展开。

第一版代码

复用父构造函数中的代码,我们可以考虑调用父构造函数并将 this 绑定到子构造函数。

复用父原型中的代码,我们只需改变原型链即可。将子构造函数的原型对象的 __proto__ 属性指向父构造函数的原型对象。

第一版代码如下:

function Animal(name){this.name = name
}function Cat(name){Animal.call(this,name)
}Cat.prototype.__proto__ = Animal.prototype
复制代码

检验一下是否继承成功:我们在 Animal 的原型对象上添加 eat 函数。使用 Cat 构造函数生成一个名为 'Tom' 的实例对象 cat 。代码如下:

function Animal(name){this.name = name
}function Cat(name){Animal.call(this,name)
}Cat.prototype.__proto__ = Animal.prototype// 添加 eat 函数
Animal.prototype.eat = function(){console.log('eat')
}var cat = new Cat('Tom')
// 查看 name 属性是否成功挂载到 cat 对象上
console.log(cat.name) // Tom
// 查看是否能访问到 eat 函数
cat.eat() // eat 
// 查看 Animal.prototype 是否位于原型链上
console.log(cat instanceof Animal) // true
// 查看 Cat.prototype 是否位于原型链上
console.log(cat instanceof Cat) //true
复制代码

经检验,成功复用父构造函数中的代码,并复用父原型对象中的代码,原型链正常。

图示

弊端

__proto__ 属性虽然可以很方便地改变原型链,但是 __proto__ 直到 ES6 才添加到规范中,存在兼容性问题,并且直接使用 __proto__ 来改变原型链非常消耗性能。所以 __proto__ 属性来实现继承并不可取。

第二版代码

针对 __proto__ 属性的弊端,我们考虑使用 new 操作符来替代直接使用 __proto__ 属性来改变原型链。

我们知道实例对象中的 __proto__ 属性指向构造函数的 prototype 属性的。这样我们 Animal 的实例对象赋值给 Cat.prototype 。不就也实现了Cat.prototype.__proto__ = Animal.prototype 语句的功能了吗?

代码如下:

function Animal(name){this.name = name
}function Cat(name){Animal.call(this,name)
}Cat.prototype = new Animal()
Cat.prototype.constructor = Cat
复制代码

使用这套方案有个问题,就是在将实例对象赋值给 Cat.prototype 的时候,将 Cat.prototype 原有的 constructor 属性覆盖了。实例对象的 constructor 属性向上查询得到的是构造函数 Animal 。所以我们需要矫正一下 Cat.prototype 的 constructor 属性,将其设置为构造函数 Cat 。

图示

优点

兼容性比较好,并且实现较为简单。

弊端

使用 new 操作符带来的弊端是,执行 new 操作符的时候,会执行一次构造函数将构造函数中的属性绑定到这个实例对象。这样就多执行了一次构造函数,将原本属于 Animal 实例对象的属性混到 prototype 中了。

第三版代码

考虑到第二版的弊端,我们使用一个空构造函数来作为中介函数,这样就不会将构造函数中的属性混到 prototype 中,并且减少了多执行一次构造函数带来的性能损耗。

代码如下:

function Animal(name){this.name = name
}function Cat(name){Animal.call(this,name)
}
function Func(){}
Func.prototype = Animal.prototypeCat.prototype = new Func()
Cat.prototype.constructor = Cat
复制代码

图示

ES6

使用 ES6 就方便多了。可以使用 extends 关键字实现继承, 复用父原型中的代码。使用 super 关键字来复用父构造函数中的代码。

代码如下:

class Animal {constructor(name){this.name = name}eat(){console.log('eat')}
}
class Cat extends Animal{constructor(name){super(name)}
}let cat = new Cat('Tom')
console.log(cat.name) // Tom
cat.eat() // eat
复制代码

相关知识点

  • 理性分析 JavaScript 中的 this
  • 理性分析 JavaScript 中的原型

参考书籍

  • 《JavaScript高级程序设计(第3版)》
  • 《Java核心技术 卷Ⅰ(第9版)》

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

最详细的排序解析,理解七大排序

最详细的排序解析,理解七大排序 mp.weixin.qq.com点击上方“方志朋”,选择“置顶或者星标” 你的关注意义重大! 注: lgN在这里为1og2N简写 为了方便描述,本文默认用int类型比较,从小到大排序 本文排序算法以java语言…

xp删除管理员账户_在Windows XP中从登录屏幕删除用户帐户

xp删除管理员账户So you login to your computer every single day, but there’s more than one account to choose from… either because you got the computer from somebody else, or some software package added a user account that you really don’t want to see. So…

Java网络爬虫实操(8)

上一篇:Java网络爬虫实操(7) 大家好,本篇文章介绍一下NetDiscovery爬虫框架里的downloader对象 1) 前言 面向对象设计仍然是目前编程的核心思想,从下面截图可以了解爬虫框架的主要对象: 程序在本地组织好一…

Pycharm下将py文件打包成exe文件

1. 在PyCharm下安装PyInstaller 1. 首先,打开自己要发布的工程 2. 点击底部的【Terminal】打开终端,中输入命令pip install pyinstaller后回车,如图所示进行安装 3. 输入命令 pyinstaller,回车显示安装成功 4. 输入命令 pyinstall…

什么是自然语言处理,它如何工作?

NicoElNino/Shutterstock.comNicoElNino / Shutterstock.comNatural language processing enables computers to process what we’re saying into commands that it can execute. Find out how the basics of how it works, and how it’s being used to improve our lives. 自…

GIT速查手册

为什么80%的码农都做不了架构师?>>> 一、GIT 1.1 简单配置 git是版本控制系统,与svn不同的是git是分布式,svn是集中式 配置文件位置 # 配置文件 .git/config 当前仓库的配置文件 ~/.gitconfig 全局配置文件# 查看所有配置项 git …

4-3逻辑非运算符及案例 4-4

创建类 LoginDemo3 这里取反 !(n%30) package com.imooc.operator; import java.util.Scanner;public class LoginDemo3 {public static void main(String[] args) {// TODO Auto-generated method stubSystem.out.println("请输入一个整数");Scanner scnew Scanner(…

assistant字体_如何使用Google Assistant设置和致电家庭联系人

assistant字体Google谷歌Google Home and Nest smart speakers and displays allow you to make calls without using your phone. By setting up “Household Contacts,” anyone in your home can easily call friends and family members with Google Assistant-enabled dev…

php队列使用

由于项目中在修改产品的同时要同步关联水单,删单,客保 等等数据。所以不可能等待所有都执行完毕以后再给客户端反馈。所以自己用写了个队列。在这里晒出来代码,以供大家参考。(项目中用到的是tp,所以在这里用tp作为演示) 思路 1,需要用到队列…

Accoridion折叠面板

详细操作见代码&#xff1a; <!doctype html> <html><head><meta charset"UTF-8"><title></title><meta name"viewport" content"widthdevice-width,initial-scale1,minimum-scale1,maximum-scale1,user-scal…

skype快捷键_每个Skype键盘快捷键及其用法

skype快捷键Roberto Ricca/Shutterstock罗伯托里卡/ ShutterstockGet familiar with Skype’s unique keyboard shortcuts that will allow you to quickly change your settings, alter your interface, and control your communications. Use these hotkeys and become a Sky…

习惯需要坚持

近期会把本地的资料上传分享出来&#xff0c;好久没更新自己的内容了&#xff0c;以后会不断的更新哦。转载于:https://blog.51cto.com/haohao1010/2087494

YouTube键盘快捷键:速查表

Google’s video website wouldn’t be complete without all sorts of useful buttons and hidden commands that aren’t immediately obvious. Use this hotkey cheat sheet to quickly navigate YouTube and gain better control over your video browsing experience. 如果…

第五章 课本题目

例 5.1 使用单分支条件结构输出两个数的最大值。 #include<stdio.h> int main() { int a,b,max; scanf("%d,%d",&a,&b); if(a>b) maxa; if(a<b) maxb; printf("max%d\n",max); return 0; } 例 5.2 用双分支条件语句求最大值。 #includ…

MySQL服务读取参数文件my.cnf的规律研究探索

在MySQL中&#xff0c;它是按什么顺序或规律去读取my.cnf配置文件的呢&#xff1f;其实只要你花一点功夫&#xff0c;实验测试一下就能弄清楚&#xff0c;下面的实验环境为5.7.21 MySQL Community Server。其它版本如有不同&#xff0c;请以实际情况为准。 其实&#xff0c;MyS…

将组策略编辑器添加到控制面板

If you find yourself using the Group Policy Editor all the time, you might have wondered why it doesn’t show up in the Control Panel along with all the other tools. After many hours of registry hacking, I’ve come up with a registry tweak to let you do ju…

cookies和session区别

cookies和session区别 1、Cookie和Session都是会话技术&#xff0c;Cookie是运行在客户端&#xff0c;Session是运行在服务器端。 2、Cookie有大小限制以及浏览器在存cookie的个数也有限制&#xff0c;Session是没有大小限制和服务器的内存大小有关。3、Cookie有安全隐患&#…

Exchange Server 2016管理系列课件50.DAG管理之激活数据库副本

激活邮箱数据库副本是将特定被动副本指定为邮箱数据库的新主动副本的过程。我们将此过程称为数据库切换。数据库切换过程是指卸除当前的活动数据库&#xff0c;然后在指定的服务器上将相应的数据库副本作为新的活动邮箱数据库副本进行装载。成为活动邮箱数据库的数据库副本必须…

常见设计模式 (python代码实现)

1.创建型模式 单例模式 单例模式&#xff08;Singleton Pattern&#xff09;是一种常用的软件设计模式&#xff0c;该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中&#xff0c;某个类只能出现一个实例时&#xff0c;单例对象就能派上用场。 比如&#…

记录一次解决httpcline请求https报handshake_failure错误

概述 当使用httpclinet发起https请求时报如下错误&#xff1a; javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failureat com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)at com.sun.net.ssl.internal.ssl.Alerts.getSSLExcep…