[JS] objecten en events 'this' refereert fout

Pagina: 1
Acties:

  • BasieP
  • Registratie: Oktober 2000
  • Laatst online: 22-07-2024
Heren (en eventueel aanwezige dames)

Ik ben bezig een simpel event handling ding te maken in JS, echter als ik een callback functie defineer, en ik refereer daarin aan 'this' dan is dat de vekeerde.


Het is zo dat ik twee objecten heb, laten we zeggen een form en een field.

de formulier voegt een veld toe, en het veld heeft een event 'datachanged'

ik heb het nu zo (testcase)
JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
<html>
    <head>
        <script type="text/javascript">
            function Formulier() {
                this.blaat = 'Ik ben een voorbeeld';  

                this.doeIets = function() {
                    alert(this.blaat);
                }
              
                this.veld = new Veld();
                this.veld.addListener('datachanged', this.doeIets);
                this.veld.fire('datachanged');
              
                return this;
            }

            function Veld() {
                this.blaat = "ik ben een Veld!! mwhahahah"
                this._listeners = {};

                this.addListener = function(type, listener) {
                    if (typeof this._listeners[type] == "undefined") {
                        this._listeners[type] = [];
                    }

                    this._listeners[type].push(listener);
                }

                this.removeListener = function(type, listener) {
                    if (this._listeners[type] instanceof Array) {
                        var listeners = this._listeners[type];
                        for (var i = 0, len = listeners.length; i < len; i++) {
                            if (listeners[i] === listener) {
                                listeners.splice(i, 1);
                                break;
                            }
                        }
                    }
                }

                this.fire = function(event) {
                    if (typeof event == "string") {
                        event = { type: event };
                    }
                    if (!event.target) {
                        event.target = this;
                    }

                    if (!event.type) {  //falsy
                        throw new Error("Event object missing 'type' property.");
                    }

                    if (this._listeners[event.type] instanceof Array) {
                        var listeners = this._listeners[event.type];
                        for (var i = 0, len = listeners.length; i < len; i++) {
                            listeners[i].call(this, event);
                        }
                    }
                }
                
                return this;
            }
        </script>
    </head>
    <body>
        <script type="text/javascript">
            var form = new Formulier();
        </script>
    </body>
</html>

nu gaat mijn event netjes af, en krijg ik ook een alert, echter is dat niet met de juiste tekst.
Ik had verwacht "Ik ben een voorbeeld" te zien te krijgen, maar ik krijg helaas "ik ben een Veld!! mwhahahah" te zien.

Mijn referentie naar 'this' is dus een verwijzing naar een instantie van 'veld', en niet van 'formulier'.

Hoe fix ik dat?

[ Voor 44% gewijzigd door BasieP op 24-02-2011 13:03 ]

This message was sent on 100% recyclable electrons.


  • MueR
  • Registratie: Januari 2004
  • Laatst online: 00:33

MueR

Admin Tweakers Discord

is niet lief

En http://www.google.nl/search?q=settimeout+scope gaf geen bruikbaar resultaat?

Anyone who gets in between me and my morning coffee should be insecure.


  • crisp
  • Registratie: Februari 2000
  • Laatst online: 11:59

crisp

Devver

Pixelated

bind gebruiken:
JavaScript:
1
veld.addListener('datachanged', this.doIets.bind(veld));

De meeste JS frameworks bieden een dergelijke methode die crossbrowser werkt als de browser er nog geen native ondersteuning voor heeft.

Intentionally left blank


  • R4gnax
  • Registratie: Maart 2009
  • Laatst online: 06-09 17:51
Laten we eens een stapje terug gaan en beginnen bij het begin: waarom ben je nou helemaal een eigen event-handling systeem aan het bouwen?

[ Voor 9% gewijzigd door R4gnax op 24-02-2011 13:05 ]


  • BasieP
  • Registratie: Oktober 2000
  • Laatst online: 22-07-2024
@MueR:
sry, ik zag de fout van mijn uitgetikte voorbeeldje toen ik een testcase ging maken, settimeout gaat natuurlijk niet werken.
Ik heb mijn voorbeeld nu aangepast in startpost.

