Kirjautuminen

Haku

Tehtävät

Keskustelu: Nettisivujen teko: JavaScript periyttäminen ja Event

Sivun loppuun

kayttaja-3842 [07.06.2014 23:53:52]

#

Terve kaikki,

Olisin kiinnostunut tietämään onnituisko JavaScriptillä jotenkin liittämään base -"luokassa" liitetyn eventin kutsumaan periytetyn luokan metodia.

Eli käytännössä miten saan A:ssa liitetyn eventin kuuntelijan kutsumaankin eventin sattuessa B:n method() eikä A:n metod(). Ongelmahan on sinänsä selvä koska bind kertoo että kutsu this = A. Mutta voiko tuon bindin korvata jotenkin järkevästi että kutsuukin B::method().

function A()
{
  window.addEventListener( 'resize', bind( this, this.method ), false );
}

A.prototype.method = function()
{

}

function B()
{

}

B.prototype = new A();

B.prototype.method = function()
{
 // Miten saan eventin kutsumaankin tätä enkä A::method -metodia
}

jlaire [08.06.2014 03:51:13]

#

Ilmeisesti oletat, että B() kutsuu automaagisesti A():ta, mutta niin ei tapahdu. A:sta luodaan tasan yksi instanssi ja se asetetaan B.prototypeksi. Jos halutaan suorittaa jotain alustuskoodia kun B():tä kutsutaan, täytyy koodi laittaa B():n sisälle.

Koodipätkien minimoiminen on yleisesti ottaen hyvä idea, mutta tässä lopputulos on niin abstrakti, että on vaikea sanoa mitä alunperin oltiin tekemässä ja miten se kannattaa toteuttaa.

Miksei tapahtumakuuntelijaa voisi yksinkertaisesti asettaa B():ssä? Usein perintä vain sekoittaa asioita.

Jos nyt välttämättä halutaan, että B:n alustus suoritetaan kutsumalla A():ta, sen voi tehdä eksplisiittisesti:

function B()
{
  A.call(this);
  // Tai näin:
  // Object.getPrototypeOf(this).constructor.call(this);
}

... tämä periaatteessa vastaa kysymykseesi, mutta ei tunnu kovin järkevältä.

The Alchemist [08.06.2014 10:25:52]

#

Unohda räpeltäminen ja käytä jotain valmista kirjastoa, josta löytyy toimiva periyttäminen. Minä kopioin usein omiin projekteihini Backbonen (ja Underscore.js:n) extend-funktion.

kayttaja-3842 [08.06.2014 19:17:29]

#

jlaire kirjoitti:

Ilmeisesti oletat, että B() kutsuu automaagisesti A():ta, mutta niin ei tapahdu.

Lähinnä alunperin ajattelin että toimisi niikuin C++ virtuaali -funktio. Eli et voisin määrittää tuohon metodille ns. uuden toiminnon eri luokista josta kanta luokka on peritty.

Kuten jo aloitus tekstissäni selitinkin epäilykseni A konstruktorissa bindataan A eventin kutsuun joten event listener kutsuu A:n instanssia. Lähinnä olin kinnostunut olisiko mitään tapaa saada tuon funktio kutsun hakemaan tuota B:tä.

Mutta ilmeisemmin tämä ei nimeen onnistu koska A näkee vain itsensä.

Tosin javascriptissähän periytys toimii tuolla new -operaattorilla.

The Alchemist kirjoitti:

Unohda räpeltäminen ja käytä jotain valmista kirjastoa, josta löytyy toimiva periyttäminen. Minä kopioin usein omiin projekteihini Backbonen (ja Underscore.js:n) extend-funktion.

Itsekkin ajattelin tuota valmiin kirjaston käyttöä. Muistaakseni jQuerykin taitaa sisältää tuon extend -funktion. Pitänee käyttää sitten jotain valmista kirjastoa. :)

Kiitoksia vastanneille avusta.

kayttaja-3842 [09.06.2014 10:23:47]

#

...pitänee vielä vähän kysästä tarkemmin. Kokeilin tuossa paria lisäkirjastoa ja päädyin käyttämään prototype nimistä kirjastoa.

Kuitenkin nämä kirjastot ei tuo ratkaisua ongelmaani. Eli miten javascriptillä saisi näppärästi base -luokassa kytketyt eventin kutsumaan derived -luokan metodia base -luokan metodin sijaan?

Eli tarkoitus olisi että voisin määrittää base -luokaan perus eventit ja määrittää eri derived -luokissa noitten eventien käyttötavat.

Googlekaan ei anna oikein mitään järkevää tulosta. Heittää useimmiten java ratkaisut eikä javascript ratkaisua.

jlaire [09.06.2014 11:09:21]

#

The Alchemist kirjoitti:

Unohda räpeltäminen ja käytä jotain valmista kirjastoa, josta löytyy toimiva periyttäminen.

Kirjasto on yksi vaihtoehto, toinen on opetella miten JavaScript toimii ja käyttää sitä järkevästi. Puhtaan JavaScriptin kirjoittamisen ei suinkaan tarvitse olla "räpeltämistä".

kayttaja-3842 kirjoitti:

Eli miten javascriptillä saisi näppärästi base -luokassa kytketyt eventin kutsumaan derived -luokan metodia base -luokan metodin sijaan?

Yksi vaihtoehto voisi olla tehdä erillinen init()-metodi A:han ja kutsua sitä konstruktor(e)ista.

function A() { this.init(); }
A.prototype.init = function() {
	window.addEventListener('resize', this.callback.bind(this), false);
};
A.prototype.callback = function() {
	console.log('A');
};

