類別(class)是什麼?|JavaScript 初學者筆記(4)
更新日期: 2024 年 4 月 1 日
身為一位 Javascript 菜雞,小弟在學習「類別」(class)時總是感覺異常疑惑。
後來才發現若想要對「類別」有更深入的理解,一定要先理解「原型」(prototype)的相關概念,才能更容易知道運作邏輯。
因為類別的本質,就是基於原型衍伸出來的語法糖。
本文,就是要針對「類別」此概念,向如同自己一樣的程式新手,盡可能白話地解釋相關意涵。
閱讀要求
建議閱讀本文前,務必先閱讀以下 3 篇「物件」的基本概念,才會更清楚理解內文。
什麼是類別(Class)?
如果我們能理解上一篇文章中,物件「原型」(prototype)、「原型繼承」(prototype-inheritance)等相關概念,對於「類別」(Class)就能更簡單的認識。
原因在於,「類別」就是基於「原型繼承」相關模型衍生出來的「語法糖」(Syntactic sugar)
它最初是在 JavaScript 2015 年版本(ES6)出現的語法,主要在於提供使用者以更簡潔的方式,使用物件原型的相關代碼。
以下,我們分別針對「類別建構子」與「類別方法」這兩點進行討論。
類別建構子(Class Constructors)
在 Class 語法之前,若我們想要建立一個物件,可以使用建構子函式此方法。
例如若我們想要建立使用者物件,可以先建立一個建構子:
function User(name, age, id) {
this.name = name;
this.age = age;
this.id = id;
}
再搭配使用 new 關鍵字,建立一個物件實體。
function User(name, age, id) {
this.name = name;
this.age = age;
this.id = id;
}
const user01 = new User("徐培鈞", 25, 9527);
如果你看不懂這上述代碼,建立你先理解一下建構子的概念,補充背景知識。
在 ES6 版本中,我們可以將上述代碼轉換成另一種形式。
class User {
constructor(name, age, id){
this.name = name;
this.age = age;
this.id = id;
}
}
const user01 = new User("徐培鈞", 25, 9527);
我們可以發現,原先的 function 關鍵字被 constructor 取代,在外圍又包裹了一層 class 語法。
你可能想說:「哪有變更簡潔,原先只有一層 function 代碼,現在外面又多包了一層 class 代碼?」
你想懂!?本文下面有些好康的,請繼續閱讀下去。
類別方法(Class Methods)
我們除了能在建構子中建立屬性(property)成員,也能新增一些方法(method)成員。
例如新增一個 showId 函式:
function User(name, age, id) {
this.name = name;
this.age = age;
this.id = id;
showId = function (){
console.log(`${this.name},${this.id} 是你的終身代號,記住了嗎!?`);
}
}
貼心叮嚀:在建構子中函式的寫法,有兩種不同形式,不要忘記嘍
// 寫法一
function User(name, age, id) {
showId = function (){
console.log(`${this.name},${this.id} 是你的終身代號,記住了嗎!?`);
}
}
// 寫法二
function User(name, age, id) {
showId(){
console.log(`${this.name},${this.id} 是你的終身代號,記住了嗎!?`);
}
}
當然,我們前一篇文章也說過,由於我們希望自己建立出來的實體,有更簡潔的代碼呈現方式,因此通常會將方法成員丟進原型(prototype)中,只保留屬性成員而已。
原先代碼會轉變成以下:
// 區塊一
function User(name, age, id) {
this.name = name;
this.age = age;
this.id = id;
}
// 區塊二
User.prototype.showId = function(){
console.log(`${this.name},${this.id} 是你的終身代號,記住了嗎!?`);
}
這時你會發現,代碼因為需要使用到原型的屬性,因此被拆解成兩個區塊。
這時,新版的 class 關鍵字就能起到整合的作用,將原先分開的兩個部分重新包再一起,方便使用者閱讀。
class User {
constructor(name, age, id){
this.name = name;
this.age = age;
this.id = id;
}
showId(){
console.log(`${this.name},${this.id} 是你的終身代號,記住了嗎!?`);
}
}
const user01 = new User("徐培鈞", 25, 9527);
我們可以發現 class 關鍵字不只是針對建構子優化,同時還在原型方法的使用納入其中。
這一切的調整,其實就是為了後續的閱讀與使用而已。
什麼是方法鍊(Method Chaining)
對於一位 JS 新手來說,通常學習到函式的使用都是一次呼叫執行一項函式。
function xxx(){
//..........
}
function ooo(){
//..........
}
xxx();
ooo();
這種為單一函式各自呼叫一次的做法,雖然操作起來簡單理解,但是當函式數量變多時,就會使代碼變的混亂、難以理解。
你可試想如果上述的例子函式,從 2 個暴增到 20 個以後,又會是一個怎樣的光景!?
「方法鏈」(Method Chaining)這個技術,就是為了解決以上問題而出現的機制。
它將原本散落在各處呼叫函數的代碼,簡化並壓縮到只剩一行代碼。
// 普通方式
物件.xxx();
物件.ooo();
物件.zzz();
//函式鏈
物件.xxx().oooo().zzz();
具體來說,它是透過 this 關鍵字會指向原本物件實體本身的特性,再搭配 return 關鍵字回傳,讓每一次執行完物件方法後,都會不斷回傳該物件實體本身。
如此,就能以一行代碼執行多次物件方法。
套用到實際例子,如果我們將 User 建構子再新增一個方法,取名為 answer
class User {
constructor(name, age, id){
this.name = name;
this.age = age;
this.id = id;
}
showId(){
console.log(`${this.name},${this.id} 是你的終身代號,記住了嗎!?`);
}
answer(){
console.log(`回答:代號 ${this.id} 記住了。`);
} //新增此段代碼
}
const user01 = new User("徐培鈞", 25, 9527);
如果我希望能夠一次就呼叫使用 showId 與 answer 兩個方法,可以再各自的函式中增加 return this 此關鍵字
class User {
constructor(name, age, id){
this.name = name;
this.age = age;
this.id = id;
}
showId(){
console.log(`${this.name},${this.id} 是你的終身代號,記住了嗎!?`);
return this; //新增此段代碼
}
answer(){
console.log(`回答:代號 ${this.id} 記住了。`);
return this; //新增此段代碼
}
}
const user01 = new User("徐培鈞", 25, 9527);
如此一來,就能順利藉由以下代碼,一次呼叫多個方法。
user01.showId().answer();
類別繼承(Class Inheritance)
「類別繼承」(Class Inheritance)是指一個類別「繼承」另一個類別的方法與屬性。
在 ES6 版本前,我們是透過「原型繼承」此方法完成,使用 Apply 方法繼承屬性、使用 Object.create 繼承原型方法。
不知道我在供蝦咪的人,可以點擊連結查看說明。
在 ES6 版本以後,若我們可以藉由 class 搭配 extend 關鍵字,完成相同的目標。
class User {
constructor(name, age, id){
this.name = name;
this.age = age;
this.id = id;
}
showId(){
console.log(`${this.name},${this.id} 是你的終身代號,記住了嗎!?`);
return this; //新增此段代碼
}
answer(){
console.log(`回答:代號 ${this.id} 記住了。`);
return this; //新增此段代碼
}
}
const user01 = new User("徐培鈞", 25, 9527);
我們將上方代碼,藉由圖像描繪出 user01 實體與 User 建構子之間的關鍵。
假如我們想要創立另一個 Admin 建構子,它會繼承 User 建構子所有的方法與屬性,並擁有權限使用他們。
我們就必須使用以下代碼:
class Admin extends User {
}
const Admin01 = new Admin("店長", 33, 8787);
這樣,我們就完成 Admin 的繼承動作了。
如果我們想要針對 Admin 新增一個它獨有的方法:meet,只需要在接續寫在尖括號「{}」中即可。
class Admin extends User {
meet() {
console.log(`${this.name} 請支援收銀!`);
}
}
const Admin01 = new Admin("店長", 33, 8787);
我們將代碼轉換成圖下,就能理解彼此之間的關係。
以上就是針對類別、類別繼承的說明,我們下篇文章見!
系列文章統整
- 物件導向是什麼?|JavaScript 四大物件特性簡介|初學者筆記(1)
- 如何建立物件?|JavaScript 初學者筆記(2)
- 什麼是原型(Prototype)?|JavaScript 初學者筆記(3)
- 類別(class)是什麼?|JavaScript 初學者筆記(4)