资讯专栏INFORMATION COLUMN

javascript面向对象之继承(上)

ivyzhang / 953人阅读

摘要:使用原型链实现对原型属性和方法的继承,用借用构造函数模式实现对实例属性的继承。

我们之前介绍了javascript面向对象的封装的相关内容,还介绍了js的call方法,今天开始讨论js的继承
这篇文章参考了《javascript高级程序设计》(第三版),但内容不局限于,网上很多关于js继承的相关内容都是来自于这本书,有兴趣的同学可以翻阅查看

原型链继承

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

//创建自定义构造函数
function Hqg() {
    this.name = "洪七公";
}
//在当前构造函数的原型链上添加属性skill
Hqg.prototype.skill = "打狗棒"

//通过自定义构造函数Hqg实例化一个对象gj
const gj = new Hqg()
console.log(gj.skill);//=>打狗棒
//通过自定义构造函数Hqg实例化一个对象hr
const hr = new Hqg()
console.log(hr.skill);//=>打狗棒

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

//上面代码省略
const gj = new Hqg()//通过自定义构造函数Hqg实例化一个对象gj
gj.skill = "降龙十八掌"//重新对gj的skill赋值
console.log(gj.skill);//=>降龙十八掌
//通过自定义构造函数Hqg实例化一个对象hr
const 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中最常用的继承模式
今天就讨论前三个,还有三个明天继续,不见不散

参考链接
你们真的了解JS的继承嘛?

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/100165.html

相关文章

  • javascript面向对象“多态”

    摘要:之前,本质上不能算是一门面向对象的编程语言,因为它对于封装继承多态这些面向对象语言的特点并没有在语言层面上提供原生的支持。所以在中出现了等关键字,解决了面向对象中出现了问题。 ES6之前,javascript本质上不能算是一门面向对象的编程语言,因为它对于封装、继承、多态这些面向对象语言的特点并没有在语言层面上提供原生的支持。但是,它引入了原型(prototype)的概念,可以让我们以...

    JerryWangSAP 评论0 收藏0
  • 面向对象JavaScript继承(一) 类式继承

    摘要:那你们肯定会问为什么共用,而没有共用呢,下面就给你解释,请看引用类型是共用的值类型是私用的。 引言 面向对象的编程语言都具继承这一机制,而 JavaScript 是基于原型(Prototype)面向对象程序设计,所以它的实现方式也是基于原型(Prototype)实现的. 继承的方式 类式继承 构造函数继承 组合继承 原型式继承 寄生式继承 寄生组合式继承 1.类式继承 //声明父...

    forsigner 评论0 收藏0
  • SegmentFault 技术周刊 Vol.32 - 七夕将至,你的“对象”还好吗?

    摘要:很多情况下,通常一个人类,即创建了一个具体的对象。对象就是数据,对象本身不包含方法。类是相似对象的描述,称为类的定义,是该类对象的蓝图或原型。在中,对象通过对类的实体化形成的对象。一类的对象抽取出来。注意中,对象一定是通过类的实例化来的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 马上就要到七夕了,离年底老妈老爸...

    李昌杰 评论0 收藏0
  • SegmentFault 技术周刊 Vol.32 - 七夕将至,你的“对象”还好吗?

    摘要:很多情况下,通常一个人类,即创建了一个具体的对象。对象就是数据,对象本身不包含方法。类是相似对象的描述,称为类的定义,是该类对象的蓝图或原型。在中,对象通过对类的实体化形成的对象。一类的对象抽取出来。注意中,对象一定是通过类的实例化来的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 马上就要到七夕了,离年底老妈老爸...

    Lyux 评论0 收藏0
  • SegmentFault 技术周刊 Vol.32 - 七夕将至,你的“对象”还好吗?

    摘要:很多情况下,通常一个人类,即创建了一个具体的对象。对象就是数据,对象本身不包含方法。类是相似对象的描述,称为类的定义,是该类对象的蓝图或原型。在中,对象通过对类的实体化形成的对象。一类的对象抽取出来。注意中,对象一定是通过类的实例化来的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 马上就要到七夕了,离年底老妈老爸...

    AaronYuan 评论0 收藏0
  • JS面向对象的程序设计继承的实现-组合继承

    摘要:实现思路使用原型链实现对原型方法和方法的继承,而通过借用构造函数来实现对实例属性的继承。继承属性继承方法以上代码,构造函数定义了两个属性和。 JS面向对象的程序设计之继承的实现-组合继承 前言:最近在细读Javascript高级程序设计,对于我而言,中文版,书中很多地方翻译的差强人意,所以用自己所理解的,尝试解读下。如有纰漏或错误,会非常感谢您的指出。文中绝大部分内容引用自《Java...

    antz 评论0 收藏0

发表评论

0条评论

ivyzhang

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<