0

The technique used by object c below to get past the loss of object instance b smells a bit to me. Is there a more accepted way?

function A()  {
    this.prop = "cat";
}

A.prototype.test = function() {
    console.log(this.prop);
}

function B() {}

B.prototype.test = function(meth) {
    meth();
}

function C() {}

C.prototype.test = function(obj, meth) {
    obj[meth]();
}

var a = new A();
var b = new B();
var c = new C();

//tests
b.test(a.test);     // undefined
c.test(a, 'test');  // cat
jontyc
  • 3,445
  • 6
  • 29
  • 36

2 Answers2

1

There's no need to pass a string, you can still pass a function:

C.prototype.test = function(obj, meth) {
    meth.call(obj);
}

// ...

c.test(a, a.test);  // cat

Function#call calls a function explicitly setting this within the call to be the first argument you give call. (There's also Function#apply; the only difference is how you pass additional arguments for the function.)

But usually (not always) this is considered the caller's problem, and they would typically solve it either using Function#bind (on an ES5-enabled engine or with a shim):

c.test(a.test.bind(a));

...or using a closure:

c.test(function() {
    a.test();
});

...where in both cases, you just call meth() within C.prototype.test.

Function#bind creates a new function that, when called, will call the original function with this set to the value you pass into bind and then it returns that new function.

Related posts on my blog:

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Very helpful answer as well and had trouble deciding which to give the tick to. Hopefully a personal thanks evens it up--thanks! – jontyc Nov 11 '13 at 02:31
1

Copied from: https://stackoverflow.com/a/16063711/1641941

The this variable

In all the example code you'll see this referring to the current instance.

The this variable actually refers to the invoking object, it refers to the object that came before the function.

To clarify see the following code:

theInvokingObject.thefunction();

The instances where this would refer to the wrong object are usually when attaching event listeners, callbacks or timeouts and intervals. In the next 2 lines of code we pass the function, we don't invoke it. Passing the function is: someObject.aFunction and invoking it is: someObject.aFunction(). The this value does not refer to the object the function was declared on but on the object that invokes it.

setTimeout(someObject.aFuncton,100);//this in aFunction is window
somebutton.onclick = someObject.aFunction;//this in aFunction is somebutton

To make this in the above cases refer to someObject you can pass a closure instead of the function directly:

setTimeout(function(){someObject.aFuncton();},100);
somebutton.onclick = function(){someObject.aFunction();};

I like to define functions that return a function for closures on the prototype to have fine control over the variables that are included in the closure scope.

var Hamster = function(name){
  var largeVariable = new Array(100000).join("Hello World");
  // if I do 
  // setInterval(function(){this.checkSleep();},100);
  // then largeVariable will be in the closure scope as well
  this.name=name
  setInterval(this.closures.checkSleep(this),1000);
};
Hamster.prototype.closures={
  checkSleep:function(hamsterInstance){
    return function(){
      console.log(typeof largeVariable);//undefined
      console.log(hamsterInstance);//instance of Hamster named Betty
      hamsterInstance.checkSleep();
    };
  }
};
Hamster.prototype.checkSleep=function(){
  //do stuff assuming this is the Hamster instance
};

var betty = new Hamster("Betty");
Community
  • 1
  • 1
HMR
  • 37,593
  • 24
  • 91
  • 160