Classes

Klasy w Javascript zostały wprowadzone w ECMAScript 2015 jako lukier składniowy (ang. syntactic sugar) dla istniejącego, opartego na prototypach modelu dziedziczenia. Składnia klas nie wprowadza nowego zorientowanego obiektowo modelu dziedziczenia. Klasy wprowadzają znacznie prostszą i bardziej czytelną składnię do tworzenia obiektów i dziedziczenia.

Definiowanie klas

Klasy są w zasadzie "szczególnymi funkcjami". Podobnie jak w funkcji można definiować wyrażenie function i deklaracje funkcji, tak składnia klasy posiada dwa komponenty: wyrażenie class i deklaracje klasy.

Deklaracje klas

Jednym ze sposobów definiowania klas jest deklaracja klasy. Aby zadeklarować klasę, należy użyć słowa kluczowego class wraz z nazwą klasy (w tym przypadku "Prostokat").

class Prostokat {
  constructor(wysokosc, szerokosc) {
    this.wysokosc = wysokosc;
    this.szerokosc = szerokosc;
  }
}

Hoisting

Ważną różnicą pomiędzy deklaracją funkcji a deklaracją klasy jest to, że deklaracje funkcji są przenoszone na początek (Hoisting) a klas nie. Najpierw musisz zadeklarować swoją klasę, by mieć do niej dostęp, w przeciwnym razie kod, jak ten poniżej, wygeneruje błąd ReferenceError:

var p = new Prostokat(); // ReferenceError

class Prostokat {}

Wyrażenie class

Wyrażenie class jest kolejnym sposobem definiowania klasy. Wyrażenia class mogą być nazwane lub nienazwane. Nazwa przypisana nazwanemu wyrażeniu class jest lokalna dla ciała klasy. (można ją odczytać z właściwości name klasy)

// nienazwane
var Prostokat = class {
  constructor(wysokosc, szerokosc) {
    this.wysokosc = wysokosc;
    this.szerokosc = szerokosc;
  }
};
console.log(Prostokat.name); // Prostokat

// nazwane
var Prostokat = class Prostokat2 {
  constructor(wysokosc, szerokosc) {
    this.wysokosc = wysokosc;
    this.szerokosc = szerokosc;
  }
};
console.log(Prostokat.name); // Prostokat2 

Uwaga: Wyrażenia class dotykają te same kwestie związane z przenoszeniem na początek (ang. hoisting) co wspomnianych deklaracji klas.

Ciało klasy i definicje metod

Ciało klasy jest umieszczane w nawiasach klamrowych {}. To tam definiuje się metody, czy konstruktory.

Tryb ścisły

Ciało klasy jest wykonywane w trybie ścisłym (ang. strict mode). W celu poprawienia wydajności, kod wykorzystywany tutaj podlega ścisłej składni; nie pozwala to na ukrycie niektórych wyjątków, a pewne słowa kluczowe są rezerwowane dla przyszłych wersji ECMAScript.

Konstruktor

Constructor jest szczególną metodą, która służy tworzeniu i inicjalizowaniu obiektu zdefiniowanego słowem kluczowym class. Dozwolony jest tylko jeden konstruktor w danej klasie. Jeśli klasa posiada więcej niż jedno wystąpienie metody constructor, wygenerowany zostanie błąd SyntaxError.

Aby wywołać konstruktor klasy bazowej, należy użyć słowa kluczowego super.

Metody

Zobacz też definiowanie metod.

class Prostokat {
  constructor(wysokosc, szerokosc) {
    this.wysokosc = wysokosc;
    this.szerokosc = szerokosc;
  }
  // Getter
  get pole() {
    return this.liczPole();
  }
  // Method
  liczPole() {
    return this.wysokosc * this.szerokosc;
  }
}

const kwadrat = new Prostokat(10, 10);

console.log(kwadrat.pole); // 100

Metody i właściwości statyczne

Słowo kluczowe static definiuje metodę kub właściwość statyczną w klasie. Statyczne metody i właściwości są wywoływane bez inicjalizowania ich klas i nie mogą być wywołane przez instancję klasy.

