« 1 2 »
Autor Zpráva
Suta
Profil
Snažím se proniknout do tajů objektově orientovaného programování, takže se potýkám s novými věcmi. Většinou si poradím sám, teď jsem se však zasekl na delší dobu, takže se obracím s prosbou sem.

Pro ukázku vytvořím jednoduchý příklad.

<script>
function classMojeTrida() {
    //definice promenne
    this.jmeno = "Petr";
    //definice funkce vypisujici jmeno
    this.zobrazJmeno = function() {
        //pri prvotnim zavolani probehne vypsani promenne v poradku
        alert(this.jmeno);
        this.vnitrniFunkce = function() {
            //v definovano funkci probehne vypsani promenne take v poradku
            alert(this.jmeno);
        }
        this.vnitrniFunkce();
        //pri opetovnem zavolani funkce jiz bude promenna jmeno nedostupna
        setTimeout(this.zobrazJmeno,2000);
    }
}

var instance = new classMojeTrida();
instance.zobrazJmeno();
</script>


Po spuštění kódu proběhne čtyřikrát alert, při prvních dvou dojde k vypsaní proměnné "jmeno", a po dvousekundové pauze (setTimeout), kdy je funkce volána znovu pomocí setTimeout již proměnná (this.jmeno) dostupná není (víz poznámky v kódu a příklad níže).

Jak tento problém vyřešit?

(poznámka: samozřejmě nechci použít řešení, kdy bych parametr "this.jmeno" přeposílal vytvořením anonymní funkce do funkce setTimeout, tím bych degradoval výhodu objektů a jednou definovaných parametrů pomocí klíčového slova this...)

Ukázka zde: http://www.petrzavicak.cz/ukazky_problemu/ukazka_10.html
_es
Profil
Po dôkladnom prečítaní tohoto by si mal prísť na riešenie.
Nechcem ti ho písať, je viacero možností ako to vyriešiť.
Menšia pomôcka:
var x = "premenna x";
var o = {x:"parameter x"};
function g(){alert(this.x);}
o.f = g;
alert(o.f === g); // true (funkcie sú identické)
o.f(); // "parameter x"
g(); // "premenná x"
(o.f)(); // "parameter x"
(g)(); // "premenná x"
(o.f = g)(); // "premenná x"
(g = o.f)(); // "premenná x"
(o.f = o.f)(); // "premenná x"
alert(o.f === g); // true (funkcie sú identické)
Suta
Profil
_es
Díky. Sic je pro mě tebou uvedená pomůcka stále "vyšší dívčí". Nemyslím to tak, že bych nerozuměl syntaxi nebo tomu, co a jak kód provádí, ale stále mi dělá obrovské problémy "objektové myšlení", je to pro mě čerstvá látka, stále jsem zatížený "klasickým" (nechápej jako špatným) programováním. Po třech týdnech už vím, že začít se učit objektové programování na javascriptu nebylo dobrou volbou. Tak to hold v životě chodí.

Ale k tématu. Našel jsem pro mě velmi jednoduché a myslím že i pěkné řešení.

http://fiddlerelf.com/2007/03/26/51/

Řešení příkladu v úvodním příspěvku by tedy spočívalo v nahrazení:
setTimeout(this.zobrazJmeno,2000);

za:
var _self = this;
        setTimeout(function(){
            _self.zobrazJmeno();
            }, 2000);


Příklad po této úpravě funguje správně, resp. proměnné definované na stejné úrovni jsou dostupné. Má-li někdo připomínky k tomuto řešení a případným komplikacím, nebudu se zlobit.
_es
Profil
Suta
V tom vlákne, čo som dal odkaz, sú dobré rady a vysvetlenia mnohých komplikácií, čo môžu nastať, hlavne rady Ondráša a Aichiho.
Je tam tiež zaujímavé si všimnúť, ako veľmi ľahko môže dôjsť k chybe vo veľmi krátkom kóde.

Uvedomuješ si, že s každým objektom vytváraným v classMojeTrida vytváraš tiež funkciu zobrazJmeno, ktorá je navyše vnorená?
Teda ak vytvoríš 1 000 takýchto objektov tak zároveň vytvoríš aj 1 000 funkcií, no s rovnakým kódom.
Nevytváraj vnorenú funkciu, ak naozaj nechceš, aby bola vnorená.
Ak dôkladne používaš this, tak najjednoduchšia rada je metódy vždy volať v tvare o.f() a máš zaručené, že vo funkcii f bude this objekt o.
Konštruktor classMojeTrida by mal mať nejaký rozumný zmysel. Aký má zmysel to, aby mali všetky objekty rovnakú vlastnosť jmeno?
Teda asi nejako takto:
function classMojeTrida(jmeno){
    this.jmeno = jmeno;
}
classMojeTrida.prototype.zobrazJmeno = function (){alert(this.jmeno); };
classMojeTrida.prototype.FunkceZobrazJmeno = function(){var o = this; return function(){o.zobrazJmeno(); }; };

