0

I've seen many questions for that context, but I still can't figure out, what exactly my Problem is. (I'm still experimenting with JavaScript, especially with objects)

Code:

function Field(val) 
{ var value = val; 
this.__defineGetter__("value", function(){ return value; });
this.__defineSetter__("value", function(val){ value = val; if(this.onchange) this.onchange.call(); });
}


function LW_makePlan()
{

    /* [...] */
    this.Filter1=new Field("");
    this.Filter2=new Field("");
    this.Filter3=new Field("");


    this.init = function() 
    {
        /* [...] */

        this.Filter1.onchange=this.getSomething;
    }

    this.getSomething = function()
    {
        arg="modus=doWhat";
        arg=arg+"&filter1=" + this.Filter1.value;
        arg=arg+"&filter2=" + this.Filter2.value;
        arg=arg+"&filter3=" + this.Filter3.value;
        request_fkt(null, true, arg , this.setSomething);
    }

    this.setSomething = function(data)
    {
        alert(data);
    }

    this.init();

};

What I'm trying:

test = new LW_makePlan();
test.Filter1.value="anything";

test.Filter1 has an "onchange"-property, that is checked in the setter of "Field". if set, the setter will also call the object given within the onchange-property.

this works so far BUT it seems, that this call creates a whole new object-instance ... no not an instance, it is, as if the function "getSomething" is copied as a stand-alone function, because the Code i called, but for example this.Filter1 within the function "getSomething" is undefined ...

Why is this happening and how can I avoid this?

PS: I don't want to use some type of event-handling-Things from 3rd Party codes, I'd like to do it myself with a little help maybe.

EDIT:

Thanks to Steffen Heil, changed to:

var scope=this;
this.Filter1.onchange=function() { scope.getSomething(); };

and it works!

mech
  • 617
  • 6
  • 16
  • of course, made changes, hope ist clearer now – mech Oct 12 '15 at 09:55
  • @mech: You seem to be confused over how JS binds the `this` reference (ad-hoc context binding). When you assing a handler (`this.Filter1.onchange=this.getSomething;`), the context of `this.getSomething` (where `this` points to) will not be the main object, but it'll point to `this.Filter1` instead. – Elias Van Ootegem Oct 12 '15 at 09:56
  • you could add `var value = val, that = this;` and then make your changes with `if (that.onChange)`... – Icepickle Oct 12 '15 at 10:00
  • *confused* if i debug, this.onchange (within the Function-Object Field), holds the correct function-code, but that function-code seems not connected to the originating object it Comes from, it seems to be cut off – mech Oct 12 '15 at 10:08
  • @mech: the point at which you assign `this.getSomething` isn't what I'm talking about. `this.getSomething` will refer to the correct function (unless you start using `.bind`, or functions like `call` or `apply`, but once `this.getSomething` is called, the `this` keyword inside `getSomething` will point to the context in which `getSomething` is invoked. I've posted a couple of answers explaining JS scopes and context resolution, [this one](http://stackoverflow.com/a/15174505/1230836) for example, [this one](http://stackoverflow.com/a/14701820/1230836) should clear things up for you – Elias Van Ootegem Oct 12 '15 at 10:13
  • [This one](http://stackoverflow.com/a/16472719/1230836) also deals with context bindings, I believe – Elias Van Ootegem Oct 12 '15 at 10:18

1 Answers1

1

Your call to this.onchange is in Field, so you are calling a function of Field. The assignment this.Filter1.onchanged=this.getSomething kind of copies the method getSomething from LW_makePlan to Field, where it will be called.

So inside of getSomething that is now called onchanged the reference this referes to the Field not the LW_makePlan.

Replace the assignment with this:

var source = this;
this.Filter1.onchange = function() { return source.getSomething(); };

And it will work. Most frameworks have a bindmethod that makes this more readable (hiding the extra variable in a scope).


In reply to the first comment:

You can explicitly call a function like this:

x.call( object, arg1, arg2, ag3 );
x.apply( object, [ arg1, arg2, arg3 ] );

These the are the same and it does not matter what x is. Inside the called function this has the value of object. x can be:

alert
window.alert
(function(){})
(alert)
(window.alert)

Normal calls to a function are shortcuts:

object.f = g;
object.f( arg1 )        =>  g.call( object, arg1 );
f( arg1 )               =>  f.call( window, arg1 );

While window is the global object in a browser; other environments may use another global object.

While the difference between these two shortcuts seems tivial, what about the following?

(object.f)( arg1 )

This is completely valid javascript, as object.f is a function and a function can be invoked using (args1). But:

object.f = g;
(object.f)( arg1 )       => g.call( window, arg1 )

So a.f = b.f; copies a member reference from a to b, but the this context, the code is executon on depends on the way f is called.

a.f(x) == a.f.call(a,x) == (a.f).call(a,x) == b.f.call(a,x) == (b.f).call(a,x)
b.f(x) == b.f.call(b,x) == (b.f).call(b,x) == a.f.call(b,x) == (a.f).call(b,x)

By the way, you can define your own bind very easily:

function bind( object, method ) {
  return function() {
    return object[ method ].apply( object, arguments );
  };
}

Then the original code would become:

this.Filter1.onchange = bind( this, 'getSomething' );

This would match the fix I gave above using "late binding". Most libraries prefer "early binding":

function bind( object, method ) {
  return function() {
    return method.apply( object, arguments );
  };
}

Then the original code would become:

this.Filter1.onchange = bind( this, this.getSomething );

The advantage is better performance, but the main difference is what happens, when getSomething changes after bind was called. The first implementation calls the new value, the second the old value.

Steffen Heil
  • 4,286
  • 3
  • 32
  • 35
  • nice it worrks .... so if i understand it right, if i set onchange=this.something, then "this" is unspecified and will be specified within the "Field"-function so it Points to itself? thats ... crazy ... well probably not, but for now it's crazy for me ;) THANKS! – mech Oct 12 '15 at 10:18
  • @mech: You're _always_ able to predict what `this` will be. It'll always point at the _current_ calling context, except for global functions called in strict mode, in which case `this` will be `null`. In case of `this.Filter1.onchange = someFunction;`, calling `this.Filter1.onchange`, the context of `someFunction` (ie `this`) will be `this.Filter1`. – Elias Van Ootegem Oct 12 '15 at 10:21
  • but if the "this" of this.someFunction is pointing to the object i'm trying to set the value of, then, for example Filter1, then i should get an error, because Filter1 is a Field-Object, that doesn't have a someFunction-Property ... but I think i understood it wrongly – mech Oct 12 '15 at 10:25
  • _"The advantage is better performance"_? How so? That's simply not true. The advantage is that user code can't muck up the context as easily, the advantage is more safety related than it is performance related, especially if you implement your won `bind` function which bloats the GC cycle (due to closure scopes referencing objects indefinitely), and wrapping functions in functions (again: creating additional objects). What you're saying is that wrapping a gift in 2 boxes makes it lighter to carry, whereas what it really does is make the contents less prone to breakage – Elias Van Ootegem Oct 12 '15 at 11:16
  • wow, have to study this in the evening ... thanks for the great work! – mech Oct 12 '15 at 11:33
  • @Elias: I meant the advantage of the first over the second example implementation of `bind`. – Steffen Heil Oct 13 '15 at 11:41