摘要:并且用驗(yàn)證了中一系列的實(shí)質(zhì)就是魔法糖的本質(zhì)。抽絲剝繭我們首先看的編譯結(jié)果這是一個(gè)自執(zhí)行函數(shù),它接受一個(gè)參數(shù)就是他要繼承的父類,返回一個(gè)構(gòu)造函數(shù)。
如果你已經(jīng)看過(guò)第一篇揭秘babel的魔法之class魔法處理,這篇將會(huì)是一個(gè)延伸;
如果你還沒(méi)看過(guò),并且也不想現(xiàn)在就去讀一下,多帶帶看這篇也沒(méi)有關(guān)系,并不存在理解上的障礙。
上一篇針對(duì)Babel對(duì)ES6里面基礎(chǔ)“class”的編譯進(jìn)行了分析。這一篇將會(huì)對(duì)class的繼承,包括extends和super進(jìn)行講解。
什么?你還不了解ES6如何實(shí)現(xiàn)繼承?沒(méi)關(guān)系,下文內(nèi)容也有詳細(xì)示例。
再啰嗦一句,這一系列的文章并不是科普ECMAScript新規(guī)范。她的意義在于分析Babel對(duì)ES6的編譯,從而希望讀者對(duì)JS語(yǔ)言基礎(chǔ),程序設(shè)計(jì)理念等有更深刻的認(rèn)識(shí)。
Class的繼承在這篇文章中,我會(huì)講解Babel如何處理ES6 Class里面的繼承功能,同樣,這其實(shí)是一系列語(yǔ)法糖的實(shí)現(xiàn)。
我們先來(lái)溫習(xí)一下實(shí)現(xiàn)方式:
首先,我們定義一個(gè)父類:
class Person { constructor(){ this.type = "person" } }
這個(gè)類包含了一個(gè)實(shí)例屬性。
然后,實(shí)現(xiàn)一個(gè)Student類,這個(gè)“學(xué)生”類繼承“人”類:
class Student extends Person { constructor(){ super() } }
從簡(jiǎn)出發(fā),我們定義的Person類只包含了type為person的這一個(gè)屬性,不含有方法。所以我們extends+super()之后,Student類
也繼承了同樣的屬性。
如下:
var student1 = new Student(); student1.type // "person"
我們進(jìn)一步可以驗(yàn)證原型鏈上的關(guān)系:
student1 instanceof Student // true student1 instanceof Person // true student1.hasOwnProperty("type") // true
一切看上去cool極了,我們實(shí)現(xiàn)了ES6里面的繼承。并且用instanceof驗(yàn)證了ES6中一系列的實(shí)質(zhì)就是“魔法糖”的本質(zhì)。
那么,經(jīng)過(guò)Babel編譯,我們的代碼是什么樣呢?
我們一步一步來(lái)看,
Step1: Person定義
class Person { constructor(){ this.type = "person" } }
被編譯為:
var Person = function Person() { _classCallCheck(this, Person); this.type = "person"; };
如果你看過(guò)這一篇的前傳,
你應(yīng)該就熟悉這一系列的變換,也可能會(huì)記得_classCallCheck函數(shù)到底是什么鬼。這里因?yàn)槠腿ト哂嗟脑颍筒辉僬归_。
Step2:Student探秘
我們這次嘗試觀察Student子類:
class Student extends Person { constructor(){ super() } }
編譯結(jié)果:
// 實(shí)現(xiàn)定義Student構(gòu)造函數(shù),它是一個(gè)自執(zhí)行函數(shù),接受父類構(gòu)造函數(shù)為參數(shù) var Student = (function(_Person) { // 實(shí)現(xiàn)對(duì)父類原型鏈屬性的繼承 _inherits(Student, _Person); // 將會(huì)返回這個(gè)函數(shù)作為完整的Student構(gòu)造函數(shù) function Student() { // 使用檢測(cè) _classCallCheck(this, Student); // _get的返回值可以先理解為父類構(gòu)造函數(shù) _get(Object.getPrototypeOf(Student.prototype), "constructor", this).call(this); } return Student; })(Person); // _x為Student.prototype.__proto__ // _x2為"constructor" // _x3為this var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; // Student.prototype.__proto__為null的處理 if (object === null) object = Function.prototype; // 以下是為了完整復(fù)制父類原型鏈上的屬性,包括屬性特性的描述符 var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; function _inherits(subClass, superClass) { // superClass需要為函數(shù)類型,否則會(huì)報(bào)錯(cuò) if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } // Object.create第二個(gè)參數(shù)是為了修復(fù)子類的constructor subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); // Object.setPrototypeOf是否存在做了一個(gè)判斷,否則使用__proto__ if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
雖然我加上了注釋,但是這一坨代碼仍然看上去惡心極了!沒(méi)關(guān)系,下面我們進(jìn)行拆解,你很快就能明白。
Step3:抽絲剝繭
我們首先看Student的編譯結(jié)果:
var Student = (function(_Person) { _inherits(Student, _Person); function Student() { _classCallCheck(this, Student); _get(Object.getPrototypeOf(Student.prototype), "constructor", this).call(this); } return Student; })(Person);
這是一個(gè)自執(zhí)行函數(shù),它接受一個(gè)參數(shù)Person(就是他要繼承的父類),返回一個(gè)構(gòu)造函數(shù)Student。
上面_inherits方法的本質(zhì)其實(shí)就是讓Student子類繼承Person父類原型鏈上的方法。它實(shí)現(xiàn)原理可以歸結(jié)為一句話:
Student.prototype = Object.create(Person.prototype); Object.setPrototypeOf(Student, Person)
注意,Object.create接收第二個(gè)參數(shù),這就實(shí)現(xiàn)了對(duì)Student的constructor修復(fù)。
如果你不了解Object.create,那么請(qǐng)參考這里。
以上通過(guò)_inherits實(shí)現(xiàn)了對(duì)父類原型鏈上屬性的繼承,那么對(duì)于父類的實(shí)例屬性(就是constructor定義的屬性)的繼承,也可以歸結(jié)為一句話:
Person.call(this);
如果你還不理解使用call或者apply或者bind來(lái)改變JS中this的指向,那么請(qǐng)參考這篇文章。
這樣,我們便透析了Babel編譯這一切的秘密。
總結(jié)如果你看完這一系列的文章可能會(huì)有體會(huì):我想灌輸?shù)目隙ú皇荅S6新特性的使用,關(guān)于這些東西有太多的文章、博客、書籍去討論。
我是在講Babel對(duì)這些新特性的編譯產(chǎn)出,那為什么我會(huì)在乎這些呢?
其實(shí)通過(guò)分析,我們悄然回顧了JS中很多重點(diǎn)以及難點(diǎn),還包括程序設(shè)計(jì)上的一些小思想。
最近面試了很多前端“新同學(xué)”:有的人癡迷于框架,可以使用React或者Vue比照tutorial做出頁(yè)面炫酷的交互,甚至自覺(jué)SPA也不在話下;
有的人ES6、ES7了解很多,generator,async都能說(shuō)出一二,仿佛Promise處理異步已經(jīng)成為了“時(shí)代棄兒”。
可是同樣是這些人,對(duì)原型原型鏈、this、作用域、閉包都沒(méi)有深刻地理解和掌握。
同樣是這些頁(yè)面,即便用callback處理異步回調(diào),嵌套最多也不到兩層。
也許,同樣一批人也會(huì)問(wèn):“我能用前端框架、ES6擼出好多頁(yè)面,可是為什么感覺(jué)進(jìn)步很慢處于瓶頸中、面試也總被掛呢?”
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/81245.html
摘要:年,很多人已經(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)行編譯。很多人可能沒(méi)有關(guān)心過(guò),...
摘要:前言見(jiàn)解有限,如有描述不當(dāng)之處,請(qǐng)幫忙及時(shí)指出,如有錯(cuò)誤,會(huì)及時(shí)修正。倘若用的是中文搜索。所以最終的實(shí)例對(duì)象仍然能進(jìn)行正常的原型鏈回溯,回溯到原本的所有原型方法這樣通過(guò)一個(gè)巧妙的欺騙技巧,就實(shí)現(xiàn)了完美的繼承。 前言 見(jiàn)解有限,如有描述不當(dāng)之處,請(qǐng)幫忙及時(shí)指出,如有錯(cuò)誤,會(huì)及時(shí)修正。 20180201更新: 修改用詞描述,如組合寄生式改成寄生組合式,修改多處筆誤(感謝@Yao Ding的...
摘要:中的同名的實(shí)際上就是我們?cè)诘脑屠^承中使用的構(gòu)造函數(shù),所以中的是對(duì)中的構(gòu)造函數(shù)的一種包裝。我們發(fā)現(xiàn),在中設(shè)定的屬性被放在的構(gòu)造函數(shù)中,而方法則以鍵值對(duì)的形式傳入一個(gè)函數(shù)中。大家是不是對(duì)這種繼承模式似曾相識(shí)呢對(duì)了,這就是所謂的構(gòu)造函數(shù)竊取。 ES6中增加了一些新特性,但從底層的角度來(lái)說(shuō),只是一些語(yǔ)法糖。但是就我個(gè)人來(lái)說(shuō),如果不了解這些語(yǔ)法糖的本質(zhì),是用不安心的。那我們要如何揭開這些語(yǔ)法糖...
摘要:我們都知道您是國(guó)內(nèi)知名的專家,是什么樣的情結(jié)使得您愿意將魔法作為自己的別名大家好,很榮幸接受圖靈的專訪。在這一堆書里,有一套上下冊(cè)教程叫作談是由圖靈引進(jìn)的哦。從偶像那里得來(lái)一個(gè)名字,很榮幸而且這其中也有圖靈的功勞,也是緣份。 非商業(yè)轉(zhuǎn)載請(qǐng)注明作譯者、出處,并保留本文的原始鏈接:http://www.ituring.com.cn/article/216538 showImg(https:...
閱讀 2518·2021-09-24 10:29
閱讀 3799·2021-09-22 15:46
閱讀 2571·2021-09-04 16:41
閱讀 2977·2019-08-30 15:53
閱讀 1258·2019-08-30 14:24
閱讀 3052·2019-08-30 13:19
閱讀 2170·2019-08-29 14:17
閱讀 3520·2019-08-29 12:55