詳解babel是如何將class語法糖轉(zhuǎn)換為es5的語法
準(zhǔn)備工作
- 在目錄下創(chuàng)建兩個(gè)文件,分別是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
編譯后私有變量和方法怎么存儲(chǔ)?
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); }
- 總結(jié)這部分代碼:私有變量會(huì)存儲(chǔ)在weakMap中,鍵是對(duì)象,值是變量值;私有方法存儲(chǔ)在weakSet中,鍵是對(duì)象。對(duì)于方法存儲(chǔ)了對(duì)象還不夠,執(zhí)行方法是需要函數(shù)體的,函數(shù)體定義在外部。
- 問題是,我調(diào)用的是
seeSalary
又不是seeSalary2
。首先要說的是,私有方法只能在類方法中調(diào)用,外部是沒辦法調(diào)用的,那么在方法中調(diào)用的時(shí)候會(huì)對(duì)調(diào)用seeSalary
進(jìn)行攔截去執(zhí)行seeSalary2
。 - 還有一個(gè)問題,調(diào)用babel轉(zhuǎn)換為es5的語法,怎么還有
weakMap
和weakSet
呢?Babel 是包含編譯和polyfill兩部分的。
編譯后靜態(tài)或公開變量和方法怎么存儲(chǔ)?
var Parent = function() { function Parent() { ... _defineProperty(this, "name", ''); } // 第一個(gè)參數(shù)是public方法,第二個(gè)參數(shù)是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; }
- 總結(jié)這部分代碼:public的屬性會(huì)定義在實(shí)例自身上,public的方法會(huì)定義在構(gòu)造器的
prototype
身上;static的屬性和方法都會(huì)定義在類自身上。
那么繼承是怎么實(shí)現(xiàn)的?
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)); }
- 總結(jié)這部分代碼:繼承是通過修改子類的
prototype
指向了一個(gè)新對(duì)象,新對(duì)象的prototype
指向了父類的prototype
,且新對(duì)象的constructor
保持子類的constructor
不變且允許外部代碼修改。然后將子類的prototype
拒絕被賦值為其他對(duì)象。最后將子類的__proto__
指向父類。 - 有個(gè)問題,為什么要?jiǎng)?chuàng)建一個(gè)新對(duì)象而不是讓子類的
prototype
直接指向父類的prototype
呢?這是因?yàn)樵谥按a中給子類prototype
添加公開方法的時(shí)候避免影響父類。 - 還有一個(gè)問題,為什么需要
__proto__
指向父類呢?這是為了靜態(tài)屬性和方法也能讓子類調(diào)用到父類的,前面也提到了靜態(tài)的方法和屬性都是掛載到類自身。
拓展:原型鏈
- 每個(gè)對(duì)象(數(shù)組、函數(shù)等)都有
__proto__
屬性,通過該屬性指向其他對(duì)象串聯(lián)出原型鏈 - 函數(shù)不僅僅有
__proto__
還有prototype
,但是尋找原型鏈并不會(huì)經(jīng)過prototype
,除非你是new了一個(gè)類,因?yàn)閚ew關(guān)鍵字將類的prototype
作為實(shí)例__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語法糖轉(zhuǎn)換為es5的語法的詳細(xì)內(nèi)容,更多關(guān)于babel class轉(zhuǎn)換為es5的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
javascript簡單實(shí)現(xiàn)表格行間隔顯示顏色并高亮顯示
表格行間隔顯示顏色并實(shí)現(xiàn)高亮顯示,這種效果大家都有見到過吧,下面就為大家詳細(xì)介紹下,需要的朋友可不要錯(cuò)過2013-11-11JavaScript中if、else?if、else和switch的語法、用法及注意事項(xiàng)
這篇文章主要介紹了JavaScript中的條件判斷語句,包括if、elseif、else和switch的基本語法、用法及注意事項(xiàng),通過這些語句,可以根據(jù)不同的條件執(zhí)行相應(yīng)的代碼塊,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2025-04-04原生js實(shí)現(xiàn)的貪吃蛇網(wǎng)頁版游戲完整實(shí)例
這篇文章主要介紹了原生js實(shí)現(xiàn)的貪吃蛇網(wǎng)頁版游戲完整實(shí)例,可實(shí)現(xiàn)自主選擇游戲難度進(jìn)行貪吃蛇游戲的功能,涉及javascript鍵盤事件及頁面元素的操作技巧,需要的朋友可以參考下2015-05-05通過seajs實(shí)現(xiàn)JavaScript的模塊開發(fā)及按模塊加載
seajs實(shí)現(xiàn)了JavaScript 的 模塊開發(fā)及按模塊加載。用來解決繁瑣的js命名沖突,文件依賴等問題,其主要目的是令JavaScript開發(fā)模塊化并可以輕松愉悅進(jìn)行加載。下面我們來一起深入學(xué)習(xí)下吧2019-06-06- 作為一名優(yōu)秀的接口調(diào)用工程師,對(duì)接口的返回信息進(jìn)行校驗(yàn)是必不可少的,本文整理的是一些常用的校驗(yàn)方式,希望能夠?qū)Υ蠹矣兴鶐椭?/div> 2023-05-05
javascript實(shí)現(xiàn)將數(shù)字轉(zhuǎn)成千分位的方法小結(jié)【5種方式】
這篇文章主要介紹了javascript實(shí)現(xiàn)將數(shù)字轉(zhuǎn)成千分位的方法,結(jié)合實(shí)例形式分析了5種常用的數(shù)字轉(zhuǎn)換的常用方法,涉及字符串與正則操作的相關(guān)技巧,需要的朋友可以參考下2016-12-12詳解 javascript對(duì)象創(chuàng)建模式
這篇文章主要介紹了詳解 javascript對(duì)象創(chuàng)建模式的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)JavaScript的相關(guān)知識(shí)。感興趣的朋友可以了解下2020-10-10正則中的回溯定義與用法分析【JS與java實(shí)現(xiàn)】
這篇文章主要介紹了正則中的回溯定義與用法,結(jié)合實(shí)例形式分析了回溯的概念、功能并提供了JS與java實(shí)現(xiàn)方法,需要的朋友可以參考下2016-12-12最新評(píng)論