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!

6
  • of course, made changes, hope ist clearer now Commented Oct 12, 2015 at 9: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. Commented Oct 12, 2015 at 9:56
  • you could add var value = val, that = this; and then make your changes with if (that.onChange)... Commented Oct 12, 2015 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 Commented Oct 12, 2015 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 for example, this one should clear things up for you Commented Oct 12, 2015 at 10:13

1 Answer 1

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.

Sign up to request clarification or add additional context in comments.

6 Comments

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: 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.
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
"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
wow, have to study this in the evening ... thanks for the great work!
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.