ECMAScript 之建立 Object
ECMAScript 也有 Object 概念,但其 Object 與傳統 OOP 的 Object 又不太一樣。傳統 OOP 的 Object 都必須由 class 而來,但 ECMAScript 的 Object 卻有多種建立方式。
建立 Object
有別於傳統 OOP 一定要先建立 class,才能使用 new
建立 object,ECMAScript 提供了 6 種建立 object 方式:
- Object Literal
- Empty Object
- New Object
- Constructor Function
- Class
- Object.create()
Object Literal
不需要建立 class,可以直接以 declarative 方式建立 object。
1 | var person = { |
以 key-value 方式直接在 {}
之間建立 object,其中 fullName
相當於傳統 OOP 的 method,但是將 function 指定給 fullName
property。
- 直接將 function 指定給 property
- 因為
person
為 object,可如同 OOP 般使用 method 方式使用fullName()
Empty Object
ECMAScript 有一個傳統 OOP 沒有的特色,就是可以動態新增 property,既然如此,我們就可以一開始只宣告一個 空物件
:{}
,事後再動態新增 property 即可。
1 | var person = {}; |
一開始只要指定 {}
即可,表示其為 Object
type,事後再動態新增 property。
- 一開始只要宣告為
{}
即可,不需要另外建立 class,也不需要new
,事後再動態建立 property - 因為
person
為 object,可如同 OOP 般使用 method 方式使用fullName()
New Object
1 | var person = new Object(); |
由於 Object 為 ECMAScript 內建型別之一,因此你也可以使用 new Object()
方式建立 object。
不過實務上幾乎不會這樣寫,因為
let person = {}
寫法更精簡
- 也可以使用
new Object()
建立 object,但 WebStorm 已經提出建議:是否要重構成 object literal
,也就是使用 Empty Object 方式。
Constructor Function
以上 3 種方式適合需要以 declarative 方式建立 object 時使用,也就是 data 自己可以決定,但實務上 data 幾乎由 user 決定,也就是要以 parameter 傳入。
另外這 3 種方式,每次建立 object 時,都會重新建立 function,然後指定到 fullName
property,事實上我們發現,每個 object 只有 data 會不一樣,但 function 都是一樣的,因此不斷地建立 相同的 funtion
很浪費的記憶體。
比較好的方式是 function
只建立一次,然後各 object 共用相同的 function。
1 | function Person(firstName, lastName) { |
由於 ECMAScript 本來就是以 function 為主的語言,因此使用 function 建立 object 也就不意外了。
其中 this
所建立的 property 都是 public
。
為了避免 function 重複建立,在 Person
constructor function 的 prototype 指定 fullName
property 為 fuction,也就是儘管建立多個 object,但 fullName
都指向同一個 function,因此節省記憶體。
是否發現這種寫法,似乎就是傳統 OOP 的 Class + Constructor 合體呢 ?
- 將 data 由 Constructor Function 的 argument 傳入,只定義 property 部分
- method 都定義在 Constructor Function 的 prototype
- 使用
new
建立 object
Class
1 | class Person { |
ECMAScript 2015 新增了 class
與 constructor
,讓我們可以類似傳統 OOP 使用 class
,但其本質其實是 ES5 的 Constructor Function,是道地的 syntax sugar。
與傳統 OOP 不同的是:ECMAScript 2015 的 class 並不用宣告 public property (也不能宣告 property,因為不合語法),而是直接在
constructor()
內使用this
定義 property,因為其本質仍是 ES5 的 Constructor Function。
- 由 constructor function 改成 class
- 一樣使用
this
定義 property - 一樣使用
new
建立 objec
雖然 fullName()
看起來是寫在 class
內,但仍然是透過 prototype 建立,我們可以使用 TypeScript Playground 獲得證明:
fullName()
寫在 class 內- 但仍然是透過 prototype 建立
Object.create()
1 | var prototype = { |
Object.create()
也可以建立 object,它提供了兩個參數。
- 第一個參數:指定新 object 的 prototype object
- 第二個參數:指定新 object 的 property object,可省略
由於 ECMAScript 可以動態新增 property,因此可以先不指定 property object,事後再動態新增 property。
但 method 部分會建立在 prototype,因此先將 fullName()
建立在 prototype object,再透過 Object.create()
建立,並將 prototype object 傳入。
- 建立 prototype object,並將 method 定義在 prototype 內
- 將 prototype object 傳進
Object.create()
,表示person
的fullName()
來自於 prototype object - Property 動態建立即可
1 | var prototype = { |
Object.create()
還有第二種用法,將 property 定義在第二個參數 property object,但 method 一樣定義在 prototype object。
- Method 一樣定義在 prototype object
- Property 改定義在 property object
- 使用
Object.create()
建立,同時傳入 prototype object 與 property object {}
是 Quokka 的 bug
- 在 Firefox 中可看到
person
完整印出,這才是對的
Conclusion
- Object Literal、Empty Object 或 New Object 方式,雖然可以建立 method,但只能建立在 object 上,較浪費記憶體
- Constructor Function、Class 或
Object.create()
,則能夠將 method 建立在 object 的 prototype 上,較節省記憶體 - Class 本質上仍然是 Constructor Function,可由 TypeScript 與 Babel 得證