Autor Zpráva
Witiko
Profil
Ačkoliv se javascriptem jako takovým zabývám už delší dobu, občas se stane, že mi stále připraví perné chvilky. Jednu takovou jsem zažil, když jsem po připojení posluchače na iframe zjistil, že navracená funkce je spouštěna pod scope daného iframe:

function Konstruktor() {
  element.addEventListener("load", this.funkce, false);
}

Konstruktor.prototype.funkce = function() {
  alert(this === element); // True
  alert(this instanceof Konstruktor); // False
}

Byv mírně vytočen tímto chováním, jež nebylo tím, co jsem potřeboval, jsem po chvíli skončil s tímto řešením:

function Konstruktor() {
  var that = this;
  element.addEventListener("load", this.funkce, false);
  this.funkce = function() {
    alert(this === element); // True
    alert(this instanceof Konstruktor); // False
    alert(that === element); // False
    alert(that instanceof Konstruktor); // True
  }
}

Toto řešení, ač funkční, ale rozhodně není ideální a takovýto způsob definice veřejných funkcí prototypu způsobí tvoření nového objektu anonymní funkce s každou instancí daného prototypu, což není žádoucí. Má někdo návrh lepšího řešení, které zachovává definici pomocí Konstruktor.prototype.funkce?
_es
Profil
Witiko:
když jsem po připojení posluchače na iframe zjistil, že navracená funkce je spouštěna pod scope daného iframe
Pri funkcii, spustenej ako globálna funkcia v globálnom kontexte, ukazuje this na globálny objekt, teda objekt window, v ktorom je funkcia definovaná. Ak má this v tomto prípade ukazovať na iný globálny objekt, treba, aby bola funkcia definovaná v inom okne (iframe, frame, …). Netýka sa to len objektu this, ale aj ostatných globálnych premenných a vlastností.
V tom tvojom kóde asi nerátaš s IE.
Pri priradení funkcie z iného okna ako ovládača udalosti je this rovnaké, ako by bolo pri hocijakej inej funkcii. No pre premenné a globálne vlastnosti platí to, čo je uvedené vyššie.
Witiko
Profil
_es:
Nezdá se být pravda, že by funkce přebírala this od objektu pod kterým je definovaná, spíše jej přebírá od objektu pod kterým je volaná:
function Konstruktor() {
  this.funkce();
}

Konstruktor.prototype.funkce = function() {
  alert(this instanceof Konstruktor); // True
}

