在查詢 MDN 語法關於 string、array、object 的內建方法時,有沒有發現開頭都有 prototype
這個字樣,可是明明在使用上沒有呀!
// MDN 語法
Array.prototype.map()
// 實際使用
['Ritz', 'Lotus', 'Oreo'].filter(chocolate => chocolate.length > 4)
認識 JavaScript 的第一門課,應該聽過這個語言本身是以原型為基礎的物件導向設計,沒錯,prototype 翻譯為原型,在學習 JavaScript 路上不能錯過的一個大大大重點!
推出新款麵包時,若麵包師傅先分享了背後的故事與設計理念,這樣品嚐時是不是會更深刻富有情感連結呢。
比起直接奔向原型、原型鏈,各位小白們,讓我先從當初 JavaScript 的由來說起,再帶到原型物件導向吧。
從前從前(講故事起手式),1995 年前的瀏覽器只能進行瀏覽,無法和使用者互動,若是網頁上有一欄「用戶名」要求填寫,瀏覽器無法判斷使用者是否真的填寫完畢,須交由後面的伺服器端來判斷,現在看來,超級浪費時間與資源對吧!當時的網景公司也這麼覺得,他們需要一種網頁腳本語言來實現與瀏覽器的互動,基於這個需求,由工程師 Brendan Eich 負責,JavaScript 因此誕生。
當時 1994 年物件導向程式設計 OOP 概念正夯,可說是歸功於當時最流行的語言 C++,Brendan Eich 也跟上這股潮流,將物件導向程式設計帶入 JavaScript,但是與其他使用 class 類別達到繼承的語言不同, JavaScript 採用了以原型為基礎的物件導向設計。
那,什麼是 物件導向程式設計?
與傳統的程式設計主張將程式看作一系列函式的集合不同,物件導向程式設計 OOP 是一種是以物件概念為主的程式設計思維,將物件作為程式的基本單位,彼此獨立且能互相呼叫,其中的每一個物件都應該能夠接受資料、處理資料並將資料傳達給其它物件。
重要的物件導向程式語言包含: Common Lisp、Python、C++、Objective-C、Smalltalk、Delphi、Java、Swift、C#、Perl、Ruby、JavaScript 與 PHP等。
雖然這些程式語言都使用了 OOP 設計,但也因不同的風格而有所差異,這裡介紹兩種風格:類別基礎(Class-based)與原型基礎 (Prototype-based)
基於類別 class-based 的物件導向語言,物件必須透過 類別 Class才能被創造出來,以此創出來的物件都稱為該類別的 實例 instance。
以蓋房子舉例:類別 Class 就是設計圖,不同設計圖蓋出來的房子造型都不相同,若A版設計圖上畫了房子有 10 層樓、尖尖的屋頂、大大的落地窗,依照 A 版設計圖蓋出的房子,就稱為 A 版設計圖的 實例 instance,每棟房子都是參照設計圖建造出來的,這個過程稱為 實體化 instance。
類別 Class:用來定義某一種物件所擁有的屬性,類別 Class 是抽象的事物,例:房子設計圖,定義了房子要有的設計,但並不是真的房子。
實例 Instance:透過類別 Class產生出的實體,例:依照設計圖建造的房子。
class-based 的物件導向語言中,類別 Class有專屬的定義方式並且有層級概念,生成了第一個 類別 Class後,可以再生成第二個 類別 Class 成為第一個類的子類 subClass,第二個類會繼承第一個類中定義的屬性。
基於原型 prototype-based programming 的語言並不存在 類別 Class 與 實體 instance的差異:它只有物件。
不具有 類別 Class 的 JavaScript 怎麼創造物件呢?
也是使用 new + 建構式
,但這裡的建構式與 class-based 語言使用 類別 Class 的建構器不同,因此就算 ES6 新增了一個 class 保留字用來當 Constructor 創建 實體 instance,也**不代表它的物件導向的方式會變成 Class-Based,只是被 Class 包裝的 Prototype-Based 而已。
Class 只是簡化了 JavaScript 中操作 Constructor 的語法糖而已。
因此為了實現繼承的概念,加上 原型 prototype使 實例 instance 可以獲得此原型物件上的屬性,任何物件都可以指定其自身的屬性,在創建時或運行時都可以。
基於類別 Class based (Java) | 基於原型(JavaScript) |
---|---|
類別和實例是不同的事物。 | 所有物件均為實例。 |
通過類別定義來定義類;通過建構函數來產生實體。 | 通過建構函數來定義和創建一組物件。 |
通過 new 操作符來創建物件。 | 相同。 |
通過類別定義來定義現存類的子類,從而建構物件的層級結構。 | 通過將一個物件作為原型,指定關聯於建構函數來建構物件的層級結構。 |
遵循類別鏈繼承屬性。 | 遵循原型鏈繼承屬性。 |
類別定義指定類別的所有實例的所有屬性。 | 無法在運行時添加屬性。 |
建構函式或原型指定初始的屬性集。 | 允許動態地向單個的物件或者整個物件集中添加屬性,或者從中移除屬性。 |
你所不知道的JS
深入了解物件模型
Javascript继承机制的设计思想
从设计初衷解释 JavaScript 原型链
物件導向程式設計
基於原型編程
類別為基編程
程式語言的特性本質(二)類別與原型的物件管理學
物件導向--基於類別與原型的範例
相信看完以上能區分原型的物件導向概念,明天就可以解答一開始的問題,進一步講 prototype 的用法。
這個超重要喔!我之前就是不知道物件導向是蝦餃,每天都不知道在寫蝦餃
是不是!我也是最近補起來
蝦餃 ??? 很適合當舌尖系列的文章名字誒
寫得相當簡短精要呢!
請問後續會比較js物件的建構函式和類別函式(classes)兩者之間的取捨嘛?
因為沒寫過較龐大複雜的程式碼,在一般撰寫上,兩者都能拿來作使用,也都能有繼承行為,覺得光是能使用prototype就已經有大的操作空間了
之後會寫到 class 的介紹,但我也還在學習中沒有實際比較過和 constructor 的差異,在查找文章的過程如果有看到相關介紹再整理分享在文章內!謝謝你的留言:)