iT邦幫忙

2022 iThome 鐵人賽

DAY 2
0

前言

我相信每個語法的發明都有它意義存在,以我看來Prototype的存在,是為了要讓JavaScript 也能實現物件導向,準確點來說,可以用來做到物件的繼承,透過Prototype的方式。

Prototype的產生是為了JavaScript的繼承

而所謂物件的繼承,就是可以從其他地方拿到本身沒有的方法或是屬性,藉由去繼承有方法跟屬性的物件,來獲得使用那些方法跟屬性的權利。

JavaScript中,每個object都會去連結到Prototype object => 每個object都可以看得到裡面有Prototype(null是例外~)。

這個Prototype[[prototype]]也是原型物件。

舉例來說,創造一個空物件,會看見[[Prototype]]:

但是用Object.create使用null當原型的這個新物件是會看到no properties,很乾淨的那種。

Prototype object 包含了 properties(屬性) 跟 methods(方法)

簡單解釋一下什麼是propertiesmethods
首先要先知道物件會有key-value pairs,接著看下方程式碼:

const fruit = {
  name: "apple",  // name => properties
  weight: "300g", // weight => properties

  callSell: function () {
    console.log("好吃的蘋果,快來給我買");
  }, 
}; // callSell => methods

value 是一般值 => properties
value 是一個函式 => methods

意思是連結到這個Prototype的所有 object,都可以去使用這個Prototype objectproperties以及methods,這就是Prototype的奇妙之處,我沒有但我可以還是用。

再說一次,這種我沒有,但是我還是可以用的行為,其實是一種繼承的概念,因為是用原型來達成的,所以會把它稱為原型繼承。

如何設定Prototype

為什麼要設定,要如何設定,讓我用一個例子來舉例:

Prototype世界的小白家有餅乾,小紅家有花朵,他們住在不同的地方,要去拿到小白的餅乾,就沒辦法拿到小紅的花朵,反之也是一樣。

想要從小白那邊獲得餅乾,又能拿到花朵,這時候需要電話,比如説小白吃著餅乾,又想要手上拿著花朵,但這時候小白家沒有花朵,但是可以打電話給小紅,叫她把花給速速送過來。

這個電話號碼其實就是Object.setPrototypeOf

這個語法會需要兩個參數,如下用A跟B來表示:

Object.setPrototypeOf(A, B)

第一個參數A代表的是要設定原型的物件,第二個參數B代表的是參數A的新原型物件。

所以在這邊可以藉由小白獲得了小紅的電話號碼,獲得可以拿到小紅花朵這個概念,拿來比擬小白透過 Object.setPrototypeOf() 將「小紅指定為原型」。

用這個例子的範例來說,程式會長這樣:

// 小白擁有很多餅乾
const white = { cookies: true };
// 小紅擁有很多花朵
const red  = { flowers: true };

// 小白獲得了可以打給小紅的電話號碼
// 指定 red 為 white 的 Prototype
Object.setPrototypeOf(white, red);

// 真是太好了,現在去找小白也能獲得花朵
console.log( 'flowers' in white );     // true

//這是不太嚴謹的例子,因為現實中可能多試幾次後小白那邊就拿不到花朵,因為電話打太多次小紅會把小白封鎖。

在上面的程式裡面,小白就是物件,小紅就是原型物件,小白可以指定原型物件(打電話),來獲得原型物件的東西。

那假如我今天又想要在小白家拿到披薩呢? 現在知道說,小綠家有很多披薩,一樣把他的電話新增到小白手機裡,讓小白打電話給他。

const white = { cookies: true };
const red  = { flowers: true };
Object.setPrototypeOf(white, red);

// 小綠擁有很多披薩 (小知識:pizza是不可數名詞,可以不用加s)
const green  = { pizza: true };

Object.setPrototypeOf(white, green);

// 又多一個朋友,今晚我想來點餅乾+花朵+披薩
console.log( 'cookies' in white );     // true
console.log( 'flowers' in white );     // false
console.log( 'pizza' in white );     // true

// 從小白家竟然拿不到小紅的花朵,難道小紅生氣了嗎? 