Jak bys tedy funkci napsal tak, aby zachovala funkčnost druhého kódu z [#1] při zachování zápisu kódu prvního s použitím definice pomocí Konstruktor.prototype.funkce?

Takovýto zápis stále není ideální, stále dochází ke tvoření nových a nových privátních funkcí funkce s každou další instancí:

function Konstruktor() {
  var that = this;
  element.addEventListener("load", funkce, false);
  function funkce() {
    that.funkce();
  }
}

Konstruktor.prototype.funkce = function() {
  alert(this === element); // False
  alert(this instanceof Konstruktor); // True
}
_es
Profil
Witiko:
Ani konštruktory rovnakých dátových typov v rôznych oknách sa nerovnajú. Budeš sa musieť podľa toho už od začiatku zariadiť a nie opačne násilne prispôsobovať kód.
Witiko
Profil
_es:
Jediné o co mi jde je to, abych mohl funkci instance prototypu připojit na posluchač událostí a aby po spuštění události měla zavolaná funkce přístup k referenci na danou instanci prototypu. Chci toho příliš?
_es
Profil
Witiko:
Vyjadruješ sa príliš neurčito a všeobecne.
Prečo používaš metódu addEventListener nefungujúcu v IE?
Čo je tá premenná? element v tvojom kóde?
Ak to je objekt window, ktorému je priradená funkcia definovaná v inom okne, ako ovládač udalosti onload, tak pomocou this je možný prístup k oknu, kde udalosť vznikla, a inými spôsobmi prístup k oknu, kde bola funkcia definovaná.
Witiko
Profil
_es:
Vyjadruješ sa príliš neurčito a všeobecne.
Protože mi spíše než o konkrétní problém jde o všeobecný problém a sice: Jak připojit funkci k posluchači tak, aby si libovolným způsobem zachovala referenci na instanci prototypu pod kterou náleží.

Prečo používaš metódu addEventListener nefungujúcu v IE?
Pro účely ilustrace? Celý "kód" v prvním příspěvku je spíše zjednodušené schéma poukazující na problém, abych to tu nezanášel tunami balast kódu, který s problémem nesouvisí. Ale pro mě za mě: element.addEventListener?element.addEventListener("load", funkce, false):element.attachEvent("onload", funkce);

Čo je tá premenná? element v tvojom kóde?
Naprosto libovolný element podporující event onload, je to pro účely příkladu tak podstatné? Jak říkám v [#1], šlo o iframe:
Jednu takovou jsem zažil, když jsem po připojení posluchače na iframe zjistil, že navracená funkce je spouštěna pod scope daného iframe

Dám jiný příklad: Řekněme, že si vytvořím prototyp Člověk, kterému při volání konstruktoru přiřadím atribut jméno:
function Člověk(jméno) {
  this.jméno = jméno;
}

Prototyp Člověk bude mít funkci řekniJméno, která způsobí, že se pomocí window.alertu zobrazí pozdrav:
Člověk.prototype.řekniJméno = function() {
  alert("Ahoj, já jsem " + this.jméno);
}

Co udělám, pokud budu chtít v konstruktoru napojit funkci řekniJméno pomocí addEventListener (nebo attachEvent když už zmiňuješ IE) na načtení obsahu stránky (nebo libovolného elementu)?
_es
Profil
Witiko:
V IE ale pri metóde attachEvent nezodpovedá objekt this objektu this pri metóde addEventListener.
Ak už teda musíš používať funkcie definované v rôznych rámoch toho istého okna prehliadača, tak používaj odkaz na objekt top, ktorý vo všetkých rámoch iframe a pod. ukazuje na ten istý objekt window.
Witiko
Profil
_es:
Nechci používat funkce definované na různých rámech jednoho okna, nevím jak jsi k tomu přišel. Neposlouchám na objektu window dokumentu uvnitř daného iframe, ale na elementu iframe - tzn. ne window.frames[xyz] ale document.getElementsByTagName("iframe") - pracuji celou dobu v jednom dokumentu. Ohledně attachEvent a addEventListener: attachEvent v daném kódu stejně použit nebude, protože se jedná o userScript.

Jinak celkově tvojí odpověď s ohledem na mojí otázku mírně nechápu a problémem není jazyková bariéra. Příspěvek [#8] nemá alespoň co já jsem pochopil žádnou spojitost s otázkou k ukázkovému příkladu objektu Člověk, kterou pokládám v příspěvku [#7].
_es
Profil
Witiko:
Neposlouchám na objektu window dokumentu uvnitř daného iframe, ale na elementu iframe
Element iframe je dokument HTML načítaný do stránky a má vlastný globálny objekt window. Takže ty „počúvaš“ na globálnom objekte window toho konkrétneho iframe. Každý iframe na stránke vytvára vlastný objekt typu window, rovnakého typu, ako má celé okno.
Witiko
Profil
_es:
Takže ty ‚počúvaš‘ na globálnom objekte window toho konkrétneho iframe
var iframe = document.createElement("iframe");
iframe.name = "rámec";
document.body.appendChild(iframe);

window.frames["rámec"] != iframe

iframe instanceof Element == true // Element iframe - zde „počuvám“
window.frames["rámec"] instanceof Element == false // Objekt window daného iframe
_es
Profil
Witiko:
Z toho posledného a iných príspevkov, som pochopil, že sa nejako snažíš využiť udalosť onload elementu iframe.
Bez konkrétnejšieho popisu využitia a konkrétnejšieho popisu problému asi nepôjde dostatočne konkrétne poradiť.
window.frames["rámec"].onload = funkcia;
nefunguje podľa očakávania?
Witiko
Profil
_es:
nefunguje podľa očakávania?
Funguje, nicméně v userScriptech pod prohlížeči běhajícími pod webkitem je přístup k jiným objektům window bohužel blokován a script samotný má přístup k dokumentu jen pomocí DOM metod, jelikož ten je obalený v XPCWrapperu.

Nicméně všeobecně si myslím, že tohle s mým problémem nesouvisí. Pro účely příkladu můžeme poslouchat klidně na objektu window bez jakéhokoliv iframe. Příklad by v tom případě vypadal takto:

function Člověk(jméno) {
  var that = this;
  this.jméno = jméno;
  window.addEventListener("load", this.funkce, false);
  this.funkce = function() {
    alert("Ahoj, já jsem " + that.jméno);
  }
}

Definice globálních funkcí uvnitř konstruktoru je ale znásilňování kódu a způsobuje tvorbu spousty anonymních funkcí. Je tu způsob jak přepsat výše uvedenou funkci pomocí standardní definice funkcí prototypu?
_es
Profil
Witiko:
A tá funkcia Člověk je použitá ako konkrétne? A kde konkrétne je definovaná?
Stále nechápem, v čom je ten problém, podstatnú časť zatajuješ a stále tu rozvádzaš nepodstatné veci.
Witiko
Profil
_es:
Nějak takhle?
<!doctype><html><head>
<script type = "text/javascript">

  var jan = new Člověk("Jan Novák");
  
  function Člověk(jméno) {
    var that = this;
    this.jméno = jméno;
    window.addEventListener("load", this.funkce, false);
    this.funkce = function() {
      alert("Ahoj, já jsem " + that.jméno + ".");
    }
  }

</script></head><body> obsah </body></html>

A očekávám, že po načtení obsahu okna a triggernutí window.onload eventu vyskočí window.alert s hláškou "Ahoj, já jsem Jan Novák.". A to se také skutečně stane, ale ten kód je slátanina.

Stále nechápem, v čom je ten problém
Problém je v desátém řádku výše uvedeného kódu - v definici funkce prototypu uvnitř jeho konstruktoru pomocí anonymní funkce.
_es
Profil
Witiko:
Musíš rátať aj s tým, že metóda alert nevisí len tak v lufte, ale je to tiež metóda niektorého objektu window. Ak to používaš v spojitosti s viacerými objektmi window, teda frame, iframe, iné okná, … Napríklad Mozilla pri viacerých oknách podľa toho prepína focus okna.
V tomto konkrétnom kóde, teda s použitím new, je this v tej funkcii závislé od toho, kde je funkcia Člověk definovaná, teda aj konštruktor toho nového objektu bude zviazaný s objektom window definície funkcie.
Witiko
Profil
_es:
je this v tej funkcii závislé od toho, kde je funkcia Člověk definovaná, teda aj konštruktor toho nového objektu bude zviazaný s objektom window definície funkcie
Uvnitř konstruktoru odkazuje this na nově vytvořenou instanci prototypu. Kód z mého předchozího příspěvku [#15] funguje, jediné o co mi jde je jeho přepis takovým způsobem, aby funkci funkce nebylo nutné definovat uvnitř funkce konstruktoru (Člověk) ale mimo pomocí Člověk.prototype.funkce = function() {...}. Je to možné?
_es
Profil
Witiko:
ediné o co mi jde je jeho přepis takovým způsobem, aby funkci funkce nebylo nutné definovat uvnitř funkce konstruktoru (Člověk) ale mimo pomocí Člověk.prototype.funkce = function() {…}. Je to možné?
Funkcia je do prototypu len voľne priradená. Ak sa v tej funkcii odkazuješ na this, musíš zabezpečiť aby this odkazovalo na správny objekt, napríklad tak, aby nastalo volanie v tvare: objekt.funkcia();
Witiko
Profil
_es:
Právě, jde mi o to zajistit, aby this v této funkci odkazovalo na objekt. Při použití window.addEventListener("load", objekt.funkce, false) neodkazuje potom při zavolání funkce při události "onload" this v této funkci na objekt, ale na window. A právě s tím si nevím rady.

Je samozřejmě možné zajistit, aby this odkazoval na objekt pomocí opisu: window.addEventListener("load", function() {objekt.funkce}, false), ale pak se jedná o anonymní funkci a nelze daného posluchače pomocí removeEventListener odstranit.

A když dám anonymní funkci jméno: window.addEventListener("load", function funkce() {objekt.funkce}, false) tak sice lze použít removeEventListener, ale stále nelze odstranit posluchače z ostatních funkcí prototypu, protože tato privátní funkce funkce je přístupná pouze z konstruktoru.
_es
Profil
Witiko:
Při použití window.addEventListener("load", objekt.funkce, false) neodkazuje potom při zavolání funkce při události "onload" this v této funkci na objekt, ale na window. A právě s tím si nevím rady. :)
Tak vytvoríš len minimálnu verziu funkcie:
window.addEventListener("load", function(){that.funkce();}, false);
Witiko
Profil
_es:
Jistěže, ale jak už jsem zmínil, tento zápis mi neumožňuje následně daného posluchače odstranit pomocí removeEventListener díky anonymitě funkce.
_es
Profil
Witiko:
tento zápis mi neumožňuje následně daného posluchače odstranit pomocí removeEventListener díky anonymitě funkce.
Tak potom si tú krátku funkciu budeš musieť do niečoho priradiť, napríklad do vlastnosti f toho objektu:
window.addEventListener("load", that.f=function(){that.funkce();}, false);
Witiko
Profil
_es:
Ano, nicméně poté jsme opět u konceptu, kdy s každou novou instancím tvořím zbytečně funkci navíc, která v tomto případě ani na rozdíl od anonymní funkce nebude automaticky smazána garbage collectorem. Pravdou zůstává, že po spuštění eventu můžu vlastnost f deletenout a až na celkovou ohavnost té implementace (co do logiky a čitelnosti kódu) půjde nejspíš o menší zlo, než definice funkce funkce v konstruktoru prototypu.

Pokud nenajdu elegantnější řešení, tak asi použiju toto. Děkuju za trpělivost, diskusi provázely problémy se vzájemným porozuměním, no nakonec jsme se přece jenom domluvili. :)

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:

0