Javascript 是個真正的「物件」導向程式語言

我不是針對你,我是說在座的各位,都是物件。

Schaos
Schaos’s Blog
9 min readMay 30, 2019

--

標題很農場,我們晚點再談 XD。

前陣子看了部門面試前端新人的題目,其中一題在考面試者對 Javascript Prototype 的認識;這篇就讓我們來好好認識一下 Javascript 的型別與 Prototype。

基本型別

Javascript 是 弱型別 語言,所有的資料都會在這些基本型別中轉換;在 Javascript 中一共有六種基本型別,其中最常見、最好懂的應該是這三者:

  • boolean布林值,就是真假值、truefalse 啦。
  • number數字,有關數字的都找他。
  • string字串,就是一串文字。

接下來的這兩位對剛學 Javascript 的新手來說,應該是最常搞不清楚的吧:

  • undefined未定義,可以想像成是變數的 placeholder。
  • null,其實是一個內建的特製 物件

undefinednull 的用法不同,也隱含著不同的語意,使用時應該要把明確指定是空值的東西賦值成 null,並且 極力避免把任何東西賦值成 undefined;保留好未定義的語意,幫自己跟同事節省除錯的時間。

另外一種基本型別,是 ES6 新增的 Symbol,用來建立一個匿名且獨一無二的值,有興趣深入理解的讀者可以參考 MDN 的介紹,這邊就不贅述了。

最後一種基本型別就是 object 了。

你才 Object,你全家都 Object

對,Javascript 是真的全家都 Object。

我就突然很想要寫這句,我很抱歉 XDDD

例如常用的 Math,是一個包裹著數學相關功能的內置物件;console 則是含有許多工具函式,供工程師開發使用的物件,例如最常用的:console.log('print something')

另外有一群物件,如同前面提到的 null 一樣,是在底層被特別處理過的物件,如 ArrayRegExpFunction 等,除了各自擁有眾多功能函式外,還有從底層就支援了 物件實體語法(object literal)

透過物件實體語法,讓撰寫程式者可以更快速的完成物件的建立、初始化。

Function

在前述的眾多預設物件中,最特別、最核心,也最需要理解的,莫過於 Function 了。

Function 在 Javascript 中是很特別的存在,是個有預設屬性、可呼叫、還會建立 執行環境 的物件。

之前關於閉包的文章中 也有提到 Function 會建立執行環境的特性,還沒看過的讀者可以點過去看看,可以幫助你了解閉包及執行環境喔!

例如前面舉例的 func1,他擁有 name: "func1", length: 1 等預設屬性,可以被執行,也會建立自己的執行環境;但要注意的是,透過 new Function() 建立的函式,EC 會建立在 Global EC 上:

因為建立 Function 牽扯到底層的 EC 建立,透過 new Function()eval() 動態建立的函式,在效能表現上勢必會比一般的函式差;另外,動態函式還會帶來安全性上的潛在風險,在一般的情況下應該要盡量避免透過這些方法動態的建立函式喔!

Prototype

說明完基本型別,該來說明這個文章農場標題了。

Javascript 是個基於原型(Prototype)的物件導向程式語言。不同於如 Java、C# 等 基於類別(Class)的物件導向程式語言,透過定義 Class、指定繼承來傳遞屬性及函式;在 Javascript 中會預先建立好 物件原型,並在新物件建立時,指定他的 原型 要參照到哪個物件:

上例中,我們建立了新的原型 Person,並將原型指定為自己建立的新物件;接著透過 new 運算子,建構一個原型參照 Person 的新物件 john

可以從 console.log 觀察到,john 中包含了建構式中的指定的所有屬性及函式,並擁有一個新的屬性 __proto__,參照到了建構他的物件 - Person,再看看 john.__proto__ 中的 __proto__ 屬性,參照到了 Object;這種一層一層往上參照的物件模型,也就是俗稱的 原型鏈,是 Javascript 這類基於 Prototype 的物件導向程式語言中,至關重要的機制。

如果再繼續沿著原型鏈往上找,你會找到 Object 的物件原型,最後找到一切的原型 - null

另外,如果我們在 Person 原型中加入新的屬性,會發生什麼事呢?

可以看到,如果更動了物件原型,無論是已經存在的,或是原型變動後才新建的,整條原型鏈的相關物件都會因此跟著變動;在實務上應該要盡量避免處理原生物件的物件原型,以避免影響其他模組套件;如果真的不得已非動不可,也請務必要小心。

Class

最後提一下 ES6 新增的語法 Class,有寫過 React 的讀者應該對類似下面的 Class 語法不陌生:

雖然他看起來、寫起來,都很像是 Java、C# 等語言中的「類別」,但其實 它只是 Prototype 的語法糖,底層一樣是透過 Prototype 進行物件的定義與繼承。

結語

回到標題:Javascript 是個真正的「物件」導向程式語言;會這樣說,是因為 Javascript 中幾乎一切都是物件!不同於基於類的程式語言,在基於原型的語言設計中,透過「物件原型」定義了物件模板,透過「原型鏈」,一層一層的參照物件原型,實現了屬性及函式的傳遞;另外,也因為一切都是參照到物件原型,使用時要注意避免對原生物件原型的變動,以預防牽一髮動全身的大災難。

希望透過這篇文章,能夠讓讀者您對 Javascript 中的型別、物件、Prototype 等有一些基本概念。如果看完後有任何心得,都歡迎您在底下回應,一起討論;若文中有不清楚或錯誤的地方,也請您不吝告知!

--

--