ES6學習歷程 12 — Class(一)
ES6 Class 介紹
ES6以前,JavaScript沒有class的概念。為了模仿class,還使用了建構函式 (constructor function) ,如下:
function Person(name) { this.name = name;}Person.prototype.getName = function () { return this.name; };var john = new Person("John Doe");console.log(john.getName());// John Doe
首先,創建一個建構函式Person() ,可以接收一個參數name 。接著將函式getName() assign給prototype,這樣就可以讓Person() 的所有實例共享到了。當Person使用new 創建新的實例john時,便會透過prototype繼承getName() 。看下方程式碼:
console.log(john instanceof Person); // trueconsole.log(john instanceof Object); // true
instanceof 是用來判斷 A是否是B的實例,比較的是原型(prototype)。是則回傳 true,否則回傳 false。
class 的宣告
ES6 是如何宣告class的呢?看下方程式碼:
class Person { constructor(name) { this.name = name; } getName() { return this.name; }}
使用關鍵字class宣告一個class。class下有建構子constructor(),可以在裡面初始化實例。
如何使用看範例:
class Person { constructor(name) { this.name = name; } getName() { return this.name; }}let john = new Person("John Doe");let name = john.getName();console.log(name);// "John Doe"
class vs. 自定義類型 (custom type)
除了透過定義建構函式這點相同外,有些重要的不同之處:
1. class不像函式那樣宣告會提升 (hoisting),class宣告不會提升(hoisting) 。
2. 所有的在class中的程式碼都在 ’ strict ’ 模式下執行,且不可更改。
3. class 方法是不可列舉的。
4. 調用class時必須使用new,若沒使用就會出現錯誤。
class 表達式
除了剛剛介紹的class的宣告以外,還能用表達式的方式來宣告:
let Person = class { constructor(name) { this.name = name; } getName() { return this.name; }}
一級公民 (First-class citizen)
Javascript class是一級公民。這意思是,class可以作為參數傳遞到另一個函式、也可以被另一個函式作為回傳值、也可以被當作值一樣指派給另一個變數。
看範例:
function factory(aClass) { return new aClass();}let greeting = factory(class { sayHi() { console.log('Hi'); }});greeting.sayHi(); // 'Hi'
- 首先,定義一個函式factory(),傳入的參數類型為class,且亦回傳一個class。
- 再來,將一個未命名的class的表達式傳入 factory(),並將其結果 (assign)傳給一個變數greeting。class的表達式中有一個方法sayHi()。
- 第三,透過greeting物件調用sayHi()。
Singleton
Singleton是一種設計模式,他將class的實例化限制為單個實例,確保整個系統只能創建一個class實例 (instance)。透過class表達式創建實例 (instance),可以立即調用class constructor()。
為此,使用new關鍵字來宣告class表達式,並在最後加上括號,看範例:
let app = new class { constructor(name) { this.name = name; } start() { console.log(`Starting the ${this.name}...`); }}('Awesome App');app.start(); // Starting the Awesome App...
建立一個class表達式,透過在表達式的最後面加上括號來傳遞參數,就可以立刻調用他的constructor()。
Static methods 靜態函式
在ES6前,若要定義一個靜態方法,就要將方法加入建構子中,如下:
function Person(name) { this.name = name;}Person.prototype.getName = function () { return this.name;};
然後,增加一個名為createAnonymous()的方法到Person中:
Person.createAnonymous = function (gender) { let name = gender == "male" ? "John Doe" : "Jane Doe"; return new Person(name);};
createAnonymous()就是一個靜態方法,因為Person的屬性值不依賴任何實例。
若要呼叫createAnonymous()方法,就使用Person class,而非Person的實例 (instance):
var anonymous = Person.createAnonymous()
ES6 中的靜態方法
在ES6要定義靜態方法只需要使用static關鍵字。
看範例:
class Person { constructor(name) { this.name = name; } getName() { return this.name; } static createAnonymous(gender) { let name = gender == "male" ? "John Doe" : "Jane Doe"; return new Person(name); }}
要調用靜態方法的話就使用以下方法:
let anonymous = Person.createAnonymous("male");
Computed Property 計算屬性
ES6可以在方括號 [ ] 中使用表達式,然後將表達式的結果作為物件的屬性名稱傳入。
let propName = "c";const rank = { a: 1, b: 2, [propName]: 3,};console.log(rank.c); // 3
上面範例中,[propName]是rank物件的計算屬性,屬性名稱是propName變數的值。
當訪問rank.c時,JavaScript會評估propName並回傳其值。
再看一例:
let name = 'fullName';class Person { constructor(firstName, lastName) { this.firstName = firstName; this.lastName = lastName; } get[name]() { return `${this.firstName} {this.lastName}`; }}let person = new Person('John', 'Doe');console.log(person.fullName); // John Doe