Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >类的继承

类的继承

作者头像
我是leon
发布于 2019-08-28 04:04:39
发布于 2019-08-28 04:04:39
95800
代码可运行
举报
文章被收录于专栏:leon的专栏leon的专栏
运行总次数:0
代码可运行

本文讲述JavaScript中类继承的实现方式,并比较实现方式的差异。

一、何为继承

继承,是子类继承父类的特征和行为,使得子类对象具有父类的实例域和方法。 继承是面向对象编程中,不可或缺的一部分。

1.1 优点

  • 减少代码冗余 父类可以为子类提供通用的属性,而不必因为增加功能,而逐个修改子类的属性
  • 代码复用 同上
  • 代码易于管理和扩展 子类在父类基础上,可以实现自己的独特功能

1.2 缺点

  • 耦合度高 如果修改父类代码,将影响所有继承于它的子类
  • 影响性能 子类继承于父类的数据成员,有些是没有使用价值的。但是,在实例化的时候,已经分配了内存。所以,在一定程度上影响程序性能。

二、例子

例子以图书馆中的书入库归类为例。 以下是简化后的父类Book(也可称为基类)。 目的是通过继承该父类,产出Computer(计算机)子类。 并且,子类拥有新方法say,输出自己的书名。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function Book(){
    this.name = ''; // 书名
    this.page = 0; // 页数
    this.classify = ''; // 类型
}
Book.prototype = {
    constructor: Book,
    init: function(option){
        this.name = option.name || '';
        this.page = option.page || 0;
        this.classify = option.classify || '';
    },
    getName: function(){
        console.log(this.name);
    },
    getPage: function(){
        console.log(this.page);
    },
    getClassify: function(){
        console.log(this.classify);
    }
};

接下来会讲解子类Computer几种继承方式的实现和优化方法。开始飙车~

三、实例式继承

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function Computer(){
    Book.apply(this, arguments);
}
Computer.prototype = new Book();
Computer.prototype.constructor = Computer;
Computer.prototype.init = function(option){
    option.classify = 'computer';
    Book.prototype.init.call(this, option);
};
Computer.prototype.say = function(){
    console.log('I\'m '+ this.name);
}

3.1 调用父类构造器进行初始化

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function Computer(){
    Book.apply(this, arguments);
}

Computer的构造函数里,调用父类的构造函数进行初始化操作。使子类拥有父类一样的初始化属性。

3.2 将父类的原型传递给子类

Computer.prototype = new Book();使用new操作符对父类Book进行实例化,并将实例对象赋值给子类的prototype。 这样,子类Computer就可以通过原型链访问到父类的属性。

3.3 缺点

  • 父类Book的构造函数被执行了2次
    • 一次是在Computer的构造函数里Book.apply(this, arguments);
    • 一次是在Computer.prototype = new Book(); 这种模式,存在一定的性能浪费。
  • 父类实例化无法传参 Computer.prototype = new Book();,这种实例化方式,无法让Book父类接收不固定的参数集合。

四、原型式继承

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function Computer(){
    Book.apply(this, arguments);
}
Computer.prototype = Object.create(Book.prototype);
Computer.prototype.constructor = Computer;
Computer.prototype.init = function(option){
    option.classify = 'computer';
    Book.prototype.init(option);
};
Computer.prototype.say = function(){
    console.log('I\'m '+ this.name);
}

这里的改进:是使用Object.create(Book.prototype)。它的作用是返回一个继承自原型对象Book.prototype的新对象。且该对象下的属性已经初始化。 用Object.create生成新对象,并不会调用到Book的构造函数。 这种方式,也可以通过原型链实现继承。

五、Object.create的简单版兼容

由于低版本的浏览器是不支持Object.create的。所以这里简单介绍下兼容版本:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Object.create = function(prototype){
    function F(){}
    F.prototype = prototype;
    return new F();
}

原理是定义一个空的构造函数,然后修改其原型,使之成为一个跳板,可以将原型链传递到真正的prototype。

六、函数化继承

上述两种实现方式,都存在一个问题:不存在私有属性私有方法。也就是说,存在被篡改的风险。 接下来就用函数化来化解这个问题。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function book(spec, my){
    var that = {};

    // 私有变量
    spec.name = spec.name || ''; // 书名
    spec.page = spec.page || 0; // 页数
    spec.classify = spec.classify || ''; // 类型

    var getName = function(){
        console.log(spec.name);
    };
    var getPage = function(){
        console.log(spec.page);
    };
    var getClassify = function(){
        console.log(spec.classify);
    };

    that.getName = getName;
    that.getPage = getPage;
    that.getClassify = getClassify;

    return that;
}

function computer(spec, my){
    spec = spec || {};
    spec.classify = 'computer';
    var that = book(spec, my);

    var say = function(){
        console.log('I\'m '+ spec.name);
    };
    that.say = say;

    return that;
}

var Ninja = computer({name: 'JavaScript忍者秘籍', page: 350});

函数化的优势,就是可以更好地进行封装和信息隐藏。 也许有人疑惑为什么用以下这种方式声明和暴露方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var say = function(){
    console.log('I\'m '+ spec.name);
};
that.say = say;

其实是为了保护对象自身的完整性。即使that.say被外部篡改或破坏掉,function computer内部的say方法仍然能够正常工作。 另外,解释下thatspecmy的作用:

  • that是一个公开数据存储容器,暴露出去的数据接口,都放到这个容器
  • spec是用来存储创建新实例所需的信息,属于实例之间共同编辑的数据
  • my是用来存储父类、子类之间共享的私密数据容器,外部是访问不到的。

七、ES6继承

最后,看下现代版ES6的类继承。不禁感慨以前的刀耕火种,是多么折磨人?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Book {
    constructor(){
        this.name = ''; // 书名
        this.page = 0; // 页数
        this.classify = ''; // 类型
    }
    init(option) {
        this.name = option.name || '';
        this.page = option.page || 0;
        this.classify = option.classify || '';
    }
    getName() {
        console.log(this.name);
    }
    getPage (){
        console.log(this.page);
    }
    getClassify (){
        console.log(this.classify);
    }
}
class Computer extends Book{
    constructor(...args){
        super(...args);
    }
    init(option) {
        super.init(option);
        this.classify = 'computer';
    }
    say() {
        console.log('I\'m '+ this.name);
    }
}

结语

