JavaScript ES6 Class




JavaScript是一個以原型為基礎(prototype-based)的物件導向程式語言,而 ES6 Class 只是個語法糖(syntactical sugar),目的是提供更簡潔的語法來作物件建立與繼承。

我們過去使用 function constructor 來產生類別物件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function Employee(name, age,salary) {
    // 定義基本屬性
this.name = name;
this.age = age;
this.salary = salary;
}
// 原型方法
Employee.prototype.getName = function() {
return this.name;
}

Employee.prototype.employeeDetails = function() {
return 'Name: '+this.name+', Age:'+this.age+', salary:'+this.salary;
}

var felix = new Employee('Felix', 18, 22000);
//Name: Felix, Age:18, salary:22000
console.log(felix.employeeDetails());

var hector= new Employee('Hector', 25, 36000);
//Name: Hector, Age:25, salary:36000
console.log(hector.employeeDetails());

ES6 Constructor

類別宣告(Class Declaration)

一個定義類別的方法是使用類別宣告(class declaration),使用關鍵字 class 搭配類別名稱(此例為 “Employee”)。

1
2
3
4
5
6
7
class Employee{
constructor(name, age, salary) {
    this.name= name;
    this.age = age;
    this.salary= salary;
}
}

類別敘述(Class Expression)

類別敘述是定義類別的另一種方法,可區分為有名稱或無名稱的類別敘述。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// named class expression
var Employee = class {
constructor(name, age, salary) {
    this.name= name;
    this.age = age;
    this.salary= salary;
}
}

// unnamed class expression
var Employee = class Employee{
constructor(name, age, salary) {
    this.name= name;
    this.age = age;
    this.salary= salary;
}
}

var hector= new Employee('Hector', 25, 36000);

Hoisting

函式宣告和類別宣告的一個重要差別在於函式宣告是會 hoisted,而類別宣告則不會。使用類別宣告方法,需要先宣告類別才能進行存取,否則會出現 ReferenceError 的錯誤。

1
2
3
4
//Uncaught ReferenceError: Cannot access 'Employee' before initialization
var Vincent = new Employee();

class Employee{}

以下為將第一個例子修改為 Class 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Employee{
constructor(name, age, salary) {
    // 定義基本屬性
this.name= name;
this.age = age;
this.salary= salary;
}
    // 原型方法
getName() {
return this.name;
}
    
employeeDetails() {
return 'Name: '+this.name+', Age:'+this.age+',                 salary:'+this.salary;
}
}

//Name: Felix, Age:18, salary:22000
var felix = new Employee('Felix', 18, 22000);
console.log(felix.employeeDetails());


//Name: Hector, Age:25, salary:36000
var hector= new Employee('Hector', 25, 36000);
console.log(hector.employeeDetails());

改由 constructor 定義物件內的屬性,並將以前的 prototype 直接寫在 class 內,讓程式碼更為直觀。

靜態方法

我們可以在 class 內定義靜態方法,靜態方法只能被原型使用,無法在創立的物件上使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Employee{
constructor(name, age, salary) {
    this.name= name;
    this.age = age;
    this.salary= salary;
}
static testMethod(){
return 'static method has been called.';
}
}

var hector= new Employee('Hector', 25, 36000);

//hector.testMethod is not a function
hector.testMethod();

// 'static method has been called.'
Employee.testMethod()

Get and Set

get 與 set 關鍵字分別代表取得方法和設定方法,一般的公開的的屬性不需要用到這兩種方法,本來就能直接取值或設定;只有私有屬性才需要用到 get 和 set 方法來作取得或設定。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// ES6 get and set
class Employee{
constructor(name, age) {
this.name= name;
this.age = age;
}

get salary() {
console.log("The code executed on getting obj.salary");
if (this._salary!== undefined) {

return this._salary;
} else {
return 'no salary prop'
}
}

set salary(value) {
console.log("The code executed on setting obj.salary = value;")
this._salary=value;
}
}

var hector = new Employee('Hector',18);
//The code executed on setting obj.salary = value;
hector.salary='35000';
//The code executed on getting obj.salary
//"35000"
hector.salary;

getter不會有傳入參數,setter 則只能傳入一個參數。

繼承

我們之前透過函式建構式來達成類別繼承,為了讓子類別繼承父類別建構函式的內容,所以我們必須在子類別建構函式中呼叫父類別建構函式:

1
2
3
4
5
6
7
8
9
10
11
12
// Person 的 constructor function
function Person(name,age) {
this.name = name || 'default';
this.age = age || 0;
this.skill= ['HTML','CSS'];
}
// Student 的 constructor function
function Student(name) {
this.name = name;
this.score = 100;
Person.call(this,name);
}

extends

ES6 簡化類別宣告的過程,我們不需要再去修改原型物件,也能直接完成繼承的效果。

這裡會使用到兩個關鍵字:

  • extends: 繼承於另一個原型之下。
  • super : 使用上層的值(屬性)。

創造子類別 Student,並使用 extends 指向 Person,讓 Student 繼承 Person:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Person{
constructor(name, age) {
this.name = name || 'default';
this.age = age || 0;
this.skill= ['HTML','CSS'];
}

hi() {
    console.log(`Hi, ${this.name} ,My age is ${this.age}.`);
}
}

class Student extends Person{
constructor(name) {
super(name);
this.name = name;
this.score = 100;
}

say() {
    console.log(`Say, ${this.name} ,My score is ${this.score}.`);
}
}

var roman = new Student('roman');

繼承的子類別中的建構式, super() 需要放在建構式第一行,這是標準的呼叫方式。如果有需要傳入參數可以傳入。

繼承的子類別中的屬性與方法,都會覆蓋掉原有的在父母類別中的同名稱屬性或方法,要區分不同的屬性或方法要用 super 關鍵字來存取父母類別中的屬性或方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Person{
constructor(name, age) {
this.name = name || 'default';
this.age = age || 0;
this.skill= ['HTML','CSS'];
}
hi() {
console.log(`Hi, ${this.name} ,My age is ${this.age}.`);
}
}

class Student extends Person{
constructor(name) {
super(name);
this.name = name;
this.score = 100;
}
hi() {
console.log(super.hi());
}
}

var roman = new Student('roman');

// Hi, roman ,My age is 0.
roman.hi();

參考文獻

  1. https://ithelp.ithome.com.tw/articles/10185583

  2. https://ithelp.ithome.com.tw/articles/10195056

  3. https://ithelp.ithome.com.tw/articles/10226111

  4. https://ithelp.ithome.com.tw/articles/10196867