class Punkt {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  static nazwa = "Punkt";
  static odleglosc(a, b) {
    const dx = a.x - b.x;
    const dy = a.y - b.y;

    return Math.sqrt(dx*dx + dy*dy);
  }
}

const p1 = new Punkt(5, 5);
const p2 = new Punkt(10, 10);
p1.odleglosc; // undefined
p1.nazwa; // undefined
p2.odleglosc; // undefined
p2.nazwa; // undefined

console.log(Punkt.nazwa); // "Punkt"
console.log(Punkt.odleglosc(p1, p2)); // 7.0710678118654755

Powiązanie this z metodami niestatycznymi i statycznymi

Kiedy metoda typu static lub prototype jest wywoływana bez this (na przykład poprzez przypisanie metody do zmiennej), wtedy this będzie undefined w środku metody. Takie zachowanie będzie takie same, nawet jeżeli dyrektywa "use strict" nie będzie obecna, ponieważ kod w obrębie metody danej klasy zawsze będzie wykonywał się jako strict mode.

class Animal { 
  speak() {
    return this;
  }
  static eat() {
    return this;
  }
}

let obj = new Animal();
obj.speak(); // obiekt Animal
let speak = obj.speak;
speak(); // undefined

Animal.eat(); // klasa Animal
let eat = Animal.eat;
eat(); // undefined

Jeśli przepiszemy powyższy przykład z użyciem tradycyjnych funkcji bez dyrektywy "use strict", to this wywołane w metodzie będzie automatycznie przypisane do pierwotnej wartości this, którą domyślnie jest global object.

function Animal() { }

Animal.prototype.speak = function() {
  return this;
}

Animal.eat = function() {
  return this;
}

let obj = new Animal();
let speak = obj.speak;
speak(); // global object

let eat = Animal.eat;
eat(); // global object

Właściwości instancji

Właściwości instancji muszą być zdefiniowane wewnątrz metody klasy:

class Rectangle {
  constructor(height, width) {    
    this.height = height;
    this.width = width;
  }
}

Statyczne właściwości i właściwości prototypu muszą być zdefiniowane poza ciałem klasy:

Rectangle.staticWidth = 20;
Rectangle.prototype.prototypeWidth = 25;

Deklaracje pól

Publiczna i prywatne deklaracje pól są funkcjonalnościami eksperymentalnymi zaproponowanymi na TC39. Wsparcie przeglądarek jest ograniczone, ale ta funkcjonalność może być używana przy użyciu systemów takich jak Babel

Deklaracje pól publicznych

Przy użyciu deklaracji pól, powyższy przykład może być przepisany na:

class Rectangle {
  height = 0;
  width;
  constructor(height, width) {    
    this.height = height;
    this.width = width;
  }
}

Dzięki deklarowaniu pól na początku klasy, definicje klas stają się bardziej samodokumentujące, a pola są zawsze obecne.

Jak widać w powyższym przykładzie, pola mogą być zadeklarowane z lub bez domyślnej wartości.

Zobacz public class fields po więcej informacji.

Deklaracje pól prywatnych

Używając deklaracji pól prywatnych, definicja może być zapisana w taki sposób:

class Rectangle {
  #height = 0;
  #width;
  constructor(height, width) {    
    this.#height = height;
    this.#width = width;
  }
}

Próba odniesienia się do prywatnego pola poza ciałem klasy wygeneruje błąd. Prywatne pola mogą być tylko odczytywane i modyfikowane wewnątrz ciała klasy. Poprzez definicję właściwości niewidocznych poza ciałem klasy, można zapewnić, że użytkownicy klasy nie będą polegali na jej wewnętrznych właściwościach.

Pola prywatne mogą być tylko zadeklarowane na początku ciała klasy

Prywatnych pól nie da się utworzyć później, poprzez przypisywanie, tak jak normalnych właściwości.

Po więcej informacji zobacz private class fields.

Podklasy z extends

