Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I was curious which way is generally preferred, or if there is even a preference, given these two options:

$.ajax({
    url: '../Component/GetSearchFilters',
    success: function (response) {
        console.log("Outer scope:", this);
    }.bind(this)
});

If I was inside of a function where I needed both "this" and outer-scope's "this," then I would assign a variable, but I generally prefer binding to keep variable usage scoped to as few lines as possible.

share|improve this question

closed as unclear what you're asking by Jamal Jul 25 at 19:41

Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.

6 Answers 6

up vote 19 down vote accepted

Things that would favor var self = this;

  • bind isn't supported in IE8 and Safari5. If you aim to build a library or code that supports legacy browsers, then var self = this would be more cross-browser friendly.

  • Sometimes, callbacks are bound to a certain context when executed like in the case of jQuery's $.each where this is the current item. If you don't want to lose this context but still want to have the parent context, then it's another reason to use var self = this;.

  • Calling bind creates a brand new function with a forced context. This function creation step might be a performance issue in the large scale especially if you call bind inside a loop.

Reasons that would favor bind

  • Performance wouldn't be an issue if you just created a bound function once and reused it in several places. Like you can create a bound function and call that bound function in a loop (instead of calling bind in a loop).

  • bind also alleviates you from doing call(customContext) or apply(customContext) explicitly all the time.

  • Scope lookup (looking for variables if not found in the current scope) can pose a performance problem especially in very deep scopes. You've probably heard of the tip "passing to local is better".

I'm not saying bind is bad (I use them extensively myself). It just needs to be used in the right situations. Also, the performance issues for both might be so negligible, they can only be seen if you aim to do stuff in less than 16ms (do stuff in 60fps).

share|improve this answer
2  
Note that the first can be solved with es5-shim. Using self requires a closure for the callback, but I haven't investigated a) if there's no closure without it and b) how much of an impact that has. –  David Harkness May 15 '14 at 20:29
1  
It all depends on what the code is doing and the js engine but I would guess that the closure of this to be a more expensive operation. IMO you should just use what you feel is best and not worry about micro optimizations. –  pllee May 15 '14 at 21:46
    
@pllee I believe that the function returned by bind is a closure as well, so this isn't really a mark against var self = this. –  wingedsubmariner May 16 '14 at 4:59
    
After doing some research the closure is much faster than bind currently in most js engines, the overhead is still minimal and I would stick to what you prefer. –  pllee May 16 '14 at 14:11
    
@pllee You are right. Self closure is faster than bind: jsperf.com/bind-vs-self-closure –  Harish Anchu Apr 11 at 7:45

Just to add another alternative, instead of doing

var self = this;
something( function () {
    // callback stuff
} );

one can also do this:

( function( self ) {
    something( function () {
        // callback stuff
    } );
} )( this );

Is it better? It might depend. The downsides are another scope and a deeper level of indentation.

One upside is that it's self-contained and the new scope avoids cluttering up the surriounding scope, though you can argue that in well-designed code there shouldn't be too much code in one scope anyway.

One could also say it's not too readable, though I personally would argue that bind( this ) really is that much more readable.

I just wanted to point out another option as having more options to choose from is generally a good thing.

share|improve this answer
    
A very nice trick. Thanks for adding this –  Ahmad Ajmi Aug 16 '14 at 18:47

Simple rule of thumb use bind if you don't need to have a reference to the original this context. If the original this context is needed use a self variable obviously.

 $.ajax({
    url: '../Component/GetSearchFilters',
    success: function (response) {
        console.log("Outer scope:", this);
    }.bind(this)
});

vs

var me = this;
$.ajax({
    url: '../Component/GetSearchFilters',
    success: function (response) {
        console.log("Outer scope:", me);
    }
});

Using bind is slightly more consise and easier to read than the me variable but one way over the other really isn't a big deal.

share|improve this answer

One thing to note about self specifically; by default, self is an alias for window. If you override that with a var self, you're fine, but if you forget to add that line and you use self in an inner scope assuming it's referring to your outer scope, there's a potential for some nasty bugs that can be hard to track down.

For that reason, I tend to use some other identifier: that, _this, some variable denoting what type it is, such as app if it's referring to something I'm calling an "application", view if it's a view, etc. In this case, as long as you're in strict mode or properly linting your code to object to using undefined variables, you'll get notified if you forget to add that alias.

share|improve this answer
    
I tend to use me, but I agree that it's better to use a name that actually means something. –  Dave Van den Eynde Oct 10 '14 at 9:36

Depending upon what you are doing, using bind will be a little slower or a bunch slower. I found myself asking this question when pondering if it were better to close over a set of variables, or pass and bind them as arguments (they never change).

Here is the code I wrote to test this out. You can change the values of I and J to adjust the loops. When it comes to actual execution, they are comparable in speed (the closure was a little bit faster). Unless of course the optimizer gets to it and then the closure is about 4 times faster. However, instantiation is about 2-3 times slower with bind.

These tests were performed in Firefox 33

function q(a, b){
  var a = {a:a}, b = {b:b};
  return {
    p:function(){ return a.a + b.b; },
    s:function(){ return a.a - b.b; },
    m:function(){ return a.a * b.b; },
    d:function(){ return a.a / b.b; },
    get_a:function(){ return a.a; },
    get_b:function(){ return b.b; },
    set_a:function(v){ a.a = v; },
    set_b:function(v){ b.b = v; },
  };
}

var I = 1000, J = 100;
var i, j;
var t0 = performance.now()
for(i = 0; i < I; i++){
  var k = new q(5, 6);
  for(j = 0; j < J; j++){
    k.p() + k.s() + k.m() + k.d();
  }
}
var t1 = performance.now();

document.write(t1 - t0)
document.write("<br/>")

var p;

(function(){
  function abp(a,b){ return a.a + b.b; }
  function abs(a,b){ return a.a - b.b; }
  function abm(a,b){ return a.a * b.b; }
  function abd(a,b){ return a.a / b.b; }
  function ga(a){ return a.a; }
  function gb(b){ return b.b; }
  function sa(a,v){ a.a = v; }
  function sb(b,v){ b.b = v; }
  function w(a, b){
    var a = {a:a}, b = {b:b};
    var m = {};
    m.p = abp.bind(m,a,b);
    m.s = abs.bind(m,a,b);
    m.m = abm.bind(m,a,b);
    m.d = abd.bind(m,a,b);
    m.get_a = ga.bind(m,a);
    m.get_b = gb.bind(m,b);
    m.set_a = sa.bind(m,a);
    m.set_b = sb.bind(m,b);
    return m;
  }
  p = w;
})();

var t2 = performance.now()
for(i = 0; i < I; i++){
  var k = new p(5, 6);
  for(j = 0; j < J; j++){
    k.p() + k.s() + k.m() + k.d();
  }
}
var t3 = performance.now();

document.write(t3 - t2)

TL;DR: .bind is slower.

share|improve this answer

Since no one has mentioned it yet. jQuery's proxy - a working cross browser solution:

$.ajax({
    url: '/echo/json/',
    success: $.proxy(function(){
        console.log(this === window); // true
    }, this)
});

this would normally refer to the jqXhr object in the success callback.

http://jsfiddle.net/thLhh54q/

share|improve this answer

Not the answer you're looking for? Browse other questions tagged or ask your own question.