小白家拿不到小紅的花朵,其實是因為Prototype世界的電話,一次只能存取一個電話號碼,小白手機裡面原本是存小紅電話號碼,但後來新增了小綠電話號碼,小紅的就消失了。

小白沒有在記別人電話號碼的,手機裡號碼不見了就不見了,現在只剩下小綠電話號碼,所以只能從小白家獲取小綠披薩。

重點 : 物件只能指定一種原型物件。

小白苦思著,竟然一次只能存取一個電話號碼,突然,小白靈光乍現,他想到了,只要叫小綠去用他的手機存取小紅電話不就好了嗎?

他打電話給小綠,小綠再打電話給小紅,之後再全部拿到小白家。

const white = { cookies: true };
const red = { flowers: true };
const green = { pizza: true };
Object.setPrototypeOf(white, green);


// 小綠獲得了小紅的電話號碼,可以打電話給小紅
Object.setPrototypeOf(green, red);

// 太好了,現在從小白家就能拿到花朵跟披薩,大家都很開心
console.log("cookies" in white); // true
console.log("flowers" in white); // true
console.log("pizza" in white); // true

透過這個友善的故事,希望能讓大家對於原型這個概念有個初步的理解,另外我還有在學習時看到一些不錯的比喻,寫得很棒歡迎去看 :

  1. 藉由洛克人打贏boss就會獲得boss新武器的機制來做原型的比喻。
    來自於重新認識 JavaScript: Day 24 物件與原型鏈
  2. 藉由猜謎問問題,遇到不會的問題就問其他人,來做原型的比喻。
    來自於忍者:JavaScript 開發技巧探秘, 2/e

設定Prototype其他方式

除了setPrototypeOf()之外其實也有一個方法可以去設定原型物件,就是__proto__,一樣可以讓小白拿到小紅的花:

const white = { cookies: true };
const red  = { flowers: true };

white.__proto__=red;
// 設定 小白的原型物件是小紅

console.log( 'flowers' in white ); //true

雖然它可以也可以拿來設定,不過我們一般不會使用它,因為它已經被認為過時以及超級不推薦使用,現在都會建議使用setPrototypeOf(),我會發現是因為研究時MDN上看到,要是你在MDN上面有查過__proto__這個語法的話,你會發現點開映入眼簾的是很多的警告,很可怕,有興趣可以研究。

圖片來源:MDN

構造函式的原型

我快寫不完,最後簡單介紹一下構造函式的原型,構造函式創個一個新的物件時,這個新的物件會被設定原型,原型物件就是構造函式,可能有些人不知道什麼是構造函式,但今天再詳細解釋會有點太長,所以關於這個以後會專門做一期文章給大家講解。

簡單一個小範例介紹:

function Food(name) {
  this.name = name;
}
const apple = new Food("apple");

Food就是建構函式,然後藉由new去實例出apple,這個新創造出來的物件,會被存到這個變數apple裡面。

然後這個apple它的原型物件就會是Food,我們可以來驗證一下這件事情。

console.log(apple.__proto__ === Food.prototype);// true

結果沒錯,相當於就是這個新的物件會繼承構造函式的原型。


明天會繼續接著講原型鏈的/images/emoticon/emoticon06.gif

reference

[1] MDN - Object prototypes
[2] W3Schools - JavaScript Object Prototypes
[3] JS 原力覺醒 Day21 - 原型


上一篇
JS之路 Day01 - 開始與結束的序言
下一篇
JS之路 Day03 - Prototype Chain(原型鏈)
系列文
JavaScript 之路,往前邁進吧!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 則留言

0
LeeFang
iT邦新手 2 級 ‧ 2022-09-17 13:29:25

j個友善的故事很vic風格/images/emoticon/emoticon12.gif

Vic iT邦新手 3 級 ‧ 2022-10-01 17:16:42 檢舉

/images/emoticon/emoticon35.gif

0
DannyChen
iT邦研究生 4 級 ‧ 2022-09-19 11:16:38

透過故事能夠加深印象,感謝分享~~/images/emoticon/emoticon37.gif

Vic iT邦新手 3 級 ‧ 2022-10-01 17:15:41 檢舉

謝謝丹尼/images/emoticon/emoticon37.gif

我要留言

立即登入留言