Programowanie obiektowe w JavaScript. OOP część 1.

JavaScript OOP

Poziom średnio-zaawansowany

Witam w 1. z dwóch części artykułów o programowaniu obiektowym (OOP) w JavaScript. Temat jest właściwie niezbędny dla zgłębienia tajników tego języka.

Programowanie obiektowe w JavaScript

JavaScript jest językiem obiektowym, mimo iż zarzuca mu się brak pewnych elementów typowych dla języków programowania obiektowego – OOP – przynajmniej w obecnych implementacjach JavaScriptu.

Przejdźmy do konkretów.

Prawie wszystko w JavaScript może być traktowane jako obiekt (tablice, daty, ciągi znaków, itd).

Możemy napisać zarówno:

var text = "Hello World";

jak i:

var text = new String("Hello World");

Obiekty to w skrócie dane (określonego typu), które posiadają właściwości (properties) i metody (methods).

Właściwości to wartości powiązane z obiektami, natomiast metody to powiązane akcje (funkcje), które można na tych obiektach wykonywać.

Przykłady właściwości:


text.length; // get

myCar.name = 'VW'; // set

Przykłady metod:


text.indexOf("World");

myCar.drive();

Tworzenie obiektów

Stworzymy teraz obiekt nowego typu. Zrobimy to poprzez zdefiniowanie funkcji, w której zaimplementujemy właściwości i metody dla obiektów naszego nowego typu.

Klasy? Specjalnie nie chciałem używać tego terminu. W typowych językach obiektowych klasa jest jakoby przepisem na tworzenie obiektów, zwykle definiuje się klasę słowem kluczowym class. Jak wspomnieliśmy w artykule o podstawach JS, w języku jest zarezerwowane słowo class, ale w celu przyszłej zgodności.

Mogło by to wyglądać tak, że „klasa” poniżej:

function Pracownik() {
    this.imie = "";
    this.dept = "IT";
}

mogła by zostać zapisana również jako (styl języka Java):

public class Pracownik {
    public String imie;
    public String dept;

    public Pracownik() {
        this.imie = "";
        this.dept = "IT";
    }
}

Wróćmy jednak do obecnego JavaScript. Funkcję pokazaną poniżej można uznać za klasę (a raczej odpowiednik klasy), co sam robię, jako sposób na uproszczenie toku myślenia.

Przykład – definicja funkcji („klasy”) i tworzenie obiektu na jej podstawie:

function Fura() {
  // właściwości
  this.name = '';
  this.speed = 0;

  // metoda
  this.getSpeed = function() {
    return this.speed;
  };

  // inny sposób zapisu
  this.accelerate = Accelerate;

  function Accelerate() {
    this.speed++;
  }
}

var myCar = new Fura();
myCar.name = 'VW';

alert(myCar.name); // VW
alert(myCar.getSpeed()); // 0

Zatem wygląda to jak tworzenie zwykłej funkcji: function Klasa() {}. Różnica tkwi w tym, że będzie ona wywoływana na rzecz tworzenia nowego obiektu: operator new.

Dostęp do członków bieżącego egzemplarza „klasy” czyli obiektu (metod i właściwości), daje nam operator this:

this.count = 128;

Są też inne sposoby (zapisu) dla tworzenia obiektów.

Przykład – new Object():

var uc = new Object();
uc.txt = 'Tekst';

uc.print = function() {
  alert(this.txt);
}

// wywołanie
uc.print();

Przykład – użycie literału obiektu (więcej w dalszej części):

Warning = {
  Tekst: '',
  Run: function() {
    alert(this.Tekst);
  }
}

Warning.Tekst = 'To jest tekst!';
Warning.Run();

Tip / wskazówka

// a, b, c odnoszą się do tego samego, pustego obiektu
a = b = c = {};

Dziedziczenie

W JavaScript odpowiednik dziedziczenia możemy osiągnąć używając słowa prototype:

// pointCounter może odwołać się do członka z klasy
// pointParent(rodzic)
pointCounter.prototype = new pointParent();

Dzięki prototype możemy wprowadzić członków klas, którzy będą ważne dla wszystkich obiektów, więc i dziedziczonych. Zatem poszukując danego członka, JavaScript najpierw przeszuka „klasę”, a potem ewentualnie prototyp.

Prototypy mogą rozszerzać wbudowane klasy:

// wprowadź prototyp 'rokPrzestepny' do klasy Date
Date.prototype.isLeapYear = isLeapYear;

Literały obiektu

Literał obiektu stanowi ujęta w nawias klamrowy ({}) lista składająca się z zera lub większej liczby par, które stanowią nazwa własności obiektu oraz przypisana jej wartość.

