JS 核心 – 使用建構式自定義原型
如何定義自己的原型
使用建構式的方式產生物件,並且會繼承同一個原型。
用建構函式,搭配 new 關鍵字的使用,以一個固定的藍圖建立許多結構相同的物件
先用一個函式(建構式)來做為他們的藍圖
- 藍圖無法變成實體 (instance)
- 若要將藍圖變成實體要透過 new 這個運算子
- 這兩隻狗是共用一個藍圖產生的 : (指 Dog 建構函式)
兩隻狗有各自的屬性,有一個共用的方法 bark (吠叫),在吼叫時會帶上自己的名字
new 運算子
- 建立一個新的物件,並且連結回原本的建構物件 (指 Dog 函式)
- 將物件的 _ proto _ 指向建構子的 prototype,形成原型串鏈
- 會把新產生物件的 this 綁定在函式之上 (在建構函式內使用的 this 就會綁定在新物件上)
- 將建構子的 this 指向 new 出來的新物件
- 回傳這個物件
Dog 就是一個構造函數,可以用 new 這個關鍵字 new 出一個 instance 來。
- 透過 「new 運算子」搭配「Dog 建構函式」來產生新的物件「狗的實體」,新的物件和原本物件沒有關聯性
function Dog(name, color, size) {
this.name = name;
this.color = color;
this.size = size;
}
var Bibi = new Dog('比比', '棕色', '小');
console.log(Bibi);
var Pupu = new Dog('噗噗', '白', '大');
console.dir(Dog);
(第 10 行) Bibi 就是透過「Dog 建構函式」產生的,Dog 就是 Bibi 的原型 (狗的藍圖)
(第 12 行) 目前在此原型上並沒有看到狗的原型方法 (如下右圖)
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
透過 prototype 的方式來新增原型方法
只要把 bark 這個 function 指定在 Dog.prototype 上面,所有 Dog 的 instance 都可以共享這個方法。
(承上程式碼) 為狗新增吼叫的能力
- 建構式(constructor)函式本身就是一個物件,建構式函式物件裡有一個特有屬性 prototype
- 透過 prototype 所新增的屬性就會作為原型的方法
- Bibi 物件的 prototype 是 Dog.prototype;換句話說,Bibi 繼承自 Dog.prototype
Dog.prototype.bark = function (){
console.log(this.name + ' 吠叫');
}
console.log(Bibi, Pupu);
Bibi.bark();
Pupu.bark();
console.log(Dog.prototype === Bibi.__proto__)
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
再複習一下 JavaScript 的基礎 :
你有一個叫做 Dog 的函數,就可以把 Dog 當作建構函式 (constructor),使用 new 來建立出一個 Dog 的實體 (instance),並且可以在 Dog.prototype 上面加上你想讓所有實體 (instance) 共享的屬性或是方法。
Prototype 原型
- 共用的屬性或方法,不用每次都幫實體建立一份,提出來放到 prototype 即可。
- 將 bark 這個共用的方法放到 Dog.prototype,暫且稱它為 Dog 的原型。
- JavaScript 的物件能夠「繼承」其 prototype 的屬性或方法。
總結
- 先建立建構函式 (普通的 function) → 透過這個 function 來建立物件
- 透過 new 運算子產生新的物件實體 (instance)
- 新產生的物件會把狗函式做為原型使用,也會把 this 套用在建構函式上
- 建構函式 (狗原型) 是共用的,有共用的屬性和方法
- 當新物件使用的方法很多時,會消耗很多記憶體
- 原型優勢 : 透過原型的方式,只要一個記憶體就可以產生大量的物件
重點
- prototype 是建構函式(constructor) 特有的原型屬性
- _ proto _ 物件上連結原型的屬性,並非正式的屬性
- 若要從原型新增方法,最好從建構函式裡的 prototype 原型作調整; 若從任意新增物件調整原型的話,維護上有很大的問題 (主要原因是會讓原型難以被追朔)
注意 : 請勿修改原生原型
以下範例來說:
由 Dog 所產生的 Bibi,卻可以改到 Dog 的原型,往後如果發現錯誤,卻無法從 "Dog" 這個建構函式找到。如果在大型專案或是有拆分多個檔案時,這個問題將更難以被發現。
function Dog(name, color, size) {
this.name = name;
this.color = color;
this.size = size;
}
Dog.prototype.bark = function () {
console.log(this.name + '吼叫');
};
// 用建構函式的產生的片段,並透過 __proto__ 覆蓋了原型的內容
var Bibi = new Dog('比比', '棕色', '小');
Bibi.__proto__.bark = function() {
console.log(this.name + '亂叫')
}
// 受影響的物件,無法使用 Dog 追朔到源頭
var Puppy = new Dog('帕比', '棕色', '小');
Puppy.bark(); // 帕比 亂叫
注意 : 不推薦直接去修改不屬於你的 Object
有些人會直接在 Array.prototype 上面加一些函式,讓自己可以更方便地做一些操作,原理也是這樣。可是一般來說,不推薦直接去修改不屬於你的 Object。
Array.prototype.last = function () {
return this[this.length - 1];
};
console.log([1,2,3].last()) // 3
補充
- console.dir() 可以顯示一個對象的所有屬性和方法(詳細打印,利於分析對象)
- console.log() 會在瀏覽器控制臺打印信息
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
學習回顧
- 使用建構式的方式產生物件,並且會繼承同一個原型。
- 建構式(constructor)函式本身就是一個物件,他有一個特有屬性 prototype
- 透過 prototype 所新增的屬性就會作為原型的方法
new 運算子
- 建立一個新的物件,並且連結回原本的建構物件 (指 DOG 函式)
- 將物件的 _ proto _ 指向建構子的 prototype,形成原型串鏈
- 在建構函式內使用的 this 就會綁定在新物件上
- 將建構子的 this 指向 new 出來的新物件
- 回傳這個物件
- 透過 「new 運算子」搭配「Dog 建構函式」來產生新的物件「狗的實體」,新的物件和原本物件沒有關聯性
重點
- 若要從原型新增方法,最好從建構函式裡的 prototype 原型作調整; 若從任意新增物件調整原型的話,維護上有很大的問題 (主要原因是會讓原型難以被追朔)
- 建構函式(函式實體) - prototype - function 原型 - object 原型
- 物件實體 - _ proto _ (等同 prototype)- object 原型
Image Not Showing
Possible Reasons
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
Learn More →
相關參考文件