function B() { this.init(); }
B.prototype = new A();
B.prototype.callback = function() {
	console.log('B');
};

Oikea koodiesimerkki olisi kuitenkin edelleen valaiseva, koska voi olla että perintä ei ylipäätään ole tarpeen.

kayttaja-3842 [09.06.2014 12:04:50]

#

Hmm, minulla tuo ei toiminut. Antoi Consoliin 'A', vaikka loin olion B -luokasta.

Eikös tuossakin ole sama ongelma kuin minun esimerkissä. Bindaat A:n (this) callbackiin ja koska A on oma instanssi niin viittaa aina A::callback.

jlaire [09.06.2014 13:00:48]

#

Consoliin tulee 'A' koska A:sta luodaan instanssi, ja A() rekisteröi sen. Voit totta kai ottaa init()-kutsun poist A():sta, jos haluat.

Jos luot instanssin B:stä niin konsoliin tulee (myös) 'B'. Toimii ainakin minulla, enkä usko että tässä on mitään selainriippuvaista.

The Alchemist [09.06.2014 13:04:35]

#

jlaire kirjoitti:

The Alchemist kirjoitti:

Unohda räpeltäminen ja käytä jotain valmista kirjastoa, josta löytyy toimiva periyttäminen.

Kirjasto on yksi vaihtoehto, toinen on opetella miten JavaScript toimii ja käyttää sitä järkevästi. Puhtaan JavaScriptin kirjoittamisen ei suinkaan tarvitse olla "räpeltämistä".

Tämä toteamus olisi paljon helpompi ottaa vakavissaan, ellet sortuisi räpeltämiseen oman esimerkkisi kanssa.

Ongelman ydin noissa yritelmissä on se, että A:n konstruktori suoritetaan jo ennen kuin mitään instansseja on varsinaisesti luotu. Näin koska B:n prototyyppiä luodessa (eli määriteltäessä luokkaa B) täytyy instantioida A.

Tutustukaa nyt vain siihen Backbonen extend-funkkariin ja katsellaan sitten uudestaan.

jlaire [09.06.2014 13:09:22]

#

The Alchemist kirjoitti:

Tämä toteamus olisi paljon helpompi ottaa vakavissaan, ellet sortuisi räpeltämiseen oman esimerkkisi kanssa.

Kuten olen monta kertaa sanonut, en itse toteuttaisi asiaa näin.

Vastaan vain kysyjän kysymykseen "miten tehdä asia X". Toki voisin olla vastaamatta ja antaa elitistisiä vinkkejä sen sijaan. "Älä tee asiaa X" tai "käytä frameworkkia A tai B plz" toimivat aina ja niistä tulee kaikille hyvä mieli.

The Alchemist kirjoitti:

Ongelman ydin noissa yritelmissä on se, että A:n konstruktori suoritetaan jo ennen kuin mitään instansseja on varsinaisesti luotu.

B.prototype on A:n instanssi. B:n instanssit eivät ole A:n instansseja.

Tämän voi joko ymmärtää ja hyväksyä tai itkeä sitä että JavaScript ei olekaan Java ja funktiot eivät olekaan luokkia.

kayttaja-3842 [09.06.2014 13:22:29]

#

jlaire kirjoitti:

Consoliin tulee 'A' koska A:sta luodaan instanssi, ja A() rekisteröi sen. Voit totta kai ottaa init()-kutsun poist A():sta, jos haluat.

Jos luot instanssin B:stä niin konsoliin tulee (myös) 'B'. Toimii ainakin minulla, enkä usko että tässä on mitään selainriippuvaista.

Niin edelleenkin olen varma ettei koodisi voi toimia. Vaan antaa A:n consoliin.

Luon B:stä instanssi ja antaa Consoliin 'A'. Ymmärrän kyllä syyn ja olen alun perinkin sen jo ymmärtänyt kuten jo aloitus tekstissäni laitoin. Käsittääkseni tuo sinun esimerkki on vastaava minun aloitus tekstissä laitaamaa koodia.

<html>
	<head>
		<title>test</title>
		<script type="text/javascript" src="test.js">
	</head>
	<body>
	<script language="JavaScript">
		var b = new B();
	</script>
	</body>
</html>

Kuitenkin projektiin olen jo heti alussa vääntänyt php pohjaisen javascript laijittelijan joka luo monesta js tiedostosta yhden riippuvuus järjestyksessä. Näin ollen ajattelin rakentaa php koodiin lisäksi vielä extend toiminnon joka kopioi base -luokan metodit toiselle luokalle.

Näin pääsen eteenpäin ja ongelma ratkeaa.

jlaire [09.06.2014 13:25:27]

#

kayttaja-3842 kirjoitti:

Niin edelleenkin olen varma ettei koodisi voi toimia.

Ymmärrän kyllä syyn ja olen alun perinkin sen jo ymmärtänyt kuten jo aloitus tekstissäni laitoin. Käsittääkseni tuo sinun esimerkki on vastaava minun aloitus tekstissä laitaamaa koodia.

Olet väärässä, et selvästikään ymmärrä ja käsität väärin.

Headin script-tagia ei suljeta. Jopa putkan koodiväritys osasi debugata tämän. Sulje tagi niin konsoliin tulee myös 'B'.

Mutta ihan sama, käytä sitä extendiä jos tuntuu helpommalta.

kayttaja-3842 [09.06.2014 14:12:37]

#

Tosiaan jäikin nopeasti testattaessa tuo </script> -tagi laittamatta ja antoi kuitenkin tuon 'A':n consoliin.

No kuitenkin, nytten näyttäisi toimivan.

Periaatteessa tämähän on aikalailla se mitä hainkin.
Kiitos avusta.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta