0

I'm working on adding a few functionality changes to a jQuery component through event callback functions input through a configuration object.

I'd really like to separate each functionality change into it's own set of functions.

What I am wondering is how best to handle the "this" reference. Since there will be multiple functions I want to attach to each callback, I'm assuming I'll need an anonymous function for each option that calls the others. Would I simply pass "this" reference through as a parameter to my functions, or is there a better way to do this?

function somePluginAfterSelectFeatureOne(this, param ){
  // do stuff
}

function somePluginAfterSelectFeatureTwo(this, param){
  // do stuff
}

$('.some-element').somePlugin({
  afterSelect: function(param){
     somePluginAfterSelectFeatureOne(this, param);
  }
});
christian
  • 2,279
  • 4
  • 31
  • 42
  • [This Q&A](http://stackoverflow.com/questions/3127429/how-does-the-this-keyword-work) is worth a read. Try to get all the answers in the quiz right - when you can do so, have another think about your design and the best way to do it :) Also further reading about managing `this` within callbacks in [this Q&A](http://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-context-inside-a-callback). – James Thorpe Mar 14 '16 at 15:31
  • btw you can't use `this` as a parameter name. – Hacketo Mar 14 '16 at 15:42

2 Answers2

2

Yes i would recommend "apply" or closures - i'm not sure what about performance.. i barely remember there was a reason why closuers work better than binding "this", but i don't believe there is a real big deal which one you want. And closures just doesn't always makes sense because it's pretty tight bound to the architecture/design of your app.

Well first of all - i would never pass "this" just as a parameter of your function, javascript knows much better ways to achieve this:

function somePluginAfterSelectFeatureOne(param ){
  // do stuff
}

function somePluginAfterSelectFeatureTwo(param){
  // do stuff
}

$('.some-element').somePlugin({
  afterSelect: function(param){
     somePluginAfterSelectFeatureOne(param);
  }
});

First, remove "this" as param from your function params, it's just wrong ;)

And now the call "somePluginAfterSelectFeatureOne(param)" will fail because, what would be this? Well "this" will lead to the scope which was valid when you defined your function (hard to explain, try to debug that down ;))

Anyways - to control the "this" of your function, you simply rewrite the call:

somePluginAfterSelectFeatureOne.apply(this, [param]);

Now, i guess the "this" which is already available inside of your "afterSelect: function(param){ }" call would be the correct one, right? So, by using the native function "apply", you're able to pass a new "this" to the called function and, still you're able to pass all normal params -> this is just the second param of "apply". But be aware, when using apply -> all params must be passed as an Array (since the internal "arguments" param which is always available on every function call, is in fact an array internally)

Now, this is still the solution with direct bind's - closures are still a different game:

$('.some-element').somePlugin({
  afterSelect: function(param){
     var _self = this,
         myFunction = function(param) {
             _self.anotherFn(param)
         };

     myFunction(param);         
  }
});

As you can see - we simply store "this" as a local variable called "_self".. Now, if the function definition is in the same scope like above -> "_self" will be available on it, even without passing it (that's what we call a "closure" ;)).

But as you can also see - it doesn't always make sense... in your example, you would be forced to move the function definitions inside of your "afterSelect" function, which is totally not the goal here.

So, i would go with an "apply" pattern and passing the "this" nicely - kind of a "delegate" ;)

Oh and to make a complete roundup - it's also possible to override "this" directly on function definition level. Use "bind" for this:

function myFunction(param) {
    this.secondFunction(param)
}.bind(somethingDifferentWhichWillBeUsedAsThisInside)

I got also some all-time favorited threads regarding these two topics here:

Community
  • 1
  • 1
jebbie
  • 1,418
  • 3
  • 17
  • 27
0

this is not a valid parameter name. Change it to element and pass it to your custom functions.

I prefer not to use this unless it's within a prototype method (or the constructor).

function somePluginAfterSelectFeatureOne(element, param ){
  // `element` is what you wanted `this` to be 
}

$('.some-element').somePlugin({
  afterSelect: function(param){
     somePluginAfterSelectFeatureOne(this, param);
  }
});

If you really want to use this, you could use Function.prototype.call

function somePluginAfterSelectFeatureOne(param ){
    console.log(this); // The element that the event fired on 
}

$('.some-element').somePlugin({
  afterSelect: function(param){
     somePluginAfterSelectFeatureOne.call(this, param);
  }
});
Ruan Mendes
  • 90,375
  • 31
  • 153
  • 217
  • Nice! Hitting the nail to the head with about 2000 fewer words than i did :P – jebbie Mar 14 '16 at 16:02
  • @jebbie :) I also wanted to point out that using `this` from global (or any free standing) functions looks really weird and confusing. – Ruan Mendes Mar 14 '16 at 16:04