摘要:中通過(guò)關(guān)鍵字,定義類經(jīng)過(guò)轉(zhuǎn)碼之后可以看到類的底層還是通過(guò)構(gòu)造函數(shù)去創(chuàng)建的。在中,構(gòu)造函數(shù)是可以直接運(yùn)行的,比如。如果你有靜態(tài)屬性,會(huì)直接添加到構(gòu)造函數(shù)上。不是很好理解,可以通過(guò)下面的方式理解是一個(gè)實(shí)例,是構(gòu)造方法的原型。
ES6中通過(guò)class關(guān)鍵字,定義類
class Parent { constructor(name,age){ this.name = name; this.age = age; } speakSomething(){ console.log("I can speek chinese"); } }
經(jīng)過(guò)babel轉(zhuǎn)碼之后
"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 Parent = function () { function Parent(name, age) { _classCallCheck(this, Parent); this.name = name; this.age = age; } _createClass(Parent, [{ key: "speakSomething", value: function speakSomething() { console.log("I can speek chinese"); } }]); return Parent; }();
可以看到ES6類的底層還是通過(guò)構(gòu)造函數(shù)去創(chuàng)建的。
通過(guò)ES6創(chuàng)建的類,是不允許你直接調(diào)用的。在ES5中,構(gòu)造函數(shù)是可以直接運(yùn)行的,比如Parent()。但是在ES6就不行。我們可以看到轉(zhuǎn)碼的構(gòu)造函數(shù)中有_classCallCheck(this, Parent)語(yǔ)句,這句話是防止你通過(guò)構(gòu)造函數(shù)直接運(yùn)行的。你直接在ES6運(yùn)行Parent(),這是不允許的,ES6中拋出Class constructor Parent cannot be invoked without "new"錯(cuò)誤。轉(zhuǎn)碼后的會(huì)拋出Cannot call a class as a function.我覺(jué)得這樣的規(guī)范挺好的,能夠規(guī)范化類的使用方式。
轉(zhuǎn)碼中_createClass方法,它調(diào)用Object.defineProperty方法去給新創(chuàng)建的Parent添加各種屬性。defineProperties(Constructor.prototype, protoProps)是給原型添加屬性。如果你有靜態(tài)屬性,會(huì)直接添加到構(gòu)造函數(shù)上defineProperties(Constructor, staticProps)。但是貌似并沒(méi)有用到,下面可以證明.
這兩個(gè)流程走下來(lái),其實(shí)就創(chuàng)建了一個(gè)類。
上面講的是創(chuàng)建一個(gè)類的過(guò)程,那ES6如何實(shí)現(xiàn)繼承的呢?還是上面的例子,這次我們給Parent添加靜態(tài)屬性,原型屬性,內(nèi)部屬性
class Parent { static height = 12 constructor(name,age){ this.name = name; this.age = age; } speakSomething(){ console.log("I can speek chinese"); } } Parent.prototype.color = "yellow" //定義子類,繼承父類 class Child extends Parent { static width = 18 constructor(name,age){ super(name,age); } coding(){ console.log("I can code JS"); } } var c = new Child("job",30); c.coding()
轉(zhuǎn)碼之后的代碼變成了這樣
"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 _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; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var Parent = function () { function Parent(name, age) { _classCallCheck(this, Parent); this.name = name; this.age = age; } _createClass(Parent, [{ key: "speakSomething", value: function speakSomething() { console.log("I can speek chinese"); } }]); return Parent; }(); Parent.height = 12; Parent.prototype.color = "yellow"; //定義子類,繼承父類 var Child = function (_Parent) { _inherits(Child, _Parent); function Child(name, age) { _classCallCheck(this, Child); return _possibleConstructorReturn(this, (Child.__proto__ || Object.getPrototypeOf(Child)).call(this, name, age)); } _createClass(Child, [{ key: "coding", value: function coding() { console.log("I can code JS"); } }]); return Child; }(Parent); Child.width = 18; var c = new Child("job", 30); c.coding();
我們可以看到,構(gòu)造類的方法都沒(méi)變,只是添加了_inherits核心方法來(lái)實(shí)現(xiàn)繼承,下面我們就看下這個(gè)方法做了什么?
首先是判斷父類的類型,然后
subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } });
這段代碼翻譯下來(lái)就是
function F(){} F.prototype = superClass.prototype subClass.prototype = new F() subClass.prototype.constructor = subClass
接下來(lái)subClass.__proto__ = superClass
_inherits核心思想就是下面兩句
subClass.prototype.__proto__ = superClass.prototype subClass.__proto__ = superClass
一圖勝千言
那為什么這樣一倒騰,它就實(shí)現(xiàn)了繼承了呢?
首先 subClass.prototype.__proto__ = superClass.prototype保證了c instanceof Parent是true,Child的實(shí)例可以訪問(wèn)到父類的屬性,包括內(nèi)部屬性,以及原型屬性。其次,subClass.__proto__ = superClass,保證了Child.height也能訪問(wèn)到,也就是靜態(tài)方法。
subClass.__proto__ = superClass不是很好理解,可以通過(guò)下面的方式理解
function A(){} var a = new A() a.__proto__ = A.prototype
a是一個(gè)實(shí)例,A.prototype是構(gòu)造方法的原型。通過(guò)這種方式,那么a就可以訪問(wèn)A.prototype上面的方法。
那把 subClass類比成 a,superClass類比成A.prototype,那是不是subClass可以直接訪問(wèn) superClass的靜態(tài)屬性,靜態(tài)方法了。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/94848.html
摘要:歡迎關(guān)注我的博客正文讓我來(lái)構(gòu)造函數(shù)其實(shí),模擬一個(gè)類的方式非常的簡(jiǎn)單構(gòu)造函數(shù)。我們先來(lái)看一個(gè)例子這里通過(guò)構(gòu)造函數(shù)模擬出來(lái)的類,其實(shí)和其他語(yǔ)言的類行為上是基本一致的,唯一的區(qū)別就是它不具備私有方法。 前言 ES6時(shí)代的來(lái)臨,使得類繼承變得如此的圓滑。但是,你有思考過(guò)ES6的類繼承模式嗎?如何去實(shí)現(xiàn)它呢? 類繼承對(duì)于JavaScript來(lái)說(shuō),實(shí)現(xiàn)方式與Java等類語(yǔ)言大不相同。熟悉JavaS...
摘要:類的實(shí)現(xiàn)轉(zhuǎn)換前轉(zhuǎn)換后可見(jiàn)的底層依然是構(gòu)造函數(shù)調(diào)用方法判斷當(dāng)前函數(shù)調(diào)用前是否有關(guān)鍵字。若構(gòu)造函數(shù)前面沒(méi)有則構(gòu)造函數(shù)的不會(huì)不出現(xiàn)在的原型鏈上,返回。典型的寄生繼承用父類構(gòu)造函數(shù)的創(chuàng)建一個(gè)空對(duì)象,并將這個(gè)對(duì)象指向子類構(gòu)造函數(shù)的。代表父類構(gòu)造函數(shù)。 在閱讀文章之前,您至少需要對(duì)JavaScript原型繼承有一定了解,如果覺(jué)得有所欠缺,可以先了解下我這篇文章:https://segmentfau...
摘要:下面是用實(shí)現(xiàn)轉(zhuǎn)成抽象語(yǔ)法樹(shù)如下還支持繼承以下是轉(zhuǎn)換結(jié)果最終的結(jié)果還是代碼,其中包含庫(kù)中的一些函數(shù)。可以使用新的易于使用的類定義,但是它仍然會(huì)創(chuàng)建構(gòu)造函數(shù)和分配原型。 這是專門(mén)探索 JavaScript 及其所構(gòu)建的組件的系列文章的第 15 篇。 想閱讀更多優(yōu)質(zhì)文章請(qǐng)猛戳GitHub博客,一年百來(lái)篇優(yōu)質(zhì)文章等著你! 如果你錯(cuò)過(guò)了前面的章節(jié),可以在這里找到它們: JavaScript 是...
摘要:面試題來(lái)源于網(wǎng)絡(luò),看一下高級(jí)前端的面試題,可以知道自己和高級(jí)前端的差距。 面試題來(lái)源于網(wǎng)絡(luò),看一下高級(jí)前端的面試題,可以知道自己和高級(jí)前端的差距。有些面試題會(huì)重復(fù)。 使用過(guò)的koa2中間件 koa-body原理 介紹自己寫(xiě)過(guò)的中間件 有沒(méi)有涉及到Cluster 介紹pm2 master掛了的話pm2怎么處理 如何和MySQL進(jìn)行通信 React聲明周期及自己的理解 如何...
閱讀 1229·2021-11-24 09:39
閱讀 380·2019-08-30 14:12
閱讀 2592·2019-08-30 13:10
閱讀 2434·2019-08-30 12:44
閱讀 958·2019-08-29 16:31
閱讀 845·2019-08-29 13:10
閱讀 2434·2019-08-27 10:57
閱讀 3152·2019-08-26 13:57