this bij callback functies

Status
Niet open voor verdere reacties.

Lapixx

Gebruiker
Lid geworden
2 mei 2008
Berichten
132
Hallo,

Ik heb een JS class geschreven voor het gebruik van de navigator.geolocation.watchPosition functie (deze functie is bedoeld om de geografische locatie mbv GPS/WiFi te bepalen, en werkt momenteel nog niet in elke browser). De watchPosition functie kent 3 argumenten, waarvan de eerste 2 callbacks zijn (succes/fail callbacks).

De reden dat ik een class gebruik is omdat er nogal wat variablen moeten worden opgeslagen, en daar ligt dan ook mijn probleem: Variables in een class kun je defineren met this.variablenaam. Echter, wanneer de watchPosition functie de callback aanroept, is this niet meer een verwijzing naar het object, maar naar... navigator.geolocation neem ik aan?

De callback functie is een methode van de class, ik roep watchPosition dan ook als volgt aan: navigator.geolocation.watchPosition(this.succes,this.fail). Die succes functie is dan weer gedefineerd door: geoObject.prototype.succes=function(position){ .... }

In die callback functie moeten een aantal variablen van het object gebruikt worden, en een method aangeroepen worden. this.methodenaam() doet echter niks meer, en na lang zoeken trok ik de conclusie dat THIS niet meer naar het object verwijst, en daardoor de methoden niet meer 'werken'.

Ik hoop dat het zo duidelijk is, ik ben namelijk zelf ook niet helemaal zeker van het probleem... Hoe dan ook, als this inderdaad niet meer naar het object verwijst, hoe kan ik dit dan oplossen?

Lapixx
 
Hallo,

Ik heb een JS class geschreven voor het gebruik van de navigator.geolocation.watchPosition functie (deze functie is bedoeld om de geografische locatie mbv GPS/WiFi te bepalen, en werkt momenteel nog niet in elke browser). De watchPosition functie kent 3 argumenten, waarvan de eerste 2 callbacks zijn (succes/fail callbacks).

De reden dat ik een class gebruik is omdat er nogal wat variablen moeten worden opgeslagen, en daar ligt dan ook mijn probleem: Variables in een class kun je defineren met this.variablenaam. Echter, wanneer de watchPosition functie de callback aanroept, is this niet meer een verwijzing naar het object, maar naar... navigator.geolocation neem ik aan?

De callback functie is een methode van de class, ik roep watchPosition dan ook als volgt aan: navigator.geolocation.watchPosition(this.succes,this.fail). Die succes functie is dan weer gedefineerd door: geoObject.prototype.succes=function(position){ .... }

In die callback functie moeten een aantal variablen van het object gebruikt worden, en een method aangeroepen worden. this.methodenaam() doet echter niks meer, en na lang zoeken trok ik de conclusie dat THIS niet meer naar het object verwijst, en daardoor de methoden niet meer 'werken'.

Ik hoop dat het zo duidelijk is, ik ben namelijk zelf ook niet helemaal zeker van het probleem... Hoe dan ook, als this inderdaad niet meer naar het object verwijst, hoe kan ik dit dan oplossen?

Lapixx

Het gebruik van this in deze context zorgt inderdaad voor problemen. Het this keyword wordt in javascript namelijk ook gebruikt voor de aanroepende functie. Wanneer een functie dus aangeroepen wordt door een event of een functie, verwijst this hiernaar.
Je kan dit voorkomen door this binnen het registreren te vervangen voor iets anders.

Zo kun je binnen je "object" bijvoorbeeld het volgende neerzetten:

me = this;

Vervolgens gebruik je bij het registeren van de callbacks me ipv this

Ik hoop dat je het begrijpt, mijn omschrijving is wat vaag.

Je krijgt dan:

me.success en me.fail
 
Laatst bewerkt:
Klopt, maar wanneer ik meerdere instanties van het object ga maken krijg ik weer problemen, omdat de variable me een openbare variable is en door elke instantie gebruikt word.

Het mooiste zou natuurlijk zijn om navigator.geolocation.me=this te gebruiken, zodat de aanroepende functie de verwijzing naar het 'parent' object bevat, en die te gebruiken i.p.v. this. Ik weet alleen niet of dit kan (zal eens proberen) maar ik vraag me af of het wel "mag": is het wel de bedoeling om, van standaard objecten, variables te veranderen/toe te voegen, of zou dit problemen kunnen veroorzaken?

