TAGS :Viewed: 8 - Published at: a few seconds ago

[ How to ensure method calls in a returned object literal use the intended "this" ]

I have a javascript function that has a number of methods and variables and returns an object literal I am using somewhat like a class, i.e.

var myObject = function {

   var somevars;
   var someMethod = function(someInput) { };

   return {
      methodA:function(inputs) { 
        // calls someMethod, using somevars and inputs 
      },
      methodB:function(inputs) { 
        // calls someMethod, using somevars and inputs 
      }

   };
}

In javascript it is common to create a variable called "that" or "self" or some such thing that stores the value of "this" at creation time so that in future calls one can use it to point to the objects own self because "this" may be pointing to something else. This is useful if, e.g. methodA gets used as a click handler.

How can I create a "that" variable in the object literal I return?

Is there a good way to initialize a "that" variable in an object literal, or is something more round about necessary?

Update

Yes, the object I want to be able to reference is the object literal itself.

Yes, methodA and methodB might also call each other and refer to other members of the returned object literal. That is why I care about "this".

I create a number of instances of this object via "new". Call one of them X. Then I want to use X.methodA as a mouse event handler, e.g. I have jquery code that attaches mouseup on a dom element to X.methodA. But that looks like $("#domElementId").mousemove(X.methodA) But when mousemove is called, the "this" variable used in methodA no longer points to X as I understand. Feel free to correct me if I am wrong. Specifically, calls within method A to, say, method B will fail because they have do be done using this.methodB and "this" points to the global object.

Answer 1


If you want to "bind" the functions to the object, you need to have a reference to the object inside the function, which means you have to assign it to a variable:

var obj = {
    methodA: function() {
      // use obj here
    }
};
return obj;

However, this is only necessary if methodA actually references any other property from the object.

If you are only accessing what you mentioned in your comment, then there is no need for that. No matter how the function is called, you will always have access to someMethod, somevars and inputs, since they are lexically scoped.

Answer 2


When you say new myObject() this is what happens:

  1. JS creates a new object.
  2. JS assigns myObject as the prototype of the new object.
  3. JS runs the myObject function with the new object bound to this within the scope of the function.
  4. The new expression evaluates to the object created in step 1, unless the myObject function call returned an object (as you do here).

Typically when invoking a function with new, that function should set up the this object instead of creating a new object.

So, what you should do to attach methods to the object is either modify this or use prototypal inheritance to attach the methods. The first approach would look something like this:

function myObject() {
    var somevars;

    this.methodA = function(inputs) { /* ... */ }.bind(this);
    this.methodB = function(inputs) { /* ... */ }.bind(this);
}

Then, from within the method functions you can just use this to refer to the object on which the method was initially bound.

Since you need to use the private data somevars then you can't (easily) use the prototypal approach; functions assigned to the prototype are all effectively shared between object instances, whereas in the approach above you create new function objects for each instance of myObject, meaning they can each have access to a different instance of somevars.

(Note that binding the functions is not strictly necessary as long as you don't mind that if a method's function reference gets copied to another object, this will instead refer to that other object when the function gets called through that object. Whether or not you should use bind() depends on other details of your application, so I can't tell you definitively whether or not you need to use it here.)