前言

从我之前的一篇笔记对象的继承中, 我们可以知道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. C# 读取和写入txt文件

    读取: 1.使用StreamReader读取文件,然后一行一行的输出 StreamReader sr = new StreamReader(path,Encoding.Default); String ...

  2. Java 调用系统系统可执行文件

    public class Test { public static Map<String, String> executeCmd(String cmd) { Runtime rt = Ru ...

  3. spring boot中不能识别RestController

    参考:https://blog.csdn.net/qq_16739693/article/details/80271987

  4. SpringBoot Controller找不到视图路径

    在启动类加注解@ComponentScan("com.controller")即可,括号里表示Controller所在包名. 参考:https://blog.csdn.net/ji ...

  5. centos6.9下 svn 1.7.10版本 编译安装

    svn安装推荐文章: 1.    http://blog.51cto.com/myhat/786950 2.    https://blog.csdn.net/test1280/article/det ...

  6. Session 'app': Error Installing APKs app 在手机或虚拟机上调试报错

    解决方案: build --clean project

  7. Golang gin框架学习

    今天开始学习gin框架,在Github上找的示例的go-gin-example, 进度 日期 进展 疑惑 进展 1.30 下拉代码,初步了解gin的介绍.搭建 .mod文件 module原理.使用方法 ...

  8. elasticsearch mapping简单介绍

    这两天一直在看elasticsearch相关的内容,看到mapping这一块,就折腾了下. 一般情况下,我们不需要对elasticsearch的mapping进行设置,但如果希望对索引使用自定义的管理 ...

  9. Java单例模式:为什么我强烈推荐你用枚举来实现单例模式

    单例模式简介 单例模式是 Java 中最简单,也是最基础,最常用的设计模式之一.在运行期间,保证某个类只创建一个实例,保证一个类仅有一个实例,并提供一个访问它的全局访问点.下面就来讲讲Java中的N种 ...

  10. JSP数据交互二

    1.JSP内置对象:JSP内置对象是 Web 容器创建的一组对象,不用通过手动new就可以使用2.JSP9大内置对象:      对象名称 类型 request (请求对象)  javax.servl ...