摘要:年,很多人已經(jīng)開始接觸環(huán)境,并且早已經(jīng)用在了生產(chǎn)當(dāng)中。我們發(fā)現(xiàn),關(guān)鍵字會(huì)被編譯成構(gòu)造函數(shù),于是我們便可以通過(guò)來(lái)實(shí)現(xiàn)實(shí)例的生成。下一篇文章我會(huì)繼續(xù)介紹如何處理子類的并會(huì)通過(guò)一段函數(shù)橋梁,使得環(huán)境下也能夠繼承定義的。
2017年,很多人已經(jīng)開始接觸ES6環(huán)境,并且早已經(jīng)用在了生產(chǎn)當(dāng)中。我們知道ES6在大部分瀏覽器還是跑不通的,因此我們使用了偉大的Babel來(lái)進(jìn)行編譯。很多人可能沒有關(guān)心過(guò),經(jīng)過(guò)Babel編譯之后,我們?nèi)A麗的ES6代碼究竟變成了什么樣子?
這篇文章,針對(duì)Babel對(duì)ES6里面“類class”的編譯進(jìn)行分析,你可以在線測(cè)試編譯結(jié)果,畢竟紙上得來(lái)終覺淺,自己動(dòng)手,才能真正體會(huì)其中的奧秘。
另外,如果你還不明白JS中原型鏈等OOP相關(guān)知識(shí),建議出門左轉(zhuǎn)找到經(jīng)典的《JS高級(jí)程序設(shè)計(jì)》來(lái)補(bǔ)課;如果你對(duì)JS中,通過(guò)原型鏈來(lái)實(shí)現(xiàn)繼承一直云里霧里,安利一下我的同事,前端著名網(wǎng)紅顏海鏡大大早在2014年的文章
為什么使用選擇BabelBabel:The compiler for writing next generation JavaScript;
我們知道,現(xiàn)在大部分瀏覽器或者類似NodeJS的javascript引擎還不能直接支持ES6語(yǔ)法。但這并不構(gòu)成障礙,比如Babel的出現(xiàn),使得我們?cè)谏a(chǎn)環(huán)境中書寫ES6代碼成為了現(xiàn)實(shí),它工作原理是編譯ES6的新特性為老版本的ES5,從而得到宿主環(huán)境的支持。
在這篇文章中,我會(huì)講解Babel如何處理ES6新特性:Class,這其實(shí)是一系列語(yǔ)法糖的實(shí)現(xiàn)。
Old school方式實(shí)現(xiàn)繼承在探究ES6之前,我們先來(lái)回顧一下ES5環(huán)境下,我們?nèi)绾螌?shí)現(xiàn)類的繼承:
// Person是一個(gè)構(gòu)造器 function Person(name) { this.type = "Person"; this.name = name; } // 我們可以通過(guò)prototype的方式來(lái)加一條實(shí)例方法 Person.prototype.hello = function() { console.log("hello " + this.name); } // 對(duì)于私有屬性(Static method),我們當(dāng)然不能放在原型鏈上了。我們可以直接放在構(gòu)造函數(shù)上面 Person.fn = function() { console.log("static"); };
我們可以這么應(yīng)用:
var julien = new Person("julien"); var darul = new Person("darul"); julien.hello(); // "hello julien" darul.hello(); // "hello darul" Person.fn(); // "static" // 這樣會(huì)報(bào)錯(cuò),因?yàn)閒n是一個(gè)私有屬性 julien.fn(); //Uncaught TypeError: julien.fn is not a functionNew school方式(ES6)實(shí)現(xiàn)繼承
在ES6環(huán)境下,我們當(dāng)然迫不及待地試一試Class:
class Person { constructor(name) { this.name = name; this.type="person" } hello() { console.log("hello " + this.name); } static fn() { console.log("static"); }; }
這樣寫起來(lái)當(dāng)然很cool,但是經(jīng)過(guò)Babel編譯,我們的代碼是什么樣呢?
Babel transformation我們一步一步來(lái)看,
Step1: 定義
我們從最簡(jiǎn)單開始,試試不加任何方法和屬性的情況下,
Class Person{}
被編譯為:
function _classCallCheck(instance, Constructor) { // 檢查是否成功創(chuàng)建了一個(gè)對(duì)象 if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var Person = function Person() { _classCallCheck(this, Person); };
你可能會(huì)一頭霧水,_classCallCheck是什么?其實(shí)很簡(jiǎn)單,它是為了保證調(diào)用的安全性。
比如我們這么調(diào)用:
// ok var p = new Person();
是沒有問題的,但是直接調(diào)用:
// Uncaught TypeError: Cannot call a class as a function Person();
就會(huì)報(bào)錯(cuò),這就是_classCallCheck所起的作用。具體原理自己看代碼就好了,很好理解。
我們發(fā)現(xiàn),Class關(guān)鍵字會(huì)被編譯成構(gòu)造函數(shù),于是我們便可以通過(guò)new來(lái)實(shí)現(xiàn)實(shí)例的生成。
Step2:Constructor探秘
我們這次嘗試加入constructor,再來(lái)看看編譯結(jié)果:
class Person() { constructor(name) { this.name = name; this.type = "person" } }
編譯結(jié)果:
var Person = function Person(name) { _classCallCheck(this, Person); this.type = "person"; this.name = name; };
看上去棒極了,我們繼續(xù)探索。
Step3:增加方法
我們嘗試給Person類添加一個(gè)方法:hello:
class Person { constructor(name) { this.name = name; this.type = "person" } hello() { console.log("hello " + this.name); } }
編譯結(jié)果(已做適當(dāng)省略):
// 如上,已經(jīng)解釋過(guò) function _classCallCheck.... // MAIN FUNCTION 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; }; })(); var Person = (function () { function Person(name) { _classCallCheck(this, Person); this.name = name; } _createClass(Person, [{ key: "hello", value: function hello() { console.log("hello " + this.name); } }]); return Person; })();
Oh...no,看上去有很多需要消化!不要急,我嘗試先把他精簡(jiǎn)一下,并加上注釋,你就會(huì)明白核心思路:
var _createClass = (function () { function defineProperties(target, props) { // 對(duì)于每一個(gè)定義的屬性props,都要完全拷貝它的descriptor,并擴(kuò)展到target上 } return defineProperties(Constructor.prototype, protoProps); })(); var Person = (function () { function Person(name) { // 同之前... } _createClass(Person, [{ key: "hello", value: function hello() { console.log("hello " + this.name); } }]); return Person; })();
如果你不明白defineProperty方法, 請(qǐng)參考這里
現(xiàn)在,我們知道我們添加的方法:
hello() { console.log("hello " + this.name); }
被編譯為:
_createClass( Person, [{ key: "hello", value: function hello() { console.log("hello " + this.name); } }]);
而_createClass接受2個(gè)-3個(gè)參數(shù),分別表示:
參數(shù)1 => 我們要擴(kuò)展屬性的目標(biāo)對(duì)象,這里其實(shí)就是我們的Person 參數(shù)2 => 需要在目標(biāo)對(duì)象原型鏈上添加的屬性,這是一個(gè)數(shù)組 參數(shù)3 => 需要在目標(biāo)對(duì)象上添加的屬性,這是一個(gè)數(shù)組
這樣,Babel的魔法就一步一步被揭穿了。
總結(jié)希望這篇文章能夠讓你了解到Babel是如何初步把我們ES6 Class語(yǔ)法編譯成ES5的。下一篇文章我會(huì)繼續(xù)介紹Babel如何處理子類的Super(), 并會(huì)通過(guò)一段函數(shù)橋梁,使得ES5環(huán)境下也能夠繼承ES6定義的Class。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/81192.html
摘要:并且用驗(yàn)證了中一系列的實(shí)質(zhì)就是魔法糖的本質(zhì)。抽絲剝繭我們首先看的編譯結(jié)果這是一個(gè)自執(zhí)行函數(shù),它接受一個(gè)參數(shù)就是他要繼承的父類,返回一個(gè)構(gòu)造函數(shù)。 如果你已經(jīng)看過(guò)第一篇揭秘babel的魔法之class魔法處理,這篇將會(huì)是一個(gè)延伸;如果你還沒看過(guò),并且也不想現(xiàn)在就去讀一下,單獨(dú)看這篇也沒有關(guān)系,并不存在理解上的障礙。 上一篇針對(duì)Babel對(duì)ES6里面基礎(chǔ)class的編譯進(jìn)行了分析。這一篇將...
摘要:我們都知道您是國(guó)內(nèi)知名的專家,是什么樣的情結(jié)使得您愿意將魔法作為自己的別名大家好,很榮幸接受圖靈的專訪。在這一堆書里,有一套上下冊(cè)教程叫作談是由圖靈引進(jìn)的哦。從偶像那里得來(lái)一個(gè)名字,很榮幸而且這其中也有圖靈的功勞,也是緣份。 非商業(yè)轉(zhuǎn)載請(qǐng)注明作譯者、出處,并保留本文的原始鏈接:http://www.ituring.com.cn/article/216538 showImg(https:...
摘要:我們都知道您是國(guó)內(nèi)知名的專家,是什么樣的情結(jié)使得您愿意將魔法作為自己的別名大家好,很榮幸接受圖靈的專訪。在這一堆書里,有一套上下冊(cè)教程叫作談是由圖靈引進(jìn)的哦。從偶像那里得來(lái)一個(gè)名字,很榮幸而且這其中也有圖靈的功勞,也是緣份。 非商業(yè)轉(zhuǎn)載請(qǐng)注明作譯者、出處,并保留本文的原始鏈接:http://www.ituring.com.cn/article/216538 showImg(https:...
摘要:它并不是實(shí)際在內(nèi)部的工作方式,而且它只是一個(gè)提案,在未來(lái)都會(huì)有可能發(fā)生變化。這意味著,數(shù)據(jù)的存儲(chǔ)是獨(dú)立于組件之外的。因此,有一個(gè)訣竅就是你需要思考作為一組需要一個(gè)匹配一致的指針去管理的數(shù)組染陌譯。 原文地址:https://medium.com/@ryardley/... 譯文:染陌 (Github) 譯文地址:https://github.com/answershuto/Blog 轉(zhuǎn)...
閱讀 2781·2021-10-14 09:42
閱讀 838·2021-10-11 10:57
閱讀 785·2019-08-30 15:54
閱讀 1927·2019-08-30 13:50
閱讀 1693·2019-08-30 11:19
閱讀 943·2019-08-29 12:38
閱讀 1435·2019-08-26 11:51
閱讀 1401·2019-08-26 10:48