@crisp:
Ik heb nu in mijn voorbeeld van hierboven regel 12 vervangen door:
JavaScript:
1
                this.veld.addListener('datachanged', this.doeIets().bind(this));

en dat werkt idd :)

Echter moet ik die haakjes er bij zetten. (dus anders dan in jouw voorbeeld en anders dan op de website waar je naar linkt...
Is dat nog bezwaarlijk?

Ik gebruik nu geen framework, gewoon plain js. Bind werkt bij mij wel in firefox en IE6.
Zijn er ook browsers die het niet ondersteunen?
R4gnax schreef op donderdag 24 februari 2011 @ 13:04:
Laten we eens een stapje terug gaan en beginnen bij het begin: waarom ben je nou helemaal een eigen event-handling systeem aan het bouwen?
1. omdat ik geen zin heb een 2 mb library te includen
2. omdat ik graag begrijp wat er gebeurd
3. omdat ik 1 a 2 classes heb die mogelijk elk 1 a 2 events gaan afvuren. Geen rocketsience dus.

[ Voor 37% gewijzigd door BasieP op 24-02-2011 13:23 ]

This message was sent on 100% recyclable electrons.


  • BasieP
  • Registratie: Oktober 2000
  • Laatst online: 22-07-2024
oke nog even terug...

ik heb wat lopen zoeken/testen etc. etc. en uiteindelijk kwam ik hier op uit:

JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Function.prototype.bind = function(context) {
    var fun = this;
    return function(){
        return fun.apply(context, arguments);
    };
};


function Formulier() {
    this.blaat = 'Ik ben een formulier';  
        this.doeIets = function() {
        alert(this.blaat);
    }
  
    this.veld = new Veld();
    this.veld.callbackFunc = this.doeIets.bind(this);
    this.veld.execCallbackFunc();
              
    return this;
}

function Veld() {
    this.blaat = "ik ben een Veld!! mwhahahah"

    this.execCallbackFunc = function() {
        this.callbackFunc.call(this);
    }
            
    return this;
}

var form = new Formulier();

(waarbij ik het eventhandler gedeelte even uit mijn testcase gesloopt heb)

De .bind functie schijnt niet standaard te bestaan, dus die moet ik zelf defineren, maargoed dat deed ik ook al voor .trim() en nog wat meer van dat soort functies...

[ Voor 5% gewijzigd door BasieP op 24-02-2011 14:54 ]

This message was sent on 100% recyclable electrons.


  • crisp
  • Registratie: Februari 2000
  • Laatst online: 11:59

crisp

Devver

Pixelated

BasieP schreef op donderdag 24 februari 2011 @ 14:53:
[...]
De .bind functie schijnt niet standaard te bestaan, dus die moet ik zelf defineren, maargoed dat deed ik ook al voor .trim() en nog wat meer van dat soort functies...
Wel in IE9, Firefox 4 etcetera. Plus dat jouw functie niet ES5-compatible is :P

Wij gebruiken zoiets:
JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
if (!Function.prototype.bind)
{
    Function.prototype.bind = function(obj)
    {
        var fn = this, args;

        if (arguments.length > 1)
        {
            args = [].slice.call(arguments, 1);

            return function()
            {
                return arguments.length ? fn.apply(obj, args.concat([].slice.call(arguments))) : fn.apply(obj, args);
            }
        }

        return function()
        {
            return arguments.length ? fn.apply(obj, arguments) : fn.call(obj);
        }
    }
}


verder zou ik ipv this.veld.callbackFunc = <iets> een setCallback method maken.

Intentionally left blank


  • BasieP
  • Registratie: Oktober 2000
  • Laatst online: 22-07-2024
crisp schreef op donderdag 24 februari 2011 @ 15:28:
[...]

Wel in IE9, Firefox 4 etcetera. Plus dat jouw functie niet ES5-compatible is :P

Wij gebruiken zoiets:--knip..

verder zou ik ipv this.veld.callbackFunc = <iets> een setCallback method maken.
tnx.. ik zal eens opzoeken wat ES5 is ;)
(de 'callback =' was beetje voor testcase, minder regels code om zelfde te laten zien)

[ Voor 34% gewijzigd door BasieP op 24-02-2011 15:45 ]

This message was sent on 100% recyclable electrons.

Pagina: 1