2

I have been fiddling with code to call a function with the name of the value of a variable and then keep the this scope when called, but the this pointer seems to be in context of the element I have used jQuery's bind method on, rather than the object the function I might be calling is within. To clarify here´s some code to illustrate the problem:

classname.prototype = {
    bindElementToFunction: function(element, functionToCall){
        $(element).bind("click", 
                        {realThis: this, functionToCall: functionToCall}, 
                        this.callFunction);
    },

    // I had hoped I could change the this pointer back to the object by running 
    // it through this function, I have tried using .apply and .call but I can't 
    // seem to get them to work with function pointers
    callFunction: function(event){
        var realThis = event.data.realThis;
        var functionToCall = event.data.functionToCall;
        functionToCall = realThis[functionToCall];
        // I have tried .apply and .call in several different ways but can't seem 
        // to get them to work in this context
        functionToCall(); 
    },
    abitraryFunction: function(){
        this.test();
    },
};

The problem here is then that everything works fine up until abitraryFunction where this is still referring to the element from the bind function. I have tried doing .apply() with the appropriate this pointers, but they do not seem to work.

So here's the question how do I change the context of the "this" pointer in combination with function pointers? Feel free to scrap all the code I have written, as long as I am able to do a bind function to an element that then runs a method within a object where "this" is refferring to the object the method is within.

Thanks

  • I don't think `pointer` is the right term outside of C. – millimoose Jun 27 '12 at 12:08
  • reference to the function then? I am rather new to javascript so any help/educational thoughts are appriciated :) So Thanks :) – user1485496 Jun 27 '12 at 12:08
  • 1
    Nitpick: make sure you indent code pasted on SO with spaces instead of tabs, it's easier to not mess up the formatting that way. – millimoose Jun 27 '12 at 12:10
  • Did you try looking at this code in the Javascript console? For one, `bindElementToFunction` fails because you need to use `this.callFunction` instead of just `callFunction`, this isn't implicit in Javascript. You might also want to take a look at this question: http://stackoverflow.com/questions/2025789/preserving-a-reference-to-this-in-javascript-prototype-functions . The general problem is that jQuery really likes to change `this` for you, so if you want to use object methods as event handlers or other callbacks, you need to preserve it yourself. – millimoose Jun 27 '12 at 12:18
  • Right I should just have copied the code from my project, it's a typo that got lost in me rewriting it. Too fast. So how do I change it back when .apply() and .call() for me failing when using function-pointers? – user1485496 Jun 27 '12 at 12:20
  • So, I'm guessing what you want to do is uh… `var foo = new classname(); foo.bindElementToFunction(elmt, foo.arbitraryFunction);`, and when the event fires and `arbitraryFunction()` is called, `this` should be the object `foo`? – millimoose Jun 27 '12 at 12:23
  • But you can't use the dot operator because it can not evaluate a variable lookup, it much be constant. So I turned the names into function pointers by objectPointer["name"], in that way it will point to the function with "name" within object. But if I can change the this pointer before or in runFunction so the context is set before abitrary function then that would be great. BTW is there really a difference between doing this.x and foo.x when this references foo? It didn't work for me. But Thanks! – user1485496 Jun 27 '12 at 12:42
  • Wasn't your problem that in `arbitraryFunction()`, `this` *doesn't* reference what you want? – millimoose Jun 27 '12 at 12:44
  • And my point is that you shouldn't need to pass around an "object, function name" pair around in the first place if you use `Function.prototype.bind()` (as outlined in the other SO question I linked) to manage the value of `this` when using jQuery. – millimoose Jun 27 '12 at 12:45
  • ArbitraryFunction could be any of any number of functions in any number of objects. I do apologize if I completely missing the point. I am going to read the link you linked again thoroughly. – user1485496 Jun 27 '12 at 12:48
  • I'm not really sure what you're trying to accomplish, that's all. It just seems to that `bindElementToFunction` and `callFunction` are both completely unnecessary, if what you're trying to do is bind a method of `classname` to an event with jQuery. – millimoose Jun 27 '12 at 12:53
  • But isn't bind somewhat like apply and call? Those functions I was unable to use in conjunction with the variable function call. – user1485496 Jun 27 '12 at 12:57
  • callFunction might be unnecessary I agree, it was my attempt to get it working, and I figured that through I perhaps would be able to change the context of "this" in it, though it didn't work. So we can perhaps just scrap that :) But the bindElementToFunction will be a function that takes in an element on the page and associates it with a function in an object. the "arbitraryFunction" is not one function it could be any function of any number of functions within any number of objects. arbitraryFunction should just be consider to be a random function an arbitrary picked method within a object. – user1485496 Jun 27 '12 at 13:01
  • Merging `runFunction` and `bindElementToFunction` will be very nice. It probably shouldn't have been in the post. But i figured it might clarify, though I see it did the opposite : / – user1485496 Jun 27 '12 at 13:02

1 Answers1

1

I think the jQuery bind is making your code way more complicated than it needs to be. The JavaScript bind() function works perfectly:

http://jsfiddle.net/bQGWS/

By simply assigning a function to the onclick (or any other event hook) of an element, this is evaluated from the element's point of view and so points to the element itself.

When you use bind, you end up with a copy of the function where this is effectively replaced with the var you passed into bind().

classname = function(){}

classname.prototype = {
    method: function(){
        try {
            alert( this.othermethod() );
        } catch(e) {
            // Method doesn't exist in scope
            alert( 'Wrong scope :(');
        }
    },

    othermethod: function(){
        return 'hello desired scope!';
    },

    referenceToElement: function(elementId, functionname){
        var el = document.getElementById(elementId);

        // Just assigning the function as is
        el.onclick = this[functionname];
    },

    bindToElement: function(elementId, functionname){
        var el = document.getElementById(elementId);

        // Using the bind function to create a copy in the
        // scope of this (within the prototype)
        el.onclick = this[functionname].bind(this);
    }
}

var instance = new classname();
instance.referenceToElement('reference', 'method');
instance.bindToElement('bound', 'method');
Stecman
  • 2,890
  • 20
  • 18