var instance = new classMojeTrida("Petr");
instance.zobrazJmeno(); // Zobrazí instance.jmeno
setTimeout(function(){instance.zobrazJmeno(); }, 2000); // Zobrazí instance.jmeno za 2 s
setTimeout(instance.FunkceZobrazJmeno(), 3000); // Zobrazí instance.jmeno za 3 s ("Zapuzdrenejšia forma")
Suta
Profil
_es
V první řadě díky za tvůj čas a rady, cením si toho. Na začátek poznamenám, že "klasické" programování pomocí funkcí a proměnných používám cca 6 let, dá se tedy říct, že za tu dobu jsem toho vypotil již opravdu hodně (relativně). Po necelém měsíci pronikání do objektově orientovaného programování (zatím pouze javascript) musím říct, že mi přináší mnohé výhody a postupy včetně přehlednější správy kódu (přehlednost skutečně roste s množstvím kódu). Tím bych chtěl zamezit jakýmkoliv dalším poznámkám na téma "vytvářet či nevytvářet objekty". Ostatně, využívání objektových postupů přece neznamená využívat je pro veškerý kód.

Aký má zmysel to, aby mali všetky objekty rovnakú vlastnosť jmeno?
Samozřejmě kromě toho, že byl příklad sestrojen jako jednoduchá ukázka problému, vůbec žádnou...

Uvedomuješ si, že s každým objektom vytváraným v classMojeTrida vytváraš tiež funkciu zobrazJmeno
Uvědomuji a díky za upozornění. O definování metod na úrovni prototypu jsem věděl, ale zatím nepoužíval. Začnu.

Musím přiznat, že mám taky pěkný hokej v tom, kdy a jakým způsobem vytvořit objekt, podobně jako javascript v tebou uvedeném odkaze. Vím o čtyřech různých způsobech, jak v javascriptu vytvořit objekt, což mě zatím pěkně mate. Použít:

var Colors = new function() { ... }
s voláním
Colors.metoda()
, či
function Colors() { ... }
s inicializací a voláním
var Color = new Colors(x); Color.metoda();


Co se týče posledních dvou řádků v kódu tvého posledního příspěvku, nevím, zda-li je nějaký problém v tom, když setTimeout volám přímo v instanci objektu.

Uvedu část kódu, který jsem se pokusil přetransformovat objektově. Případné oponenty prosím o shovívavost, možná je tam hodně věcí "nesprávně" definovaných, na tomto poli skutečně začínám. Zároveň ale budu velmi vděčný za jakoukoliv kritiku a poznámky. Určitě mě to posune správným směrem, což teď potřebuju.

function classFade(obj,_start,_end,oKolik,rychlost) {
      /* trida pro fadeOut jakehokoliv prvku */
      /* je zde pouzit trik pro Internet Explorer s nastavenim relativni
         pozice takovemu prvku, ktery ma pozici static */
      /* pro IE 8 je nastaven z-index v pripade, ze je jeho hodnota "auto" */

      //definice vlastnosti
      this.obj = obj;
      this.opacity = _start || 100;
      this.opacityEnd = _end || 0;
      this.oKolik = oKolik || 5;
      this.rychlost = rychlost || 30;
      
      this.originalPosition = getStyle(this.obj,"position"); //vlastni funkce getStyle zjistujici aktualni styl prvku
      this.originalZindex = getStyle(this.obj,"z-index");

      //definice metod
      this.fadeOut = fadeOut;
      this.setPosition = setPosition;
      this.setZindex = setZindex;
      this.returnStyle = returnStyle;

      function setPosition() {
            if(this.originalPosition!="relative" && this.originalPosition!="absolute")
            this.obj.style.position = "relative";
      }
      function setZindex() {
            if(this.originalZindex=="auto")
            this.obj.style.zIndex = 0; //zde bude funkce zjistujici zIndex rodice, pripadne dalsich v hierarchii, 0 bude nastavena az v pripade, ze bude mit z-index u vsech prvku hodnotu "auto"
      }
      function returnStyle() {
            this.obj.style.position = this.originalPosition;
            this.obj.style.zIndex = this.originalZindex;
      }
      //zavolani metod
      this.setPosition();
      this.setZindex();
      //
      function fadeOut() {
            this.opacity -= this.oKolik;
            if(this.opacity > this.opacityEnd) {
                nastavPrusvitnost(this.obj, this.opacity); //vlastni funkce nastavujici opacity v zavislosti na prohlizeci
                var _self = this;
                setTimeout(function(){ //rekurze na tuto funkci, k provedeni dalsiho stupne zmeny pruhlednosti
                    _self.fadeOut();
                    }, this.rychlost);
            }
            else {
                nastavPrusvitnost(this.obj, this.opacityEnd); //osetreni
                this.returnStyle();
            }
      }
}

var instance = new classFade(mujObjekt,pripadne_parametry); //pokud parametry neupresnim, budou pouzity vychozi
instance.rychlost = 50; //pripadne i takto muzu upravit vybrany z parametru
instance.fadeOut(); //spustim fadeOut objektu
Ondráš
Profil *
var Colors = new function() { ... }

Téhle konstrukce bych se celkem vyvaroval. Ve skutečnosti je v tomto zápisu skrytá definice "anonymního konstruktoru", které je okamžitě instancializován a Colors je pak výsledný objekt. Čili interpret tento zápis vidí jako
var Colors = new ( function() {} )()

což je v tomhle případě zhruba stejně užitečné, jako (o dost jednodušeji zapsatelné)
var Colors = {};


Jinak posledí uvedený dlouhý kus kódu vypadá OK, akorát se tam pro každou iteraci animace vyrábí nová funkce. Osobně bych asi šel nějakou takovouhle cestou:
var classFade = function() {
  /* tady si vyrobim pomocnou funkcni volanou v timeoutu */
  var o = this;
  this.docasnyAnimacniKrok = function() {
    o.animacniKrok();
  }
}

