ES6:類

引用:http://www.tuicool.com/articles/BFf6jiB

從本質上說,ES6的classes主要是給創(chuàng)建老式構造函數(shù)提供了一種更加方便的語法,并不是什么新魔法 —— Axel Rauschmayer,Exploring ES6作者
從功能上來講,class聲明就是一個語法糖,它只是比我們之前一直使用的基于原型的行為委托功能更強大一點。本文將從新語法與原型的關系入手,仔細研究ES2015的class關鍵字。文中將提及以下內容:

  • 定義與實例化類;
  • 使用extends創(chuàng)建子類;
  • 子類中super語句的調用;
  • 以及重要的標記方法(symbol method)的例子。

在此過程中,我們將特別注意 class 聲明語法從本質上是如何映射到基于原型代碼的。

退一步說:Classes不是什么

JavaScript的『類』與Java、Python或者其他你可能用過的面向對象語言中的類不同。其實后者可能稱作面向『類』的語言更為準確一些。
在傳統(tǒng)的面向類的語言中,我們創(chuàng)建的類是對象的模板。需要一個新對象時,我們實例化這個類,這一步操作告訴語言引擎將這個類的方法和屬性復制到一個新實體上,這個實體稱作實例。實例是我們自己的對象,且在實例化之后與父類毫無內在聯(lián)系。
而JavaScript沒有這樣的復制機制。在JavaScript中『實例化』一個類創(chuàng)建了一個新對象,但這個新對象卻不獨立于它的父類。
正相反,它創(chuàng)建了一個與原型相連接的對象。即使是在實例化之后,對于原型的修改也會傳遞到實例化的新對象去。
原型本身就是一個無比強大的設計模式。有許多使用了原型的技術模仿了傳統(tǒng)類的機制,class便為這些技術提供了簡潔的語法。
總而言之:

  • JavaScript不存在Java和其他面向對象語言中的類概念;
  • JavaScript 的class很大程度上只是原型繼承的語法糖,與傳統(tǒng)的類繼承有很大的不同。

類基礎:聲明與表達式

我們使用class 關鍵字創(chuàng)建類,關鍵字之后是變量標識符,最后是一個稱作類主體的代碼塊。這種寫法稱作類的聲明。沒有使用extends關鍵字的類聲明被稱作基類:

"use strict";

// Food 是一個基類
class Food {

    constructor (name, protein, carbs, fat) {
        this.name = name;
        this.protein = protein;
        this.carbs = carbs;
        this.fat = fat;
    }

    toString () {
        return `${this.name} | ${this.protein}g P :: ${this.carbs}g C :: ${this.fat}g F`
    }

    print () {
        console.log( this.toString() );
    }
}

const chicken_breast = new Food('Chicken Breast', 26, 0, 3.5);

chicken_breast.print(); // 'Chicken Breast | 26g P :: 0g C :: 3.5g F'
console.log(chicken_breast.protein); // 26 (LINE A)

需要注意到以下事情:

  • 類只能包含方法定義,不能有數(shù)據(jù)屬性;
  • 定義方法時,可以使用簡寫方法定義;
  • 與創(chuàng)建對象不同,我們不能在類主體中使用逗號分隔方法定義;
  • 我們可以在實例化對象上直接引用類的屬性(如 LINE A)。

類有一個獨有的特性,就是 contructor 構造方法。在構造方法中我們可以初始化對象的屬性。
構造方法的定義并不是必須的。如果不寫構造方法,引擎會為我們插入一個空的構造方法

"use strict";

class NoConstructor {
    /* JavaScript 會插入這樣的代碼:
     constructor () { }
    */
}

const nemo = new NoConstructor(); // 能工作,但沒啥意思

將一個類賦值給一個變量的形式叫類表達式,這種寫法可以替代上面的語法形式:

"use strict";

// 這是一個匿名類表達式,在類主體中我們不能通過名稱引用它
const Food = class {
    // 和上面一樣的類定義……
}

// 這是一個命名類表達式,在類主體中我們可以通過名稱引用它
const Food = class FoodClass {
    // 和上面一樣的類定義……

    //  添加一個新方法,證明我們可以通過內部名稱引用 FoodClass……        
    printMacronutrients () {
        console.log(`${FoodClass.name} | ${FoodClass.protein} g P :: ${FoodClass.carbs} g C :: ${FoodClass.fat} g F`)
    }
}

const chicken_breast = new Food('Chicken Breast', 26, 0, 3.5);
chicken_breast.printMacronutrients(); // 'Chicken Breast | 26g P :: 0g C :: 3.5g F'

// 但是不能在外部引用
try {
    console.log(FoodClass.protein); // 引用錯誤
} catch (err) {
    // pass
}

這一行為與匿名函數(shù)與命名函數(shù)表達式很類似。

使用extends創(chuàng)建子類以及使用super調用

使用extends創(chuàng)建的類被稱作子類,或派生類。這一用法簡單明了,我們直接在上面的例子中構建:

"use strict";

// FatFreeFood 是一個派生類
class FatFreeFood extends Food {

    constructor (name, protein, carbs) {
        super(name, protein, carbs, 0);
    }

    print () {
        super.print();
        console.log(`Would you look at that -- ${this.name} has no fat!`);
    }

}

const fat_free_yogurt = new FatFreeFood('Greek Yogurt', 16, 12);
fat_free_yogurt.print(); // 'Greek Yogurt | 26g P :: 16g C :: 0g F  /  Would you look at that -- Greek Yogurt has no fat!'

派生類擁有我們上文討論的一切有關基類的特性,另外還有如下幾點新特點:

  • 子類使用class關鍵字聲明,之后緊跟一個標識符,然后使用extend關鍵字,最后寫一個任意表達式。這個表達式通常來講就是個標識符,但理論上也可以是函數(shù)。
  • 如果你的派生類需要引用它的父類,可以使用super關鍵字。
  • 一個派生類不能有一個空的構造函數(shù)。即使這個構造函數(shù)就是調用了一下super(),你也得把它顯式的寫出來。但派生類卻可以沒有構造函數(shù)。
  • 在派生類的構造函數(shù)中,必須先調用super,才能使用this關鍵字(譯者注:僅在構造函數(shù)中是這樣,在其他方法中可以直接使用this)。
    在JavaScript中僅有兩個super關鍵字的使用場景:
  • 在子類構造函數(shù)中調用。如果初始化派生類是需要使用父類的構造函數(shù),我們可以在子類的構造函數(shù)中調用super(parentConstructorParams),傳遞任意需要的參數(shù)。
  • 引用父類的方法。在常規(guī)方法定義中,派生類可以使用點運算符來引用父類的方法:super.methodName。
    我們的 FatFreeFood 演示了這兩種情況:
  • 在構造函數(shù)中,我們簡單的調用了super,并將脂肪的量傳入為0。
  • 在我們的print方法中,我們先調用了super.print,之后才添加了其他的邏輯。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,837評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,196評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,688評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,654評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,456評論 6 406
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,955評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,044評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,195評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,725評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,608評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,802評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,318評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,048評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,422評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,673評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,424評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,762評論 2 372

推薦閱讀更多精彩內容

  • 面向對象的語言都有一個類的概念,通過類可以創(chuàng)建多個具有相同方法和屬性的對象,ES6之前并沒有類的概念,在ES6中引...
    Erric_Zhang閱讀 1,120評論 1 4
  • class的基本用法 概述 JavaScript語言的傳統(tǒng)方法是通過構造函數(shù),定義并生成新對象。下面是一個例子: ...
    呼呼哥閱讀 4,115評論 3 11
  • 假如我們想要創(chuàng)建一個經(jīng)典的面向對象設計示例:Circle類。想象一下我們正在為一個簡單的Canvas庫編寫這個Ci...
    糖心m閱讀 396評論 0 2
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,709評論 18 399
  • 獲取信息 落榜的,在讀的,瀘職院,品牌營銷知曉度。 途徑:QQ,熟人,招人。運營好QQ,裂變,增強粘性。網(wǎng)絡搜索 ...
    問學行者閱讀 160評論 0 0