class People { constructor(name) { //構(gòu)造函數(shù) this.name = name; } sayName() { console.log(this.name); }}
上面定義了一個(gè)People類(lèi),他有一個(gè)屬性 name 和一個(gè)方法 sayName(),還有一個(gè)構(gòu)造函數(shù); 你可以這樣使用這個(gè)類(lèi):
var p = new People("Tom");p.sayName();
就像函數(shù)有函數(shù)聲明和函數(shù)表達(dá)式兩種定義方式,類(lèi)也可以通過(guò)類(lèi)表達(dá)式來(lái)定義:
let People = class { constructor(name) { //構(gòu)造函數(shù) this.name = name; } sayName() { console.log(this.name); } }
你可能以為類(lèi)聲明和類(lèi)表達(dá)式的區(qū)別在于變量提升的不同。但是事實(shí)是無(wú)論是類(lèi)聲明還是類(lèi)表達(dá)式的方式來(lái)定義,都不會(huì)有變量提升。所以下面的寫(xiě)法是錯(cuò)的:
var p = new People("Tom"); //錯(cuò)誤,People 未定義class People { //...};
類(lèi)中的所有方法默認(rèn)都是 strict mode
,所以不用再次聲明了。
繼承
通過(guò)關(guān)鍵字 extends
來(lái)繼承一個(gè)類(lèi),并且,可以通過(guò) super
關(guān)鍵字來(lái)引用父類(lèi)。
class People { constructor(name) { //構(gòu)造函數(shù) this.name = name; } sayName() { console.log(this.name); }}class Student extends People { constructor(name, grade) { //構(gòu)造函數(shù) super(name); //調(diào)用父類(lèi)構(gòu)造函數(shù) this.grade = grade; } sayGrade() { console.log(this.grade); }}
上面的例子中我們定義了一個(gè) Student ,他是 People 的子類(lèi)。
注意我們?cè)?constructor 中是如何通過(guò) super
調(diào)用父類(lèi)的構(gòu)造函數(shù)的。
getters & setters
現(xiàn)在我們可以通過(guò) get 和 set
關(guān)鍵字來(lái)定義 getters 和 setters 了。
下面我們給 name
屬性定義 getter 和 setter
class People { constructor(name) { //構(gòu)造函數(shù) 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); //1console.log(p._name); //2p.sayName(); //3
仔細(xì)看上面的例子,搞清楚最后三行分別會(huì)輸出什么,就明白getter 和 setter該怎么用了。
主要是要區(qū)分 this._name 和 this.name 的區(qū)別。因?yàn)槲覀兌x了 name
的讀寫(xiě)器,而沒(méi)有定義 _name
的讀寫(xiě)器,所以訪問(wèn)這兩個(gè)屬性的結(jié)果是不同的。
但是要注意一點(diǎn),不要這樣寫(xiě):
set name(name) { this.name = name;}
因?yàn)榻o this.name
賦值的時(shí)候會(huì)調(diào)用 set name
,這樣會(huì)導(dǎo)致無(wú)限遞歸直到棧溢出。
靜態(tài)方法
通過(guò) static
關(guān)鍵字定義靜態(tài)方法:
class People { constructor(name) { //構(gòu)造函數(shù) this.name = name; } sayName() { console.log(this.name); } static formatName(name) { return name[0].toUpperCase() + name.sustr(1).toLowerCase(); }}console.log(People.formatName("tom"));
靜態(tài)方法一般用來(lái)提供一些工具方法。
私有屬性
很不幸的時(shí)ES6并沒(méi)有提供對(duì)私有屬性的語(yǔ)法支持,但是我們可以通過(guò)閉包來(lái)實(shí)現(xiàn)私有屬性。
關(guān)于 WeakMap,會(huì)在下一篇博客仔細(xì)講解。 為什么要用WeakMap呢?因?yàn)閃eakMap 用object作為key,并且是一個(gè)弱引用,也就是說(shuō),WeakMap對(duì)這個(gè)對(duì)象的引用并不會(huì)導(dǎo)致GA無(wú)法回收這個(gè)對(duì)象(GA計(jì)算對(duì)象引用數(shù)量的時(shí)候并不會(huì)計(jì)算弱引用)。
var People = (function() { var p = new WeakMap(); class People { constructor(name) { //構(gòu)造函數(shù) 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();