多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
[TOC] # class ~~~ class Parent{ constructor(name,age){ this.name = name this.age = age } //类公有方法 sayName(){ console.log(this.name) } //静态方法 static sayhi(){ console.log(this.name) } } ~~~ ~~~ //经过babel官网转义后 var Parent = /*#__PURE__*/function () { function Parent(name, age) { _classCallCheck(this, Parent); this.name = name; this.age = age; } _createClass(Parent, [{ key: "sayName", value: function sayName() { console.log(this.name); } }], [{ key: "sayhi", value: function sayhi() { console.log(this.name); } }]); return Parent; }(); ~~~ 原理 1.从转义的结果来看,class的constructor本质上还是构造函数 2.首先通过\_classCallCheck 来检测是否是new,而不是直接执行构造函数,在es5中是可以直接运行构造函数的,我们看下这个函数: ~~~ function _classCallCheck(instance, Constructor) { if (! instance instanceof Constructor) { throw new TypeError("Cannot call a class as a function"); } } ~~~ 这里我们可以看出,如果你是直接执行的,那么你的这个this就是undefined,因为是严格模式,如果是非严格模式则是window对象 ,所以 this instanceof Parent,那肯定是false,就会报错,如果是通过new,那么this是Parent的一个对象, 这时候 this instanceof Parent 就是true,就会执行构造函数 3.而静态方法和类公有方法则是通过\_createClass方法添加 ~~~ 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); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } ~~~ \_createClass第一个参数是构造函数,第二个是共有方法数组,被转成了有key和value两个属性的对象,第三个就是静态方法,结构和第二个参数一致 将共有的方法添加到原型对象上Parent.prototype,将静态的方法直接添加到构造函数上,这样就可以直接通过函数名点的形式调用方法 4.最后一步将新的函数返回 # class继承 ~~~ //转义前 class Parent{ constructor(name,age){ this.name = name this.age = age } sayName(){ console.log(this.name) } static sayhi(){ console.log(this.name) } } class Child extends Parent{ constructor(name,age){ super() } sayName(){ console.log(this.name) } } //转义后 var Parent = /*#__PURE__*/function () { function Parent(name, age) { _classCallCheck(this, Parent); this.name = name; this.age = age; } _createClass(Parent, [{ key: "sayName", value: function sayName() { console.log(this.name); } }], [{ key: "sayhi", value: function sayhi() { console.log(this.name); } }]); return Parent; }(); var Child = /*#__PURE__*/function (_Parent) { //将子类构造函数的prototype指向父类构造函数的prototype //将父构造函数指向子构造函数的_proto_ _inherits(Child, _Parent); var _super = _createSuper(Child); function Child(name, age) { _classCallCheck(this, Child); return _super.call(this); } _createClass(Child, [{ key: "sayName", value: function sayName() { console.log(this.name); } }]); return Child; }(Parent); ~~~ parent部分和上方是一样的,主要讲讲Child部分 1.用一个闭包保存父类引用,在闭包内部做子类构造逻辑 2.之后执行的是\_inherits方法,它其实就是将子类构造函数的prototype指向父类构造函数的prototype,以及将父构造函数指向子构造函数的\_proto\_ 看代码: ~~~ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } //这里将子类原型对象的constructor 赋值了子类构造函数本身(之后调用super会有用) subClass.prototype = Object.create(superClass && superClass.prototype,{ constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); //子类构造函数的__proto__指向了父类构造函数(之后调用super会有用) } ~~~ \_inherits先是校验父构造函数,是不是一个函数和null, 然后用父类构造函数的proptype创建一个空对象,并将这个对象指向子类构造函数的proptype,将子类原型对象的constructor指向子类构造函数本身 3.紧接着执行var \_super = \_createSuper(Child); 这个是干嘛的呢,这个就是之后为之后执行super,子类继承父类属性做准备 ~~~ function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); //相当于 // result = Object.create(NewTarget) // Super.apply(NewTarget, arguments) } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } ~~~ 这个函数返回的是用于一个继承父类内部属性一个函数\_isNativeReflectConstruct就是看你支不支持Reflect,Proxy,如果判断之后不支持就会降级使用apply,来继承父类的内部属性和方法 一切准备就绪之后,当你创建Child的实例的时候,super()被转义成了\_super.call(this); 我就当hasNativeReflectConstruct为true,最终执行的就是 ~~~ result = Reflect.construct(Super, arguments, NewTarget); ~~~ Super = \_getPrototypeOf(Derived), \_getPrototypeOf其实就是Object.getPrototypeOf(Derived),Derived是之前传的子类构造函数,Super最终就是Child.\_*proto,而这个在上面第二步时候,子类构造函数的\_\_proto已经指向了父类构造函数*,所以Super就是父类构造函数 NewTarget =\_getPrototypeOf(this).constructor;这个也是第二步父类构造函数的proptype创建一个空对象,已经将子类原型对象的constructor指向子类构造函数本身,所以NewTarget是子类构造函数 那么result就相当于 ~~~ result = Object.create(NewTarget) Super.apply(NewTarget, arguments) ~~~ 这个不就是创建一个对象来继承父类的内部属性和方法,就达到了子类构造函数中调用父类构造函数的目的,新创建的Child实例就会动态拥有父类的内部属性和方法 Class其实就是 es6 给我们提供了一个“组合寄生继承”的简单写法 # 参考资料 [# 知识体系:理解es6 class构造以及继承的底层实现原理](https://blog.csdn.net/qq_40353716/article/details/106650468)