Sobes.tech
Middle

Czym jest dziedziczenie prototypowe w JavaScript?

sobes.tech AI

Odpowiedź od AI

W JavaScript obiekty dziedziczą właściwości i metody od swoich prototypów. Prototyp każdego obiektu jest innym obiektem, którego właściwości i metody są dostępne przez łańcuch prototypów.

Przy dostępie do właściwości obiektu, JavaScript najpierw szuka jej bezpośrednio w samym obiekcie. Jeśli właściwość nie zostanie znaleziona, wyszukiwanie kontynuowane jest w prototypie tego obiektu, następnie w prototypie prototypu i tak dalej, aż właściwość zostanie znaleziona lub osiągnięty zostanie koniec łańcucha (null).

Dziedziczenie prototypowe różni się od dziedziczenia klasycznego (takiego jak w Java czy C++), gdzie obiekty tworzone są z klas opisujących ich strukturę i zachowanie. W JavaScript klasy, pojawiające się w ES6, są składnią cukrową nad dziedziczeniem prototypowym.

Główne aspekty:

  • __proto__: Właściwość wewnętrzna obiektu, odwołująca się do jego prototypu.
  • prototype: Właściwość konstruktora (funkcji używanej jako konstruktor), odwołująca się do obiektu, który będzie służył jako prototyp dla tworzonych instancji.
  • Object.getPrototypeOf(obj): Standardowa metoda do pobrania prototypu obiektu.
  • Object.setPrototypeOf(obj, proto): Standardowa metoda do ustawienia prototypu obiektu.

Przykład:

// Funkcja konstruktora
function Animal(name) {
  this.name = name;
}

// Dodanie metody do prototypu Animal
Animal.prototype.sayHello = function() {
  console.log(`Cześć, nazywam się ${this.name}`);
};

// Tworzymy instancję
const dog = new Animal("Buddy");

// Wywołujemy metodę z prototypu
dog.sayHello(); // Wypisze: Cześć, nazywam się Buddy

// Prototyp obiektu dog to Animal.prototype
console.log(Object.getPrototypeOf(dog) === Animal.prototype); // true

// Prototyp Animal.prototype to Object.prototype
console.log(Object.getPrototypeOf(Animal.prototype) === Object.prototype); // true

// Koniec łańcucha prototypów to null
console.log(Object.getPrototypeOf(Object.prototype) === null); // true

Porównanie z dziedziczeniem klasycznym (używając klas ES6):

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

  sayHello() {
    console.log(`Cześć, nazywam się ${this.name}`);
  }
}

class Dog extends Animal {
  constructor(name, breed) {
    super(name); // Wywołanie konstruktora klasy bazowej
    this.breed = breed;
  }

  bark() {
    console.log("Woof!");
  }
}

const buddy = new Dog("Buddy", "Golden Retriever");
buddy.sayHello(); // Wypisze: Cześć, nazywam się Buddy (dziedziczone z Animal)
buddy.bark(); // Wypisze: Woof! (metoda Dog)

// Klasy w ES6 są cukrem składniowym nad prototypami
console.log(Object.getPrototypeOf(Dog) === Animal); // true (dziedziczenie klas)
console.log(Object.getPrototypeOf(Dog.prototype) === Animal.prototype); // true (dziedziczenie metod przez prototypy)
console.log(Object.getPrototypeOf(buddy) === Dog.prototype); // true (instancja dziedziczy z prototypu klasy)

Dziedziczenie prototypowe jest kluczową koncepcją w JavaScript, której zrozumienie jest niezbędne do efektywnej pracy z tym językiem.