Alvast bedankt ;)

EDIT: het me=this idee werkt goed, bedankt hiervoor. Op het moment wordt er maar 1 instantie van het object aangemaakt, maar bij meerdere objecten kan dit een probleem worden. navigator.geolocation.me=this gebruiken, en vervolgens methods aanroepen met this.me.methode() werkte niet (dus de verwijzing naar het object opslaan in het object dat de callback aanroept), zijn hier misschien andere mogelijkheden voor?
 
Laatst bewerkt:
De me variabele moet binnen het object gedefinieerd worden en zo een instance variabele zijn. Het maakt dan niet uit of je meerdere instanties aanmaakt, het zou geen probleem moeten vormen.

Je moet in het registeren van het event gebruik maken van me, deze variabele wijst dan immers naar het object zelf (zoals this normaal zou doen), in het object behoort ook de functie te staan.

Een simpel voorbeeld:

PHP:
addEvent(button,"click",me.success);

In dit voorbeeld koppel je (binnen je object) een onclick event van een knop (button variabele) aan de functie success.

De success functie is in dit geval ook een functie binnen je object. Wanneer de functie niet binnen je object zou staan, zou je namelijk een gewone variabele naam gebruiken, en niet het this keyword.

EDIT: Wanneer je het object aan zou willen roepen, moet je deze mee kunnen geven als variabele: me.success(me);
 
Laatst bewerkt:
Ik begrijp niet helemaal wat je bedoeld.

Het volgende heb ik nu binnen de class staan:

[JS]
geoObject.prototype.begin=function(){
me = this;
tracker = navigator.geolocation.watchPosition(this.succes, this.fail);
}

geoObject.prototype.succes=function(position){
//gebruik de variable position, deze wordt door de watchPosition functie meegestuurd
me.andereFunctie(); //andereFunctie() kan weer gewoon gebruik maken van het THIS keyword
}[/JS]

De variable me is in dit geval dus een globale variable (althans, dat neem ik aan, gezien je lokale variablen met this.variable moet definiëren) , wanneer ik this.me = this zou gebruiken, is this.me niet aan te roepen in de succes method (immers, this verwijst naar navigator.geolocation en niet naar mijn object).

Het kan zijn (en het lijkt erop) dat ik je gewoon niet helemaal begrepen heb, hoe wordt de me variable aangemaakt en aangeroepen?
 
Het wordt een beetje een probleem omdat ik bij OOP javascript niet bekend ben met het prototype framework. Ik kan dus niet helemaal voorspellen wat het prototype-keyword precies doet.

Ik neem echter aan dat in dit geval het me keyword zich alleen in de scope van de begin-functie bevindt. Het zou dus in geoObject moeten worden gedefinieerd.
Alleen weet ik niet precies in welke scope prototype definities werken en hoe je het dus uit zou kunnen voeren.
 
Okay, voordat je allemaal dingen overneemt, even dit: ik heb zelf ook een tijdje gewerkt met de prototype-dingetjews van Javascript, maar ik vond het gewoon te veel moeite, en snapte er soms ook helemaal de ballen van. Dus het kan zijn dat ik wat foute dingen zeg.



Anywho: het prototype keyword zorgt ervoor dat je een object onder een ander object kan hangen. Zoiets:
[JS]bbq = function()
{
this.name = 'grillmeister'
}

bbq.prototype.sausjes= function()
{
this.saz = 'garlic';
}[/JS]
dit stukje zal 'sausjes' aan je object 'bbq' vastmaken. Je hebt dan dus dit:
Code:
bbq: object
   |_ name: string
   |_ sausjes: object
      |_saz: string


Nu, naar de vraag:
[JS]geoObject.prototype.begin=function(){
me = this;
tracker = navigator.geolocation.watchPosition(this.succes, this.fail);
}

geoObject.prototype.succes=function(position){
//gebruik de variable position, deze wordt door de watchPosition functie meegestuurd
me.andereFunctie(); //andereFunctie() kan weer gewoon gebruik maken van het THIS keyword
}[/JS]
De variable me is in dit geval dus een globale variable (althans, dat neem ik aan, gezien je lokale variablen met this.variable moet definiëren) , wanneer ik this.me = this zou gebruiken, is this.me niet aan te roepen in de succes method (immers, this verwijst naar navigator.geolocation en niet naar mijn object).
nou, niet helemaal. Je variabele 'me' is alleen globaal in die 'aftakking' en 'eronder', en sinds de 'succes' prototype dezelfde laag is, werkt ie niet.

