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,此時會依序發生下列事件:
- 一個空物件
{}
被創立,且占據RAM的空間 - 執行
BadmintonPlayer
函式 (函式中的屬性依序被創造、賦值) 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()
執行結果如下:
我們用下面的例子來實驗看看,如果這個函式是某個物件的方法,那此時的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物件本身。
而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')
從上圖的例子來看,執行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做個總結
- 定義constructor時,會創建一個空物件
{}
,此時函式中的this
會指向此物件 - 使用this.[名稱] = value 的形式來設定屬性或方法
- 命名習慣第一個字母為大寫
- 創建新的物件時,呼叫constructor前面要加上關鍵字
new
- constructor中不能使用return,否則只會回傳return指定的值,而非一個新的物件
以上是我理解建構式函式的筆記,如有理解錯誤的地方還請各為先進不吝指教,有任何建議也歡迎一起討論,謝謝閱讀!