Nie powinno się używać literału obiektu na początku instrukcji. Doprowadzi to do wystąpienia błędu lub nieoczekiwanych zachowań, gdyż { zostanie zinterpretowany jako początek bloku.

Poniżej podany jest przykład literału obiektu. Pierwszy element obiektu auto definiuje własność mojeAuto. Drugi element, własność pobierzAuto, wywołuje funkcję (typyAut(„Polonez”) – pobiera z niej dane. Trzeci element, własność „dodatkowe”, używa istniejącej zmiennej (bonus).

Przykład:


var bonus = "Klimatyzacja";

function typyAut(nazwa) {
    if (nazwa == "Polonez")
        return nazwa;
    else
        return "Nie posiadamy marki " + nazwa + ".";
}

auto = { mojeAuto: "Caro", pobierzAuto: typyAut("Polonez"), 
    dodatkowe: bonus }

alert(auto.mojeAuto); // Caro
alert(auto.pobierzAuto); // Polonez
alert(auto.dodatkowe); // Klimatyzacja

Dodatkowo, możemy użyć literału znakowego lub liczbowego jako nazwy własności lub zagnieździć obiekt wewnątrz innego:

auto = { wieleAut: {a: "Toyota", b: "Jeep"}, 8: "Subaru" }

alert(auto.wieleAut.b); // Jeep
alert(auto[8]); // Subaru

Przykład – definiowanie i używanie obiektu oraz dostęp do elementów:

var flight = {
    airline: "LOT",
    number: 669,
    departure: {
        TRACE: "WARSAW",
        time: "2010-07-22 15:55",
        city: "Warszawa"
    },
    arrival: {
        TRACE: "LA",
        time: "2010-07-23 11:42",
        city: "Los Angeles"
    }
};

alert(flight["airline"]); // LOT
alert(flight.departure.TRACE); // "WARSAW"

Kolejny przykład pokazuje, jak dodać metodę do obiektu.

Przykład – dodawanie metody do obiektu:

var myObject = {
    value: 0,
    increment: function (inc) {
        this.value += typeof inc === 'number' ? inc : 1;
    }
};

A na koniec zobaczmy jak stworzyć sobie odpowiednik „konstruktora”. Jego instrukcje zostaną wykonane podczas tworzenia nowego obiektu (operator new).

Przykład – „konstruktor”:

// tworzymy konstruktor Foo; konstruuje on obiekt posiadający 
// właściwość status
var Foo = function (string) {
    this.status = string;
};

// dodajemy wszystkim instancjom metodę publiczną get_status
Foo.prototype.get_status = function() {
    return this.status;  
};

var myFoo = new Foo("Przetestowany"); // instancja
myFoo.get_status();

Na podsumowanie bonus: debug obiektów i toSource()

Metoda toSource() reprezentuje kod źródłowy obiektu. Zdarzy się nam czasem potrzeba debug’owania obiektów, wtedy właśnie możemy użyć tej metody.

Konwertuje ona obiekt do postaci źródła (tekstu), a także właściwości constructor (dostępnej dla każdego obiektu), wskazującej na konstruktor obiektu.

Przykład – debugowanie obiektu:

function mojTyp(cena, kolor) {
    this.cena = cena;
    this.kolor = kolor;
}
 
var obj = new mojTyp(99, "green");
alert(obj.constructor); // #1
alert(obj.toSource()); // #2

Wyniki:

// alert #1:
function mojTyp(cena, kolor) {
this.cena = cena;
this.kolor = kolor;
}

// alert #2:
({cena:99, kolor:”green”})

W 1. części to już wszystko, dziękuję za uwagę.

Programista WWW i aplikacji mobilnych z wieloletnim doświadczeniem, początkujący bloger. Pasjonat programowania, nowych technologii, e-commerce, a także sportu i motoryzacji.

Twitter LinkedIn Google+ Skype Xing 

Podaj dalej: Share on Facebook1Tweet about this on TwitterShare on Google+2Share on LinkedIn1Share on Tumblr0Digg thisEmail this to someonePin on Pinterest1
Możesz skomentować leave a response, lub podać trackback z własnej strony.
  • I jeszcze mała ciekawostka 🙂


    < avaj> psycholodzy powinni sie zajac javascriptem
    < +madman_> why
    < avaj> praca licencjacka „Dziedziczenie przez prototypy a syndrom sztokholmski”

    (źródło: bash.org.pl)

  • W JS nie ma klas. Widzę, po wpisach, że czytałeś książkę:
    http://www.yarpo.pl/2010/11/11/ksiazka-js-dla-webmasterow-zaawansowane-programowanie/

    Tam autor ciągle mówi o klasach.

    W JS można tworzyć _obiekty_, ale nie ma klas. Są prototypy. Co tak naprawdę przy składni JS nie powoduje większych problemów. A sposób na robienie obiektów w JS jest wiele:
    http://www.yarpo.pl/2011/01/11/tworzenie-obiektow-w-js/

  • Czytałem, ale także w innych się to powtarza.
    Oczywiście nie ma klas jako takich, ja traktuję to raczej jako umowę, pozwalająca uprościć spojrzenie na temat.

    Pisałem w wielu językach, mimo że JavaScript jest raczej specyficzny w niektórych kwestiach, jedni to lubią inni nie.

    A jak dla mnie obiekty w JS tworzy się całkiem spoko 🙂