Úvod do objektů
Obsah
Fáze života objektu
Líbil se vám příměr s autem? Jak takové auto vzniká? Někdo ho asi vyrobí, pravda? A vyrobí ho podle výrobních plánů. Objekty mají podobný životní cyklus.
Třída (class)
Třídu si lze představit jako výrobní plán objektu. Pro informace, jak se třídy vytváří, nahlédněte do kapitoly Třídy.
Tento plán obsahuje definice metod, vlastností a případně konstant budoucího objektu. Během kompilace SWF se pak ze tříd stávají prototypy. Prototyp si můžete představit jako prvek knihovny, připravený k vytváření instancí v animaci.
Protože se třídy překládají během kompilace, není už možné, v běžící animaci, načítat další třídy.
Prototyp (prototype)
Jak bylo zmíněno, je to předloha objektu připravena v paměti k replikaci, vytváření svých instancí.
Instance
V podstatě finální produkt. Otisk prototypu, použitý na určitý účel.
Při samotném běhu aplikace (tzv. runtime) je možné upravovat už jen prototypy a instance, výrobní plány zůstávají u konstruktéra v šuplíku - doslova, na web už se nedávají.
Instance objektu se tvoří klíčovým slovem new.
var datum = new Date();
Metody objektů
Metody jsou de facto vnitřní funkce objektu. Fungují také podobně. Můžou přijímat argumenty i vracet výstupy. Přistupovat k metodám objektu z venku můžete operátorem tečka:
var timestamp = datum.getTime(); // počet milisekund od 1. ledna 1970
Konstruktor
Konstruktor je speciální metoda, která je zavolána při vytvoření instance objektu. Jmenuje se stejně jako objekt a jsou jí předány argumenty zadané při vytvoření instance. V tomto případě rok, měsíc a den:
var vanoce_2010 = new Date(2010, 12, 24);
U některých jazyků můžete narazit i na tzv. destruktor. Ten ActionScript nemá.
Vlastnosti objektů
Vlastnosti jsou v podstatě vnitřní proměnné objektu. Pracuje se s nimi stejně jako s metodami.
var pole = new Array('a', 'b', 'c'); var delka = pole.length; // 3
Objekty běžně můžou mít i vlastní konstanty, ty ale existují v ActionScriptu až od verze 3.0.
Rozšiřitelnost a implementace
Jedna z největších výhod objektů je jejich rozšiřitelnost a implementace. Jak je používat se dočtete v kapitole Třídy.
Rozšiřitelnost znamená, že obecný objekt je použit jako základ méně obecného objektu. Pokud bychom měli například objekt Zvíře s metodami dýchání a příjem_potravy, mohli bychom jej použít jako základ pro objekt Pták, který by měl z rodičovského objektu k dispozici dýchání i příjem potravy. Sám by pak mohl přidat metodu létání.
Většina k předdefinovaných objektů ActionScriptu má několik rodičovských objektů - vždy minimálně jeden: obecný objekt Object.
Implementace je taky druh rozšíření, s tím rozdílem, že novým objektem implementujeme metody a vlastnosti rodičovského objektu. Mějme třeba objekt Auto s abstraktní (to jest ještě nedefinovanou, jen připravenou) metodou motor. Objekt Dieselové_auto by pak mohlo být jeho implementací, které by definovalo podobu motoru.
Instanční a statická oblast působnosti
Objekty a jejich prvky mají dva základní druhy působnosti:
Instanční prvky se vztahují ke své instanci (tj. kopii prototypu).
Například objekt
Stringmá většinu metod instančních, protože se samozřejmě vztahují ke konkrétnímu řetězci a nikoliv k řetězcům jako takovým.var retezec = new String('Lorem Ipsum'); var retezec_velke_pismena = retezec.toUpperCase(); // LOREM IPSUM
Statické prvky se vztahují k samotnému prototypu.
Například objekt
Mathv sobě sdružuje běžné matematické funkce a konstanty, jako je třeba sinus, logaritmus nebo pí. Protože vytváření instance takového objektu by bylo zbytečné a nesmyslné, jsou všechny prvky dostupné staticky.var funkcni_hodnota = Math.sin(Math.PI/2); // 1
Úprava a tvorba prototypů za běhu programu (runtime)
Vlastní objekty se od verze AS2.0 tvoří nejčastěji napsáním příslušné třídy, která se pak při kompilaci přeloží do prototypu. Je ale možné vytvářet prototypy i za běhu programu. Kromě toho, a to je možná důležitější, je možné i existující předdefinované prototypy upravovat.
Přidání metody předdefinovanému objektu
To je asi nejčastější činnost, kdy se zasahuje do prototypů. V následující ukázce bychom například chtěli objekt Array naučit novu metodu - shuffle (náhodné zamíchání prvků).
//Definování nové metody "shuffle" prototypu objektu Array Array.prototype.shuffle = function(){ this.sort(function(A, B){ return Math.round(2*Math.random()-1); }); } var pole = new Array('a', 12, 'c', 'x', 6); pole.shuffle(); // přibližně: c,6,x,a,12
Vidíte, že přístup k prototypu nám zprostředkovává vlastnost prototype.
Vytvoření nového prototypu
Nový prototyp lze za běhu programu vytvořit definováním jeho konstrukční funkce (konstruktoru).
function circle(radius){ this.radius = radius; this.getArea = function(){ return Math.PI * Math.pow(this.radius, 2); } this.getCircumference = function(){ return Math.PI * this.radius * 2; } } var kruh = new circle(10); trace(kruh.getArea()); // 314 trace(kruh.getCircumference()); // 63
Zde vidíme konstrukční funkci, která definuje vlastnosti radius a metody pro vrácení aktuálního obsahu a obvodu. Všimněte si také, že konstruktor má jeden argument - v našem případě pomocí něj nastavujeme hodnotu vlastnosti radius už při vytvoření objektu.
V AS3 nemůže funkce sloužit jako konstruktor runtime prototypu. Tento postup je tedy v AS3 nefunkční.
Přístupové metody vlastností (gettery a settery)
Přístup k vlastnosti může zprostředkovávat i metoda objektu. Používá se to především ke zpracování dat při zápisu do vlastností nebo naopak generování dynamických hodnot při jejich čtení. Význam je především ve zpřehlednění programů. Podrobněji v kapitole Třídy.
Přístupovou metodu (tzv. accessor) můžete nastavit i dynamickému (runtime) prototypu.
function circle() { this._radius = 0; this.setRadius = function(radius) { if (radius > 0) { this._radius = radius; } else { this._radius = 0; } }; this.getRadius = function() { return this._radius; }; this.getArea = function() { return Math.PI * Math.pow(this._radius, 2); }; this.getCircumference = function() { return Math.PI * this._radius * 2; }; this.addProperty('radius',this.getRadius,this.setRadius); this.addProperty('area',this.getArea,null); this.addProperty('circumference',this.getCircumference,null); } var kruh = new circle(); kruh.radius = 10; trace(kruh.area); trace(kruh.circumference);
Vidíte, že zde jsme vytvořili přístupové metody vlastnosti radius (pro zápis i čtení) a k obsahu a obvodu teď přistupujeme také jako k vlastnostem. Ty mají definovány už jen metodu pro vrácení hodnoty (getter), protože zápis by zde nedával smysl.
Všimněte si, že u setteru vlastnosti radius je kontrolována kladnost vložené hodnoty (aby mělo nějaký smysl setter použít).
Úprava vlastního dynamického prototypu
Stejná jako u prototypů předdefinovaných.
Metoda __resolve pro zachycení nedefinovaných prvků
Vycházejme z předchozího příkladu. Pokud bychom chtěli přečíst vlastnost kruh.pejsek, tak, protože náš kruh pejska nemá, obdrželi bychom hodnotu undefined.
Každý objekt má i metodu __resolve, pomocí které lze přístupy k nedefinovaným prvkům zachytit a zpracovat.
trace(kruh.pejsek); // undefined circle.prototype.__resolve = function(name) { return name + ' není definován!'; }; trace(kruh.pejsek); // pejsek není definován!
Protože definujeme metodu __resolve vně konstrukční funkce, nesmíme zapomenout na prototype.
Funguje to stejně i na nedefinované metody. Přístup k případným volaným argumentům umožňuje objekt arguments, stejně jako u funkcí.
Metoda __resolve už není v AS3 k dispozici. Místo ní se používá třída Proxy.
Vlastnost __proto__ pro přístup k rodičovskému prototypu
U instancí nebo častěji u rozšířených objektů potřebujeme někdy přistoupit k rodičovskému prototypu. Je možné využít vlastnosti __proto__.
Následující dva zápisy jsou ekvivalentní:
kruh.__proto__.clear = function() { this._radius = 0; } // je ekvivalentní k circle.prototype.clear = function() { this._radius = 0; }
Vlastnost __proto__ už není v AS3 k dispozici.
Mám vytvářet objekty jako třídy nebo jako prototypy až za běhu?
Jen málokdy je potřeba rozhodovat o struktuře objektů až za běhu programu. Málokdy je třeba posouvat stěny postaveného domu. Proto preferuji třídy - jejich použití má menší režii, nabízí širší možnosti a pohodlněji se s nimi pracuje.
I vlastní třídu můžete označit jako dynamic, pak půjde za běhu upravovat výše popsanými způsoby.
V AS3 nelze vytvářet runtime prototypy.
Ve Flashi je všechno objekt
Flash je ryze objektové prostředí. Například hlavní scéna je instance objektu MovieClip, proto můžete použít například jeho metodu gotoAndPlay().
Když přetáhnete na scénu tlačítko z knihovny a nazvete jej tlacitko, tak jste právě vytvořili vlastnost tlacitko aktuálního MovieClipu obsahující instanci objektu Button.
Když vytvoříte funkci, vytváříte vlastně metodu aktuálního objektu (tedy v případě animačního prostředí MovieClipu).
Všechny datové typy jsou objekty, včetně těch primitivních. Pochopitelně, primitivní typy mají též primitivní syntaxi pro deklaraci, aby se s nimi lépe pracovalo. Například následující zápisy jsou všechny platné:
var retezec:String; retezec = "Lorem Ipsum"; retezec = new String("Lorem Ipsum"); trace(retezec.toUpperCase()); // LOREM IPSUM trace("Lorem Ipsum".toUpperCase()); // LOREM IPSUM trace("Lorem Ipsum".length); // 11