摘要:正常情況,的返回值就是一個(gè)對象,其實(shí)也就是對象。好了,上面算是基本說清楚了使用語法定義類繼承類,到底發(fā)生了什么,如果錯(cuò)誤,還請指正,謝謝
自從有了webpack之后,我們這些jscoder似乎得到了前所未有的解放,箭頭函數(shù),對象解構(gòu),let,const關(guān)鍵字,以及class、extends等等關(guān)鍵字使用得不亦樂乎,反正,webpack會幫我們把這些es6代碼轉(zhuǎn)換成瀏覽器能夠識別的es5代碼,那么,我們有多少人真正的看過,babel轉(zhuǎn)換之后的代碼呢?今天,我就來看一下,當(dāng)我們使用關(guān)鍵詞class的時(shí)候,babel到底做了什么?
1、打開網(wǎng)址:https://babeljs.io/repl我推薦打開網(wǎng)址:https://babeljs.io/repl,這里我們左邊寫es6代碼,馬上右邊就能轉(zhuǎn)譯出es5代碼,然后,我在左邊輸入了如下代碼:
class A { constructor(name) { this.name = name } getName() { return this.name } }
這是一個(gè)最簡單的類,一個(gè)屬性,一個(gè)方法。
這時(shí)候,右邊框已經(jīng)給我轉(zhuǎn)譯出了瀏覽器可識別的es5代碼了,格式化之后是這樣的:
"use strict"; var _createClass = 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); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var A = function () { function A(name) { _classCallCheck(this, A); this.name = name; } _createClass(A, [{ key: "getName", value: function getName() { return this.name; } }]); return A; }();
好,現(xiàn)在來分析一下這段代碼。
2、es6里面的類,本質(zhì)上其實(shí)就是一個(gè)函數(shù)// 自執(zhí)行函數(shù) var A = function () { function A(name) { // 這個(gè)函數(shù)的目的其實(shí)是防止這個(gè)構(gòu)造函數(shù)被當(dāng)做普通函數(shù)執(zhí)行 _classCallCheck(this, A); this.name = name; } // 對函數(shù)A執(zhí)行_createClass方法,其實(shí)就是給A的原型上綁定方法 _createClass(A, [{ key: "getName", //方法名 value: function getName() { //函數(shù)體 return this.name; } }]); return A; }();
這段代碼,變量A是一個(gè)自執(zhí)行函數(shù)的返回值,該自執(zhí)行函數(shù)的返回值其實(shí)就是我們熟悉的構(gòu)造函數(shù),所以,es6里面的類其實(shí)就是一個(gè)構(gòu)造函數(shù)。
3、_classCallCheck函數(shù)function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
這個(gè)函數(shù)特別簡單,當(dāng)執(zhí)行函數(shù)A的時(shí)候,不允許this不是A的子類實(shí)例,比如直接這樣調(diào)用A(),但是在A的子類B中可以這樣調(diào)用:A.apply(this, arguments)。
該函數(shù)的目的是防止構(gòu)造函數(shù)被當(dāng)做普通函數(shù)執(zhí)行。
//該函數(shù)也是一個(gè)自執(zhí)行的函數(shù),其返回值是一個(gè)函數(shù) var _createClass = function () { // 把props數(shù)組上每一個(gè)對象,通過Object.defineProperty方法,都定義到目標(biāo)對象target上去 function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { //這里要確保props[i]是一個(gè)對象,并且有key和value兩個(gè)鍵 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); } } return function (Constructor, protoProps, staticProps) { // 如果傳入了原型屬性數(shù)組,就把屬性全部定義到Constructor的原型上去 if (protoProps) defineProperties(Constructor.prototype, protoProps); // 如果傳入了靜態(tài)屬性數(shù)組,就把屬性全部定義到Constructor對象自身上去 if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
其實(shí)_createClass函數(shù)做的事情,就是把幾個(gè)方法拷貝到構(gòu)造函數(shù)A的原型上去。
4、使用關(guān)鍵詞extends,發(fā)生了什么?我在https://babeljs.io/repl 左側(cè)輸入框上加了下面這行代碼:
class B extends A {}
這時(shí)候,右側(cè)多出了以下幾行代碼:
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn"t been initialised - super() hasn"t been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var B = function (_A) { _inherits(B, _A); function B() { _classCallCheck(this, B); //這里的重點(diǎn)是第二個(gè)參數(shù):(B.__proto__ || Object.getPrototypeOf(B)).apply(this, arguments); //這里其實(shí)是將子類的實(shí)例對象,調(diào)用了父類的構(gòu)造函數(shù)方法,這樣父類的屬性就都可以拷貝到子類上來 return _possibleConstructorReturn(this, (B.__proto__ || Object.getPrototypeOf(B)).apply(this, arguments)); } return B; }(A);5、_inherits函數(shù)
function _inherits(subClass, superClass) { //簡單校驗(yàn) if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } //把子類的原型指向父類的原型創(chuàng)建出來的對象(注意不是直接指向父類原型),并且修正constructor屬性為子類自己 subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); // 這一步操作,其實(shí)是想把superClass放到subClass下,相當(dāng)于subClass.super = superClass,這樣后面的代碼中,subClass里面能方便的引用到superClass函數(shù) if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }6、_possibleConstructorReturn函數(shù)
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn"t been initialised - super() hasn"t been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
如果call不是對象或者函數(shù),即該調(diào)用:(B.__proto__ || Object.getPrototypeOf(B)).apply(this, arguments)的返回值既不是對象,也不是函數(shù),那么,就直接返回當(dāng)前的self,而self其實(shí)就是子類B里面的實(shí)例指針this。正常情況,(B.__proto__ || Object.getPrototypeOf(B)).apply(this, arguments)的返回值就是一個(gè)對象,其實(shí)也就是對象。
好了,上面算是基本說清楚了使用es6語法定義類、繼承類,到底發(fā)生了什么,如果錯(cuò)誤,還請指正,謝謝!
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/107871.html
摘要:升級之后,項(xiàng)目的壓縮包并沒有什么明顯變化。這里可以參考下阮老師介紹的基本語法的循環(huán)是通過遍歷器迭代的,循環(huán)數(shù)組時(shí)并非是,然后通過下標(biāo)尋值。樓主好奇為什么不能消除未引用的類。樓主我的代碼沒什么副作用啊。 本文將探討tree-shaking在當(dāng)下(webpack@3, babel@6 以下)的現(xiàn)狀,以及研究為什么tree-shaking依舊舉步維艱的原因,最終總結(jié)當(dāng)下能提高tree-sha...
摘要:大概就是將對象里面的一些屬性轉(zhuǎn)換成數(shù)組,方便解構(gòu)賦值的進(jìn)行。而則更貼近的寫法,性能更好一些,兼容性更好一些,但將這部份代碼再轉(zhuǎn)換成的話會比較麻煩一些感覺這一點(diǎn)并不是缺點(diǎn),有源碼就可以了。上面解決的辦法,實(shí)質(zhì)就是將改成。 原文鏈接:https://github.com/lcxfs1991/blog/issues/9 前言 將babel捧作前端一個(gè)劃時(shí)代的工具一定也不為過,它的出現(xiàn)讓許多程...
摘要:你可能認(rèn)為和它的新模塊系統(tǒng)出現(xiàn)得有點(diǎn)晚。聚合模塊有時(shí)候一個(gè)包的主模塊只不過是導(dǎo)入包其他所有的模塊,并用統(tǒng)一的方式導(dǎo)出。靜態(tài)動態(tài),或者說規(guī)則如何打破規(guī)則作為一個(gè)動態(tài)編譯語言,令人驚奇的是擁有一個(gè)靜態(tài)的模塊系統(tǒng)。 回想2007年,那時(shí)候我剛加入Mozillas JavaScript團(tuán)隊(duì),那時(shí)候的一個(gè)典型的JavaScript程序只需要一行代碼,聽起來像個(gè)笑話。 兩年后,Google Map...
摘要:因此,你還是需要各種各樣雜七雜八的工具來轉(zhuǎn)換你的代碼噢,我可去你媽的吧,這些東西都是干嘛的我就是想用個(gè)模塊化,我到底該用啥子本文正旨在列出幾種可用的在生產(chǎn)環(huán)境中放心使用模塊化的方法,希望能幫到諸位后來者這方面的中文資源實(shí)在是忒少了。 原文發(fā)表在我的博客上。最近搗鼓了一下 ES6 的模塊化,分享一些經(jīng)驗(yàn) :) Python3 已經(jīng)發(fā)布了九年了,Python 社區(qū)卻還在用 Python 2...
摘要:并且用驗(yàn)證了中一系列的實(shí)質(zhì)就是魔法糖的本質(zhì)。抽絲剝繭我們首先看的編譯結(jié)果這是一個(gè)自執(zhí)行函數(shù),它接受一個(gè)參數(shù)就是他要繼承的父類,返回一個(gè)構(gòu)造函數(shù)。 如果你已經(jīng)看過第一篇揭秘babel的魔法之class魔法處理,這篇將會是一個(gè)延伸;如果你還沒看過,并且也不想現(xiàn)在就去讀一下,單獨(dú)看這篇也沒有關(guān)系,并不存在理解上的障礙。 上一篇針對Babel對ES6里面基礎(chǔ)class的編譯進(jìn)行了分析。這一篇將...
閱讀 860·2021-09-22 15:18
閱讀 1227·2021-09-09 09:33
閱讀 2781·2019-08-30 10:56
閱讀 1226·2019-08-29 16:30
閱讀 1518·2019-08-29 13:02
閱讀 1489·2019-08-26 13:55
閱讀 1671·2019-08-26 13:41
閱讀 1976·2019-08-26 11:56