前言

从我之前的一篇笔记对象的继承中, 我们可以知道JS的继承方式依赖原型链,而比较好的继承方式是寄生组合式继承

先来温习下什么是寄生组合式继承

function Rectangle(length, width) {
this.length = length;
this.width = width;
}
Rectangle.prototype.getArea = function() {
return this.length * this.width;
};
function Square(length) {
Rectangle.call(this, length, length);
// 1 调用父类构造函数
}
Square.prototype = Object.create(Rectangle.prototype, {
constructor: {
value:Square,
enumerable: true,
writable: true,
configurable: true
}
});
// 2 Object.create会在内部创建一个空对象来连接两个原型对象, 再手动将constructor指向自身 var square = new Square(3);
console.log(square.getArea()); // 9
console.log(square instanceof Square); // true
console.log(square instanceof Rectangle); // true
  1. 在子构造函数中调用父级构造函数,来将属性定义在自己身上
  2. 原型继承主要是为了继承原型对象上的方法

这就是在ES6之前的继承方式,对原型链理解不够深透的话很容易混乱

但在ES6推出class这个类之后,一切都变得简单(再次提醒:class只是语法糖,实质就是对寄生组合式继承的封装

派生类进行继承

首先我们将继承其他类的的类称为派生类(derived classes), 再来看看上面的例子, 利用class如何轻松实现

class Rectangle {
constructor(length, width) {
this.length = length;
this.width = width;
}
getArea() {
return this.length * this.width;
}
}
class Square extends Rectangle {
constructor(length) {
// 与 Rectangle.call(this, length, length) 相同
super(length, length);
}
}
var square = new Square(3);
console.log(square.getArea()); // 9
console.log(square instanceof Square); // true
console.log(square instanceof Rectangle); // true
console.log(Square.prototype.constructor === Square) // true

实现继承只需要两步

  1. classextends继承父类
  2. 在构造函数中调用super()

super也是ES6中的内容,它是指向当前对象的原型的一个指针,实际上就是Object.getPrototypeOf(this)的值。

根据上面的例子我们来看下

Object.getPrototypeOf(Square) === Rectangle // true

super(length, lenght)应该是Rectangle(lenght, length)才对啊,其实在ES6中真正出现了方法的概念,从前只能说是一个函数属性, 在方法中会有一个内部属性[[HomeObject]]任何对super的引用都会使用[[HomeObject]]属性来判断要做什么。第一步是在[[HomeObject]]上调用Object.getPrototypeOf()来获取对原型的引用;最后,创建this绑定并调用该方法的对象。因此是Rectangle.call(this, length, length)

注意点:

  1. 使用了extends就必须在构造器中调用super()
  2. super必须要在this前面
  3. 要想不用super()
  • 不用构造器, 它会默认创建,并按照顺序传入所有参数
  • return返回一个对象,不能是number等基本数据类型,否则return的是this
class Rectangle {
constructor(length, width) {
this.length = length;
this.width = width;
}
getArea() {
return this.length * this.width;
}
}
// 不传super()
class Square extends Rectangle {
constructor(length) {
}
}
let s1 = new Square(3) //Uncaught ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructorat new Square
// 报错 必须在访问this前面调用super构造器或者在返回一个新的Square实例对象必须调用super构造器 // 直接不传入构造器
class Square extends Rectangle {}
let s2 = new Square(3, 4)
console.log(s2.getArea()) //12
console.log(s2.width) // 4
console.log(s2.length) // 3
// 其实默认调用了构造器
//class Square extends Rectangle {
// constructor(...args) {
// super(...args)
// }
//} // 返回一个对象
class Square extends Rectangle {
constructor(length) {
return {}
}
}
let s2 = new Square()
console.log(s2 instanceof Square) // false

继承静态成员

其实从之前的super就能看出个大概了

Object.getPrototypeOf(Square) === Rectangle // true

因此Rectangle的静态成员自然可以被Square访问到

Rectangle.create = function(l, w) {
return new Rectangle(l, w)
}
console.log('create' in Square) // true
console.log(Square.hasOwnProperty('create')) // false

继承非类

其实只要一个表达式能够返回一个具有[[Construct]]属性的以及原型的函数,就可以对其实使用extends

一般来说,对象的原型会在通过构造器Object.create() 方法创建该对象时被指定。而[[Construct]]只有箭头函数没有

因此一下几种情况都是可以的

function Parent() {}

class Child extends Parent {

}
console.log(Child.prototype.__proto__ === Parent.prototype) // true
console.log(Child.__proto__ === Parent) // true let SerializableMixin = {
serialize() {
return JSON.stringify(this);
}
};
let AreaMixin = {
getArea() {
return this.length * this.width;
}
};
function mixin(...mixins) {
var base = function() {};
Object.assign(base.prototype, ...mixins);
return base;
}
class Square extends mixin(AreaMixin, SerializableMixin) {
constructor(length) {
super();
this.length = length;
this.width = length;
}
}
var x = new Square(3);
console.log(x.getArea()); // 9
console.log(x.serialize()); // "{"length":3,"width":3}"

class(二)--派生类的继承的更多相关文章

  1. C++继承具体解释之二——派生类成员函数具体解释(函数隐藏、构造函数与兼容覆盖规则)

    在这一篇文章開始之前.我先解决一个问题. 在上一篇C++继承详解之中的一个--初探继承中,我提到了在派生类中能够定义一个与基类成员函数同名的函数,这样派生类中的函数就会覆盖掉基类的成员函数. 在谭浩强 ...

  2. Python 派生类子类继承类

    1.创建list类的子类Namedlist,初始化新类,创建新对象实例johnny,检查对象类型,并使用list的一些功能来存储数据 >>> class Namedlist(list ...

  3. java基础二、类与继承

    员工类 Employee, 经理类:Manager public class Employee { private String name; private double salary; privat ...

  4. C++中类的继承与Java中的不同,C++的派生类不能继承父类的构造函数和析构函数(不一定正确)

    http://blog.csdn.net/guodongxiaren/article/details/24885023

  5. c++ 的类 和 类继承, 什么是c++中的基类和派生类?

    闲云潭影日悠悠,物换星移几度秋 你既然已经做出了选择, 又何必去问为什么选择.鬼谷绝学的要义, 从来都不是回答, 而是抉与择 普通类 #ifndef TABTENN0_H_ #define TABTE ...

  6. java类的继承(基础)

    ---恢复内容开始--- 这篇随笔和大家讲讲java中类的继承是什么?希望对你们有所帮助. 目录 一.java继承是什么? 二.为什么使用java继承 三.java继承的实现 1.1  java继承的 ...

  7. 面向对象【day07】:类的继承(七)

    本节内容 1.概述 2.类的继承 3.总结 4.练习 一.概述 之前我们说到了类的公有属性和类的私有属性,其实就是类的封装,下面我们来讲讲继承,是面向对象的第二大特性. 面向对象编程 (OOP) 语言 ...

  8. C++基础知识-派生类、调用顺序、访问等级、函数遮蔽

    一.派生类的概念 类之间有一种层次关系,有父亲类,有孩子类. 车这个类,当成父类(也叫基类.超类),派生出卡车.轿车,他们属于孩子类(子类.派生类) 继承:有父亲类,有孩子类,构成了层次关系.继承这种 ...

  9. OOP1(定义基类和派生类)

    面向对象程序设计基于三个基本概念:数据抽象,继承和动态绑定 数据抽象是一种依赖于接口和实现分离的编程技术.继承和动态绑定对程序的编号有两方面的影响:一是我们可以更容易地定义与其它类相似但不完全相同的类 ...

随机推荐

  1. 吴裕雄--天生自然PYTHON爬虫:爬取某一大型电商网站的商品数据(效率优化以及代码容错处理)

    这篇博文主要是对我的这篇https://www.cnblogs.com/tszr/p/12198054.html爬虫效率的优化,目的是为了提高爬虫效率. 可以根据出发地同时调用多个CPU,每个CPU运 ...

  2. 方法重载(Overload)

    方法重载(Overload):多个方法名称一样,但参数列表不一样. (一个方法名称,实现类似的多个功能) 方法重载与下列因素有关: 1. 参数个数不同 public static int sum(in ...

  3. Linux三剑客之awk精讲(基础与进阶)

    第1章 awk基础入门 要弄懂awk程序,必须熟悉了解这个工具的规则.本实战笔记的目的是通过实际案例或面试题带同学们熟练掌握awk在企业中的用法,而不是awk程序的帮助手册. 1.1 awk简介 一种 ...

  4. HackerOne去年发放超过8200万美元的赏金,联邦政府参与度大幅上涨

    2019年,由黑客驱动的漏洞赏金平台HackerOne支付的漏洞奖金几乎是前几年总和的两倍,达到8200万美元. HackerOne平台在2019年也将注册黑客数量翻了一番,超过了60万,同时全年收到 ...

  5. 「HNOI2004」宠物收养场

    「HNOI2004」宠物收养场 传送门 对宠物和人各维护一棵平衡树,每次 \(\text{split}\) 的时候记得判一下子树是否为空,然后模拟就好了. 参考代码: #include <alg ...

  6. A Simple Problem with Integers-POJ3468 区间修改+区间查询

    题意: 给你n个数和2个操作,C操作是将一个区间内的每个数都加上k,Q操作是询问一个区间的和 链接:http://poj.org/problem?id=3468 思路: 线段树区间修改+区间查询 代码 ...

  7. HTML相关知识点(2)

     CSS: 字体: 网页默认字体16px; 网站通用字体大小14px 最小是12px,最大无限大 单位换算:1em=16px 选择器:标签选择器:选择页面中所有指定标签,权重为1 通配符选择器:选择所 ...

  8. windowsService 程序

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...

  9. HDFS 命令行基本操作

    1.hdfs命令行 (1)查看帮助 hdfs dfs -help (2)查看当前目录信息 hdfs dfs -ls / (3)上传文件 hdfs dfs -put /本地路径 /hdfs路径 (4)剪 ...

  10. 今日份学习:初步的springboot

    今日记录 今日份BUG清单 flyway的sql文件有两个下划线 __ , _ 是不可以的. 高版本的freemarker默认的扩展名变成了flth,而不是ftl 今日份用到的网址 1. freema ...