為何使用prototype而不使用function?
在JS的世界中,並沒有真實的Class類別,JS所提供的類別不過是使用原型所實作出的語法糖。
在JS ES5中:
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.toString = function () {
return '(' + this.x + ', ' + this.y + ')';
};
var p = new Point(1, 2);
使用JS ES6提供的Class語法糖:
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
因此,在使用Class之前,我們都應該先暸解Prototype的基本用法。
這邊用一個更簡單的例子比較為什麼要使用原型而不是function。
假設我們今天要用JS去實作一個程式,它有著“誰說了什麼”的簡單功能,當我們使用function時會長成這樣:
const say = (name, msg) => {
console.log(`${name}:${msg}`)
}
say('ian','hi!') // ian:hi!
say('coco','hello!') // coco:hello!
使用function看似精簡,但當今天有很多話要說時就會變成:
say('ian','hi!') // ian:hi!
say('coco','hello!') // coco:hello!
say('ian','hi!') // ian:hi!
say('coco','hello!') // coco:hello!
say('ian','hi!') // ian:hi!
say('coco','hello!') // coco:hello!
say('ian','hi!') // ian:hi!
say('coco','hello!') // coco:hello!
在這邊不難發現,這段對談其實只有ian和coco在對話,但我們卻在執行函式時都多用了一個變數去存放人名。
在這邊即使我們沒有原型的概念,也同樣可以利用物件解決問題!
const ian = {
name:'ian',
say(text){
console.log(`${this.name}:${text}`)
}
}const coco = {
name:'coco',
say(text){
console.log(`${this.name}:${text}`)
}
}ian.say('hi!') // ian:hi!
coco.say('hello!') // coco:hello!
這樣一來,我們就能夠在每次呼叫函式時少傳一個變數。
但我們再仔細比較一下這兩個物件就會發現:這兩個物件的變數以及方法根本一模模一樣樣啊!!!
這時候如果我們知道怎麼使用new建構物件,就能輕鬆解決這個問題:
function People(name){
this.name = name
this.say = function(text){
console.log(`${this.name}:${text}`)
}
}//使用new建構物件實體const ian = new People('ian');
const coco= new People('coco');ian.say('hi!') // ian:hi!
coco.say('hello!') // coco:hello!
做到這邊,大家可能會想說:不對啊,主題不是原型嗎?說好的原型勒???
別急,上面的範例雖然有效解決了前面的所有問題,但是當我們這樣做時:
ian.say = null;
coco.say('hello!') // coco:hello!
我們會發現如果把ian物件的say()給清除時,coco物件的say()卻還是能夠執行,這是因為當我們使用new去創造實體物件時,JS會分別做出一個say()放到各自的物件當中,換言之,這兩個say()並不是存放在同一個記憶體位置。
那如果我希望兩個物件的say()是指向同樣的記憶體位置呢???
別急別急,Prototype不就來了嗎?
function People(name){
this.name = name
}People.__proto__.say = function(text){
console.log(`${this.name}:${text}`)
}const ian = new People('ian');
const coco= new People('coco');ian.__proto__.say = null;
coco.say() // 不能用了!
這邊補充一下,範例中的People.__proto__.say便是指定原型的方式。
也因為say()是使用原型指定的,所以當ian物件中的say函式被清掉,coco物件的say()就也不能使用了!
今天的筆記就到這邊結束,希望各位讀者看到這篇文章有解決跟我一樣的問題!
最後的最後,特別感謝神Q超人的耐心講解,雖然他好像看不到就是了XD