--- title: Classes slug: Web/JavaScript/Reference/Classes tags: - Classes - Constructors translation_of: Web/JavaScript/Reference/Classes ---
ECMAScript 6 中引入了類別 (class) 作為 JavaScript 現有原型程式(prototype-based)繼承的語法糖。類別語法並不是要引入新的物件導向繼承模型到 JavaScript 中,而是提供一個更簡潔的語法來建立物件和處理繼承。
類別實際上是一種特別的函數(functions),就跟你可以定義函數敘述和函數宣告一樣,類別的語法有兩個元件:類別敘述(class expressions)和類別宣告(class declarations)。
一個定義類別的方法是使用類別宣告(class declaration),要宣告一個類別,你要使用關鍵字 class
搭配類別名稱(此例為 "Polygon")。
class Polygon { constructor(height, width) { this.height = height; this.width = width; } }
函數宣告和類別宣告的一個重要差別在於函數宣告是 {{Glossary("Hoisting", "hoisted")}} ,類別宣告則不是。 你需要先宣告你的類別,然後存取它,否則像是下面的程式碼就會丟出一個 {{jsxref("ReferenceError")}}:
var p = new Polygon(); // ReferenceError class Polygon {}
類別敘述是定義類別的另一種方法。類別敘述可以有名稱或是無名稱。賦予一個有名稱類別敘述的名稱只在類別主體(class's body)中有作用。(但是類別敘述的名稱可以透過該類別(不是實例)的 .name 屬性存取。)
// unnamed var Polygon = class { constructor(height, width) { this.height = height; this.width = width; } }; // named var Polygon = class Polygon { constructor(height, width) { this.height = height; this.width = width; } };
注意:類別敘述跟上述提到的類別宣告一樣,都會受到hoisting的影響。
類別的主體指的是被大括號({}
)包含的部分,你可以在這裡面定義類別成員(members),例如方法(methods)或建構子(constructors)。
類別宣告與類別敘述的主體都會以嚴格模式(strict mode)執行,也就是說,建構子、靜態方法和原型方法、getter及setter函數等都會以嚴格模式執行。
建構子(constructor)
方法是一個特別的方法,用來建立和初始化一個類別
的物件。一個類別只能有一個名為建構子(constructor)的特別方法。當類別中含有一個以上的建構子
方法時,{{jsxref("SyntaxError")}} 將會被拋出。
一個建構子可以用關鍵字 super
來呼叫父類別的建構子。
class Polygon { constructor(height, width) { this.height = height; this.width = width; } // Getter get area() { return this.calcArea(); } // Method calcArea() { return this.height * this.width; } } const square = new Polygon(10, 10); console.log(square.area); //100
關鍵字 static
定義了一個類別的靜態方法,靜態方法不需要實體化它所屬類別的實例就可以被呼叫,它也無法被已實體化的類別物件呼叫。靜態方法經常被用來建立給應用程式使用的工具函數。
class Point { constructor(x, y) { this.x = x; this.y = y; } static distance(a, b) { const dx = a.x - b.x; const dy = a.y - b.y; return Math.sqrt(dx*dx + dy*dy); } } const p1 = new Point(5, 5); const p2 = new Point(10, 10); console.log(Point.distance(p1, p2)); // 7.0710678118654755
當一個靜態方法或原形方法被呼叫,但沒有一個物件的值與this綁定時,被呼叫的函數中this關鍵字會是undefined
。在此情況下,自動裝箱(autoboxing)不會發生。?即使我們在非嚴格模式中寫程式,此行為仍然會存在,這是因為所有的函式、定義方法、建構子、getters和setters都是在嚴格模式中執行。因此,若我們沒有定義this的值,this會是undefined
。
class Animal { speak() { return this; } static eat() { return this; } } let obj = new Animal(); obj.speak(); // Animal {} let speak = obj.speak; speak(); // undefined Animal.eat() // class Animal let eat = Animal.eat; eat(); // undefined
若我們將上述程式用傳統的函式基礎類別(function based classes)表達,自動裝箱則會依據this在其被呼叫的函式中所綁定的值發生。
function Animal() { } Animal.prototype.speak = function() { return this; } Animal.eat = function() { return this; } let obj = new Animal(); let speak = obj.speak; speak(); // 全域物件 let eat = Animal.eat; eat(); // 全域物件
extends
建立子類別關鍵字 extends
是在類別宣告或是類別敘述中建立子類別的方法。
class Animal { constructor(name) { this.name = name; } speak() { console.log(this.name + ' makes a noise.'); } } class Dog extends Animal { speak() { console.log(this.name + ' barks.'); } } var d = new Dog('Mitzie'); d.speak(); // Mitzie barks.
若在子類別中有建構子(constructor),要使用this前則必須先呼叫super()函式。
你也可以擴充(extends)傳統的函式基礎"類別"。
function Animal (name) { this.name = name; } Animal.prototype.speak = function () { console.log(this.name + ' makes a noise.'); } class Dog extends Animal { speak() { console.log(this.name + ' barks.'); } } var d = new Dog('Mitzie'); d.speak(); // Mitzie barks.
注意類別並無法擴充一般(non-constructible不可建構的)物件。如果您想要繼承自一般的物件,可以使用{{jsxref("Object.setPrototypeOf()")}}來達成。
var Animal = { speak() { console.log(this.name + ' makes a noise.'); } }; class Dog { constructor(name) { this.name = name; } } // 如果你沒有用以下的方法,當你呼叫speak時會出現TypeError Object.setPrototypeOf(Dog.prototype, Animal); var d = new Dog('Mitzie'); d.speak(); // Mitzie makes a noise.
你可能會希望在陣列的衍生類別 MyArray
中回傳陣列 ({{jsxref("Array")}}) ,Species 這個模式讓你能覆寫默認的建構子 (contructor)。
舉例來說,當你使用像 {{jsxref("Array.map", "map()")}} 這類會回傳默認建構子的方法時,你希望能回傳父物件 Array
,而不是 MyArray
物件。 {{jsxref("Symbol.species")}} 符號讓你做到這件事:
class MyArray extends Array { // Overwrite species to the parent Array constructor static get [Symbol.species]() { return Array; } } var a = new MyArray(1,2,3); var mapped = a.map(x => x * x); console.log(mapped instanceof MyArray); // false 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.'); } } var l = new Lion('Fuzzy'); l.speak(); // Fuzzy makes a noise. // Fuzzy roars.
TBD
TBD
規格 | 狀態 | 評論 |
---|---|---|
{{SpecName('ES6', '#sec-class-definitions', 'Class definitions')}} | {{Spec2('ES6')}} | Initial definition. |
{{CompatibilityTable}}
Feature | Chrome | Firefox (Gecko) | Edge | Internet Explorer | Opera | Safari |
---|---|---|---|---|---|---|
Basic support | {{CompatChrome(42.0)}}[1] {{CompatChrome(49.0)}} |
{{CompatGeckoDesktop(45)}} | 13 | {{CompatNo}} | {{CompatNo}} | {{CompatSafari(9.0)}} |
Feature | Android | Firefox Mobile (Gecko) | IE Mobile | Opera Mobile | Safari Mobile | Chrome for Android |
---|---|---|---|---|---|---|
Basic support | {{CompatNo}} | {{CompatGeckoMobile(45)}} | {{CompatUnknown}} | {{CompatUnknown}} | 9 | {{CompatChrome(42.0)}}[1] {{CompatChrome(49.0)}} |
class
declarationclass
expression