前言

从我之前的一篇笔记对象的继承中, 我们可以知道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. 八 Spring的IOC的XML和注解的区别及其整合开发

    xml和注解的区别 xml和注解整合开发 注解:取消扫描配置开启注解配置 扫描:<context:component-scan base-package="" />  ...

  2. 吴裕雄 Bootstrap 前端框架开发——Bootstrap 表格:让表格更加紧凑

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  3. leetcode #980 不同路径||| (java)

    在二维网格 grid 上,有 4 种类型的方格: 1 表示起始方格.且只有一个起始方格.2 表示结束方格,且只有一个结束方格.0 表示我们可以走过的空方格.-1 表示我们无法跨越的障碍.返回在四个方向 ...

  4. python爬虫(二) urlparse和urlsplit函数

    urlparse和urlsplit函数: urlparse: url='http://www.baidu.com/s?wd=python&username=abc#1' result=pars ...

  5. Pyhton语言的优缺点

    python作为一门高级编程语言,它的诞生虽然很偶然,但是它得到程序员的喜爱却是必然之路. 龟叔给Python的定位是“优雅”.“明确”.“简单”,所以Python程序看上去总是简单易懂,初学者学Py ...

  6. intelliJ IDEA 全屏键盘手

    从MyEclipse到IntelliJ IDEA --让你脱键盘,全键盘操作 从MyEclipse转战到IntelliJ IDEA的经历 我一个朋友写了一篇"从Eclipse到Android ...

  7. Go语言的流程控制(条件,选择,控制,跳转,闭包)

    1.条件语句: 跟C和python又不同了Go的if -else是这样的 if a<5{ return 0 } else { reutrn 1 } 1.条件不需要用括号括起来 2.左边的花括号必 ...

  8. java编程,通过代理服务器访问外网的FTP

    有些时候我们的网络不能直接连接到外网, 需要使用http或是https或是socket代理来连接到外网, 这里是java使用代理连接到外网的一些方法, 希望对你的程序有用.方法一:使用系统属性来完成代 ...

  9. sklearn中调用集成学习算法

    1.集成学习是指对于同一个基础数据集使用不同的机器学习算法进行训练,最后结合不同的算法给出的意见进行决策,这个方法兼顾了许多算法的"意见",比较全面,因此在机器学习领域也使用地非常 ...

  10. 网络协议-webService协议

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