classFade.prototype.animacniKrok = function() {
  this.nejakaHodnota++; /* nebo cokoliv jineho */
}

classFade.prototype.spustAnimaci = function() {
  setTimeout(this.docasnyAnimacniKrok, 50);
}

var instance = new classFade();
instance.spustAnimaci();


Princip: funkce volaná v timeoutu má this == window. Proto v timeoutu volám "docasnyAnimacniKrok", který žádné "this" nepoužívá a jen zavolá skutečný "animacniKrok" se správným this.
ah01
Profil
Suta
Uvedený kód vypadá OK, přijde mi ale trochu nepřehledný a některé věci lze řešit elegantněji. Zkusil jsem to tedy trochu přepsat. Dodržoval jsem při tom zavedené zvyklosti formátování a komentářů v JS, které je dobré si osvojit.
/**
 * FadeOut efekt libovolného elementu
 *  
 * @param {HTMLElemen} element
 * @param {Number} startOpacity
 * @param {Number} endOpacity
 * @param {Number} opacityStep
 * @param {Number} speed
 */
function FadeOut(element, startOpacity, endOpacity, opacityStep, speed) {

    this.element = element;
    this.startOpacity = startOpacity || 100;
    this.opacityEnd = endOpacity || 0;
    this.opacityStep = opacityStep || 5;
    this.speed = speed || 30;
    
    //inicializace elementu
    this.initStyle();
}

/**
 * Změní počáteční styl elementu nezbytný pro hladký průběh efektu  
 */ 
FadeOut.prototype.initStyle = function() {
      
    // je zde pouzit trik pro Internet Explorer s nastavenim relativni
    // pozice takovemu prvku, ktery ma pozici static
    // pro IE 8 je nastaven z-index v pripade, ze je jeho hodnota "auto"
    
    this.originalPosition = getStyle(this.element, "position");
    if(this.originalPosition!="relative" && this.originalPosition!="absolute"){
        this.element.style.position = "relative";
    }
    
    this.originalZindex = getStyle(this.element, "z-index");
    if(this.originalZindex=="auto"){
        //TODO: zde bude funkce zjistujici zIndex rodice, pripadne dalsich v hierarchii, 0 bude nastavena az v pripade, ze bude mit z-index u vsech prvku hodnotu "auto"
        this.element.style.zIndex = 0; 
    }
}

/**
 * Vrátí styl elementu na původní hodnoty
 */ 
FadeOut.prototype.revertStyle = function () {
    this.element.style.position = this.originalPosition;
    this.element.style.zIndex = this.originalZindex;
}

/**
 * Start efektu 
 */ 
FadeOut.prototype.fadeOut = function() {
  var opacity = this.startOpacity,
      that = this;
  
  // vnitřní fce. - jeden krok efektu
  function fade(){
    opacity -= that.opacityStep;
    if(opacity > that.opacityEnd){
        nastavPrusvitnost(that.element, opacity);
        setTimeout(fade, that.speed);
    }else{
        nastavPrusvitnost(that.element, that.opacityEnd); //osetreni
        that.revertStyle();
    }
  }
  
  // spustit efekt
  fade();
}
Suta
Profil
Ondráš
ah01
Díky oběma. S dovolením vámi nabídnuté varianty řádně nastuduju a během dneška nebo spíše zítřka sem připíšu případné otázky.

Trošku mě trápí, že na webu nemůžu najít žádný podrobnější tutoriál pro osvojení si správných způsobů pro objektově orientované programování v javascriptu. Základní principy jsou samože taky užitečné, ale někdy je lepší navést spíše na "praktické použití" (jako jste mi pomohli vy příklady výše) než zavalit teorií vytváření objektů (kterých je na webu dost).
_es
Profil
Suta
... v tom, kdy a jakým způsobem vytvořit objekt, ...

Treba si uvedomiť, že konštruktor je len obyčajná funkcia.
A že funkcia f pri volaní new f() robí niečo iné, ako pri volaní f(), alebo o.f() .
1) Volanie new f() na začiatku vytvorí prázdny objekt, prístupný pod this, ktorý dedí vlastnosti a metódy z objektu f.prototype a návratová hodnota funkcie bude this. Teda je to to isté, ako keby bol posledný príkaz vo funkcii return this; . Teoreticky môže funkcia aj vtedy vrátiť niečo iné, ak bude ukončená príkazom return.
2) Ak je funkcia f zavolaná ako f() , tak sa žiadny objekt nevytvára a platí (this === window) .
3) Ak je funkcia f zavolaná ako o.f(), tak sa tiež žiadny objekt nevytvára a platí (this === o) .
Tento spôsob vyžaduje, aby bola tá funkcia k o nejako "priradená".
Ešte je možné tiež použiť funkcie apply alebo call s ľubovolným objektom a ľubovolnou funkciou.
Ondráš
Profil *
Volanie new f() na začiatku vytvorí prázdny objekt, prístupný pod this, ktorý dedí vlastnosti a metódy z objektu f.prototype

Tohle patří mezi "nejvymazlenější" části Javascriptu. Ten nově vytvořený objekt "new f()" do vínku dostane jedinou věc, a to skrytou vlastnost __proto__, která je odkazem na (kupodivu vždy existující) objekt "f.prototype". Toho je pak využito vždy, když se pokusíme přistoupit k libovolné vlastnosti nově vzniklého objektu: pokud není definována přímo v něm, je rekurzivně hledána v jeho vlastnosti __proto__.

Příklad:
var F = function() {}
F.prototype.A = 31;
var f = new F();

/* toto sice vypise 31, ale pozor! Promenna 'f' nema _vlastni_ vlastnost A, nicmene odkazuje se do prototypoveho objektu sveho rodice a proto je mozne se ptat na f.A */
alert(f.A); 

F.prototype.B = 125;
alert(f.B);
/* tohle opet funguje, prestoze jsem "instanci" f nijak nezmenil - jen jsem ovlivnil f.__proto__.B :) */


Teoreticky môže funkcia aj vtedy vrátiť niečo iné, ak bude ukončená príkazom return.

A tohle je taky speciální vychytávka - hodnoty "return" jsou v případě volání s "new" ignorovány, ledaže by splňovaly typeof(hodnota) == "object". Jinými slovy:

var F1 = function() {
  return [1,2,3];
}
var f1 = new F1(); /* f1 == [1,2,3] */

var F2 = function() {
  return 17;
}
var f2 = new F2(); /* vracena hodnota je ignorovana, f2 == nove vyrobeny objekt */
_es
Profil
Ondráš
To s tým __proto__ bude asi záležitosť len niektorých implementácií JavaScriptu.
Vo Firefoxe je možné k tej vlastnosti priamo pristupovať, v IE neexistuje. No uvedený kód je samozrejme správny.

To s tou "vychytávkou return" som nevedel, niekedy sa to môže hodiť.

Ako si písal, že použitie var x = new function() { ... } je málo užitočné, tak ma napadlo podivné využitie:
var x = new function(){};
var y = new x.constructor;
var z = {};
x.constructor.prototype.A = 15;
alert(x.A); // 15
alert(y.A); // 15
alert(z.A); // undefined

Objekty x a y sú rovnakej anonymnej "triedy", z je inej "triedy" - len nešpecifikovaný objekt.
Ondráš
Profil *
Vo Firefoxe je možné k tej vlastnosti priamo pristupovať, v IE neexistuje. No uvedený kód je samozrejme správny.

Je to tak, v některých interpretech je tuto vlastnost možno přímo testovat a měnit. Termín "__proto__" jsem použil proto, že právě pod tímto názvem bývá ona skrytá reference dostupná (ve specifikaci se jmenuje [[Prototype]]). V IE je to samosebou implementováno stejně, akorát nevíme, jak se ona vlastnost jmenuje, protože není veřejná :)

Ako si písal, že použitie var x = new function() { ... } je málo užitočné, tak ma napadlo podivné využitie:

Mně napadlo zase, že pomocí "new function" je možno vykonat kód v separátním jmenném prostoru bez nutnosti použití většího množství kulatých závorek:
new function() {
  /* libovolny kod ve vlastnim scopu */
}


vs. (tradiční způsob)

(function() {
  /* libovolny kod ve vlastnim scopu */
})();
_es
Profil
Ondráš
Mně napadlo zase, že pomocí "new function" je možno vykonat kód v separátním jmenném prostoru bez nutnosti použití většího množství kulatých závorek:
Okrem "separátneho menného priestoru" má taký kód aj separátne this .
Okrem toho som zistil, že tá "return vychytávka" povoľuje vracať aj funkcie, nemusí platiť (typeof(hodnota) == "object"), obidve funkcie fungujú:
var f = (function() {
  var x=0;
  return function(){return x++;};
})();
var g = new function() {
  var x=0;
  return function(){return x++;};
};
alert(f()); // 0
alert(f()); // 1
alert(f()); // 2
alert(g()); // 0
alert(g()); // 1
alert(g()); // 2
Suta
Profil
ah01
Tebou uvedené řešení mi rozhodně přijde lépe strukturované než můj původní kód, navíc se změnou definování funkcí na úrovni prototypu. Měl bych ještě pár dalších otázek. Odpovídat může samozřejmě kdokoliv. Prosím o zbytečné nenafoukávání témat, stačí stručně.

1. Když jsem před měsíce začal pomalinku přecházet na objektové programování v javascriptu, používal jsem (a zatím používám) v začátku názvu třídy slovo "class", abych si tak odlišil třídy od obyčejných funkcí (v jiných jazycích je třída také definována pomocí class). Tedy function classFadeOut místo function FadeOut. Je to špatná cesta?

2. Chápu správně, že do "samotné" třídy, pomocí níž vytvářím instanci objektu dám pouze proměnné a metody, které jsou pro každý objekt různé, a VŠECHNY ostatní definuji "mimo" na úrovni prototypu? Není výhoda sdílení funkcí pomocí prototypové definice pouze u tříd, díky nímž budu vytvářed desítky či stovky objektů?

3. Zarazilo mě používání diakritiky u některých tvých komentářů v kódu, vždy jsem byl zvyklý takovéhoto používání se vyvarovávat. Je dnes situace jiná než dříve a diakritika v komentářích nemůže přinést žádný problém při interpretaci kódu?

4. Obezličku s duplikací "this" chápu správně tak, že "this" odkazující vždy na aktuální objekt ztrácí po zavolání funkce setTimeOut (setInterval aj.) spojitost s původním objektem a reprezentuje objekt window, tudíž je před zavoláním funkce třeba původní this uložit do jakékoliv proměnné a tak tato proměnná bude později vždy odkazovat správně na původní objekt?

5. Je určitým standardem začínat názvy tříd velkým písmenem a ostatní metody písmenem malým? Určitě mi to přijde jako dobrý nápad.

