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)
继承胜利。
相干文章
- ES2020 中 Javascript 10 个你应该晓得的新性能
- 重温ES6外围概念和根本用法
- JavaScript 对象:咱们真的须要模仿类吗?
原文:https://juejin.im/post/684490...
最初,欢送关注我的公众号:前端开发博客,每日分享陈腐技术文章。