在 ECMAScript 6 引入的 JavaScript 類(class)是 JavaScript 現有的原型繼承的語法糖。 類並非 JavaScript 里加入的新的面向對象的繼承模型。JavaScript 中的類只是能讓咱們用更簡潔明瞭的語法建立對象及處理相關的繼承。數組
類其實是個「特殊的函數」,並且正如函數的定義方式有函數聲明和函數表達式兩種同樣,類的定義方式也有兩種,分別是:類聲明和類表達式。app
類聲明是定義類的一種方式,就像下面這樣,使用 class
關鍵字後跟一個類名(這裏是 Polygon),就能夠定義一個類。dom
1 class Polygon { 2 constructor(height, width) { 3 this.height = height; 4 this.width = width; 5 } 6 }
類聲明和函數聲明不一樣的一點是,函數聲明存在變量提高現象,而類聲明不會。也就是說,你必須先聲明類,而後才能使用它,不然代碼會拋出 ReferenceError
異常,像下面這樣:函數
1 var p = new Polygon(); // ReferenceError 2 3 class Polygon {}
類表達式是定義類的另一種方式。在類表達式中,類名是無關緊要的。若是定義了類名,則該類名只有在類體內部才能訪問到。工具
1 // 匿名的 2 var Polygon = class { 3 constructor(height, width) { 4 this.height = height; 5 this.width = width; 6 } 7 }; 8 9 // 命名的 10 var Polygon = class Polygon { 11 constructor(height, width) { 12 this.height = height; 13 this.width = width; 14 } 15 };
注意: 類表達式和類聲明同樣也不會有提高的現象。this
類的成員須要定義在一對花括號 {}
裏,花括號裏的代碼和花括號自己組成了類體。類成員包括類構造器和類方法(包括靜態方法和實例方法)。spa
類體中的代碼都強制在嚴格模式中執行。prototype
構造器方法是一個特殊的類方法,其用於建立和初始化對象(用該類生成的)。一個類只能擁有一個名爲constructor
的方法,不然會拋出 SyntaxError
異常。翻譯
在子類的構造器中可使用 super
關鍵字調用父類的構造器。code
參見方法定義。
1 class Polygon { 2 constructor(height, width) { 3 this.height = height; 4 this.width = width; 5 } 6 7 get area() { 8 return this.calcArea() 9 } 10 11 calcArea() { 12 return this.height * this.width; 13 } 14 } 15 const square = new Polygon(10, 10); 16 17 // 100 18 console.log(square.area);
static
關鍵字用來定義類的靜態方法。靜態方法是指那些不須要對類進行實例化,使用類名就能夠直接訪問的方法,須要注意的是靜態方法不能被實例化的對象調用。靜態方法常常用來做爲工具函數。
1 class Point { 2 constructor(x, y) { 3 this.x = x; 4 this.y = y; 5 } 6 7 static distance(a, b) { 8 const dx = a.x - b.x; 9 const dy = a.y - b.y; 10 11 return Math.sqrt(dx*dx + dy*dy); 12 } 13 } 14 15 const p1 = new Point(5, 5); 16 const p2 = new Point(10, 10); 17 18 console.log(Point.distance(p1, p2));
extends
建立子類extends
關鍵字能夠用在類聲明或者類表達式中來建立一個繼承了某個類的子類。
1 class Animal { 2 constructor(name) { 3 this.name = name; 4 } 5 6 speak() { 7 console.log(this.name + ' makes a noise.'); 8 } 9 } 10 11 class Dog extends Animal { 12 speak() { 13 console.log(this.name + ' barks.'); 14 } 15 } 16 17 var d = new Dog('Mitzie'); 18 // 'Mitzie barks.' 19 d.speak();
一樣也能夠用於原有的原型繼承的「類」:
1 function Animal (name) { 2 this.name = name; 3 } 4 Animal.prototype.speak = function () { 5 console.log(this.name + ' makes a noise.'); 6 } 7 8 class Dog extends Animal { 9 speak() { 10 super.speak(); 11 console.log(this.name + ' barks.'); 12 } 13 } 14 15 var d = new Dog('Mitzie'); 16 d.speak();
須要注意的是類不能繼承通常(非構造的)對象。若是你想要建立的類繼承某個通常對象的話,你要使用 Object.setPrototypeOf()
:
1 var Animal = { 2 speak() { 3 console.log(this.name + ' makes a noise.'); 4 } 5 }; 6 7 class Dog { 8 constructor(name) { 9 this.name = name; 10 } 11 speak() { 12 super.speak(); 13 console.log(this.name + ' barks.'); 14 } 15 } 16 Object.setPrototypeOf(Dog.prototype, Animal); 17 18 var d = new Dog('Mitzie'); 19 d.speak();
你可能想要數組類 MyArray
返回的是 Array
對象。這個 species 模式能讓你重寫默認的構造器。
例如,當使用像 map()
這樣的方法來返回默認的構造器時,你想要這個方法返回父級的 Array
對象,而不是MyArray 對象。
Symbol.species
能實現:
1 class MyArray extends Array { 2 // Overwrite species to the parent Array constructor 3 static get [Symbol.species]() { return Array; } 4 } 5 var a = new MyArray(1,2,3); 6 var mapped = a.map(x => x * x); 7 8 console.log(mapped instanceof MyArray); // false 9 console.log(mapped instanceof Array); // true
super
引用父類super
關鍵字能夠用來調用其父類的構造器或者類方法
class Cat { constructor(name) { this.name = name; } speak() { console.log(this.name + ' makes a noise.'); } } class Lion extends Cat { speak() { super.speak(); console.log(this.name + ' roars.'); } }
抽象子類或者 mix-ins 是類的模板。 一個 ECMAScript 類只能僅有一個父類,因此想要從工具類來多重繼承的行爲是不可能的。子類繼承的只能是父類提供的功能性。
在 ECMAScript 裏一個將父類做爲輸入且將其子類做爲輸出的函數能夠用來實現 mix-ins:
1 var calculatorMixin = Base => class extends Base { 2 calc() { } 3 }; 4 5 var randomizerMixin = Base => class extends Base { 6 randomize() { } 7 };
使用 mix-ins 的類能夠像下面這樣寫:
1 class Foo { } 2 class Bar extends calculatorMixin(randomizerMixin(Foo)) { }
相關:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Classes