Ik weet helemaal niet zeker (eigenlijk denk ik dat het niet gaat werken...) of dit gaat werken, maar probeer zoiets:
[JS]
geObject = function()
{
/* stuff die er al stond */

this.pointer = this;


}

geoObject.prototype.begin=function()
{
tracker = navigator.geolocation.watchPosition(this.succes, this.fail);
}

geoObject.prototype.succes=function(position)
{
//gebruik de variable position, deze wordt door de watchPosition functie meegestuurd


var pointer = this.pointer;

pointer.andereFunctie();
}[/JS]


:thumb:
 
Laatst bewerkt:
Hmm, dat is een redelijke uitleg, ik had helemaal niet gedacht aan de verhoudingen van de prototype functies. Dat komt omdat ik *eigenlijk* geen ervaring heb met OOP in JS, maar ik had ergens gelezen dat het werken met prototype beter is omdat de methods dan niet voor elke instantie gekopieerd zouden worden, of iets in die richting.

Terugkomend op je antwoord, een paar berichten eerder:
...is this.me niet aan te roepen in de succes method...

In jouw geval wordt this.pointer in het geoObject aangemaakt, en staat dus direct onder het eerste element uit de 'boomstructuur'. Het succes object/method staat verder naar onderen, en het keyword this verwijst dan naar succes en niet meer naar het bovenste object geoObject.

Code:
geoObject
    - pointer
    - succes
         -- pointer

this.pointer is dus voor geoObject en succes een andere variable. Daarbij vraag ik me af of het keyword this überhaupt wel verwijst naar de succes method, of naar de functie die hem aanroept (watchPosition in mijn geval). In beide gevallen kan ik het id van de instantie van geoObject niet meer terugvinden.
 
Dat artikel gaat over de prototype library, waar ik geen gebruik van maak (waarom iemand op het idee komt om die naam voor zijn library te kiezen weet ik niet, want prototype wordt al door JS gebruikt).

Het gaat zich dus om prototype based programming.

Prototype-based
prototypes
JavaScript uses prototypes instead of classes for inheritance. It is possible to simulate many class-based features with prototypes in JavaScript.

functions as object constructors
Functions double as object constructors along with their typical role. Prefixing a function call with new creates a new object and calls that function with its local this keyword bound to that object for that invocation. The constructor's prototype property determines the object used for the new object's internal prototype. JavaScript's built-in constructors, such as Array, also have prototypes that can be modified.

functions as methods
Unlike many object-oriented languages, there is no distinction between a function definition and a method definition. Rather, the distinction occurs during function calling; a function can be called as a method. When a function is called as a method of an object, the function's local this keyword is bound to that object for that invocation.

Dit schijnt dus de enige (goede) manier te zijn om OO in JS te kunnen werken.
 
Toch denk ik dat je de functionaliteit moet inkapselen in het prototype. Het probleem - denk ik - ligt in het feit dat je wanneer je nu properties e.d. toevoegt aan het object, je dit doet vanuit het window object.

Je zou iets moeten doen als

PHP:
object.prototype = function()
{
  // hier komt je OO 
  me = this

this.fail = function()
{
// do fail
}

this.success = function()
{
// do success
}


registreercallback(call,me.success,me.fail);
}

Dan liggen de functies ingekapseld in je object. Alleen weet ik niet precies hoe prototype werkt.
 
Zoals ik uit verschillende artikels begrijp, is het inkapselen van de methods exact hetzelfde als het gebruik van prototype. Het enige verschil is dat de ingekapselde methods voor elke instantie worden gedefinieerd, en met het gebruik van prototype is dat niet het geval. Qua werking zal alles hetzelfde moeten zijn, het enige verschil zit zich in het (theoretische) verschil van snelheid (hoewel ik durf te betwijfelen dat dit op kleine schaal merkbaar is).

Dit wetende denk ik dus dat het "probleem" niet aan het prototype based programmeren ligt, maar aan iets anders, en behalve het object dat de callback aanroept zou ik niet weten wat invloed kan hebben op het this keyword.
 
Ja, en daarom zou je alleen dat gedeelte op een of andere manier in moeten kapselen in prototype. Dus niet geheel op basis van inkapselen OO werken, maar alleen dat gedeelte. Hoe dat moet zou ik echter niet weten.
 
Status
Niet open voor verdere reacties.
Terug
Bovenaan Onderaan