虽然ES5终究会被淘汰,但是了解下其工作原理,还是很有必要。因为很多源码还是有用到里面的模式。 附带的价值就是,ES5的继承玩到飞起,ES6的继承就是小菜一碟。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-07-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
万字长文深度剖析面向对象的javascript
本将会深入讲解面向对象在javascript中的应用,并详细介绍三种对象的生成方式:构造函数,原型链,类。
程序那些事
2020/12/14
3450
详解JavaScript对象继承方式
其原理如下:构造函数使用 this 关键字给所有属性和方法赋值(即采用类声明的构造函数方式)。因为构造函数只是一个函数,所以可使 Parent 构造函数 成为 Children 的方法,然后调用它。Children 就会收到 Parent 的构造函数中定义的属性和方法。例如,用下面的方式定义 Parent 和 Children:
用户6167509
2019/09/04
4530
JavaScript的几种继承方式
这篇文章称为笔记更为合适一些,内容来源于 《JavaScript高级程序设计 (第三版)》第六章 6.3 继承。
木子星兮
2020/07/16
5290
js 继承的是什么?如何实现继承?
继承是面向对象编程中的一个重要概念,通过继承可以使子类的实例使用在父类中定义的属性和方法。
青梅煮码
2023/01/16
1.9K0
【THE LAST TIME】一文吃透所有JS原型相关知识点
首先我想说,【THE LAST TIME】系列的的内容,向来都是包括但不限于标题的范围。
Nealyang
2019/11/04
1.1K0
JS入门难点解析12-继承的实现方式与优缺点
(注1:如果有问题欢迎留言探讨,一起学习!转载请注明出处,喜欢可以点个赞哦!) (注2:更多内容请查看我的目录。)
love丁酥酥
2018/08/27
1.3K0
JS入门难点解析12-继承的实现方式与优缺点
深入理解继承
学习怎样创建对象是理解面向对象编程的第一步,第二步是理解继承。在传统的面向对象编程语言中,类继承其他类的属性。 然而,JS的继承方式与传统的面向对象编程语言不同,继承可以发生对象之间,这种继承的机制是我们已经熟悉的一种机制:原型。
小周sir
2019/09/23
4930
深入理解继承
实现JavaScript继承
使用TypeScript或者ES2015+标准中的extends关键字是很容易实现继承的,但这不是本文的重点。JS使用了基于原型(prototype-based)的继承方式,extends只是语法糖,本文重点在于不使用extends来自己实现继承,以进一步理解JS中的继承,实际工作中肯定还是要优先考虑使用extends关键字的。
雪飞鸿
2020/12/29
5960
面向对象之继承的那几种模式
往往在项目中都会看到有用class,或者OOP思想去组织业务代码,本篇只做项目中常用到的继承以及对不同继承方式的回顾,也是再次加深对继承的一些理解,希望你在项目中有些帮助和思考。
Maic
2022/07/28
2290
面向对象之继承的那几种模式
前端开发,必知ES5、ES6的7种继承
众所周知,在ES6之前,前端是不存在类的语法糖,所以不能像其他语言一样用extends关键字就搞定继承关系,需要一些额外的方法来实现继承。下面就介绍一些常用的方法,红宝书已经概括的十分全面了,所以本文基本就是对红宝书继承篇章的笔记和梳理。
青梅煮码
2023/03/13
2530
JavaScript实现继承
本文不准备深入细节,主要是对《JavaScript高级程序设计中》介绍的JS如何实现继承做一个总结,毕竟好记性不如烂笔头。文末会附带一张神图,搞清楚这张图,原型链也就没有什么问题了。
leocoder
2018/10/31
6740
JavaScript 中的六种继承方式
关键点:子类原型等于父类的实例Child.prototype = new Person()
Jimmy_is_jimmy
2019/07/31
5040
JS继承机制总结
(无法实现函数复用’父类构造函数中的某个函数可能只是一个功能型的函数,它不论被复制了多少份,输出的结果或者功能都是一样的,那么这类函数是完全可以拿来复用的。但是现在用了构造函数继承,由于它是复制了父类构造函数中的属性和方法,这样产生的每个子类实例中都会有一份自己各自的方法,可是有的方法完全没有必要复制,可以用来共用的,所以就说不能够「函数复用」。)
玖柒的小窝
2021/12/08
1.6K0
Javascript 的继承总结
写惯了 TypeScript 的人很容易了解继承(extends),比如类的继承和接口的继承等,传送门:www.tslang.cn/docs/handbo… ,但是对于ES2015出现之前,JavaScript如何实现继承的呢?毫无疑问,只能通过原型链的方式实现继承,本篇主要是在读书时遇到了原型继承的问题,回顾以下原型继承的集中方式并整理成笔记方便日后查阅。
Meteors
2021/12/08
2740
JS继承有哪些,你能否手写其中一两种呢?3
本篇是 JS系列中第 3 篇,文章主讲 JS 继承,包括原型链继承、构造函数继承、组合继承、寄生组合继承、原型式继承、 ES6 继承,以及 多继承与 new 。
helloworld1024
2023/01/05
4170
ES5、ES6 如何实现继承
完整高频题库仓库地址:https://github.com/hzfe/awesome-interview
HZFEStudio
2021/09/25
6790
代码详解:使用JavaScript进行面向对象编程的指南
对象,即我们相互交流的一个载体,有其属性和方法。对象是面向对象编程的核心,不仅用于JavaScript,而且还适用于Java、C语言、C++等。不再考虑单个变量和函数,而选择自给型的对象。
木禾wen
2019/11/19
7650
代码详解:使用JavaScript进行面向对象编程的指南
JavaScript中6种继承方式总结
我们在代码里的操作本意是只改变goku1的属性,但是为什么goku2的属性也被改变了呢?因为skill是一个数组,为引用类型,goku1与goku2的skill实际是指向同一块内存空间,因此修改会变得混乱。我们将在接下来的继承方式中解决这个问题。
henu_Newxc03
2022/05/05
3710
JavaScript中6种继承方式总结
this_原型链_继承
this 相关问题 1: apply、call 、bind有什么作用,什么区别? 在JS中,这三者都是用来改变函数的this对象的指向,相似点: 1.都是用来改变函数的this对象的指向的。 2.
小胖
2018/06/27
5980
JS面试题-JS实现继承的方法(共6种)
① 引用类型的属性被所有实例共享。 ② 在创建 Child 的实例时,不能向Parent传参
用户10106350
2022/10/28
7250
JS面试题-JS实现继承的方法(共6种)
相关推荐
万字长文深度剖析面向对象的javascript
更多 >
LV.1
这个人很懒,什么都没有留下~
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验