prethodna      sadržaj     
Vodič za core JavaScript 1.5 



Poglavlje 8   Detalji objekt modela


JavaScript je objektno-zasnovan jezik zasnovan na prototipovima, za razliku od class-zasnovanog. Zbog ovih različitosti, može biti manje uočljivo kako vam JavaScript dopušta da kreirate hijerarhiju objekata te da imate nasljeđivanje svojstava i njihovih vrijednosti. Ovo poglavlje će pokušati rasvijetliti situaciju.

Ovo poglavlje pretpostavlja da već nešto znate o JavaScriptu i da ste koristili JavaScript funkcije za kreiranje jednostavnijih objekata.

Ovdje ćete naći slijedeće odlomke:



Class-zasnovan nasuprot Prototype-zasnovanog jezika

Class-zasnovan objektno-orijentirani jezici, Kao što su Java i C++, se utemeljuju na konceptu dva različita entiteta: class-ovima i instancama.

Prototype-zasnovan jezik, kao što je JavaScript, ne pravi ovakve razlike nego jednostavno ima objekte. Prototype-zasnovan jezik ima oznaku prototypical object (prototipski objekt), objekt upotrijebljen kao uzorak iz kog se dobivaju početna svojstva za novi objekt. Svakom objektu mogu se odrediti njegova specifična svojstva, bilo pri njegovu kreiranju bilo pri njegovom izvršavanju (run time). Nadalje, svaki objekt može postati prototip nekom drugom objektu, omogućujući drugom objektu da dijeli svojstva prvog.


Definiranje class-a

Kod class-zasnovanih jezika, class se definira u posebnoj class definiciji . U toj definiciji mogu se definirati specijalne metode, zvane constructors (konstruktori), koji služe kreiranju instanci class-a. Constructor metoda može odrediti početne vrijednosti za svojstva instance. Koristi se new operator zajedno sa constructor metodom da bi se stvorile instance class-a.

JavaScript slijedi sličan model, ali nema definiciju class-a odvojenu od constructora. Umjesto tog, definira se constructor funkcija za stvaranje objekata sa početnim skupom svojstava i vrijednosti. Svaka JavaScript funkcija može biti upotrijebljena kao constructor. Takođe se koristi new operator sa constructor funkcijom za stvaranje novog objekta.


Subclass-e (podklase) i nasljeđivanje

Kod class-zasnovanog jezika, kreira se hijerarhija klasa kroz class definicije. U class definiciji, može se odrediti da nova klasa bude subclass podklasa postojeće klase. Podklasa nasljeđuje sva svojstva superklase te joj se mogu dodati druga svojstva ili pak modificirati nasljeđena. Npr., pretpostavimo da Employee class ima samo name i dept svojstva, a Manager je subclass (podklasa) od Employee koji dodaje reports svojstvo. U tom slučaju, instanca Manager klase će imati sva tri svojstva: name, dept i reports.

JavaScript primjenjuje nasljeđivanje dopuštajući vam da pridružite prototipski objekt pomoću bilo koje constructor funkcije. Tako se može napraviti i Employee- Manager primjer, no koristi se nešto drugačija terminologija. Prvo se definira Employee constructor funkcija, određujući name i dept svojtva. Dalje, definira se Manager constructor funkcija, određujući reports svojstvo. Na kraju, novi Employee objekt dodjeljuje se  kao prototip za Manager constructor funkciju. Zatim, kada se novi Manager kreira, on nasljeđuje name i dept svojstva iz Employee objekta.


Dodavanje i uklanjanje svojstava

Kod class-zasnovanih jezika, klasa se stvara za vrijeme kompajliranja te se zatim stvaraju instance klase i to ili za vrijeme kompajliranja ili za vrijeme izvršavanja. Broj ili tip svojstava klase ne može se promijeniti nakon što se definira klasa. U JavaScriptu, se za vrijeme izvršavanja mogu dodati ili ukloniti svojstva objekta. Ako se svojstvo dodaje objektu koji je prototip za skup objekata, onda i taj skup objekata dobiva isto svojstvo.


Sažetak različitosti

Naredna tablica daje kratak pregled nekih razlika. Ostatak ovog poglavlja opisuje upotrebu JavaScript constructora i prototipova za stvaranje objekt hijerarhije i to upoređuje sa Javom.


Tablica 8.1    Usporedba class-zasnovanog (Java) i prototype-zasnovanog (JavaScript) objekt sustava




