JavaScriptObiekty i klasy

extends

Tworzy klasę pochodną, która dziedziczy metody innej klasy i może je rozszerzać lub nadpisywać.

Na tej stronie

Przykład

#
JavaScript
class Exercise {
  constructor(title, points) {
    this.title = title
    this.points = points
  }

  describe() {
    return `${this.title} (${this.points} pkt)`
  }
}

class Quiz extends Exercise {
  constructor(title, points, questions) {
    super(title, points)
    this.questions = questions
  }
}

const quiz = new Quiz('Test z pętli', 10, 5)

console.log(quiz.describe())
console.log(quiz)
console.log(quiz instanceof Exercise)
Konsola
Test z pętli (10 pkt)
Quiz { title: 'Test z pętli', points: 10, questions: 5 }
true

Definicja i zastosowanie

#

Słowo extends w deklaracji klasy wskazuje klasę bazową, czyli rodzica. Klasa pochodna dostaje wszystkie jego metody i może dodać własne albo nadpisać odziedziczone, zapisując metodę o tej samej nazwie. Pod spodem działa łańcuch prototypów: prototyp klasy pochodnej wskazuje na prototyp klasy bazowej.

Jeśli klasa pochodna ma własny konstruktor, musi w nim wywołać super(...), zanim pierwszy raz użyje this. To konstruktor rodzica tworzy obiekt, a dopiero potem klasa pochodna może dopisać swoje pola. Gdy klasa pochodna nie ma konstruktora, JavaScript doda domyślny, który przekaże wszystkie argumenty do rodzica.

Po extends może stać dowolne wyrażenie zwracające konstruktor, także klasa wbudowana, jak Error, Array czy Map. Dziedziczyć można tylko po jednej klasie. Gdy chcesz połączyć zachowania z kilku źródeł, zwykle lepsza jest kompozycja, czyli trzymanie innych obiektów w polach.

Składnia

#
Składnia
class Child extends Parent {
  constructor(...args) {
    super(...args)
  }
}

class MyError extends Error {}

Parametry

#
  • Parent

    klasa

    Klasa bazowa, po której dziedziczy nowa klasa. Może to być też klasa wbudowana, np. Error lub Array.

Więcej przykładów

#
Nadpisanie metody i domyślny konstruktor
JavaScript
class Exercise {
  constructor(title) {
    this.title = title
  }

  reward() {
    return 5
  }
}

class Project extends Exercise {
  reward() {
    return 25
  }
}

const tasks = [new Exercise('Pytanie ABCD'), new Project('Strona wizytówka')]

for (const task of tasks) {
  console.log(task.title, task.reward())
}
Konsola
Pytanie ABCD 5
Strona wizytówka 25

Klasa Project nie ma konstruktora, więc JavaScript użył domyślnego, który przekazał tytuł do konstruktora Exercise.

Pułapka: this przed super()
JavaScript
class Student {
  constructor(name) {
    this.name = name
  }
}

class Mentor extends Student {
  constructor(name, course) {
    this.course = course
    super(name)
  }
}

try {
  new Mentor('Kuba', 'React')
} catch (error) {
  console.log(error.name)
}
Konsola
ReferenceError

Obiekt powstaje dopiero w konstruktorze rodzica, więc przed wywołaniem super() nie ma jeszcze czego przypisać do this. Treść komunikatu błędu różni się między przeglądarkami.

Rozszerzanie klasy wbudowanej
JavaScript
class Playlist extends Array {
  totalMinutes() {
    return this.reduce((sum, video) => sum + video.minutes, 0)
  }
}

const playlist = new Playlist()
playlist.push({ title: 'Wstęp', minutes: 4 }, { title: 'Pętle', minutes: 11 })

console.log(playlist.length)
console.log(playlist.totalMinutes())
console.log(Array.isArray(playlist))
Konsola
2
15
true

Obsługa przeglądarek

#

Szeroko dostępne

Działa we wszystkich nowoczesnych przeglądarkach, także na telefonach. Możesz używać bez obaw.

  • Chrome
  • Edge
  • Firefox
  • Safari

Dobre praktyki

#
  • Dziedzicz tylko wtedy, gdy klasa pochodna naprawdę jest odmianą klasy bazowej, np. quiz jest zadaniem. Gdy obiekt tylko ma inny obiekt, np. gracz ma ekwipunek, wybierz kompozycję.
  • W konstruktorze klasy pochodnej wywołuj super() na samym początku. Użycie this przed nim kończy się błędem ReferenceError.
  • Unikaj głębokich hierarchii. Dwa, trzy poziomy dziedziczenia to zwykle rozsądne maksimum, dalej kod trudno śledzić.

Powiązane hasła

#

Widzisz błąd albo brakuje przykładu? Napisz do nas.