前言
我们都知道,es6
的class
实现了类,class
关键字呢仅仅就是一个语法糖而已,本质上还是利用的函数原型。但是babel
给我们进行转化后的代码肯定没有那么简单,还是有很多值得我们学习的地方,所以今天我们就来看看class
实现的继承,用babel进行转化后的代码到底是什么。
class
先看看一个简单的代码
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
playing() {
console.log(this.name + " playing")
}
}
这段简单的代码,如果我们自己用函数原型方式进行实现的话,一定是这样的
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.playing = function () {
console.log(this.name + ' playing')
}
但是babel
给我们做了很多很多的edge case
,下面我们就来看看吧(我附上详细的注释)
//这么简单的代码,用babel转化之后这么大一堆,是不是想吐了
//先看最后!!!(纯函数那里)
"use strict";
function _classCallCheck(instance, Constructor) {
//如果Constructor.prototype没有出现在instance的原型链,这报错
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
//循环props,拿到每个对象
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
/**
设置之后变为
{
key: "palying",
value: function palying() {
console.log(this.name + " eating~");
},
enumerable: false,
configurable: true,
writable: true
}
*/
//调用defineProperty,传入descriptor(数据属性描述符)设置这个key
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
//调用_defineProperties,Constructor就是下面定义的Person函数, protoProps下面就是那个数组
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
//我们如果在Person类中写static run = function() {}这种代码就会传入作为staticProps,
//也就是转化为类的静态函数,转为es5就会变成Person.run = function () {}
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
// /*#__PURE__*/ 纯函数,纯函数概念大家都懂吧,就是幂等性(确定的输入必定产生确定的输出),
//纯函数执行过程中是不会产生副作用的
// /*#__PURE__*/这种注释大家应该也懂,魔法注释,意味着webpack会压缩 tree-shaking
var Person = /*#__PURE__*/ (function () {
function Person(name, age) {
//这个函数我在前面做了注释,也就意味着我们只能通过new Person进行调用(逻辑太缜密了)
_classCallCheck(this, Person);
this.name = name;
this.age = age;
}
//前面坐了详细的解析
_createClass(Person, [
{
key: "palying",
value: function palying() {
console.log(this.name + " eating~");
}
}
]);
//最后返回
return Person;
})();//立即执行
相信在看了我的注释之后,是不是觉得babel
还是有点意思哈!
class实现继承
下面来看重头戏,先看看es6的代码
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
running() {
console.log(this.name + " running~")
}
static staticMethod() {
}
}
class Student extends Person {
constructor(name, age, sno) {
super(name, age)
this.sno = sno
}
studying() {
console.log(this.name + " studying~")
}
}
我们知道es6
实现继承呢,不过是大家耳熟能详的寄生组合式继承,下面就是我们大概率会写的寄生组合式继承,然后我们再看看与babel
转化生成的有什么区别
function inheritPrototype(SubType, SuperType) {
SubType.prototype = Object.create(SuperType.prototype)
Object.defineProperty(SubType.prototype, 'constructor', {
enumerable: false,
configurable: true,
writable: true,
value: SubType
})
}
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.running = function () {
console.log(this.name + ' running~')
}
Person.staticMethod = function () {}
function Student(name, age, sno) {
Person.call(this, name, age)
this.sno = sno
}
inheritPrototype(Student, Person)
Object.setPrototypeOf(Student, Person)//实现静态方法继承
Student.prototype.studying = function () {
console.log(this.name + ' studying~')
}
const stu = new Student('zdy', 18, 111)
stu.studying()
stu.running()
//执行结果
//zdy studying~
//zdy running~
我们自己写的话,很简单,但是来看看babel写的,你会感叹真的有点东西!!(我附上详细注释)
"use strict";
var Person = /*#__PURE__*/ (function () {
function Person(name, age) {
//这个函数限制我们只能对其new调用
_classCallCheck(this, Person);
this.name = name;
this.age = age;
}
//上一段源码解释过了,这里不再注释
_createClass(Person, [
{
key: "running",
value: function running() {
console.log(this.name + " running~");
}
}
]);
return Person;
})();
var Student = /*#__PURE__*/ (function (_Person) {
// 实现之前的寄生式继承的方法(静态方法的继承)
_inherits(Student, _Person);
var _super = _createSuper(Student);
function Student(name, age, sno) {
var _this;
_classCallCheck(this, Student);
// Person不能被当成一个函数去调用
//意味着不能Person.call(this, name, age)
//所以只能耍手段拿到super,super其实本来是Person,但是他的constuctor指向的Student,
//而this = stu;所以stu instanceof Student =true,及可以调用super
_this = _super.call(this, name, age);
// 创建出来的对象 {name: , age: }
_this.sno = sno;
// {name: , age:, sno: }
return _this;
}
//请看上一段代码注释
_createClass(Student, [
{
key: "studying",
value: function studying() {
console.log(this.name + " studying~");
}
}
]);
return Student;
})(Person);
//symbol是es6出现的,我们要转为es5代码,就需要对他做支持(_typeof就是对symbol的支持)
function _typeof(obj) {
"@babel/helpers - typeof";
if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
_typeof = function _typeof(obj) {
return typeof obj;
};
} else {
_typeof = function _typeof(obj) {
return obj &&
typeof Symbol === "function" &&
obj.constructor === Symbol &&
obj !== Symbol.prototype
? "symbol"
: typeof obj;
};
}
return _typeof(obj);
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function");
}
//寄生组合式继承的核心,做完这一步,subClass.prototype.__proto__ = superClass.prototype
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: { value: subClass, writable: true, configurable: true }
});
// 实现静态方法的继承
// Student.__proto__ = Person
if (superClass) _setPrototypeOf(subClass, superClass);
}
// o: Student
// p: Person
// 静态方法的继承
function _setPrototypeOf(o, p) {
_setPrototypeOf =
Object.setPrototypeOf ||
function _setPrototypeOf(o, p) {
o.__proto__ = p;
return o;
};//这里本质就是Student.__proto__ = Person,让Student也能调用Person的静态方法
return _setPrototypeOf(o, p);
}
//Derived = Student
//Derived = Student
function _createSuper(Derived) {
//_isNativeReflectConstruct判断支不支持Reflect
var hasNativeReflectConstruct = _isNativeReflectConstruct()
return function _createSuperInternal() {
//Super = Person(看我下面注释)
var Super = _getPrototypeOf(Derived),
result
if (hasNativeReflectConstruct) {
console.log(this)
//这里的this,是我们new调用的创建出的stu对象
//所以NewTarget = Student
var NewTarget = _getPrototypeOf(this).constructor
//Reflect.construct会通过Super创建出来一个函数,
//但是这个实例的原型constructor指向的是NewTarget
//为什么这么做,是因为我们限制了不能通过除了new调用的方式来调用Perosn或者Student
//本来我们要Person.call(this, name, age)来借用构造函数的,但是不能这么用,只能耍一点手段
result = Reflect.construct(Super, arguments, NewTarget)
} else {
result = Super.apply(this, arguments)
}
return _possibleConstructorReturn(this, result)
//_possibleConstructorReturn就是容错判断,最后返回的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;
}
//判断支不支持Reflect
function _isNativeReflectConstruct() {
if (typeof Reflect === "undefined" || !Reflect.construct) return false;
if (Reflect.construct.sham) return false;
if (typeof Proxy === "function") return true;
try {
Boolean.prototype.valueOf.call(
Reflect.construct(Boolean, [], function () {})
);
return true;
} catch (e) {
return false;
}
}
//做了一些edge case判断,本质就是拿到o这个对象的对象原型,也就是返回o.__proto__
function _getPrototypeOf(o) {
_getPrototypeOf = Object.setPrototypeOf
? Object.getPrototypeOf
: function _getPrototypeOf(o) {
return o.__proto__ || Object.getPrototypeOf(o);
};
return _getPrototypeOf(o);
}
//请看上一段代码的注释
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a 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);
}
}
//请看上一段代码的注释
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
是不是绕来绕去的,如果我们仔细看的话,一定会有很多收获!babel
原来偷偷的为我们做了这么多edgecase
,babel真是一个良心插件!!!