Wyszukaj / o blogu

JavaScript - konstruktor, prototyp i dziedziczenie

Opublikowano wto 28 kwietnia 2020 w javascript • 3 min read

Funkcja konstruktora pozwala na stworzenie wielu obiektów według zdefiniowanego schematu, który jest nazywany prototypem

Nazwa funkcji konstruktora często zaczyna się od dużej litery

Schemat:

  function NazwaFunkcji (właściwość) { // zdefiniowanie konstruktora, przekazanie właściwości
        this.atrybut1 = właściwość; //
        this.atrybut2 = function(argument) {  // funkcja zawarta w ramach obiektu stająca się metodą obiektu
              console.log(this.atrybut1); // przykłądowe wyrażenie/wywołujące obiekt
        }
  }

Korzystanie z funkcji - tworzenie nowego obiektu (musi być poprzedzonę słowem kluczowym new)

  const nazwaZmiennej = new nazwaFunkcji('argument')

  console.log(nazwaZmiennej)

  >> nazwaFunkcji { atrybut1:"argument", atrybut2: {...}}

  console.log(nazwaZmiennej.atrybut2()) // wywołanie metody

  >> właściwość // wartość przypisana do atrybut1 tego wywoływanego obiektu

Przykładowa funkcja konstruktora - tworzenie obiektu Person

  function Person (name) {
        this.name = name;
  }

słowo kluczowe this odwołuje się do aktualnej instancji/wywołania obiektu

Wywołanie funkcji

  const mike = new Person(mike)
  console.log(mike)
  >> Person{name:"mike"}

Słowo kluczowe this odwołuje się do aktualnej instancji/wywołania obiektu. Przykładowo w tym przypadku this jest wywoływanym obiektem mike

  function Person (name) {
        this.name = name;
        console.log(this);
  }

  const mike = new Person(mike)
  >> Person{name:"mike"}

this wywołane po za funkcją zwraca obiekt window

  console.log(this)
  >> Window { frames, Window....}

Aby zmieniać właściwości konstruktorów można słowo kluczowe .prototype (będzie to miało wpływ na wszystkie stworzone na jego podstawie obiekty - jego instancji!!!) i edytować prototyp danej funkcji

Dodawanie nowej przypisanej właściwości

Funkcja wyjściowa

  function Person (name) {
        this.name = name;
  }

Dodanie właściwości

  Person.prototype.type = "human"
  console.log(mike.type) // wywołanie
  >> human

Ale ->

  console.log(mike)
  >> Person {name:"mike"} // brak właściwości `type` chociaż w konsoli zwróci również info następującego typi ->
   __proto__ :
        type: "human"

  console.log(mike.type);
  >> human

Pojawić się również powinna wiadomość na temat prototypu obiektu

  __proto__: Object
  np. hasOwnProperty: f

  console.log(mike.hasOwnProperty('name'))
  >> true

Ale:

  console.log(mike.hasOwnProperty('type'))
  >> false // ponieważ należy do prototypu, a nie właściwości obiektu (konstruktora)

Dodawanie nowej metody

  Person.prototype.showName = function() { return this.name}

  console.log(mike.showName());
  >> mike // wywołuje funkcję
  console.log(mike.showName);
  >> function(){return this.name;} // zwraca funkcję

JS - zawiera wiele funkcji konstruktorów, które pozwalają na stworzenie obiektów według wcześniej zdefiniowanych prototypów

new String(), new Boolean(), new Number(), new Array(), new Function(), new Object(), new RexExp() - regular expression

::: warto pamiętać o tym, że w ten sposób tworzy się obiekty a nie typy prymitywne choć wywołanie go odbywa się w taki sam sposób jak przy typie prymitywnym/podstawowym :::

Wbudowana funkcja konstrukcyjna dla tablic

  const arr = new Array(22,33,44)
  console.log(arr) // [22,33,44]

Funkcji

  const func = new Function('x', 'y', 'return x + y')
  console.log(func(1,1))
  >> 2

Obiekt

  const obj = new Object({name: "r2d2"})

Prototypy - każdy obiekt ma swój prototyp, który również jest obiektem i dziedziczy z niego metody oraz właściwości

Object.prototype

Przykładowa funkcja konstruktora zawierająca funkcję liczenia wieku

  function Droid(name, constDate) {
  this.name = name;
  this.birthday = new Date(constDate);
  this.showAge = function(){
        const diff =  Date.now() - this.birthday.getTime();
        const ageDate = new Date(diff);
        return Math.abs(ageDate.getUTCFullYear() - 1970);
        }
  }

  const c3po = new Droid('C3PO', '2-2-2222');
  console.log(c3po.showAge());

Każdy ze stworzonych obiektów na podstawie tego konstruktora, również zawiera w sobie tą funkcję aby tego uniknąć można zadeklarować funkcję po za konstruktorem, wówczas zostanie ona zapisana do prototypu ale nie przypisana do każdego utworzonego obiektu

  function Droid(name, constDate) {
  this.name = name;
  this.birthday = new Date(constDate);
  }

  Droid.prototype.showAge = function(){
        const diff =  Date.now() - this.birthday.getTime();
        const ageDate = new Date(diff);
        return Math.abs(ageDate.getUTCFullYear() - 1970);
  }

Standard ES6 wprowadza również możliwość zadeklarowania klasy, której skutek będzie zbliżony

  class Droid {
        constructor(name, constDate) {
              this.name = name;
              this.constDate = constDate
        }

        showName() {
              return `Hello ${this.name}`
        }
  }

  const c3po = new Droid('c3po', '2222')

  console.log(c3po)

  >> Droid {name: "c3po", constDate: "2222"}
        constDate: "2222"
        name: "c3po"
              __proto__:
              constructor: class Droid
              showName: ƒ showName()
              __proto__: Object

Dziedziczenie

  function Robot (name) {
        this.name = name;
  }

Dodanie funkcji w prototypie konstruktora Robot

  Robot.prototype.greeting = function(){
        return `hello ${this.name}`;
  }

Konstruktor droid, który dziedziczy właściwości konstruktora Robot

  function Droid(type) {
        Robot.call(this, name)
        this.type = type
  }

:::.call() - funkcja call pozwala na wywołanie funkcji z innego kontekstu:::

Innymi metodami są:

:::.bind():::

:::.apply():::

Więcej na ten temat czytaj: How-to: call() , apply() and bind() in JavaScript

aby zapewnić dziedziczenie prototypie należy to zaznaczyć w innym przypadku nie będzie to możliwe

  Droid.prototype = Object.create(Robot.prototype)

Object.create - metoda, która pozwala na przekazanie dziedziczenia prototypu, te mogą być nadpisana nową metodą o tej samej nazwie. Ta metoda tworzy nowy obiekt, korzystając z istniejących obiektów jako jej prototypu stąd:

Należy zdefiniować używanie konstruktora z Droida, w innym przypadku zostanie on odziedziczony

  Droid.prototype.constructor = Droid;

Źródła:

https://developer.mozilla.org/pl/docs/Web/JavaScript/Guide/Obsolete_Pages/Przewodnik_po_j%C4%99zyku_JavaScript_1.5/Tworzenie_nowych_obiekt%C3%B3w/Zastosowanie_konstruktor%C3%B3w_funkcji

http://kursjs.pl/kurs/obiekty/konstruktor.php

https://www.udemy.com/course/modern-javascript-from-the-beginning/