4

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.

  • So what prevented the use of function binding? – Kyll Jun 15 '15 at 16:53
  • Do you want to get reference to the object literal itself or to the "myObject" object?\ – James Montagne Jun 15 '15 at 16:57
  • If your goal is to add a `that` property to the literal being returned which is self-referential then no, there is no way to do that with *just* object literal syntax. You would have to do `var obj = { ... }; obj.that = obj; return obj;` instead of directly returning a literal. However I question the usefulness of doing this. What is the point of having an object's property refer to itself? If you can access this property then you must already have a reference to the object. What problem are you trying to solve? – cdhowie Jun 15 '15 at 16:57
  • 1
    I have no idea what you want `this` to refer to. Looking at your code, you don't need any sort of `that` variable since you're just calling a function that's held by a variable. If you want it to refer to the object you're returning, then store that object. –  Jun 15 '15 at 17:04
  • @JamesMontagne .Great clarifying question. I want it to point to the returned object. I suppose I thought that was the typical scenario for this sort of code, and didn't recognize the ambiguity. My fault. I have used javascript all of a month and a half so still sorting things out. –  Jun 15 '15 at 17:05
  • @JohnRobertson In your updated question I see no need for you to store the returned object literal anywhere, you can just use `someMethod` and `somevars` within the "method" functions. If you need access to the object being returned from the `myObject` function (which is indeed a function, not an object!) then you need to store that object in a variable so that it can be referred to from within those functions. – cdhowie Jun 15 '15 at 17:11
  • @cdhowie So 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. –  Jun 15 '15 at 17:13
  • There's usually [nothing wrong with using `this`](http://stackoverflow.com/questions/10711064/javascript-object-literal-reference-in-own-keys-function-instead-of-this) – Bergi Jun 15 '15 at 17:14
  • 1
    @JohnRobertson: Right, but then you should just do `$("#domElementId").mousemove(X.methodA.bind(X))`, which makes the intent very clear.\ – Felix Kling Jun 15 '15 at 17:18
  • @JohnRobertson If you are using `new` to invoke the function then *the return value is completely ignored*. JS will create a new object, set its prototype to be `myObject`, execute the function with the newly created object visible to the function as `this` and then the `new` expression evaluates to the object that JS created. The object literal you return is discarded! You would instead want to do `this.methodA = function(foo) { /* ... */ }.bind(this);` and so on. – cdhowie Jun 15 '15 at 18:03
  • @cdhowie, Are you sure. I was pretty sure that if I called a function with new then the returned value of the function was ignored UNLESS it was an object, in which case, new will elect to return the object the function returns instead of the object created by the invocation of new. (So, yes, the object initially created by new is actually left for garbage collected) –  Jun 15 '15 at 18:15
  • @JohnRobertson That is true, I forgot about that detail. Nonetheless, if you are using `new` then typically you want to be setting up `this` instead of creating a completely new object. – cdhowie Jun 15 '15 at 18:34

3 Answers3

6

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.

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • 4
    I'm not sure why this got downvoted. It's more correct than any other answer given here, which will all bind the functions to a different object than is being returned by the function. – cdhowie Jun 15 '15 at 17:03
0

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.)

cdhowie
  • 158,093
  • 24
  • 286
  • 300
  • That's not correct. `new` returns the return value of the function **unless** it is **not** an object. See: `function Foo() { return {bar: 42};} console.log(new Foo());`. – Felix Kling Jun 15 '15 at 18:26
  • I forgot about that detail, I will fix that. Nonetheless, if `new` is used then usually you want to be dealing with `this` and not returning anything. – cdhowie Jun 15 '15 at 18:34
-1

You can use the bind()...

var myObject = function() {

   var somevars;
   var someMethod = function(someInput) { };
   this.foo = "bar";
   return {
      methodA:function(inputs) { 
        // calls someMethod, using somevars and inputs 
        //you can use the this.foo
      }.bind(this),
      methodB:function(inputs) { 
        // calls someMethod, using somevars and inputs 

      }.bind(this)

   };
}
rink.attendant.6
  • 44,500
  • 61
  • 101
  • 156
Luan Castro
  • 1,184
  • 7
  • 14
  • 4
    This will bind the functions to `this`, which is a different object than is being returned by the function -- probably not what OP wants. If this function is intended to be a "power constructor" (that is, called without `new`) then `this` is likely to be the global object, which, depending on what these bound functions do, could clobber the global scope. – cdhowie Jun 15 '15 at 17:02