详解babel是如何将class语法糖转换为es5的语法
作者:xxyCoder
这篇文章主要详细介绍了babel是如何将class语法糖转换为es5的语法,文中通过代码示例给大家介绍的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
准备工作
- 在目录下创建两个文件,分别是index.js和.babelrc
class Parent { static type = 'Parent'; #salary = 0; name = ''; static showType() { console.log(this.type) } #seeSalary() { console.log(this.#salary) } speakName() { this.#seeSalary() console.log(this.name) } } class Child extends Parent { constructor(name) { super(); this.name = name; } speakName() { super.speakName(); } }
{ "presets": [ "@babel/preset-env" ] }
npm install @babel/core @babel/cli @babel/preset-env --save-dev npx babel index.js -o dist.js
编译后私有变量和方法怎么存储?
var _salary = new WeakMap(); var _seeSalary = new WeakSet(); var Parent = function () { function Parent() { _classPrivateMethodInitSpec(this, _seeSalary); _classPrivateFieldInitSpec(this, _salary, { writable: true, value: 0 }); } } function _seeSalary2() { console.log(_classPrivateFieldGet(this, _salary)); } function _classPrivateMethodInitSpec(obj, privateSet) { privateSet.add(obj); } function _classPrivateFieldInitSpec(obj, privateMap, value) { privateMap.set(obj, value); }
- 总结这部分代码:私有变量会存储在weakMap中,键是对象,值是变量值;私有方法存储在weakSet中,键是对象。对于方法存储了对象还不够,执行方法是需要函数体的,函数体定义在外部。
- 问题是,我调用的是
seeSalary
又不是seeSalary2
。首先要说的是,私有方法只能在类方法中调用,外部是没办法调用的,那么在方法中调用的时候会对调用seeSalary
进行拦截去执行seeSalary2
。 - 还有一个问题,调用babel转换为es5的语法,怎么还有
weakMap
和weakSet
呢?Babel 是包含编译和polyfill两部分的。
编译后静态或公开变量和方法怎么存储?
var Parent = function() { function Parent() { ... _defineProperty(this, "name", ''); } // 第一个参数是public方法,第二个参数是static方法 _createClass(Parent, [{ key: "speakName", value: function speakName() { _classPrivateMethodGet(this, _seeSalary, _seeSalary2).call(this); console.log(this.name); } }], [{ key: "showType", value: function showType() { console.log(this.type); } }]); return Parent; } _defineProperty(Parent, "type", 'Parent'); function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; }
- 总结这部分代码:public的属性会定义在实例自身上,public的方法会定义在构造器的
prototype
身上;static的属性和方法都会定义在类自身上。
那么继承是怎么实现的?
var Child = function(_Parent2) { _inherits(Child, _Parent2); function Child(name) { var _this; _this = _callSuper(this, Child); _this.name = name; return _this; } _createClass(Child, [{ key: "speakName", value: function speakName() { _get(_getPrototypeOf(Child.prototype), "speakName", this).call(this); } }]); return Child; }(Parent); function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, "prototype", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); }
- 总结这部分代码:继承是通过修改子类的
prototype
指向了一个新对象,新对象的prototype
指向了父类的prototype
,且新对象的constructor
保持子类的constructor
不变且允许外部代码修改。然后将子类的prototype
拒绝被赋值为其他对象。最后将子类的__proto__
指向父类。 - 有个问题,为什么要创建一个新对象而不是让子类的
prototype
直接指向父类的prototype
呢?这是因为在之前代码中给子类prototype
添加公开方法的时候避免影响父类。 - 还有一个问题,为什么需要
__proto__
指向父类呢?这是为了静态属性和方法也能让子类调用到父类的,前面也提到了静态的方法和属性都是挂载到类自身。
拓展:原型链
- 每个对象(数组、函数等)都有
__proto__
属性,通过该属性指向其他对象串联出原型链 - 函数不仅仅有
__proto__
还有prototype
,但是寻找原型链并不会经过prototype
,除非你是new了一个类,因为new关键字将类的prototype
作为实例__proto__
的值了。
例子
- 例一
function P() {} P.prototype.x = 'x' function C() {} C.prototype = P.prototype console.log(C.x) // undefined
- 例二
function P() {} P.prototype.x = 'x' P.x = 'xxx' function C() {} C.__proto__ = P; console.log(C.x) // xxx
以上就是详解babel是如何将class语法糖转换为es5的语法的详细内容,更多关于babel class转换为es5的资料请关注脚本之家其它相关文章!