6. Jak je to s používáním proměnných definovaných uvnitř třídy či metody pomocí klíčového slova var či bez něj? Stejně, jako u funkcí? Tedy pokud použiji var, bude tato proměnná lokální a dostupná pouze uvnitř funkce (i ve všech vnořených)? V metodě fadeOut jsi definoval "that = this" bez použití var, přepsal bych si tak případnou globální proměnnou that, byla-li by definována? Není "jistější" používat raději pro všechny vnitřní proměnné tříd a metod klíčové slovo "var"?

7. Ještě by mě zajímala práce s pamětí prohlížeče. Pokud vytvořím instanci s názvem "instance", tedy var instance = new FadeOut(), kdy zanikne? Pokud později použiji stejný název pro vytvoření instance nové, tedy opět vytvořím instanci var instance = new FadeOut(), co se stane s tou původní? S objektem a všemi jeho dalšími metodami či vnořenými instancemi? Je třeba jej nějak odstranit nebo se o "vyčištění" paměti postará prohlížeč sám?

Vím, že je otázek hodně. Stačí mi kousek času od každého z vás... :) Předem díky!
_es
Profil
Suta
V metodě fadeOut jsi (ah01) definoval "that = this" bez použití var,
Pozri si to lepšie, mne to však na prvý pohľad pripadalo tiež mätúce. Ide o to, kde končí príkaz.

Není výhoda sdílení funkcí pomocí prototypové definice pouze u tříd, díky nímž budu vytvářed desítky či stovky objektů?
Prototypy prinášajú aj iné výhody, môžeš jedným príkazom predefinovať nejakú metódu-vlastnosť u všetkých objektov a tiež vytvárať "nadriadené" a "podriadené" triedy.

"this" odkazující vždy na aktuální objekt ztrácí po zavolání funkce setTimeOut (setInterval aj.) spojitost s původním objektem
Skús si znovu pozrieť tie krátke príklady, no zopakujem to: pri zavolaní o.f() bude vo funkcii f platiť (this===o), pri zavolaní (x=o.f)() bude platiť (this===window). To, na aký objekt odkazuje this, závisí len od toho, akým spôsobom bola funkcia zavolaná, this je navyše len na čítanie, nedá sa prepísať. setTimeOut, alebo aj hocijaká iná funkcia nemá ako zistiť pôvodný objekt, musí sa buď do funkcie tiež predať, alebo spôsobiť, aby bol ten objekt nejakou "fintou" priamo vo funkcii f. No vtedy samozrejme nebude prístupný cez this, ale nejak inak.

... Stejně, jako u funkcí?
Áno, sú to všetko len "obyčajné" funkcie a treba len poznať rozdiel pri tom zavolaní s new.

tedy var instance = new FadeOut(), kdy zanikne?
Je to rovnaké ako pri hocijakých iných premenných, zanikne, ak sa už nijako nedá dostať k tomu na pravej strane definície:
var instance = new FadeOut(); //existuje
var x = instance; //existuje
instance = void 0; //existuje
x = void 0; // neexistuje

Čo sa stane s „objektem a všemi jeho dalšími metodami či vnořenými instancemi?“ je len zložitejšia aplikácia toho istého princípu.

Je třeba jej nějak odstranit nebo se o "vyčištění" paměti postará prohlížeč sám?
Treba to nechať na prehliadač.

Ešte zaujímavosť, ak by si to už nepostrehol, výrazy (new FadeOut()) a (new FadeOut) spôsobujú to isté, je to taká menšia výnimka v syntaxe.
Suta
Profil
_es
Velké díky za odpovědi!

Ještě jeden praktický dotaz:
Předpokládejme, že mám na stránce více prvků, které chci skrývat a opět zobrazovat s efektem vytracení. Tedy např. menu, levý panel, pravý panel, atd. Po kliknutí na odkaz umožňující vytracení prvku tedy vytvořím instanci:
var instance = new FadeOut(muj_objekt_menu);


a poté spustím metodu fadeOut() (efekt vytracení):
instance.fadeOut();


Jelikož je možné a taky pravděpodobné, že budu chtít za malou chvíli vytvořit instanci novou pro jiný prvek na stránce, tedy:
instance = new FadeOut(levy_panel);


, je dobré již jednou vytvářené instance pro různé objekty ukládat např. do pole tak, abych při potřebě zavolat později metodu fadeOut znovu (či jinou, např. fadeIn pro zobrazení prvku) nemusel vytvářet znovu instanci, která pro prvek byla vytvořena již dříve?

Jinak řečeno otázka směřuje také k tomu, jak moc zatěžuje prohlížeč vytváření nových instancí. Tedy když vím, že budu mít na stránce více prvků, ale dopředu je přesně neznám (mohou být vytvářeny dynamicky) a budu na ně chtít aplikovat efekt fadeOut.

Je myšlenka uvedená dále zcestná? Tedy vytvoření jedné globální proměnné např. s názvem "var instance", do které při požadavku na fadeOut prvního prvku vytvořím instanci třídy pro tento prvek a spustím metodu vytracení, při požadavku na fadeOut druhého prvku vytvořím objekt pro tento prvek a spustím metodu vytracení, a při opětovném požadavku na fadeOut prvního prvku vytvořím do této proměnné znovu instanci prvního prvku. Jak bude prohlížeč zvládat takovéto operace? Je to pro něj stejně jednoduché jako poškrábat se za uchem?

Snad jsem to napsal srozumitelně...
_es
Profil
Suta
Nie je nejaká univerzálna najsprávnejšia rada.
Mal by si to používať tak, aby ti to vyhovovalo a bolo pre teba užitočné.
Z hľadiska prehľadnosti kódu, výkonu, obsadenia pamäte..., ak tie požiadavky idú proti sebe tak nejaký kompromis.
V tej tvojej prvej aplikácii konštruktoru classFade toho pri vytváraní "inštancie" vznikalo dosť veľa, okrem jednoduchých vlastností priradených k objektu aj niekoľko vnorených funkcií, ktoré obsadzujú viac pamäte, aj sú náročnejšie na vytvorenie ako nevnorené.
Pri tej zlepšenej aplikácii, čo ti poradil ah01 vzniká len samotný objekt a niekoľko jednoduchých vlastností je k nemu priradených.
Ak by záležalo na čo najrýchlejšom vytváraní a tá animácia má nejaké vhodné predvolené parametre, tak by sa dali aj tie jednoduché vlastnosti priradiť do prototypu napr.:
FadeOut.prototype.startOpacity = 100;
a ak by tá predvolená hodnota nevyhovovala, tak by sa vytvorila vlastná vlastnosť:
instance.startOpacity = 80;
Ďalej je otázne, či potrebuješ vytvárať vlastné objekty, keď už ti prehliadač toho tak či tak vytvorí vcelku dosť. Pre každý ten "prvok" už máš nejaký objekt vytvorený, tak prečo to nevyužiť:
<div id=x>xxx</div>
<div id=y>yyy</div>
<script>
var p;
try{p = document.getElementById("x").constructor.prototype;}catch(e){}
p = p || Object.prototype;

p.startOpacity = 100;
/* atď. */
p.initStyle = function() {
/* atď.*/
}
/* atď. */

var y = document.getElementById("y");
y.fadeOut();
</script>

Niektoré prehliadače tú funkčnosť priradia ku všetkým objektom, aj k takým, pri ktorých to nemá zmysel, napríklad bude možné vykonať príkaz (8).fadeOut();
No ak to robíš pre seba a nie ako knižnicu pre iných ,tak by to vadiť nemuselo.
To zisťovanie toho prototypu sa dá asi spraviť lepšie, no chcel som len trochu načrtnúť iný princíp, ktorý ti možno nemusí vyhovovať.
Suta
Profil
Přidám dotaz ohledně další zajímavosti. Mám dejme tomu takovouto funkci definovanou na úrovni prototypu:

NewWindow.prototype.createCloseButton = function() {
    var closeButton = document.creatElement("div");
    // zde prvku nastavim dalsi parametry a vlozim do prvku this.element (definovan v hlavni tride)
    var that = this;
    //prvku closeButton pridam udalost onclick, ktera spusti funkci a rodicovsky prvek (this.element) skryje
    closeButton.onclick = function() { that.element.style.display = "none"; }
}

Kód výše funguje správně. Upravím-li část kódu výše tak, že bude funkce volána způsobem níže, funkčnost (dostupnost "this") selže:

    closeButton.onclick = this.mojeFunkce;


Definice this.mojeFunkce pak bude vypadat třeba takto:

NewWindow.prototype.mojeFunkce = function() {
//nevim, jak do teto funkce dostat dany this
that.element.style.display = "none";
}


Jedine co mi funguje je něco na způsob:

    closeButton.onclick = function() { that.closeAction(this); }


tj. přeposlání odkazu na objekt parametrem funkce..

Nevím ale, zda-li je to to pravé ořechové?
_es
Profil
Suta
close.onclick = this.mojeFunkce;
Do onclick môžeš priradiť hocijakú funkciu, no aj tak bude v tej funkcii pri vyvolaní udalosti onclick vždy platiť (this===close). Na to this slúži. Vyvolanie udalosti onclick je ekvivalentné príkazu close.onclick();.
Má to výhodu, že môžeš rovnakú funkciu priradiť veľa tlačítkam, a pre každé tlačítko má tá funkcia možnosť zistiť, ktoré tlačítko bolo stlačené. Ak to zistiť nepotrebuješ, tak nemá zmysel v tej funkcii this použiť.
Používaš prototyp na to, aby si priradil každému prvku inú funkciu, to nemá veľký zmysel, funkcia stačí len jedna.
Miesto toho aby si si to správnym návrhom zjednodušil, tak si to stále viac a viac komplikuješ.
Myslím, že ti nie je celkom jasné, kedy vznikajú vnorené funkcie a aké komplikácie alebo výhody to prináša.
Najlepšie by ti asi pomohla nejaká literatúra, venujúca sa dôkladnejšie syntaxe, veľmi dobrá je: http://knihy.cpress.cz/Book.asp?ID=491
A nechať si na to dosť času na pomalšie dôkladnejšie spracovanie.
Suta
Profil
_es
Zřejmě si nerozumíme. Nevím, co je chybného na definici funkce
NewWindow.prototype.createCloseButton = function() { }

na úrovni prototypu. Já v tom naopak vidím výhodu.

Funkce má vytvořit zavírací tlačítko, vložit jej do kořenového elementu a přiřadit mu funkci onclick. Ani v této fázi nevidím žádný problém. Jediné, co jsem chtěl kvůli přehlednosti bylo místo kódu funkce přímo v prototypu dát funkci bokem a zavolat ji...
_es
Profil
Suta
To už trochu dáva zmysel, no ide o to, že než tú funkciu do onclick priradí tak ju najprv vyrobí a každé tlačítko bude mať priradenú odlišnú funkciu, navyše vnorenú.
Pritom by stačila len jedna funkcia, možno takto nejak:
NewWindow.closeButtonsOnclick = function(){/*Kód obsluhy onclick*/};
NewWindow.prototype.createCloseButton = function() {
    this.closeButton = document.createElement("div");
    // zde prvku nastavim dalsi parametry a vlozim do prvku this.element (definovan v hlavni tride)
 
    //prvku closeButton pridam udalost onclick, ktera spusti funkci a rodicovsky prvek (this.element) skryje
    this.closeButton.onclick = this.constructor.closeButtonsOnclick;
};

Ten prvý riadok slúži len na to, aby nebolo treba definovať globálnu funkciu a súčasne bola tá funkcia nejak priradená k tej "triede".
Suta
Profil
_es
ide o to, že než tú funkciu do onclick priradí tak ju najprv vyrobí a každé tlačítko bude mať priradenú odlišnú funkciu

Souhlasím, a je to také to, co nechci. Bohužel jsem však u této varianty skončil poté, když mi selhaly veškeré pokusy s odkázáním se na (kořenový) element "this.element" pomocí this ve volané prototypové funkci, tedy:

<script>
...... // prototypova funkce vytvarejici tlacitko a prirazujici udalost onclick
this.closeButton.onclick = this.mojePrototypovaFunkce;
......

// prototypova funkce volana z udalosti onclick, pracujici s promennymi instance
NewWindow.prototype.mojePrototypovaFunkce = function() {
//jakakekoliv promenne instance dostupne pod "this" jsou zde nedostupna
}
</script>


Přece nemůže být nic špatného na tom, když potřebuji jakémukoliv elementu přiřadit událost onclick svázanou s (prototypovou) funkcí, v níž se bude pracovat s elementy instance (tedy těmi, jež jsou v hlavní třídě dostupné pod "this").

Tvému řešení pomocí "constructor" pak zaprvé nerozumím, za druhé mi nefunguje.
_es
Profil
Suta
Tvému řešení pomocí "constructor" pak zaprvé nerozumím, za druhé mi nefunguje.
Mne táto základaná konštrukcia funguje:
function NewWindow(){};
NewWindow.closeButtonsOnclick = function(){/* prístup k celému objektu cez: this.newWindow */};
NewWindow.prototype.createCloseButton = function() {
  this.closeButton = document.createElement("div"); this.closeButton.onclick = this.constructor.closeButtonsOnclick;
  this.closeButton.newWindow = this;
};
var x = new NewWindow; x.createCloseButton();
alert(x);alert(x.closeButton);alert(x.closeButton.onclick); // Len na overenie správneho vytvorenia objektu x

Namiesto this.constructor sa dá použiť aj NewWindow, no pri premenovaní by sa mohlo na to zabudnúť.
Jednoducho tá funkcia closeButtonsOnclick pred jej priraďovaním do objektov musí existovať a byť nejak dostupná, vytvorenie globálnej funkcie na to nie je dobré, tak sa priradí do vytvorenej vlastnosti rovnakého mena konštruktora NewWindow.
Pri skutočnom nastatí udalosti onclick však bude v tej funkcii platiť, že this bude ten <div> closeButton a nie celý objekt, čo ho obaľuje.
Ak sa chceš v tej funkcii dostať k tomu celému "obalu", tak ho musíš k tomu <div>u nejako priradiť.
A asi by to malo byť nejako trochu lepšie pomenované, tie pomenovania vyzerajú mätúco.
_es
Profil
Suta
Přece nemůže být nic špatného na tom, když ...

Obvykle nie, no tá zviazanosť vzniká vytvorením vnorenej funkcie, čo môže byť niekedy zdrojom ťažko odhaliteľných problémov.
Trochu som sa pohral a vytvoril jednoduchý príklad:
<script>
var n1 = 100, n2 = 1000000;
var x = "x";
var f = [];
var h = function(){x && alert("ok"); };
function g(){
//  var h = function(){x && alert("ok"); };
  var x = [];
  for(var j = 0; j < n2; ++j) x[j] = j;
  f[n] = h;
}
for(var n = 0; n < n1; ++n) g(), document.write(i + 1, "/", n1, "<BR>");
document.write("koniec");
f[0]();
</script>

Výsledkom je vytvorenie poľa 100 funkcií, ktoré po vyvolaní len vypíšu hlášku. Prvá z nich je na konci spustená.
Vo funkcii g sú nejaké pamäťovo náročné operácie.
Skript je treba vyskúšať na rôznych prehliadačoch a sledovať obsadenie pamäte počas behu, aj po skončení, prípadne aj chvíľu počkať na "upratanie" po skončení.
Pre niektoré prehliadače treba zredukovať n1, alebo aj n2.
Potom to isté spraviť po odkomentovaní toho zakomentovaného riadka.
Suta
Profil
_es
Mne táto základaná konštrukcia funguje:
Teď tedy funguje i mně. Nepochopil jsem správně funkčnost, díky!

Moje skutečně poslední otázka:

//vytvorim instanci noveOkno, v niz bude vytvoren novy objekt dostupny pod this.element
var noveOkno = new NewWindow();

//definuji dve metody, prvni objekt zobrazi, druha skryje
NewWindow.prototype.openWindow = function() { this.element.style.display = "block" }
NewWindow.prototype.closeWindow = function() { this.element.style.display = "none" }

//zavolani metody, ktera prvek zobrazi
noveOkno.openWindow();

//zavolani metody, ktera prvek skryje
noveOkno.closeWindow();

-------------------------------------------------------------------------------------------------------

Kód výše pracuje správně. Pokud však poslední řádek kódu upravím tak, že jej budu chtít zavolat po určitém čase pomocí setTimeout, v metode closeWindow pak bude platit this===window

//funkcnost pochopitelne selze, nebot v metode closeWindow this nebude odkazovat na objekty tridy
setTimeout(noveOkno.closeWindow, 3000);


V podstatě se jedná o analogii vyřešeného případu v [#7], teď se však jedná o volání metody pomocí setTimeout mimo třídu, tedy z hlavního kódu.

Problém se setTimeout je pro mě v těchto dnech kámenem úrazu. Za případnou nápomoc předem díky!

Po vyřešení tohoto konkrétního případu prosím moderátory o uzamčení tématu.
_es
Profil
Suta
teď se však jedná o volání metody pomocí setTimeout mimo třídu, tedy z hlavního kódu.

Pri funkcii zadanej ako argument do setTimeout nezáleží kde je setTimeout volaný, ale len o tú samotnú funkciu,
Kde a ako je definovaná, či je vnorená (definovaná v inej funkcii), alebo globálna, môže tam byť napríklad aj funkcia definovaná v inom okne (ráme), a pod.
Obvykle teda potrebuješ do setTimeout predať takú funkciu, pri ktorej nezáleží na tom, aké je v nej this, keď sa zavolá:
To dosiahneš jednoducho podľa vzoru [#4] predposledný riadok:
setTimeout(function(){noveOkno.closeWindow(); }, 3000);

Alebo si definuješ funkciu, ktorá ti bude vracať takto definovanú funkciu (vzor 5. a posledný riadok [#4])
Vyskúšaj si spustiť ten posledný skript v [#24], je zaujímavé, čo spôsobí taký drobný rozdiel v kóde a ako odlišne rôzne prehliadače pracujú s pamäťou.

Zamknúť si môžeš aj sám, no môže tu ešte prispieť niekto iný niečím zaujímavým k téme a vlákno sa možno zíde aj iným, preto sa mi to nezdá vhodné.
Suta
Profil
_es
Je to tak jak píšeš. Doopravdy jsem netušil že this ve volané funkci může být rozdílné při těchto "odlišných" voláních:
  setTimeout(noveOkno.closeWindow, 3000);
  setTimeout(function() { noveOkno.closeWindow(); }, 3000);


Díky moc za všechny tvé rady, hodně mi pomohly!
Suta
Profil
Nyní váhám, zda-li bych pro otázku neměl vytvořit nové téma, nicméně se vztahuje k "prototype" v javascriptu probíraném výše, tak ji zkusím přidat sem.

Při vytváření vlastní javascriptové knihovny s efekty pro objekty na stránce jsem dospěl do situace, kdy:

1. mám určitou třídu, díky níž vytvořím objekt s danými parametry
2. třída má na úrovni prototypu definovánu metodu/metody, jež s daným objektem provádí různé operace.

Tedy např. budu mít:
function VytvorObjekt() { ... }
VytvorObjekt.prototype.metodaFadeOut = function() { ... }


3. dále budu mít úplně jinou třídu, s vlastními metodami, díky níž vytvořím objekt a poté budu chtít využít metody metodaFadeOut, kteá je přidružena k jiné (první) třídě.

Jsem ve stádiu, kdy pomalu začínám využívat "sdílení metod" a dědičnost, ale nevím, jak správně sestrojit kód pro situaci, když budu pro daný objekt chtít zároveň využít jednu z metod třídy 1, jednu z metod třídy 2 a jednu z metod třídy 3, ale nechtěl zbytečně vytvářet tři nové instance.
Suta
Profil
Uvedu příklad kódu, který - prozatím - používám:

  // vytvorim novy objekt, kterym budu chtit prekryt celou stranku; prvek bude dostupny pod this.element (příp. test.element)
  test = new PrekryvnyObjekt("body");
  // spustim metodu, jez prekryvny objekt vlozi do tagu "body" a roztahne pres celou jeho oblast
  test.prekryj();
  //nyni budu chtit vyuzit efekt ztmavnuti prekryvneho objektu
  ztmavnuti = new Fade(test.element);
  ztmavnuti.speed = 80;
  ... // pripadne upresnim dalsi parametry, nevyhovuji-li vychozi
  // spustim fadeIn prvku
  ztmavnuti.fadeIn();
  ...
  // a takto muzu prekryvny objekt zpetne odstranit 
  test.odkryj();


Napadlo mě tedy, zda-li není výhodné "všeobecné" metody definovat na nejvyšší úrovni, tedy pomocí
Object.prototype.metodaFadeOut

,díky čemuž nemusím vytvářet nové instance, ale tato metoda bude dostupná pro všechny nově vytvořené objekty.
Yur4Y
Profil
Suta
Napadlo mě tedy, zda-li není výhodné "všeobecné" metody definovat na nejvyšší úrovni, tedy pomocí Object.prototype.metodaFadeOut
Nie je. Nepôjde to v Exploreri.
« 1 2 »

Vaše odpověď

Mohlo by se hodit

Neumíte-li správně určit příčinu chyby, vkládejte odkazy na živé ukázky.
Užíváte-li nějakou cizí knihovnu, ukažte odpovídajícím, kde jste ji vzali.

Užitečné odkazy:

Odkud se sem odkazuje


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: