前言

从我之前的一篇笔记对象的继承中, 我们可以知道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. 吴裕雄--天生自然PythonDjangoWeb企业开发:学员管理系统后台

    需求 提供一个学员管理系统,一个前台页面,展示现有学员,并供新学员提交申请,一个后台,能够处理申请. pip install django==1.11.2 创建项目 使用控制台进入到一个目录下,具体是 ...

  2. 3_05_MSSQL课程_Ado.Net_SQLDataAdapter

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Configurat ...

  3. WDF驱动中KMDF与UMDF区别

    抄的 早期的Windows 95/98的设备驱动是VxD(Virtual Device Driver),其中x表示某一类设备.从Windows 2000开始,开发驱动程序必以WDM(Windows D ...

  4. 跳转连接转base64

    //配置H5连接 @Value("${h5.domain}") private String h5Domain; // 校验商家端权限 public String checkSta ...

  5. R语言 sample抽样函数

    Sample 函数用法: sample(x, size, replace = FALSE, prob = NULL) Arguments x - 可以是含有一个或多个元素的向量或只是一个正整数.x的长 ...

  6. Codeforces 1300E. Water Balance

    给你一个数列,有一个操作,将一段数字变成其和除以个数,求字典序最小的那一个,分析知,求字典序最小,就是求一个不下降序列,但我们此时有可以更改数字的操作,已知已经不下降的序列不会因为操作而变的更小,只有 ...

  7. uniGUI之TUniHiddenPanel(14)

    TUniHiddenPanel是将不在界面上显示的  容器  控件.  只有uniDBGrid实际列才有对应的编辑控件,如果是外键列则无法设置 编辑控件. 里面的控件将不会 显示.将控件放入其中即可. ...

  8. Groovy轻松入门——通过与Java的比较,迅速掌握Groovy

    转自 :Groovy轻松入门——通过与Java的比较,迅速掌握Groovy (更新于2008.10.18) 在前几篇文章中,我已经向大家介绍了Groovy是什么,学习Groovy的重要性等内容,还不了 ...

  9. unity渲染优化

    https://blog.csdn.net/yudianxia/article/details/79339103 https://blog.csdn.net/e295166319/article/de ...

  10. 网络协议-webService协议

    webservice 协议 Web Service使用的是 SOAP (Simple Object Access Protocol)协议soap协议只是用来封装消息用的.封装后的消息你可以通过各种已有 ...