摘要:使用類創(chuàng)建實(shí)例對(duì)象也是直接對(duì)類使用命令,跟中構(gòu)造函數(shù)的用法一致。中沒有構(gòu)造函數(shù),作為構(gòu)造函數(shù)的語法糖,同時(shí)有屬性和屬性,因此同時(shí)存在兩條繼承鏈。子類的屬性,表示構(gòu)造函數(shù)的繼承,總是指向父類。
1 Class in ES6
ES6提出了類(Class)的概念,讓對(duì)象的原型的寫法更像面向?qū)ο笳Z言寫法。 ES6中通過class定義對(duì)象,默認(rèn)具有constructor方法和自定義方法,但是包含在class中的方法不可枚舉。
class Point{ constructor(){ this.x=x; this.y=y; } toString(){ return this.x+this.y; } }
注意:constructor方法對(duì)應(yīng)ES5的構(gòu)造函數(shù);創(chuàng)建類的方法不需要使用function關(guān)鍵字,方法之間不需要逗號(hào)分隔。
ES5中定義對(duì)象時(shí)組合使用構(gòu)造函數(shù)模式和原型模式,構(gòu)造函數(shù)模式用于定義實(shí)例屬性,原型模式用于定義共享方法和共享屬性,節(jié)省內(nèi)存,而且支持向構(gòu)造函數(shù)傳遞參數(shù)。
function Point (x,y){ this.x=x; this.y=y; } Point.prototype.toString= function(){ return this.x+this.y; }2 ES5和ES6創(chuàng)建實(shí)例和對(duì)象對(duì)比
1)ES5中的Person構(gòu)造函數(shù)和Person原型對(duì)象以及實(shí)例Person1、Person2的關(guān)系:構(gòu)造函數(shù)的prototype屬性以及實(shí)例的__proto__屬性指向原型對(duì)象,原型對(duì)象的constructor屬性指向構(gòu)造函數(shù)。
構(gòu)造函數(shù)的原型(prototype)屬性在ES6中依舊存在,這一點(diǎn)和ES5一樣:類的方法都定義在類的原型(prototype)上,在類的實(shí)例上面調(diào)用方法,其實(shí)就是調(diào)用原型上的方法。
//實(shí)例的constructor方法就是類的原型(prototype)的constructor方法 class B{ constructor(){} } let b = new B(); console.log(b.constructor === B.prototype.constructor);//true
2)ES6的類可以看做是構(gòu)造函數(shù)的另一種寫法(和ES5中構(gòu)造函數(shù)等同的并不是constructor方法):類是function類型,且類本身指向類的prototype對(duì)象的constructor屬性,這與ES5一樣。
class Point{ // ... } console.log(typeof Point) // "function" console.log(Point === Point.prototype.constructor) // true
3)使用類創(chuàng)建實(shí)例對(duì)象也是直接對(duì)類使用new命令,跟ES5中構(gòu)造函數(shù)的用法一致。
4)類內(nèi)部定義的方法都是不可枚舉的,這和ES5不同。
5)constructor方法
一個(gè)類必須有constructor方法,如果沒有就默認(rèn)添加constructor(){}。雖然類是函數(shù),但是和ES5不同,不通過new而直接調(diào)用類會(huì)導(dǎo)致類型錯(cuò)誤,也就是說這個(gè)函數(shù)僅當(dāng)在和new一起使用時(shí)才有意義。
6)類的實(shí)例
與ES5一樣,實(shí)例的屬性除非顯式定義在其本身(即定義在this對(duì)象上),否則都是定義在原型上(即定義在class上)。
class Point { constructor(x, y) { this.x = x; this.y = y; } toString() { return "(" + this.x + ", " + this.y + ")"; } } var point = new Point(2, 3); point.toString() // (2, 3) point.hasOwnProperty("x") // true point.hasOwnProperty("y") // true point.hasOwnProperty("toString") // false point.__proto__.hasOwnProperty("toString") // true
以上代碼中,x和y都是實(shí)例對(duì)象point自身的屬性(因?yàn)槎x在this變量上),所以hasOwnProperty方法返回true,而toString是原型對(duì)象的屬性(因?yàn)槎x在Point類上),所以hasOwnProperty方法返回false。這些都與ES5的行為保持一致。
與ES5一樣,類的所有實(shí)例共享一個(gè)原型對(duì)象。
var p1 = new Point(2,3); var p2 = new Point(3,2); p1.__proto__ === p2.__proto__ //true
可以通過實(shí)例的__proto__屬性為Class原型添加方法,增加后所有的原型都具有這個(gè)方法,這和ES5一樣。
var p1 = new Point(2,3); var p2 = new Point(3,2); p1.__proto__.printName = function () { return "Oops" }; p1.printName() // "Oops" p2.printName() // "Oops"
7)Class不存在變量提升(hoist),這一點(diǎn)與ES5完全不同。
new Foo(); // ReferenceError class Foo {}
上面代碼中,F(xiàn)oo類使用在前,定義在后,這樣會(huì)報(bào)錯(cuò),因?yàn)镋S6不會(huì)把類的聲明提升到代碼頭部。這種規(guī)定的原因與繼承有關(guān),必須保證子類在父類之后定義。
8)嚴(yán)格模式
類和模塊的內(nèi)部,默認(rèn)就是嚴(yán)格模式,所以不需要使用use strict指定運(yùn)行模式。只要你的代碼寫在類或模塊之中,就只有嚴(yán)格模式可用。考慮到未來所有的代碼,其實(shí)都是運(yùn)行在模塊之中,所以ES6實(shí)際上把整個(gè)語言升級(jí)到了嚴(yán)格模式。
Class通過extends關(guān)鍵字實(shí)現(xiàn)繼承,這和ES5通過修改原型鏈實(shí)現(xiàn)繼承不同(巧合的是,SASS也通過@extend實(shí)現(xiàn)樣式繼承):
class ColorPoint extends Point{}
子類必須在constructor方法中調(diào)用super方法,否則新建實(shí)例時(shí)會(huì)報(bào)錯(cuò)。這是因?yàn)樽宇悰]有自己的this對(duì)象,而是繼承父類的this對(duì)象,然后對(duì)其進(jìn)行加工。如果不調(diào)用super方法,子類就得不到this對(duì)象。
class ColorPoint extends Point { constructor(x, y, color) { super(x, y); // 調(diào)用父類的constructor(x, y) this.color = color; } toString() { return this.color + " " + super.toString(); // super代表父類原型,調(diào)用父類的toString() } }
上面代碼中,constructor方法和toString方法之中,都出現(xiàn)了super關(guān)鍵字,它在這里表示父類的構(gòu)造函數(shù),用來新建父類的this對(duì)象。
super這個(gè)關(guān)鍵字,既可以當(dāng)作函數(shù)使用,也可以當(dāng)作對(duì)象使用。第一種情況,super作為函數(shù)調(diào)用時(shí),代表父類的構(gòu)造函數(shù),只能用在子類的構(gòu)造函數(shù)中。ES6 要求,子類的構(gòu)造函數(shù)必須執(zhí)行一次super函數(shù)。第二種情況,super作為對(duì)象時(shí),指代父類的原型對(duì)象。
ES5的繼承,實(shí)質(zhì)是先創(chuàng)造子類的實(shí)例對(duì)象this,然后再將父類的方法添加到this上面(Parent.apply(this))。(ES5通過原型模式的繼承:創(chuàng)建子類,然后將父類的實(shí)例賦值給子類原型,也就是重寫子類原型,代之以一個(gè)新類型的實(shí)例。)ES6的繼承機(jī)制完全不同,實(shí)質(zhì)是先創(chuàng)造父類的實(shí)例對(duì)象this(所以必須先調(diào)用super方法),然后再用子類的構(gòu)造函數(shù)修改this。
如果子類沒有定義constructor方法,這個(gè)方法會(huì)被默認(rèn)添加。在子類的構(gòu)造函數(shù)中,只有調(diào)用super之后,才可以使用this關(guān)鍵字,否則會(huì)報(bào)錯(cuò)。這是因?yàn)樽宇悓?shí)例的構(gòu)建,是基于對(duì)父類實(shí)例加工,只有super方法才能返回父類實(shí)例。
class Point { constructor(x, y) { this.x = x; this.y = y; } } class ColorPoint extends Point { constructor(x, y, color) { this.color = color; // ReferenceError super(x, y); this.color = color; // 正確 } }
和ES5一樣,通過子類創(chuàng)建的實(shí)例是父類以及子類的實(shí)例:
let cp = new ColorPoint(25, 8, "green"); cp instanceof ColorPoint // true cp instanceof Point // true4 補(bǔ)充 1)類的prototype屬性和__proto__屬性(這段還沒看明白,太繞了。)
ES5中每一個(gè)對(duì)象都有__proto__屬性,指向?qū)?yīng)的構(gòu)造函數(shù)的prototype屬性。ES6中沒有構(gòu)造函數(shù),Class作為構(gòu)造函數(shù)的語法糖,同時(shí)有prototype屬性和__proto__屬性,因此同時(shí)存在兩條繼承鏈。
(1)子類的__proto__屬性,表示構(gòu)造函數(shù)的繼承,總是指向父類。
(2)子類prototype屬性的__proto__屬性,表示方法的繼承,總是指向父類的prototype屬性。
這樣的結(jié)果是因?yàn)椋惖睦^承是按照下面的模式實(shí)現(xiàn)的。
class A { } class B { } // B的實(shí)例繼承A的實(shí)例 Object.setPrototypeOf(B.prototype, A.prototype); const b = new B(); // B的實(shí)例繼承A的靜態(tài)屬性 Object.setPrototypeOf(B, A); const b = new B();
這兩條繼承鏈,可以這樣理解:作為一個(gè)對(duì)象,子類(B)的原型(__proto__屬性)是父類(A);作為一個(gè)構(gòu)造函數(shù),子類(B)的原型(prototype屬性)是父類的實(shí)例。
2)Object.getPrototypeOfObject.getPrototypeOf方法可以用來從子類上獲取父類。
Object.getPrototypeOf(ColorPoint) === Point // true
因此,可以使用這個(gè)方法判斷,一個(gè)類是否繼承了另一個(gè)類。
3)實(shí)例的__proto__屬性子類實(shí)例的__proto__屬性的__proto__屬性,指向父類實(shí)例的__proto__屬性。也就是說,子類實(shí)例的原型的原型,是父類實(shí)例的原型。
var p1 = new Point(2, 3); var p2 = new ColorPoint(2, 3, "red"); p2.__proto__ === p1.__proto__ // false p2.__proto__.__proto__ === p1.__proto__ // true
總的來說,ES6是對(duì)ES5的形式上的改變,真實(shí)內(nèi)容依舊不變,本質(zhì)上依舊是通過原型鏈實(shí)現(xiàn)繼承。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/50505.html
摘要:使用類創(chuàng)建實(shí)例對(duì)象也是直接對(duì)類使用命令,跟中構(gòu)造函數(shù)的用法一致。中沒有構(gòu)造函數(shù),作為構(gòu)造函數(shù)的語法糖,同時(shí)有屬性和屬性,因此同時(shí)存在兩條繼承鏈。子類的屬性,表示構(gòu)造函數(shù)的繼承,總是指向父類。 1 Class in ES6 ES6提出了類(Class)的概念,讓對(duì)象的原型的寫法更像面向?qū)ο笳Z言寫法。 ES6中通過class定義對(duì)象,默認(rèn)具有constructor方法和自定義方法,但是包含...
摘要:類的方法相當(dāng)于之前我們定義在構(gòu)造函數(shù)的原型上。的構(gòu)造函數(shù)中調(diào)用其目的就是調(diào)用父類的構(gòu)造函數(shù)。是先創(chuàng)建子類的實(shí)例,然后在子類實(shí)例的基礎(chǔ)上創(chuàng)建父類的屬性。 前言 首先歡迎大家關(guān)注我的Github博客,也算是對(duì)我的一點(diǎn)鼓勵(lì),畢竟寫東西沒法獲得變現(xiàn),能堅(jiān)持下去也是靠的是自己的熱情和大家的鼓勵(lì)。 許久已經(jīng)沒有寫東西了,因?yàn)殡s七雜八的原因最近一直沒有抽出時(shí)間來把寫作堅(jiān)持下來,感覺和跑步一...
摘要:的類使用熟悉的關(guān)鍵字指定類繼承的函數(shù),并且可以通過方法訪問父類的構(gòu)造函數(shù)。例如繼承一個(gè)的類繼承了,術(shù)語上稱為基類,為派生類。例如注意到上例中,不僅是派生類的實(shí)例,也是派生類的實(shí)例,內(nèi)建對(duì)象繼承的實(shí)用之處是改變返回對(duì)象的類型。 和其它面向?qū)ο缶幊陶Z言一樣,ES6 正式定義了 class 類以及 extend 繼承語法糖,并且支持靜態(tài)、派生、抽象、迭代、單例等,而且根據(jù) ES6 的新特性衍...
摘要:前言見解有限,如有描述不當(dāng)之處,請(qǐng)幫忙及時(shí)指出,如有錯(cuò)誤,會(huì)及時(shí)修正。倘若用的是中文搜索。所以最終的實(shí)例對(duì)象仍然能進(jìn)行正常的原型鏈回溯,回溯到原本的所有原型方法這樣通過一個(gè)巧妙的欺騙技巧,就實(shí)現(xiàn)了完美的繼承。 前言 見解有限,如有描述不當(dāng)之處,請(qǐng)幫忙及時(shí)指出,如有錯(cuò)誤,會(huì)及時(shí)修正。 20180201更新: 修改用詞描述,如組合寄生式改成寄生組合式,修改多處筆誤(感謝@Yao Ding的...
摘要:寄生組合式繼承的繼承方式有多種主要有原型鏈繼承借用構(gòu)造函數(shù)組合式繼承寄生式繼承和寄生組合式繼承。中利用定義類,實(shí)現(xiàn)類的繼承子類里調(diào)用父類構(gòu)造函數(shù)實(shí)現(xiàn)實(shí)例屬性和方法的繼承子類原型繼承父類原型,實(shí)現(xiàn)原型對(duì)象上方法的繼承。 JavaScript中實(shí)現(xiàn)繼承 ??在JavaScript中實(shí)現(xiàn)繼承主要實(shí)現(xiàn)以下兩方面的屬性和方法的繼承,這兩方面相互互補(bǔ),既有共享的屬性和方法,又有特有的屬性和方法。 ...
閱讀 3949·2021-11-22 13:53
閱讀 1676·2021-08-25 09:39
閱讀 2410·2019-08-29 18:36
閱讀 1469·2019-08-26 13:35
閱讀 1215·2019-08-26 11:57
閱讀 1678·2019-08-23 15:57
閱讀 803·2019-08-23 14:55
閱讀 1163·2019-08-23 14:51