Słowo kluczowe extends jest używane w deklaracjach klas lub wyrażeniach klas do tworzenia klasy jako elementu potomnego innej klasy.

class Animal { 
  constructor(name) {
    this.name = name;
  }
  
  speak() {
    console.log(this.name + ' makes a noise.');
  }
}

class Dog extends Animal {
  constructor(name) {
    super(name); // wywyłanie konstruktora klasy nadrzędnej poprzez użycie super()
  }
  speak() {
    console.log(this.name + ' barks.');
  }
}

let d = new Dog('Mitzie');
d.speak(); // Mitzie barks.

Jeśli w podklasie znajduje się konstruktor, musi najpierw wywołać super() przed użyciem "this".

Można również rozszerzyć tradycyjne klasy oparte na funkcjach:

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.');
  }
}

let d = new Dog('Mitzie');
d.speak(); // Mitzie barks

Zwróć uwagę, że klasy nie mogą rozszerzać zwykłych (niezdatnych do konstrukcji) obiektów. Jeśli chcesz dziedziczyć po zwykłym obiekcie, możesz, zamiast tego użyć Object.setPrototypeOf():

var Animal = {
  speak() {
    console.log(this.name + ' makes a noise.');
  }
};

class Dog {
  constructor(name) {
    this.name = name;
  }
}

Object.setPrototypeOf(Dog.prototype, Animal);// If you do not do this you will get a TypeError when you invoke speak

let d = new Dog('Mitzie');
d.speak(); //Mitzie makes a noise.

Species

Jeśli chcesz zwrócić obiekt Array w twojej klasie MyArray, która dziedziczy po Array, to możesz użyć wzorca "species", który pozwala na nadpisywanie domyślnych konstruktorów.

Na przykład, wywołanie metody map() zwraca domyślny konstruktor MyArray. Użycie Symbol.species pozwala na nadpisanie tego zachowania tak, by zwracany był obiekt typu Array, a nie MyArray:

class MyArray extends Array {
  // Nadpisanie domyślnego kontruktora
  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

Słowo kluczowe super

Słowo kluczowe super jest wykorzystywane do udostępniania i korzystania z funkcji klasy, po której nasz obiekt dziedziczy.

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.`);
  }
}

let l = new Lion('Fuzzy');
l.speak(); 
// Fuzzy makes a noise.
// Fuzzy roars.

Mix-ins

Abstrakcyjne podklasy lub mix-ins są szablonami dla klas. Klasa może mieć tylko jedną klasę nadrzędną, więc dziedziczenie z wielu klas jest niemożliwe. Cała funkcjonalność musi być dostarczona przez jedną klasę nadrzędną.

Funkcja przyjmująca klasę nadrzędną jako argument i zwracająca podklasę rozszerzającą klasę nadrzędną może być użyta do implementacji mix-in'ów:

var calculatorMixin = Base => class extends Base {
  calc() { }
};

var randomizerMixin = Base => class extends Base {
  randomize() { }
};

Klasa używająca tych mix-in'ów może być zapisana w taki sposób:

class Foo { }
class Bar extends calculatorMixin(randomizerMixin(Foo)) { }

Specyfikacje

Specyfikacja Status Komentarz
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'Class definitions' in that specification.
Standard Initial definition.
ECMAScript (ECMA-262)
The definition of 'Class definitions' in that specification.
Living Standard

Kompatybilność

Update compatibility data on GitHub
DesktopMobileServer
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewChrome for AndroidFirefox for AndroidOpera for AndroidSafari on iOSSamsung InternetNode.js
classesChrome Full support 49
Full support 49
No support 42 — 49
Notes
Notes Strict mode is required.
No support 42 — 49
Disabled
Disabled From version 42 until version 49 (exclusive): this feature is behind the Experimental JavaScript preference (needs to be set to Enabled). To change preferences in Chrome, visit chrome://flags.
Edge Full support 13Firefox Full support 45IE No support NoOpera Full support 36
Full support 36
No support 29 — 36
Notes
Notes Strict mode is required.
No support 29 — 36
Disabled
Disabled From version 29 until version 36 (exclusive): this feature is behind the Experimental JavaScript preference (needs to be set to Enabled).
Safari Full support 9WebView Android Full support 49
Full support 49
No support 42 — 49
Notes
Notes Strict mode is required.
Chrome Android Full support 49
Full support 49
No support 42 — 49
Notes
Notes Strict mode is required.
No support 42 — 49
Disabled
Disabled From version 42 until version 49 (exclusive): this feature is behind the Experimental JavaScript preference (needs to be set to Enabled). To change preferences in Chrome, visit chrome://flags.
Firefox Android Full support 45Opera Android Full support 36
Full support 36
No support 29 — 36
Notes
Notes Strict mode is required.
No support 29 — 36
Disabled
Disabled From version 29 until version 36 (exclusive): this feature is behind the Experimental JavaScript preference (needs to be set to Enabled).
Safari iOS Full support 9Samsung Internet Android Full support 5.0
Full support 5.0
No support 4.0 — 5.0
Notes
Notes Strict mode is required.
nodejs Full support 6.0.0
Full support 6.0.0
Full support 4.0.0
Disabled
Disabled From version 4.0.0: this feature is behind the --use_strict runtime flag.
Full support 5.0.0
Disabled
Disabled From version 5.0.0: this feature is behind the --harmony runtime flag.
constructorChrome Full support 49
Full support 49
No support 42 — 49
Notes
Notes Strict mode is required.
No support 42 — 49
Disabled
Disabled From version 42 until version 49 (exclusive): this feature is behind the Experimental JavaScript preference (needs to be set to Enabled). To change preferences in Chrome, visit chrome://flags.
Edge Full support 13Firefox Full support 45IE No support NoOpera Full support 36
Full support 36
No support 29 — 36
Notes
Notes Strict mode is required.
No support 29 — 36
Disabled
Disabled From version 29 until version 36 (exclusive): this feature is behind the Experimental JavaScript preference (needs to be set to Enabled).
Safari Full support 9WebView Android Full support 49
Full support 49
No support 42 — 49
Notes
Notes Strict mode is required.
Chrome Android Full support 49
Full support 49
No support 42 — 49
Notes
Notes Strict mode is required.
No support 42 — 49
Disabled
Disabled From version 42 until version 49 (exclusive): this feature is behind the Experimental JavaScript preference (needs to be set to Enabled). To change preferences in Chrome, visit chrome://flags.
Firefox Android Full support 45Opera Android Full support 36
Full support 36
No support 29 — 36
Notes
Notes Strict mode is required.
No support 29 — 36
Disabled
Disabled From version 29 until version 36 (exclusive): this feature is behind the Experimental JavaScript preference (needs to be set to Enabled).
Safari iOS Full support 9Samsung Internet Android Full support 5.0
Full support 5.0
No support 4.0 — 5.0
Notes
Notes Strict mode is required.
nodejs Full support 6.0.0
Full support 6.0.0
Full support 4.0.0
Disabled
Disabled From version 4.0.0: this feature is behind the --use_strict runtime flag.
Full support 5.0.0
Disabled
Disabled From version 5.0.0: this feature is behind the --harmony runtime flag.
extendsChrome Full support 49
Full support 49
No support 42 — 49
Notes
Notes Strict mode is required.
No support 42 — 49
Disabled
Disabled From version 42 until version 49 (exclusive): this feature is behind the Experimental JavaScript preference (needs to be set to Enabled). To change preferences in Chrome, visit chrome://flags.
Edge Full support 13Firefox Full support 45IE No support NoOpera Full support 36
Full support 36
No support 29 — 36
Notes
Notes Strict mode is required.
No support 29 — 36
Disabled
Disabled From version 29 until version 36 (exclusive): this feature is behind the Experimental JavaScript preference (needs to be set to Enabled).
Safari Full support 9WebView Android Full support 49
Full support 49
No support 42 — 49
Notes
Notes Strict mode is required.
Chrome Android Full support 49
Full support 49
No support 42 — 49
Notes
Notes Strict mode is required.
No support 42 — 49
Disabled
Disabled From version 42 until version 49 (exclusive): this feature is behind the Experimental JavaScript preference (needs to be set to Enabled). To change preferences in Chrome, visit chrome://flags.
Firefox Android Full support 45Opera Android Full support 36
Full support 36
No support 29 — 36
Notes
Notes Strict mode is required.
No support 29 — 36
Disabled
Disabled From version 29 until version 36 (exclusive): this feature is behind the Experimental JavaScript preference (needs to be set to Enabled).
Safari iOS Full support 9Samsung Internet Android Full support 5.0
Full support 5.0
No support 4.0 — 5.0
Notes
Notes Strict mode is required.
nodejs Full support 6.0.0
Full support 6.0.0
Full support 4.0.0
Disabled
Disabled From version 4.0.0: this feature is behind the --use_strict runtime flag.
Full support 5.0.0
Disabled
Disabled From version 5.0.0: this feature is behind the --harmony runtime flag.
Private class fieldsChrome Full support 74Edge Full support 79Firefox No support NoIE No support NoOpera Full support 62Safari Full support 14WebView Android Full support 74Chrome Android Full support 74Firefox Android No support NoOpera Android Full support 53Safari iOS Full support 14Samsung Internet Android No support Nonodejs Full support 12.0.0
Public class fieldsChrome Full support 72Edge Full support 79Firefox Full support 69IE No support NoOpera Full support 60Safari Full support 14WebView Android Full support 72Chrome Android Full support 72Firefox Android No support NoOpera Android Full support 51Safari iOS Full support 14Samsung Internet Android No support Nonodejs Full support 12.0.0
staticChrome Full support 49
Full support 49
No support 42 — 49
Notes
Notes Strict mode is required.
No support 42 — 49
Disabled
Disabled From version 42 until version 49 (exclusive): this feature is behind the Experimental JavaScript preference (needs to be set to Enabled). To change preferences in Chrome, visit chrome://flags.
Edge Full support 13Firefox Full support 45IE No support NoOpera Full support 36
Full support 36
No support 29 — 36
Notes
Notes Strict mode is required.
No support 29 — 36
Disabled
Disabled From version 29 until version 36 (exclusive): this feature is behind the Experimental JavaScript preference (needs to be set to Enabled).
Safari Full support 9WebView Android Full support 49
Full support 49
No support 42 — 49
Notes
Notes Strict mode is required.
Chrome Android Full support 49
Full support 49
No support 42 — 49
Notes
Notes Strict mode is required.
No support 42 — 49
Disabled
Disabled From version 42 until version 49 (exclusive): this feature is behind the Experimental JavaScript preference (needs to be set to Enabled). To change preferences in Chrome, visit chrome://flags.
Firefox Android Full support 45Opera Android Full support 36
Full support 36
No support 29 — 36
Notes
Notes Strict mode is required.
No support 29 — 36
Disabled
Disabled From version 29 until version 36 (exclusive): this feature is behind the Experimental JavaScript preference (needs to be set to Enabled).
Safari iOS Full support 9Samsung Internet Android Full support 5.0
Full support 5.0
No support 4.0 — 5.0
Notes
Notes Strict mode is required.
nodejs Full support 6.0.0
Full support 6.0.0
Full support 4.0.0
Disabled
Disabled From version 4.0.0: this feature is behind the --use_strict runtime flag.
Full support 5.0.0
Disabled
Disabled From version 5.0.0: this feature is behind the --harmony runtime flag.
Static class fieldsChrome Full support 72Edge Full support 79Firefox Full support 75IE No support NoOpera Full support 60Safari No support NoWebView Android Full support 72Chrome Android Full support 72Firefox Android No support NoOpera Android Full support 51Safari iOS No support NoSamsung Internet Android No support Nonodejs Full support 12.0.0

Legend

Full support  
Full support
No support  
No support
See implementation notes.
See implementation notes.
User must explicitly enable this feature.
User must explicitly enable this feature.

Zobacz też