ES6-類(Class)


ES6躬行記(20)——類

  ES6正式將類(Class)的概念在語法層面標准化,今后不必再用構造函數模擬類的行為。而ES6引入的類本質上只是個語法糖(即代碼更為簡潔、語義更為清晰),其大部分功能(例如繼承、封裝和復用等)均可在ES5中實現,只不過現在能用更符合面向對象的語法來操作類。但諸如接口、protected修飾符等一些面向對象常用的語法,ES6沒有給出相關標准。

一、創建

  在ES5時代,可以像下面這樣模擬一個類,先聲明一個構造函數,然后在其原型上定義共享的方法,最后與new運算符組合實例化一個類。

function People(name) {
  this.name = name;
}
People.prototype.getName = function () {
  return this.name;
};
var people = new People("strick");
people.getName();       //"strick"

  本節接下來的內容會與這個示例有一些關聯。

1)類聲明

  類的創建方式與函數類似,也有兩種:類聲明和類表達式。類聲明必須包含名稱和class關鍵字,下面也創建一個People類,其主體由一對花括號包裹,它的自有屬性和方法都與前一個People類相同。注意,每個類有且只有一個構造函數:constructor(),如果沒有顯式的聲明,那么會有一個空的構造函數以供調用。

class People {
  constructor(name) {
    this.name = name;
  }
  getName() {
    return this.name;
  }
}
var people = new People("strick");
people.getName();              //"strick"
typeof People;               //"function"
typeof People.prototype.getName;      //"function"

  在代碼的最后,調用了兩次typeof運算符,由於此處的People類相當於上一個示例模擬的People類,只不過寫法不同,因此兩次運算的計算結果都是“function”,這也從側面再次印證ES6的類僅僅是個語法糖。

  雖然兩種類非常相似,但是ES6中的類有其獨有的特性,具體如下所列:

(1)類聲明和即將要講解的類表達式都不會被提升。

(2)類中的代碼在執行時,會強制開啟嚴格模式。

(3)類的所有方法都不可枚舉,並且不能與new組合使用。

2)類表達式

  在類表達式中,名稱是可選的,但class關鍵字依然是必需的。如果包含名稱,那么叫做命名類表達式,反之,叫做匿名類表達式,如下所示。

var People = class {            //匿名類表達式
};
var People = class Man {        //命名類表達式
};

  命名類表達式中的名稱只能在類的內部訪問,如果在外部貿然使用,那么就會拋出未定義的錯誤。下面的例子演示了名稱的特點和局限。

var People = class Man {
  getSelf() {
    typeof Man;                 //"function"
    Man.name;                   //"Man"
    new Man().getAge();         //28
  }
  getAge() {
    return 28;
  }
};
var people = new People();
people.getSelf();
People.name;                   //"Man"
Man.name;                      //Man未定義的錯誤

  在getSelf()方法中先將typeof運算符應用於Man,然后訪問Man的name屬性,最后調用其實例的getAge()方法。在命名類的外部分別訪問People和Man的name屬性,前者能得到預期的結果,而后者卻會拋出錯誤。

  與函數表達式類似,類表達式也能立即執行,只是要像下面這樣,先在class關鍵字之前加new,然后在類的主體后面跟一對圓括號,里面的參數會傳遞給構造函數。

var people = new class {
  constructor(name) {
    this.name = name;
  }
  getName() {
    return this.name;
  }
}("strick");
people.getName();          //"strick"

二、成員

  類的成員既可以是普通的原型方法或自有屬性,還可以是有特殊功能的構造函數、生成器、靜態方法和訪問器屬性等,並且成員名可以是表達式。

1)自有屬性

  類中的自有屬性可以作為this對象的屬性,並且一般都會在構造函數中執行初始化,如下所示。

class People {
  constructor() {
    this.name = "strick";
  }
}

2)訪問器屬性

  在類中的訪問器屬性,其存取語法和ES5對象字面量中的相同,也需要get和set兩個關鍵字,具體實現如下所示。

class People {
  get prop() {
    return `getter:${this.name}`;
  }
  set prop(value) {
    this.name = value;
  }
}
var people = new People();
people.prop = "strick";
console.log(people.prop);       //"getter:strick"

  訪問器屬性還有一個便捷的地方,就是它和原型方法一樣,也能被子類繼承。

3)計算成員名

  類中的成員名既可以是標識符,也可以是要計算的表達式(如下代碼所示),其聲明語法和ES5對象字面量中的相同,也需要用一對方括號包裹。

var method = "getAge";
class People {
  ["get" + "Name"]() {
    return "strick";
  }
  [method]() {
    return 28;
  }
}
var people = new People();
people.getName();            //"strick"
people.getAge();              //28

4)生成器

  只要在某個方法之前加上星號(*),那么這個方法就能變為生成器,注意觀察下面代碼中的getName()方法。關於生成器的具體用法可以參考第19篇

class People {
  *getName() {
    yield "strick";
  }
}
var people = new People(),
  iterator = people.getName();
iterator.next();               //{value: "strick", done: false}

  如果方法的名稱是內置符號Symbol.iterator並且是一個生成器方法,那么就成功的為類創建了一個默認的迭代器,這也意味着類的實例能被for-of循環,具體實現可參考下面的代碼。

class People {
  *[Symbol.iterator]() {
    for (const item of [1, 2]) {
      yield item;
    }
  }
}
var people = new People();
/********************
  1
  2
********************/
for(var value of people) {
  console.log(value);
}

5)靜態方法

  ES6新增了static關鍵字,可把類中的方法(除了構造函數)定義成靜態的。要調用靜態方法只能通過類本身,而不是實例化的類,如下代碼所示。除了方法之外,static關鍵字還適用於訪問器屬性。

class People {
  static getName() {
    return "strick";
  }
}
People.getName();           //"strick"

  雖然ES6明確提出了靜態方法,但是沒有將靜態屬性一並標准化。如果要使用靜態屬性,可以像下面這樣用變通的方式定義。

People.age = 28;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM