ES5的寄生组合式继承

function parent (age) {    this.age = age}parent.prototype.say = function () {    console.log(this.age)}function sub (age, value) {    parent.call(this, age)    this.value = value}sub.prototype = Object.create(parent.prototype, {    constructor: {        value: sub,        enumerable: false,        writable: true,        configurable: true    }})

ES6的Class

对于Class的语法举荐看这里:es6.ruanyifeng.com/#docs/class

ES6 的class能够看作只是一个语法糖,它的绝大部分性能,ES5 都能够做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。然而它们还是有区别的。

区别:

  • 类必须应用new调用,否则会报错。ES的构造函数是能够当成一般函数应用的
  • 类的外部所有定义的办法,都是不可枚举的。(包含外部定义的静态方法)
  • 类的静态方法也能够被子类继承
  • 能够继承原生构造函数

    • ES5 是先新建子类的实例对象this,再将父类的属性增加到子类上,因为父类的外部属性无奈获取,导致无奈继承原生的构造函数。
    • ES6 容许继承原生构造函数定义子类,因为 ES6 是先新建父类的实例对象this,而后再用子类的构造函数润饰this,使得父类的所有行为都能够继承

应用ES5模仿实现ES6的class

依据下面的区别,咱们一步步的看。

1. new操作符查看函数

解决问题:

  • 类必须应用new调用,否则会报错。ES的构造函数是能够当成一般函数应用的
function _checkType (obj, constructor) {    if (!(obj instanceof constructor)) {        throw new TypeError('Cannot call a class as a function')    }}

2. 外部办法不可枚举

解决问题:

  • 类的外部所有定义的办法,都是不可枚举的。(包含外部定义的静态方法)
// 批改构造函数描述符function defineProperties (target, descriptors) {    for (let descriptor of descriptors) {        descriptor.enumerable = descriptor.enumerable || false        descriptor.configurable = true        if ('value' in descriptor) {            descriptor.writable = true        }        Object.defineProperty(target, descriptor.key, descriptor)    }}// 结构class// constructor 示意类对应的constructor对象// protoDesc 示意class外部定义的办法// staticDesc 示意class外部定义的静态方法function _createClass (constructor, protoDesc, staticDesc) {    protoDesc && defineProperties(constructor.prototype, protoDesc)    staticDesc && defineProperties(constructor, staticDesc)    return constructor}

3. 真正的创立class

const Foo = function () {    function Foo(name) {        _checkType(this, Foo) // 先查看是不是new调用的        this.name = name    }    _createClass (Foo, [ // 示意在class外部定义的办法        {            key: 'say',            value: function () {                console.log(this.name)            }        }    ], [ // 示意在class外部定义的静态方法        {            key: 'say',            value: function () {                console.log('static say')                console.log(this.name)            }        }    ])    return Foo}()

到这里class实现实现,验证一下。

  • 先间接调用一下Foo(),后果为:

  • 应用new操作符,生成一个对象
const foo = new Foo('aaa')

  • 打印一下在原型链上定义的办法

可见say办法是不可枚举的。

  • 打印一下静态方法

可见静态方法say是不可枚举的。

4. 实现原型链继承和静态方法继承,并思考到能够继承null的状况

解决问题:

  • 类的静态方法也能够被子类继承
function _inherits(subClass, superClass) {    if (typeof superClass !== 'function' && superClass !== null) {        throw new TypeError('Super expression must either be null or a function, not' + typeof superClass)    }    subClass.prototype = Object.create(superClass && superClass.prototype, {        constructor: {            value: subClass,            enumerable: false,            writable: true,            configurable: true        }    })    if (superClass) {        Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass    }}

5. 应用父类的实例对象this

解决的问题:

  • 能够继承原生构造函数

    • ES5 是先新建子类的实例对象this,再将父类的属性增加到子类上,因为父类的外部属性无奈获取,导致无奈继承原生的构造函数。
    • ES6 容许继承原生构造函数定义子类,因为 ES6 是先新建父类的实例对象this,而后再用子类的构造函数润饰this,使得父类的所有行为都能够继承
// 返回父类的this;若为null,则返回本身function _possibleConstructorReturn(self, call) {    if (!self) {        throw new ReferenceError("this hasn't been initialised - super() hasn't been called")    }    return call && (typeof call === 'object' || typeof call === 'function') ? call : self}

6. 创立子类class

const Child = function (_Parent) {    _inherits(Child, _Parent) // 继承父类原型上的属性及静态方法的继承    function Child(name, age) {        _checkType(this, Child)        // 先应用父类实例对象this,再返回        const _this = _possibleConstructorReturn(this, (Child.__proto__ || Object.getPrototypeOf(Child)).call(this, name))        _this.age = age        return _this    }    return Child}(Foo)

子类class实现实现。验证一下。

  • 打印一下Child.say()

Child并没有在本身定义静态方法,然而它的父类有定义。继承胜利。

  • 结构一个继承原生构造函数的子类
const Child = function (_Parent) {    _inherits(Child, _Parent)    function Child(name, age) {        _checkType(this, Child)        const _this = _possibleConstructorReturn(this, (Child.__proto__ || Object.getPrototypeOf(Child)).call(this, name))        _this.age = age        return _this    }    return Child}(Array)const c = new Child('bbb', 12)

继承胜利。

相干文章

  1. ES2020 中 Javascript 10 个你应该晓得的新性能
  2. 重温ES6外围概念和根本用法
  3. JavaScript 对象:咱们真的须要模仿类吗?
原文:https://juejin.im/post/684490...

最初,欢送关注我的公众号:前端开发博客,每日分享陈腐技术文章。