Skip to content

Instantly share code, notes, and snippets.

@cjohansen
Created November 23, 2012 10:43
Show Gist options
  • Save cjohansen/4135065 to your computer and use it in GitHub Desktop.
Save cjohansen/4135065 to your computer and use it in GitHub Desktop.
Naming this in nested functions

tl;dr

If you must nest functions in a way that requires access to multiple this', alias outer this to something meaningful - describe the value it's holding. Treat this as the invisible first argument.

In general though, avoiding the situation (nested functions and frivolous use of this) will frequently produce clearer results.

Naming this in nested functions

I was accidentally included in a discussion on how to best name this in nested functions in JavaScript. +1's were given to this suggestion of using _this.

Giving style advice on naming nested this without a meaningful context isn't too helpful in my opinion. Examples below have been altered to have at least some context, although a completely contrived and stupid one.

Assume this setup:

var morgan = new Person("Morgan");

Bad

morgan.logger = function() {
  var self = this;
  return function() {
    console.log(self);
  };
};

Bad

morgan.logger = function() {
  var that = this;
  return function() {
    console.log(that);
  };
};

Bad (still no good in my opinion)

morgan.logger = function() {
  var _this = this;
  return function() {
    console.log(_this);
  };
};

Meaningful name: Better

morgan.logger = function() {
  var person = this;
  return function() {
    console.log(person);
  };
};

Another more realistic example

Function.prototype.throttle = function (ms) {
    var fn = this;
    var timer;
    return function () {
        clearTimeout(timer);
        var args = [].slice.call(arguments);
        timer = setTimeout(function () {
            fn.apply(this, args);
        }, ms || 100);
    };
};

function myFunc() {
    console.log(arguments);
}

var throttled = myFunc.throttle(50);
throttled("Hey there!");

In the above example, "fn" is way superior to "_this". Still, the following example would be even better:

function throttle(fn, ms) {
    var timer;
    return function () {
        clearTimeout(timer);
        var args = [].slice.call(arguments);
        timer = setTimeout(function () {
            fn.apply(this, args);
        }, ms || 100);
    };
};

function myFunc() {
    console.log(arguments);
}

var throttled = throttle(myFunc, 50);
throttled("Hey");
throttled("Hey there!");

What about bind?

In cases where you don't also need the nested this bind works fine. However, since the bind happens on the bottom, it can also create quite confusing results. I also think the massive use of the word this in code that binds a lot - see most jQuery code snippets - is very confusing. Naming each thing is generally more readable in my opinion.

If using bind, I generally prefer a separate bind over the Function.prototype one, e.g.:

morgan.logger = function () {
    return bind(this, function() {
        console.log(this);
    });
};

Because it moves the target object up. "object, method" is also less noisy than "object.method, object".

However, this example can be even better written like so:

morgan.logger = function () {
    return bind(console.log, console, this);
};

i.e., with added partial application. With the non-Function.prototype bind, you can even do one better, like so:

morgan.logger = function () {
    return bind(console, "log", this);
};

In my opinion, this is pretty concise and readable. I think lodash's bind supports this kind of use.

In summary

See tl;dr ;)

@ralphtheninja
Copy link

I like the examples with throttled. The last one obviously much better and easier to understand. There's no use adding a throttle function to the function prototype since you can just use myFunc as a parameter to a function instead. Mind adding just a simple skeleton for myFunc( )? e.g.

function myFunc( ) { console.log(arguments); }

Makes it a little easier for people to copy paste the code and try it out.

@qerub
Copy link

qerub commented Nov 23, 2012

What about using bind?

morgan.logger = function() {
  return function() {
    console.log(this);
  }.bind(this);
};

(My personal favorite.)

@cjohansen
Copy link
Author

@wchristian The point isn't to rename this just for the sake of it. This is about those cases where you need to refer to the value in a nested function.

@ralphtheninja Good call, added.

@qerub In cases where you don't also need the nested this bind works fine. However, since the bind happens on the bottom, it can also create quite confusing results. I also think the massive use of the word this in code that binds a lot - see most jQuery code snippets - is very confusing. Naming each thing is generally more readable in my opinion.

Added a section about bind.

@hshoff
Copy link

hshoff commented Nov 23, 2012

Great write up!

We went with _this in our style guide because it means you don't have to jump back up to the top of the function to the variable assignment to verify that it was a reference to the outer scope this. But I can see how naming the saved reference could be more useful than saving you the time of jumping back to the top.

The important part is consistency. Nothing's worse than some folks on the team naming their saved reference while others use self and others use that.

Bind is great too! We didn't mention bind in the style guide because we just wanted to address how to store a reference to this, but this is specific to Airbnb code only because our legacy JavaScript doesn't use bind anywhere so we have a lot of var [self | that | _this] = this; floating around.

Hope that clears up why we went with _this and feel free to open an issue on the style guide we love feedback from the community and welcome pull requests!

@hshoff
Copy link

hshoff commented Nov 23, 2012

I added a link back to this writeup in the resources section called other styles.

Hopefully, we'll start building up a good resource on JavaScript style, so teams and developers can read about the other styles out there and make the best decision for themselves.
🍻

@sporto
Copy link

sporto commented Nov 24, 2012

I don't agree that this is good style. Let me explain why:

Dynamic context
By doing something link var person = this, you are implying that 'this' is always a kind of person. But in JS you can apply that function to any other object, so 'this' might be something entirely different.

Convention
If I see something like person.something() inside a nested function I will be forced to go up to find the definition for 'person'. However if I see something like self.something(), it is instantly clear that you are referring to the current object. Conventions like this make your code faster to read and reason about.

Familiarity
Self is a common keyword in many languages that means 'the current instance', so again I think it is clear what object it is referring to.

So in my opinion 'self' is superior alternative than using ad-hoc names for 'this'.

@sporto
Copy link

sporto commented Nov 24, 2012

After reading the examples again, I am not sure anymore about what you are suggesting. Are you suggesting not use _this all the time or only when you have a function that returns another function? In the second case I can see that there is some value on naming this to something ad-hoc.
#1

morgan.logger = function() {
  var self = this;
  setTimeOut(function () {
        self.doSomething();
    }, 100);
};

In this case I believe that 'self', 'that', '_this' is the right keyword to use.
#2

morgan.logger = function() {
  var self = this;
  return function() {
    console.log(self);
  };
};

Not sure about this one, as it is returning a function. That function could end up anywhere. And self doesn't really mean the current instance.

@millermedeiros
Copy link

@cjno you should post it on your blog, took me a while to find it again (I wasn't sure who wrote it and if it was a gist or not).

I think self is OK in most cases since it's a known convention (already have some meaning attached to it), but I do agree that descriptive names are a good idea. If you avoid using the this keyword in multiple places it gets easier to extract/reuse the methods later if needed:

Person.prototype.walkAndTalk = function(){
  walkAndTalk(this);
};

// no need for inheritance or awkward Function#call
Robot.prototype.walkAndTalk = function(){
  walkAndTalk(this);
};

function walkAndTalk(target){
   target.walk();
   targat.talk();
}

But of course the this keyword gives a lot of flexibility and is an extremely powerful tool.

I also wrote about the this keyword in jQuery and why it should be avoided: http://blog.millermedeiros.com/avoiding-the-this-keyword-on-jquery/

Cheers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment