[JS筆記] 建構式函式 Constructor Function

Kim.H
7 min readApr 29, 2023

--

What is Constructor Function?

當我們需要製作大量類似屬性(Attributes)及方法(Methods)的物件(Objects)時,如果用下方程式碼的方式來製作,會使程式碼變得很冗長,如果要修改屬性或方法的名稱,也會導致難以維護。

//如果想把rank的屬性名稱改成ranking,就得找出所有物件並一一修改rank這個屬性名稱
const TTY = {
name : 'Tai Tzu-Ying',
age: 28,
rank: 4,
country:'TPE'
}

const ASY = {
name : 'An Se-young',
age: 21,
rank: 2,
country:'KOR'
}

const Akane = {
name : 'Akane Yamaguchi',
age: 25,
rank: 1,
country:'JPN'
}

這個時候我們就可以使用建構式函式Constructor Function來創建,只要在呼叫函式時加上 new 關鍵字,就會被判斷成是建構是函式,首先我們需要定義Constructor Function:

//name = str, age = int, rank = int, country = str
function BadmintonPlayer(name, age, rank, country){
this.name = name
this.age = age
this.rank = rank
this.country = country
this.greeting = function(){
console.log(`Hi! My name is ${this.name}, I'm ${this.age} years old, from ${this.country}. Current rank is ${this.rank}.`)
}
}
const TTY = new BadmintonPlayer('Tai Tzu-Ying', 28, 4, 'TPE')
const ASY = new BadmintonPlayer('An Se-young', 21, 2, 'KOR')
const Akane = new BadmintonPlayer('Akane Yamaguchi', 25, 1, 'JPN')

改成上面的寫法,就可以快速製造出三個新的BadmintonPlayer物件啦!

constructor的命名習慣通常第一個字母為大寫,方便一眼就能辨識出這個函式的性質。由於 constructor 裡定義的物件範本是抽象的Badminton Player,而物件實例是具體的球員,為了區分,由建構式 (constructor) 建立的物件會被稱為「實例 (instance)」。

關鍵字 New 做了什麼事呢?

上面有提到,只要在function前加上 new,這個函式就會被判斷為constructor,此時會依序發生下列事件:

  1. 一個空物件 {} 被創立,且占據RAM的空間
  2. 執行 BadmintonPlayer 函式 (函式中的屬性依序被創造、賦值)
  3. BadmintonPlayer 裡的this指向第一點新創立的空物件,並依序將屬性和方法放入空物件中

要特別注意的是,定義constructor時,函式內不能放return,如果加入了return,函式就只會回傳return的內容而非一個新的物件。如果忘了加上 new 關鍵字,就只是純粹的呼叫BadmintonPlayer這個函式,因為本身內容並無指定return任何東西,所以回傳的值會是 undefined

一般函式中的this 與 construction中的this

當函式被呼叫時,一個新的函式執行環境Fucntion Excution Context(FEC)會被創造出來,代表JS已正在解析並執行程式碼,這時候就會創建 this 這個變數。當這個function只是一般函式而非method,則這個 this 會指向global object (在瀏覽器執行時是指window,node.js時是指global)。

Example :

function test(){
console.log(this)
}

test()

執行結果如下:

node.js的global object為 global

我們用下面的例子來實驗看看,如果這個函式是某個物件的方法,那此時的this會指的是什麼呢?

const TTY = {
name: "Tai Tzu-Ying",
age: 28,
rank: 4,
country: "TPE",
greeting : function(){
console.log(`Hi! My name is ${this.name}, I'm ${this.age} years old, from ${this.country}. Current rank is ${this.rank}.`)
console.log(this)
}
};

TTY.greeting()

執行結果如下:

TTY.greeting()中的this指的是TTY這個物件本身

從上圖例子來看,可以得知 TTY.greeting() 的this會指向TTY物件本身。

而constructor的this則會在呼叫new constructor當下,指向新創立的空物件 {},我們可以加入console.log來確認 this 到底發生了什麼變化:

function BadmintonPlayer(name, age, rank, country){
console.log(this)
this.name = name
console.log(this)
this.age = age
console.log(this)
this.rank = rank
console.log(this)
this.country = country
console.log(this)
this.greeting = function(){
console.log(`Hi! My name is ${this.name}, I'm ${this.age} years old, from ${this.country}. Current rank is ${this.rank}.`)
}
console.log(this)
}

const TTY = new BadmintonPlayer('Tai Tzu-Ying', 28, 4, 'TPE')
當constructor被執行時,this會被指向一個空的物件

從上圖的例子來看,執行new BadmintonPlayer()這個constructor時,會先創立一個空的物件,並使this指向這個空物件,接著依序執行this.name = name, this.age = age , this.rank = rank,將函式中的參數依序賦值並加入到一開始創立的空物件之中,此時this.name代表:這個空物件的屬性名稱為name,name的value為代入的參數 : ’Tai Tzu-Ying’。

透過console.log的方式來查看this的不同,是不是更好理解這些概念了呢?

最後來為constructor做個總結

  1. 定義constructor時,會創建一個空物件 {} ,此時函式中的 this 會指向此物件
  2. 使用this.[名稱] = value 的形式來設定屬性或方法
  3. 命名習慣第一個字母為大寫
  4. 創建新的物件時,呼叫constructor前面要加上關鍵字 new
  5. constructor中不能使用return,否則只會回傳return指定的值,而非一個新的物件

以上是我理解建構式函式的筆記,如有理解錯誤的地方還請各為先進不吝指教,有任何建議也歡迎一起討論,謝謝閱讀!

--

--

Kim.H

現任菜鳥後端工程師 / 2022.12 正式踏入轉職之旅 - 2023.09轉職成功