他们的区别

- 区别1: es5的类(其实就是函数) 可以普通函数调用
          es6的类( class声明) 不可以普通函数调用
- 区别2: 通过es5实现的静态属性方法可以枚举
          通过es6实现的静态属性方法不可枚举
- 区别3:  es5 子类.__proto__ == Function.prototype
          es6 子类.__proto__ == 父类
- 区别4: es5 实际先创建子类的实例对象`this`,在执行父类的构造函数添加实例
          es6  先创建父类的实例对象`this`, (但是this.__proto__ = 子类.prototype) 然后再用子类的构造函数修改`this`          
- 区别5: 父类不会进行变量提升          

# es5 的继承实现

js 实现继承的方法有很多种原型链继承构造函数继承组合继承寄生继承 但这些或多或少都有不足之处,所以笔者认为我们只需要记住一种就好了。寄生组合继承 首先,我们要明确我们要继承的东西:实例属性/方法 静态属性/方法 原型属性/方法

需要被继承的父类

function Sup(name) {
  this.name = name; //实例属性
}
//静态
Sup.type = "静态属性type";
Sup.sleep = function () {
  return "静态方法sleep";
};
//实例方法
Sup.prototype.say = function () {
  console.log(`我是${this.name}`);
};

1。继承实例属性/方法

//子
function Sub(name, age) {
  Sup.call(this, arguments);
  this.age = age;
}

2.继承原型属性/方法

Sub.prototype = Object.create(Sup.prototype);
Sub.constructor = Sub;

3.继承静态属性/方法

for (let key of Object.keys(Sup)) {
  // type  sleep...
  Sub[key] = Sup[key];
}

# es6 的继承实现

//上面的例子
// 父类
class Sup {
  constructor(name) {
    this.name = name;
  }

  say() {
    console.log("我叫 " + this.name);
  }

  static sleep() {
    console.log(`我在睡${this.type}`);
  }
}
// static只能设置静态方法,不能设置静态属性,所以需要自行添加到Sup类上
Sup.type = "静态属性type";
// 另外,原型属性也不能在class里面设置,需要手动设置到prototype上,比如Sup.prototype.xxx = 'xxx'

// 子类,继承父类
class Sub extends Sup {
  constructor(name, age) {
    super(name);
    this.age = age;
  }

  say() {
    console.log("你好");
    super.say();
    console.log(`今年${this.age}`);
  }
}
Sub.type = "子类自己的静态属性";

# 使用 babel 编译成 es5 的实现

# 编译后的父类

做了什么事?

  • 一个立即执行函数,最后返回Sup函数
  • _classCallCheck()检查是否是 this 是不是实例化的
  • _createClass(类,实例方法,静态方法) 给类|类的原型添加属性
var Sup = (function () {
  function Sup(name) {
    //区别1
    _classCallCheck(this, Sup);
    this.name = name;
  }
  //类 实例方法  静态方法
  _createClass(
    Sup,
    [
      {
        key: "say",
        value: function say() {
          console.log("我叫 " + this.name);
        },
      },
    ],
    [
      {
        key: "sleep",
        value: function sleep() {
          console.log("\u6211\u5728\u7761".concat(this.type, "\u89C9"));
        },
      },
    ]
  );

  return Sup;
})();
Sup.type = "静态属性type";
// instance是不是构造函数的实例
// 或者说 constructor的prototype.是否出现在instance的原型上
_classCallCheck(instance,Constructor){
  if( !(instance instanceOf Constructor)) {
    throw new TypeError("Cannot call a class as a function");
  }
}
_createClass(Constructor, protoProps, staticProps){
  //实例方法
if(protoProps) {_defineProperties(Constructor.prototype,protoProps)}
//静态方法
if(staticProps) {_defineProperties(Constructor,staticProps)}
}

_defineProperties(Constructor,props){
  for(let i =0 ;i<props.length;i++) {
    let descriptor=props[i]
    //enumerable,writable,
    descriptor.enumerable = descriptor.enumerable || false;
    //区别2
     descriptor.configurable = true;
     if ('value' in descriptor ) descriptor.writable = true;
    Object.defineProperty(Constructor,props.key,descriptor)
  }
}

# 编译后的子类

做了什么事?

  • 也是运行立即执行函数,返回Sub函数
  • _inherit() 执行 原型继承
  • 创建_super函数
  • 创建Sub函数 (检查,调用_super,初始化自己的方法,返回this) 在这个this上做文章
  • _createClass 类添加实例方法、静态方法
var Sub = (function (_Sup) {
  _inherit(Sub, _Sup);
  //放回一个方法
  var _super =_createSuper(Sub)

  function Sub(name, age) {
   var _this;
    // 检查是否当做普通函数调用,是的话抛错
    _classCallCheck(this, Sub);
    //  通过父类创建的实例对象,通过子类的构造函数修改this
    _this = _super.call(this, name);
    _this.age = age;
    return _this;
  }
  _createClass(Sub, [
    {
      key: "say",
      value: function say() {
        console.log("你好");

        _get(_getPrototypeOf(Sub.prototype), "say", this).call(this);

        console.log("\u4ECA\u5E74".concat(this.age, "\u5C81"));
      }
    }
  ]);
  return Sub;
})(Sup);
Sub.type = "子类自己的静态属性";
 _inherits(subClass,supClass) {
    if(typeof supClass !== 'function'&& supClass!==null)
    {
      throw new TypeError('超类必须是函数或是null')
    }

    //原型
    subClass.prototype = (supClass && supClass.prototype,{
      constructor:{
        value:subClass,
        enumerable:true,
        configurable:true
      }
    })
    //区别3 es6 给子类找到父类
    if(superClass) _setPropertyOf(subClass,superClass)
  }

  _setPropertyOf(o,p) {
    _setPropertyOf = Object.setPropertyOf || function setPropertyOf(o,p){
      o.__proto__ = p
    }
    _setPropertyOf(o,p)
  }

//接受一个子类构造函数 即立即执行里的function Sub ,在返回一个新函数
 _createSuper(Sub){
     //这个this是 就是子类实例Sub

   return function _createSuperInternal(){
     //检查 reflect.constructor 是否可用
     var hasNativeReflectConstruct = _isNativeReflectConstruct();
       let result;
       //区分1 拿到 Sub.__proto__ == Sup
       let Super=_getPrototypeOf(Sub) 
    if(hasNativeReflectConstruct) {
       //区分2 sub实例的__proto == Super.prototype
      let Target = _getPrototypeOf(this).constructor 
      // new Super()   第三个参数 作为新对象的构造函数  即是 result.__proto__ = Sub.prototype
      result = Reflect.constructor (Super ,arguments ,Target )
      //创建父实例,并且父实例的__proto__指向 Sub.
    }

     else {
       result = Super.apply(this,arguments) 
     }
     //返回 new的父类实例或者是一个方法
     return _possibleConstructorReturn(this,result)
   }
 } 
function _possibleConstructorReturn(self, call) {
  if (call && (_typeof(call) === 'object' || typeof call === 'function')) {
    return call
  } else if (call !== void 0) {
    throw new TypeError(
      'Derived constructors may only return object or undefined'
    )
  }
  return _assertThisInitialized(self)
}

function _assertThisInitialized(self) {
  if (self === void 0) {
    throw new ReferenceError(
      "this hasn't been initialised - super() hasn't been called"
    )
  }
  return self
}

必须调用super的原因

子没有this对象,需要通过父类创建
this 来源于 super调用(即 执行父构造创建实例,但是this指向的是Sub)