0

I'm trying to create a client-side api for a web control using the Prototype pattern. However I want to make life easier by not having to manage "this".

This is some sample code (i have commented the problematic line):

MyObject = function ()
{
    MyObject.initializeBase(this);

    this._someProperty = null;
};    

MyObject.prototype = {

    initialize: function()
    {
        // Init
    },

    get_someProperty: function()
    {
        return this._someProperty;
    },

    set_someProperty: function(value)
    {
        this._someProperty = value;
    },    

    doSomething: function ()
    {
        $('.some-class').each(function ()
        {
            $(this).click(this.doClick);  // this.doClick is wrong
        });
    },

    doClick: function ()
    {
        alert('Hello World');
    }
};

Normally, using the revealing module pattern I would declare a private variable:

var that = this;

Can I do something similar with the Prototype pattern?

Dave Schweisguth
  • 36,475
  • 10
  • 98
  • 121
Brett Postin
  • 11,215
  • 10
  • 60
  • 95
  • So **what** is the problem again? – PhD Aug 09 '12 at 16:26
  • I want to avoid littering my code with managing "this" scope. – Brett Postin Aug 09 '12 at 16:34
  • @Poz Sadly, you are programming in the wrong language if you want to avoid managing `this`. – Alex Wayne Aug 09 '12 at 16:35
  • I don't really get your problem. What do you expect? How would ECMAscript know which object you mean by referencing `this` twice within the same scope ? – jAndy Aug 09 '12 at 16:42
  • @AlexWayne is this convention uncommon/bad? I tend to do it a lot in the revealing module/prototype patterns... http://tinyurl.com/7dxkw – Brett Postin Aug 09 '12 at 16:44
  • @jAndy see this question for what I'm hoping to achieve, but local to my prototype object [What does var that = this; mean in javascript?](http://stackoverflow.com/questions/4886632/what-does-var-that-this-mean-in-javascript). – Brett Postin Aug 09 '12 at 16:54

2 Answers2

4

You can do the exact same thing you are used to, just do it within the doSomething method:

doSomething: function ()
{
    var instance = this;
    $('.some-class').each(function ()
    {
        $(this).click(instance.doClick);
    });
},

This approach has nothing to with prototype or not, it's just how to manage context with nested functions. So when a function on a prototype (method) has nested functions within in, you may have to preserve the context this at any of those level if you want to access it in a nested scope.

Alex Wayne
  • 178,991
  • 47
  • 309
  • 337
  • 1
    I think the point was that he didn't want to do what you posted. He wanted a "that" that is accessible in all methods and points to the correct this. – Matt Wonlaw Aug 09 '12 at 16:29
  • Well that's just how you do this javascript. `this` needs to be managed when nested function scope is involved. Not a way around it. Unless you want to jumped into coffee script's fat arrow `=>` but I try not evangelize coffee script in every JS post :p – Alex Wayne Aug 09 '12 at 16:34
  • Thanks Alex, I could live with this solution. However as Matt points out it would be great if I had a single reference of "this" to point to. – Brett Postin Aug 09 '12 at 16:36
  • Then use CoffeeScript and let the compiler deal with it :) http://tinyurl.com/9392ab5 – Alex Wayne Aug 09 '12 at 16:38
  • If you are attaching methods to your prototype I think this is the only solution. You could define the methods in your constructor but that actually wastes a lot of memory: https://gist.github.com/3073687 – Matt Wonlaw Aug 09 '12 at 16:39
  • @Poz It may be good to add here that jQuery isn't helping overriding `this` in the each method, and relying on `(index, element)` arguments that it passes in may clean things up. – Alex Wayne Aug 09 '12 at 16:42
0

ES5's Function.prototype.bind() might be an option for you. You could go like

doSomething: function ()
{
    $('.some-class').each(function(_, node)
    {
        $(node).click(this.doClick);  // this.doClick is right
    }.bind(this));
},

Now, we proxied each event handler by invoking .bind() and as a result, we call it in the context of the prototype object. The caveat here is, you no longer have this referencing the actuall DOM node, so we need to use the passed in arguments from jQuery instead.

jAndy
  • 231,737
  • 57
  • 305
  • 359