ES6詳解三:class
class是es6引入的最重要特性之一。在沒有class之前,我們只能通過原型鏈來模擬類。
基本用法
如果你用過java這樣的純面嚮物件語言,那麼你會對class的語法非常熟悉。
class People {
constructor(name) { //建構函式
this.name = name;
}
sayName() {
console.log(this.name);
}
}
上面定義了一個People類,他有一個屬性 name 和一個方法 sayName(),還有一個建構函式;
你可以這樣使用這個類:
var p = new People("Tom"); p.sayName();
就像函式有函式宣告和函式表示式兩種定義方式,類也可以通過類表示式來定義:
let People = class {
constructor(name) { //建構函式
this.name = name;
}
sayName() {
console.log(this.name);
}
}
你可能以為類宣告和類表示式的區別在於變數提升的不同。但是事實是無論是類宣告還是類表示式的方式來定義,都不會有變數提升。所以下面的寫法是錯的:
var p = new People("Tom"); //錯誤,People 未定義 class People { //... };
類中的所有方法預設都是 strict mode
,所以不用再次聲明瞭。
繼承
通過關鍵字 extends
來繼承一個類,並且,可以通過 super
關鍵字來引用父類。
class People { constructor(name) { //建構函式 this.name = name; } sayName() { console.log(this.name); } } class Student extends People { constructor(name, grade) { //建構函式 super(name); //呼叫父類建構函式 this.grade = grade; } sayGrade() { console.log(this.grade); } }
上面的例子中我們定義了一個 Student ,他是 People 的子類。
注意我們在 constructor 中是如何通過 super
呼叫父類的建構函式的。
getters & setters
現在我們可以通過 get
和 set
關鍵字來定義 getters 和 setters 了。
下面我們給 name
屬性定義 getter 和 setter
class People {
constructor(name) { //建構函式
this.name = name;
}
get name() {
return this._name.toUpperCase();
}
set name(name) {
this._name = name;
}
sayName() {
console.log(this.name);
}
}
var p = new People("tom");
console.log(p.name); //1
console.log(p._name); //2
p.sayName(); //3
仔細看上面的例子,搞清楚最後三行分別會輸出什麼,就明白getter 和 setter該怎麼用了。
主要是要區分 this._name 和 this.name 的區別。因為我們定義了 name
的讀寫器,而沒有定義 _name
的讀寫器,所以訪問這兩個屬性的結果是不同的。
但是要注意一點,不要這樣寫:
set name(name) {
this.name = name;
}
因為給 this.name
賦值的時候會呼叫 set name
,這樣會導致無限遞迴直到棧溢位。
靜態方法
通過 static
關鍵字定義靜態方法:
class People {
constructor(name) { //建構函式
this.name = name;
}
sayName() {
console.log(this.name);
}
static formatName(name) {
return name[0].toUpperCase() + name.sustr(1).toLowerCase();
}
}
console.log(People.formatName("tom"));
靜態方法一般用來提供一些工具方法。
私有屬性
很不幸的時ES6並沒有提供對私有屬性的語法支援,但是我們可以通過閉包來實現私有屬性。
關於 WeakMap,會在下一篇部落格仔細講解。
為什麼要用WeakMap呢?因為WeakMap 用object作為key,並且是一個弱引用,也就是說,WeakMap對這個物件的引用並不會導致GA無法回收這個物件(GA計算物件引用數量的時候並不會計算弱引用)。
var People = (function() {
var p = new WeakMap();
class People {
constructor(name) { //建構函式
var privateProperties = {
name: name
};
p.set(this, privateProperties);
}
sayName() {
console.log(this.name);
}
get name() {
return p.get(this).name;
}
}
return People;
})();
var p = new People("tom");
console.log(p.name);
p.sayName();
var p2 = new People("bob");
console.log(p2.name);
p2.sayName();
除了用WeakMap,還可以用閉包+Symbol來實現私有屬性,參見後面專門講Symbol的文章。