如果要使用继承的话, 在子类中必须执行super()调用父类, 否者编译器会抛错, 在子类中的super有三种作用, 第一是作为构造函数直接调用,第二种是作为父类实例, 第三种是在子类中的静态方法中调用父类的静态方法;
ES6继承的和ES5继承的主要区别, ES5中常用的继承是把子类的原型设置为父类的实例, 子类自然就有了父类的所有方法和属性:
运行下面代码
var Sup = function() { this.sub = true; }; Sup.prototype.protoSup = {sup:"sup"}; var Sub = function() { this.sub = true; }; Sub.prototype = new Sup(); //继承原型; Sub.prototype.constructor = Sub; //修正constructor;
而在ES6中实现的继承更加精巧, 不会有受到父类的干扰, 这种继承是结合了apply继承和原型继承实现的组合继承:
运行下面代码
var Sup = function() { this.sub = true; }; var Sub = function() { this.sup = true; Sup.apply(this); //继承this的属性和方法; }; Sub.__proto__ = Sup; //继承Sup静态属性; Sub.prototype = Object.create( Sup.prototype, {constructor : { value: Sub, enumerable: false, writable: true, configurable: true }}); //继承原型属性,并覆写constructor;
用图片可以比较容易看出两者区别, 图示ES5和ES6继承的区别: ;
ES5模拟ES6的继承:
因为有了转码器babel , 我们能通过ES5的代码, 去窥探ES6的继承到底是怎么实现, ES6的继承:
运行下面代码
"use strict"; class Person { constructor(name) { this.name = name; } say () { console.log("say hi"); return this; } }; class SMan extends Person { constructor (name, power) { super(name); this.superPower = power; } show () { console.log(this.superPower); return this; } } console.log( new SMan("Clark", "pee").show().say().name );
使用babel转化为ES5以后, 代码变成这样了, 我自己加了一点注释, 原谅我放荡不羁爱自由..:
运行下面代码
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { //复制原型 if (protoProps) defineProperties(Constructor.prototype, protoProps); //复制属性 if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 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; } //下面是ES6继承使用ES5表达出来的代码,_inherits实现的是原型的继承和父类状态属性的继承: 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); } //继承父类的原型,并修正constructor为子类; subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); //又给子类这个对象定义__proto__ 为父类, 这样能够实现静态属性继承; if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; //最后的如果开发者:new 子类, 实际的状态为: 对象{__proto__:父类,constuctor:子类} }; /* var Sup = function() {}; var Sub = function() {}; _inherits(Sub, Sup); //这个继承实现的意思; 作为对象的子类继承父类, 作为构造函数的话,子类继承 Sub.prototype.__proto__ === Sup.prototype //true Sub.prototype.constructor === Sub;//true Sub.__proto__ === Sup;//true */ var Person = function () { function Person(name) { _classCallCheck(this, Person); this.name = name; } _createClass(Person, [{ key: "say", value: function say() { console.log("say hi"); return this; } }]); return Person; }(); ; var SMan = function (_Person) { _inherits(SMan, _Person); function SMan(name, power) { //此时的this.__proto__已经指向 构造函数的prototyp了 _classCallCheck(this, SMan); //这句话相当于是ES6中的super(), 把父类的属性通过call, 执行继承; var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(SMan).call(this, name)); _this.superPower = power; //动态返回_this; return _this; } _createClass(SMan, [{ key: "show", value: function show() { console.log(this.superPower); return this; } }]); return SMan; }(Person); console.log(new SMan("Clark", "pee").show().say().name);
多重继承:
使用mix-in, 实现多重继承, 书写方式为:class Sub extends mix(obj0, obj1, obj2) , mix只是一个方法 ,这个方法我们要自己去定义:
运行下面代码