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