Class-zasnovan (Java)

Prototype-zasnovan (JavaScript)

Class i instanca su zasebni entiteti.  

Svi objekti su instance.  

Definira klasu sa class definicijom; klasi daje instancu sa constructor metodom.  

Definira i kreira skup objekata pomoću constructor funkcija.  

Kreira objekt sa new operatorom.  

Isto.  

Konstruira hijerarhiju objekta koristeći class definicije da definira podklase postojećih klasa.  

Konstruira hijerarhiju objekta određujući objekt kao prototip kojem je pridružena constructor funkcija.  

Nasljeđuju se svojstva slijedeći class niz podataka.  

Nasljeđuju se svojstva slijedeći prototype niz podataka.  

Class definicija određuje sva svojstva svih instanci klase. Svojstva se ne mogu dodati dinamično za vrijeme izvršavanja.  

Constructor funkcija ili prototip određuju početni skup svojstava. Svojstva se mogu dinamično dodavati i uklanjati pojedinim objektima ili cijelom skupu objekata.  



Primjer employee (zaposlenici)



Ostatak ovog poglavlja koristi employee hijerarhiju prikazanu na slici.

Slika 8.1    Jednostavna hijerarhija objekta

Ovaj primjer koristi objekte:



Stvaranje hijerarhije

Postoji nekoliko načina da se definiraju constructor funkcije kako bi se napravila Employee hijerarhija. Koju ćete izabrati ovisi o tome što želite da vaša aplikacija radi.

Ovo poglavlje pokazuje kako koristiti vrlo jednostvne (i usporedno nefleksibilne) definicije za demonstraciju kako omogućiti nasljeđivanje. U ovim definicijama, ne može se odrediti svojstvo kad se kreira objekt. Novonastali objekt poprima predefinirana svojstva, koja se kasnije mogu promijeniti. Slika 8.2 ilustrira hijerarhiju sa ovim jednostavnim definicijama.

U realnim aplikacijama, vjerojatno ćete definirati constructore koji dozvoljavaju stvaranje svojstava za vrijeme kreiranja objekta (vidi Još fleksibilniji constructori ). Za sada, ove jednostavne definicije demonstriraju kako se zbiva nasljeđivanje.

Slika 8.2  Definicije objekta Employee

Naredne Java i JavaScript Employee definicije su slične. Jedine razlike su da trebate odrediti tip svakog svojstva u Javi, ali ne i u JavaScriptu, i da trebate kreirati explicitnu constructor metodu za Java class.







JavaScript

Java

function Employee () {
this.name = "";
this.dept = "general";
}

 

public class Employee {
   public String name;
   public String dept;
   public Employee () {
      this.name = "";
      this.dept = "general";
   }
}

 

Manager i  WorkerBee definicije pokazuju razliku pri određivanju slijedećeg objekta više u nizu podataka koji se nasljeđuju. U JavaScriptu, dodaje se prototipska instanca kao vrijednost za prototype svojstva constructor funkcije. To se uvijek može napraviti nakon što se definira constructor. U Javi, definira se superclass unutar class definicije. Ne može se promijeniti superclass izvan class definicije.







JavaScript

Java

function Manager () {
this.reports = [];
}
Manager.prototype = new Employee;

function WorkerBee () {
this.projects = [];
}
WorkerBee.prototype = new Employee;

 

public class Manager extends Employee {
   public Employee[] reports;
   public Manager () {
      this.reports = new Employee[0];
   }
}

public class WorkerBee extends Employee {
   public String[] projects;
   public WorkerBee () {
      this.projects = new String[0];
   }
}

 

Engineer i SalesPerson definicije kreiraju objekte koji se spuštaju niz WorkerBee pa zbog toga i niz Employee. Objekti ovog tipa imaju svojstva gornjih objekata. Nadalje, ove definicije preskaču naslijeđenu vrijednost dept svojstva pomoću novih vrijednosti specifičnih ovim objektima.







JavaScript

Java

function SalesPerson () {
   this.dept = "sales";
   this.quota = 100;
}
SalesPerson.prototype = new WorkerBee;

function Engineer () {
   this.dept = "engineering";
   this.machine = "";
}
Engineer.prototype = new WorkerBee;

 

public class SalesPerson extends WorkerBee {
   public double quota;
   public SalesPerson () {
      this.dept = "sales";
      this.quota = 100.0;
   }
}

public class Engineer extends WorkerBee {
   public String machine;
   public Engineer () {
      this.dept = "engineering";
      this.machine = "";
   }
}

 

Upotrebljavajući ove definicije, mogu se kreirati instance ovih objekata koji dobivaju predefinirane vrijednosti kao svoja svojstva. Slika 8.3 ilustrira upotrebu ovih JavaScript definicija za stvaranje novih objekta te prikazuje vrijednosti svojstava za nove objekte.

Uočite Termin instanca ima određeno tehničko značenje u class-zasnovanim jezicima. U ovim jezicima, instanca je zasebni član klase i bitno se razlikuje od klase. U JavaScriptu, "instanca" nema ovo tehničko značenje jer JavaScript nema ovu razliku između klasa i instanci. Pa ipak, govoreći o JavaScriptu, "instanca" se može koristiti neformalno da označi objekt kreiran pomoću određene constructor funkcije. Tako, u ovom primjeru, možete neformalno reći da je jane instanca od Engineer . Slično, iako termini parent, child, ancestor  i  descendant nemaju formalno značenje u JavaScriptu; možete ih upotrijebiti neformalno za pristup objektima višlje ili niže prototipskom nizu podataka.

Slika 8.3    Kreiranje objekata pomoću jednostavnih definicija



Svojstva objekta



Ovo poglavlje raspravlja kako objekti nasljeđuju svojstva od drugih objekata u prototype nizu podataka i što se dešava kad dodamo novo svojstvo za vrijeme izvršavanja.


Nasljeđivanje svojstava

Pretpostavimo da smo kreirali mark objekt kao WorkerBee, prikazano na Slici 8.3 , pomoću naredbe:

mark = new WorkerBee;

Kada JavaScript ugleda new operator, tada stvara novi generični (rodni) objekt te ga prosljeđuje kao vrijednost this ključne riječi za WorkerBee constructor funkciju. Constructor funkcija explicitno postavlja vrijednost od projects svojstva. Također postavlja vrijednost od unutrašnjeg __proto__ svojstva za vrijednost od WorkerBee.prototype . (Naziv ovog svojstva ima dve crtice, jednu na početku i drugu na kraju.) Svojstvo __proto__ određuje prototype niz podataka koji se koriste za vraćanje vrijednosti svojstava. Jednom kada se ova svojstva postave, JavaScript vraća novi objekt te naredbe pridruživanja pridružuju varijablu mark objektu.

Ovaj proces ne stavlja explicitno vrijednosti u mark objekt (lokalne vrijednosti) za svojstva mark nasljeđuje iz prototype niza. Kada zatražite vrijednost svojstva, JavaScript prvo provjerava da li svojstvo postoji u tom objektu. Ako postoji, vrijednost je vraćena. Ako vrijednost tamo nije lokalno, JavaScript provjerava prototype niz (koristeći __proto__ svojstvo). Ukoliko objekt u prototype nizu ima vrijednost svojstva, onda je ta vrijednost vraćena. Ako takvo svojstvo nije pronađeno, JavaScript kaže da objekt nema takvo svojstvo. Na ovaj način, mark objekt ima naredna svojstva i vrijednosti:

mark.name = "";
mark.dept = "general";
mark.projects = [];

Objekt mark nasljeđuje svojstva za name i dept svojstva iz prototipskog objekta u mark.__proto__. Pridružuju mu se lokalna vrijednost za projects svojstvo pomoću WorkerBee constructora. Ovo vam daje nasljeđivanje svojstava i njihovih vrijednosti u JavaScriptu. O nekim procesima pogledajte u Nasljeđivanje svojstava ponovljeno.

Ova informacija je generička jer ovi konstruktori ne dozvoljavaju vrijednosti za svaku instancu posebno. Svojstva su predefinirana i dijele ih svi objekti kreirani iz WorkerBee . Može se, naravno, promijeniti bilo koje svojstvo naknadno. Tako možete dati neke informacije za mark :

mark.name = "Doe, Mark";
mark.dept = "admin";
mark.projects = ["navigator"];


Dodavanje svojstava

U JavaScriptu se svojstvo može dodati i za vrijeme izvršavanja. Niste prisiljeni koristiti samo svojstva constructor funkcije. Za dodavanje svojstva koje je specifično za neki objekt, pridružit ćete vrijednost objektu prema slijedećem:

