博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
javascript面向对象之继承(上)
阅读量:5891 次
发布时间:2019-06-19

本文共 2838 字,大约阅读时间需要 9 分钟。

我们之前介绍了javascript面向对象的封装的相关内容,还介绍了js的call方法,今天开始讨论js的继承

这篇文章参考了《javascript高级程序设计》(第三版),但内容不局限于,网上很多关于js继承的相关内容都是来自于这本书,有兴趣的同学可以翻阅查看

原型链继承

我们先通过一个栗子,了解一下原型链继承。留意代码注释内容

//创建自定义构造函数function Hqg() {    this.name = '洪七公';}//在当前构造函数的原型链上添加属性skillHqg.prototype.skill = '打狗棒'//通过自定义构造函数Hqg实例化一个对象gjconst gj = new Hqg()console.log(gj.skill);//=>打狗棒//通过自定义构造函数Hqg实例化一个对象hrconst hr = new Hqg()console.log(hr.skill);//=>打狗棒

一个简单的栗子,郭靖和黄蓉都从洪七公那里继承到了skill 打狗棒,貌似没什么问题,我们继续看demo

//上面代码省略const gj = new Hqg()//通过自定义构造函数Hqg实例化一个对象gjgj.skill = "降龙十八掌"//重新对gj的skill赋值console.log(gj.skill);//=>降龙十八掌//通过自定义构造函数Hqg实例化一个对象hrconst hr = new Hqg()console.log(hr.skill);//=>打狗棒

对郭靖的skill重新赋值,也没有影响黄蓉的skill,我们打印一下gj

gj的skill屏蔽掉了原型链上的skill,所以gj的skill是降龙十八掌,而hr的skill依然是打狗棒

问题即将暴露

function Hqg() {    this.name = '洪七公';}Hqg.prototype.skill = ['打狗棒']const gj = new Hqg()gj.skill.push ("降龙十八掌")//找到了原型链中的skill,并对其执行push操作,从而改变了构造函数中的skill属性console.log(gj.skill); //=>["打狗棒", "降龙十八掌"]const hr = new Hqg()//构造函数中的skill已经被改变console.log(hr.skill); //=>["打狗棒", "降龙十八掌"]

总结一下,gj和hr都是Hqg的实例,继承Hqg的属性和方法,当Hqg的属性或者方被改变了,后面的实例也会受影响,有时候这并不是我们希望的结果

借用构造函数

借用?就是使用call或者apply改变一下this指向,

就是子类的构造函数内部通过call或者apply调用父类的构造函数,如果对call方法有不了解的地方,
举一个栗子

//创建一个构造函数,并添加一些属性function Hqg() {    this.name = '洪七公';    this.job = '帮主';    this.skill = ['降龙十八掌', '打狗棒']}//创建一个构造函数,并借用了Hqg的构造函数function Hr() {        Hqg.call(this)        this.name = '黄蓉';        this.job = ['相夫', '教子']}//创建一个构造函数,并借用了Hqg的构造函数function Gj() {    Hqg.call(this)    this.name = '郭靖';    this.job = ['吃饭', '睡觉']}const hr = new Hr();console.log(hr);const gj = new Gj();console.log(gj);

输出

这样就避免了原型链继承中,构造函数中的属性或者方法被其他实例所改变的问题
⚠️:这里要注意call方法的执行顺序:

//部分代码省略function Hr() {    this.name = '黄蓉';    this.job = ['相夫', '教子']    Hqg.call(this)}function Gj() {    this.name = '郭靖';    this.job = ['吃饭', '睡觉']    Hqg.call(this)}//部分代码省略

如果call在之后执行就会导致一个问题

值会被覆盖,这个要注意!

借用构造函数进行传参

这个算是一个升级的玩法吧

function Hqg(name,job,skill) {  this.name = name;  this.job = job;  this.skill = skill}function Hr() {  Hqg.call(this,'黄蓉',['相夫', '教子'],['打狗棒'])}function Gj() {  Hqg.call(this,'郭靖',['吃饭', '睡觉'],['降龙十八掌'])}const hr = new Hr();console.log(hr);const gj = new Gj();console.log(gj);

输出

组合继承

将原型链和借用构造函数技术组合到一起。

使用原型链实现对原型属性和方法的继承,用借用构造函数模式实现对实例属性的继承。
这样既通过在原型上定义方法实现了函数复用,又能保证每个实例都有自己的属性
一个栗子

function Hqg(name) {  this.name = name  this.skill = ["降龙十八掌","打狗棒"]}Hqg.prototype.sayName = function () {  console.log(this.name);}function Hero(name, job) {  Hqg.call(this, name);  this.job = job}Hero.prototype = new Hqg();Hero.prototype.constructor = Hero;Hero.prototype.sayJob = function () {  console.log(this.job)}var gj = new Hero('郭靖', '吃饭睡觉');gj.skill.push("九阴真经");console.log(gj);var hr = new Hero('黄蓉', '相夫教子');console.log(hr);

先看下输出

我们把这个组合继承和之前的两个原型链继承和借用构造函数继承进行比较
不难发现组合继承融合了他们的优点,成为javascript中最常用的继承模式
今天就讨论前三个,还有三个明天继续,不见不散


参考链接

转载地址:http://zlfsx.baihongyu.com/

你可能感兴趣的文章
HSSFRow获取单元格方法与区别
查看>>
删除UINavigationItem上的BarButtonItem
查看>>
数据分析相关模块
查看>>
Python数据结构1-----基本数据结构和collections系列
查看>>
SQL Denali-FileTable
查看>>
C# 图像处理:复制屏幕到内存中,拷屏操作
查看>>
PHP微信支付流程
查看>>
linux下单节点oracle数据库间ogg搭建
查看>>
swift三方库
查看>>
杭州之行
查看>>
策略模式简介
查看>>
UIViewController中loadView的用法(应当注意的几点)
查看>>
POJ NOI0105-42 画矩形
查看>>
Java 数组在内存中的结构
查看>>
《关爱码农成长计划》第一期报告
查看>>
entity framework 6 通用数据类
查看>>
读取FTP上的excel文件,并写入数据库
查看>>
vs2008快捷键极其技巧 转载
查看>>
window 7上安装Visual Studio 2017失败的解决方法
查看>>
单元测试之Stub和Mock
查看>>