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