mark.bonus = 3000;

Sada, objekt mark ima bonus svojstvo, ali drugi WorkerBee ga nemaju.

Ako dodate novo svojstvo objektu koji se koristi kao prototip za constructor funkciju, onda dodajete to svojstvo svim objektima koja nasljeđuju svojstva iz njega. Npr., može se dodati specialty svojstvo svim zaposlenicima pomoću naredbe:

Employee.prototype.specialty = "none";

Čim JavaScript izvrši ovu naredbu, objekt mark također dobije svojstvo specialty sa vrijednošću "none". Naredna slika pokazuje efekt dodavanja ovog svojstva u Employee prototip, a zatim prebacujući na novu vrijednost zbog Engineer prototipa.

Slika 8.4    Dodavanje svojstava



Još fleksibilniji konstruktori



Dalje prikazane constructor funkcije ne dopuštaju određivanje svojstava  kada se kreira instanca. Kao u  Javi, mogu se napraviti argumenti za constructore da bi se inicijalizirala svojstva za instance. Naredna slika prikazuje jedan od načina.

Slika 8.5    Određivanje svojstava za constructor, primjer 1

Naredna tablica pokazuje Java i JavaScript definicije ovih objekata.







JavaScript

Java

function Employee (name, dept) {
this.name = name || "";
this.dept = dept || "general";
}

 

public class Employee {
   public String name;
   public String dept;
   public Employee () {
      this("", "general");
   }
   public Employee (name) {
      this(name, "general");
   }
   public Employee (name, dept) {
      this.name = name;
      this.dept = dept;
   }
}

 

function WorkerBee (projs) {
this.projects = projs || [];
}
WorkerBee.prototype = new Employee;

 

public class WorkerBee extends Employee {
   public String[] projects;
   public WorkerBee () {
      this(new String[0]);
   }
   public WorkerBee (String[] projs) {
      this.projects = projs;
   }
}

 

function Engineer (mach) {
   this.dept = "engineering";
   this.machine = mach || "";
}
Engineer.prototype = new WorkerBee;

 

public class Engineer extends WorkerBee {
   public String machine;
   public WorkerBee () {
      this.dept = "engineering";
      this.machine = "";
   }
   public WorkerBee (mach) {
      this.dept = "engineering";
      this.machine = mach;
   }
}

 

Ove JavaScript definicije koriste posebnu frazu za postavljanje predefiniranih vrijednosti:

this.name = name || "";

JavaScript logički OR operator ( ||) procjenjuje svoj prvi argument. Ako se taj argument pretvori u true, operator to i vrati. U protivnom, operator vraća vrijednost drugog argumenta. Na taj način, ova linija coda testira da li name ima upotrebljivu vrijednost za naziv svojstva. Ako ima, postavlja this.name na tu vrijednost. U protivnom, postavlja this.name na prazan string. Ovdje se ova fraza koristi radi kratkoće; pa ipak, u početku može djelovati zbunjujuće.

Pomoću ovih derfinicija, kada se kreira instanca objekta, mogu se definirati vrijednosti za lokalna svojstva. Kao što je prikazano na  Slici 8.5,  možete upotrijebiti naredno za kreiranje novog  Engineer:

jane = new Engineer("belau");

Svojstva za Jane su sada:

jane.name == "";
jane.dept == "general";
jane.projects == [];
jane.machine == "belau"

Uočite da pomoću ovih definicija ne možete odrediti početnu vrijednost za naslijeđeno svojstvo kao npr.  name. Ako želite odrediti početnu vrijednost naslijeđenog svojstva u JavaScriptu, mora se dodati više coda u constructor funkciju.

Na taj način, constructor funkcija kreira generički objekt, a zatim određuje lokalna svojstva i vrijednosti novog objekta. Može se upotrijebiti constructor za dodavanje još svojstava direktno pozivajući constructor funkciju za objekt koji je višlje u prototype nizu. Naredna slika pokazuje ovakve nove definicije.

Slika 8.6    Određivanje svojstava za constructor, primjer 2

Pogledajmo detaljno jednu od ovih definicija. Ovdje je i nova definicija za Engineer constructor:

function Engineer (name, projs, mach) {
this.base = WorkerBee;
this.base(name, "engineering", projs);
this.machine = mach || "";
}

Pretpostavimo da ste kreirali novi Engineer objekt prema slijedećem:

jane = new Engineer("Doe, Jane", ["navigator", "javascript"], "belau");

JavaScript prolazi kroz ove korake:


  1. Operator new kreira generički objekt i postavlja svoje __proto__ svojstvo u Engineer.prototype.


  2. Operator  new prosljeđuje novi objekt Engineer constructoru kao vrijednost od this ključne riječi.


  3. Constructor kreira new svojstvo nazvano base za taj objekt i pridružuje vrijednost od WorkerBee constructora  base svojstvu. Ovo čini WorkerBee constructor metodom za Engineer objekt.

    Naziv base svojstva nije posebno. Može se upotrijebiti bilo koje legalno ime; base je upotrijebljeno čisto zbog intuitivne naravi.


  4. Constructor poziva base metodu, prosljeđujući argumente kao svoje, dva argumenta proslijeđena constructoru ( "Doe, Jane" i ["navigator", "javascript"] ) , a također i string "engineering". Explicitno upotrijebljen "engineering" u constructoru pokazuje da svi Engineer objekti imaju istu vrijednost za naslijeđeno dept svojstvo, a ova vrijednost preskače vrijednost naslijeđenu iz Employee.


  5. Zato jer je base metoda za Engineer, JavaScript ve�e this za objekt kreiran u Korak 1. Na taj način, WorkerBee funkcija za uzvrat prosljeđuje "Doe, Jane" i ["navigator", "javascript"] argumente prema Employee constructor funkciji. Na povratku iz Employee constructor funkcije,  WorkerBee funkcija koristi preostali argument da postavi projects svojstvo.


  6. Na povratku iz base metode, Engineer constructor inicijalizira machine svojstvo na "belau".


  7. Na povratku iz constructora, JavaScript pridružuje novi objekt jane varijabli.

Možete pomisliti da ako pozivate WorkerBee constructor iz Engineer constructora, da postavljate nasljeđivanje za Engineer objekte. To nije slučaj. Pozivajući WorkerBee constructor omogućava da Engineer objekt započinje sa svojstvima određenim u svim constructor funckcijama koje su pozvane. Pa ipak,ako kasnije dodajete svojstva Employee ili  WorkerBee prototipovima, ta svojstva nisu naslijeđena sa Engineer objektom. Npr., pretpostavimo da imate:

function Engineer (name, projs, mach) {
this.base = WorkerBee;
this.base(name, "engineering", projs);
this.machine = mach || "";
}
jane = new Engineer("Doe, Jane", ["navigator", "javascript"], "belau");
Employee.prototype.specialty = "none";

Objekt jane ne nasljeđuje specialty svojstvo. Još uvijek trebate explicitno postaviti prototip da bi osigurali dinamičko nasljeđivanje. Pretpostavimo da zato imate slijedeće:

function Engineer (name, projs, mach) {
this.base = WorkerBee;
this.base(name, "engineering", projs);
this.machine = mach || "";
}
Engineer.prototype = new WorkerBee;
jane = new Engineer("Doe, Jane", ["navigator", "javascript"], "belau");
Employee.prototype.specialty = "none";

Vrijednost jane svojstva specialty je sada "none".



Nasljeđivanje svojstava ponovljeno



Prethodna poglavlja opisuu kako JavaScript constructori i prototipovi osiguravaju hijerarhiju i nasljeđivanje. Ovdje ćete naći neke podnaslove koji prethodno nisu bili uočljivi.


Lokalne nasuprot naslijeđenim vrijednostima

Kad pristupate svojstvima objekta, JavaScript izvodi slijedeće, što je opisano i u prethodnom poglavlju:


  1. Provjerava da li vrijednost postoji lokalno. Ako da, vraća tu vrijednost.


  2. Ako lokalna vrijednost ne postoji, provjerava prototipski niz (koristeći __proto__   svojstvo).


  3. Ako objekt u prototip nizu ima vrijednost za određeno svojstvo, onda vraća tu vrijednost.


  4. Ako takvo svojstvo ne nađe, tada objekt nema svojstvo.

Rezultat svega ovog ovisi o tome kako stvari definirate. Izvorni primjer ima ove definicije:

function Employee () {
this.name = "";
this.dept = "general";
}

function WorkerBee () {
this.projects = [];
}
WorkerBee.prototype = new Employee;

Sa ovim definicijama, pretpostavite da ste kreirali amy kao instancu za WorkerBee sa slijedećom naredbom:

amy = new WorkerBee;

Objekt  am y ima jedno lokalno svojstvo , projects. Vrijednosti za name i dept svojstva nisu lokalna za amy te su dobivena iz amy svojstva  __proto__ . Tako, amy ima slijedeća svojstva:

amy.name == "";
amy.dept = "general";
amy.projects == [];

Sada pretpostavimo da ste promijenili vrijednost name svojstva u prototip pridruženomu Employee:

Employee.prototype.name = "Unknown"

Možda ćete očekivati da će se nova vrijednost prenijeti dolje na sve instance od Employee . Pa ipak,to se neće desiti.

Kad se kreira bilo koja instanca od Employee objekta, onda ona dobije lokalnu vrijednost za name svojstvo (prazan string). Ovo znači da kada postavite WorkerBee prototip stvarajući novi Employee objekt, WorkerBee.prototype ima lokalnu vrijednost za name svojstvo. Na taj način, kada JavaScript traži name svojstvo amy objekta (instanca od WorkerBee), JavaScript nalazi lokalnu vrijednost za to svojstvo u WorkerBee.prototype . Zato dalje ne gleda u Employee.prototype.

Ako želite promijeniti svojstvo za vrijeme izvršavanja i dobiti novu vrijednost koju će naslijediti svi potomak-objekti, onda ne možete definirati svojstvo u constructor funkciji objekta. Umjesto toga, to dodajte prototipu koji je pridružen constructoru. Npr., pretpostavimo da ste prethodni code promijenili u:

function Employee () {
   this.dept = "general";
}
Employee.prototype.name = "";

function WorkerBee () {
this.projects = [];
}
WorkerBee.prototype = new Employee;

amy = new WorkerBee;

Employee.prototype.name = "Unknown";

U ovom slučaju, svojstvo name od amy postaje "Unknown".

Kao što ovi primjeri pokazuju, ako želite imati predefinirane vrijednosti za svojstva objekta i želite da možete promijeniti predefinirane vrijednost za vrijeme izvršavanja, trebate postaviti svojstva u constructorov prototip, a ne u samu constructor funkciju.


Određivanje veze između instanci

Možda ćete htjeti saznati koji su objekti u prototip nizu za neki objekt, tako da kasnije možete reći od kojih objekata ovaj objekt nasljeđuje svojstva.

Počevši od JavaScript 1.4, JavaScript ima instanceof operator za testiranje prototip niza. Ovaj operator radi upravo onako kako je instanceof funkcija opisana dolje.

Kao što je pokazano u Nasljeđivanje svojstava, kad se koristi new operator sa constructor funkcijom da bi se napravio novi objekt, JavaScript postavlja __proto__ svojstvo novog objekta na vrijednost prototype svojstva constructor funkcije. Ovo se može koristiti za testiranje prototip niza.

Npr., pretpostavimo da imate skup definicija koje smo već naveli, sa točno postavljenim prototipovima. Napravite  __proto__ objekt prema slijedećem:

chris = new Engineer("Pigman, Chris", ["jsd"], "fiji");

Sa ovim objektom, naredni izrazi su svi true:

chris.__proto__ == Engineer.prototype;
chris.__proto__.__proto__ == WorkerBee.prototype;
chris.__proto__.__proto__.__proto__ == Employee.prototype;
chris.__proto__.__proto__.__proto__.__proto__ == Object.prototype;
chris.__proto__.__proto__.__proto__.__proto__.__proto__ == null;

Sada možete definirati instanceOf funkciju:

function instanceOf(object, constructor) {
   while (object != null) {
      if (object == constructor.prototype)
         return true;
      object = object.__proto__;
   }
   return false;
}

Sa ovom definicijom, svi naredni izrazi su true:

instanceOf (chris, Engineer)
instanceOf (chris, WorkerBee)
instanceOf (chris, Employee)
instanceOf (chris, Object)

Ali je naredni false:

instanceOf (chris, SalesPerson)


Globalna informacija u constructorima

Kada kreirae constructore, morate biti pažljivi ako u constructoru postavljate globalnu informaciju. Npr., pretpostavimo da želite jedinstveni ID koji će se automatski dodjeljivati svakom novom zaposleniku. Možete upotrijebiti slijedeću definiciju za Employee:

var idCounter = 1;

function Employee (name, dept) {
   this.name = name || "";
   this.dept = dept || "general";
   this.id = idCounter++;
}

Pomoću ove definicije, kada kreirate novi Employee, constructor mu pridružuje novi ID u odjeljku, a zatim povećava globalni ID brojač. Tako,ako napišete slijedeće naredbe onda victoria.id postaje 1 ,a harry.id postaje 2:

victoria = new Employee("Pigbert, Victoria", "pubs")
harry = new Employee("Tschopik, Harry", "sales")

Na prvi pogled ovo lijepo izgleda. Pa ipak, idCounter se povećava svaki put kada se Employee objekt kreira, u bilo kakvu svrhu. Ako kreirate cijelu Employee hierarhiju kao što je pokazano u ovom poglavlju, Employee constructor se poziva svaki put kad se postavlja prototip. Pretpostavimo da imate naredni code:

var idCounter = 1;

function Employee (name, dept) {
   this.name = name || "";
   this.dept = dept || "general";
   this.id = idCounter++;
}

function Manager (name, dept, reports) {...}
Manager.prototype = new Employee;

function WorkerBee (name, dept, projs) {...}
WorkerBee.prototype = new Employee;

function Engineer (name, projs, mach) {...}
Engineer.prototype = new WorkerBee;

function SalesPerson (name, projs, quota) {...}
SalesPerson.prototype = new WorkerBee;

mac = new Engineer("Wood, Mac");

Nadalje pretpostavite da definicije koje su izostavljene imaju base svojstvo i pozivaju constructor iznad njih u prototip nizu. U ovom slučaju, povremeno se kreira i mac objekt pa je mac.id  je  5.

Ovisno o aplikaciji, i je i nije važno da je brojač dodatno povećao. Ako vam je važno točno stanje brojača, jedno od mogućih rješenja je constructor:

function Employee (name, dept) {
   this.name = name || "";
   this.dept = dept || "general";
   if (name)
      this.id = idCounter++;
}

Kada kreirate instancu od Employee koja će biti prototip, constructoru ne stavljate argumente. Koristeći ovakvu definiciju constructora, kada ne dajete argumente, constructor ne pridružuje vrijednost za id i ne osvježava brojač. Na taj način, da bi Employee dobio pridruženi id, mora se odredtiti ima zaposlenika. U ovom primjeru, mac.id će biti 1.


Bez višestrukog nasljeđivanja

Neki object-orijentirani jezici dopuštaju višestruko nasljeđivanje. Tj., objekt može nasljediti svojstva i vrijednosti iz nepovezanog roditelj-objekta. JavaScript ne podržava višestruko nasljeđivanje.

Nasljeđivanje svojstava zbiva se za vrijeme izvršavanja, kada JavaScript pretražuje prototipski niz objekata. JavaScript ne može dinamično naslijediti svojstava iz više od jednog prototipskog niza, jer objekt može imati samo jedan prototipski niz .

U JavaScriptu, constructor funkcija može pozivati više od jedne constructor funkcije. Ovo pak daje iluziju o višestrukom nasljeđivanju. Npr., uzmimo u obzir slijedeće naredbe:

function Hobbyist (hobby) {
   this.hobby = hobby || "scuba";
}

function Engineer (name, projs, mach, hobby) {
   this.base1 = WorkerBee;
   this.base1(name, "engineering", projs);
   this.base2 = Hobbyist;
   this.base2(hobby);
   this.machine = mach || "";
}
Engineer.prototype = new WorkerBee;

dennis = new Engineer("Doe, Dennis", ["collabra"], "hugo")

Nadalje pretpostavimo da definicija za WorkerBee je korištena kao u prethodnom poglavlju. U tom slučaju, objekt dennis ima svojstva:

dennis.name == "Doe, Dennis"
dennis.dept == "engineering"
dennis.projects == ["collabra"]
dennis.machine == "hugo"
dennis.hobby == "scuba"

Pema tome dennis dobiva hobby svojstvo iz Hobbyist constructora. Pa ipak, pretpostavimo da ste dodali svojstvo za prototip Hobbyist constructora:

Hobbyist.prototype.equipment = ["mask", "fins", "regulator", "bcd"]

Objekt dennis ne nasljeđuje novo svojstvo.


prethodna      sadržaj      
Copyright © 2000 Netscape Communications Corp. All rights reserved.

Posljednje izmjene Rujan 28, 2000