Hacker News new | past | comments | ask | show | jobs | submit login
What does ‘that = this’ in JavaScript mean? (dbwriteups.wordpress.com)
41 points by sidthesloth on April 8, 2017 | hide | past | favorite | 58 comments



I prefer using `self` rather than `that`, for caching `this`.

Must be because I have a strong python background, but generally I find "self" makes more sense than a wild "that"!


I prefer to use a variable name that describes the type of the object in short.

So if my "this" object is actually an AwesomeTableWidget instance, I might do:

  var table = this;
I like the bit of extra documentation it provides... Or maybe this is just a remnant of all the C code I've written over the years, where it's common to have an object pointer as the first argument to a function and it's usually named like this.


you are so much better off if you can avoid using this when writing js. It's as bad as (and as useless) the keyword 'new'


negative votes here are totally unfair. I was pointing it out that the 'this' keyword is dangerous.


Why is it dangerous?


By using `self` you shadow a global variable which is a reference to the current context (window object) in which the code is executed.


Which should be accessed by window.self anyway so it doesn't really matter? There are so many poorly named global variables (top etc) that worrying about shadowing them seems meaningless.


It matters when you are running in workers in which case the window object does not exists


I always found context, i.e. let context = this, to be far more descriptive.


I use me. or if its a jquery object its $me. Probably because of my VB6 background. :-)


Note: Arrow functions cannot help us when the function is defined on the object literal as it will resolve to the enclosing lexical scope, which in this case is the global scope.

This is not true. With an arrow function, the example prints "Object Name". MDN says: "An arrow function does not create its own this context, so this has its original meaning from the enclosing context." [1]

(The "enclosing context" in this case refers to the context in which the arrow function was created, not the context in which the function in which the arrow function was created was created.)

[1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...


    var name = "Global Name";
    var obj = {
        name : 'Object Name',
        printName : function() {
            setTimeout(() => {
                console.log(this.name);
            }, 2000);
        }
    };
    obj.printName();    //prints "Object Name"
    var printNameReference = obj.printName;
    printNameReference(); //prints "Global Name"
You will see that "Global Name" will still be printed out. The reason is because arrow functions take the enclosing lexical scope, and the arrow function to setTimeout in the example is created each time the printName function is invoked. The printNameReference() invocation sets the scope of the printName function to global because of the way it is invoked and hence the arrow functions to setTimeout will also take this scope.

Changing the printName function itself as arrow function does not help either.

    var obj = {
        name : 'Object Name',
        printName : () => {
            setTimeout(() => {
                console.log(this.name);
            }, 2000);
        }
    };
The above code will again set the printName function to the enclosing global scope, because that is where obj is declared.


If you add "var that = this;" to printName function the printNameReference still doesn't work.


For my company, `that = this` means that your code review gets marked as "Revision required".


Same here. Bind your functions properly!


Since nobody has mentioned it yet, my first introduction to that = this; was JavaScript: The Good Parts, Unearthing the Excellence in JavaScript by Douglas Crockford

Well worth a read for understanding the differences and relative powers of a prototypical language and how to get it to behave almost like a classical one. I think the one big thing it missed was immediately envoked function expressions.

http://shop.oreilly.com/product/mobile/9780596517748.do


Title should be "var that = this".

Without "var", you're assigning to a global variable which you don't want in most cases.


And if you use strict mode, the engine may throw an error when you create a global variable.

    function foo() {
      'use strict';
      bar = 5; // Error (maybe)
      window.bar = 6; // No error
    }


Yes, and other things you call from within your function might change the global variable, especially if they all use the name "that".


hidden `var that;` `that = this` solved. :)


even

    that = this; var that;
would work. JavaScript!


I'm not a JavaScript expert so I may be wrong, but I don't think that's right is it?

If you are in a function scope (which you would be in the context of this article as we're talking about what the receiver is at different points) then variables assigned without any modifier are defined as locals, in the scope of that function. They are hoisted to the function scope, out of any block scope, unless you use 'var', but they're still locals aren't they?


No, GP is correct. If you omit the `var` (or `let`/`const` in es6) then you are implicitly assigning a property on the global object (`window` in the browser), in essence setting a global variable. Never omit `var`.

If you are in a function scope, `var` declarations are hoisted to the top of the function scope, outside of any block scope, as you described. `let` and `const` declarations from es6 are block scoped. Personally I highly recommend never using `var` and simply adopting es6 and using `let` and `const`, preferring `const`, everywhere as they have significantly simpler and more intuitive semantics.


I agree with the way you've responded. But there can be a case where omitting var on a variable definition will not assign it on the global object. That is, if you hit a variable by the same name as you go up the scope stack, you will just overwrite that variable's value. Example:

  function f1(){
    var v = 'val';
    var f2 = function(){
      v = 'inner'; // will not hit global scope
    }
    f2();
    console.log(v);
  }

  f1();
  console.log(v);

output:

  val
  Uncaught ReferenceError: v is not defined


"Assigning a value to an undeclared variable implicitly creates it as a global variable (it becomes a property of the global object) when the assignment is executed."

From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...


Right. This is a typical language design mistake. It happens in phases:

- "We're not going to have declarations in our language. First use defines a variable".

- "We need some way to define local variables. But if we make that the default, existing code will break. So the default has to be global."

- Embrace the pain.

There are variants on this theme. Python is local by default. Go has variable creation by assignment with ":=", but with weird semantics for multiple assignment.

Other classic mistakes are "we don't need a Boolean type; 1 and 0 are enough", and "there's only one kind of integer". Fixing those later always sucks.


No, they're actually globals.


This an ugly convention. By always using `that` you lose an opportunity to create a meaningful variable name which would be more descriptive. Why not use?

    var widget = this
Besides using more functional approach and arrow functions you can free up your code from lining methods via this keyword.


That's way more confusing. At least with `that`, you know it is pointing at the current instance. If you see `anyOtherVariableName` you have to know what it was assigned.


This a follow up post on how to replace 'that = this' assignments with arrow functions: https://dbwriteups.wordpress.com/2017/04/14/replacing-that-t...


Is it a poor pattern to use #bind a lot instead of this or that? I tend to put most of the code in procedures like functions and bind it to whatever context I need, if not the regular this.


If you're using React and you're not using arrow functions, then it's very common to see bind() references.


I stopped using this altogether and it makes my code better


It's absolutely useless anyway unless you're trying to slightly optimize cpu and memory usage for at least hundreds of instance creations. Typically this scenario would be found in libs, not in application code.

I completely ignore this, prototypes, classes, Function.prototype.bind, etc. Code is much cleaner and easy to follow for devs of all skill level.

Also, even if you like these features, var that = this is unneeded if you use a transpiler and have access to the more modern JS constructs like arrow functions.


How do you factor out "this" in cases where methods and instance data logically belong together?


1) Either use a functional style like beaconstudios said where it's perfectly normal to separate the data and the processing.

2) Or if you want to keep an OO style, use the module pattern with private functions closing over the data.


If you're completely getting rid of "this" references then you're probably following a functional style and will keep data and functions separate, passing pure data as arguments rather than combining data and functions into classes.


Using an object factory and referencing the object within the factory's lexical scope


If you have closures, you can simulate objects. In many different ways, most of them bad. If you have an interpreter with decent variable semantics, you get closures. That's how LISP did objects in the 1980s, before people knew better. Javascript somehow got it from there.

Why do we have to keep reviving the bad ideas?


> you get closures. That's how LISP did objects in the 1980s, before people knew better

That one can use closures for objects was demonstrated with Scheme in the 70s. See for example: Scheme: An Interpreter for Extended Lambda Calculus". MIT AI Lab. AI Lab Memo AIM-349. December 1975.

http://library.readscheme.org/page1.html

It's also a typical topic in education to show how to use closures to implement a primitive object system, similar how one learns to 'implement' numbers in pure lambda calculus.

But actual object systems in Lisp from the 70s/80s mostly did not use closures as objects. None of LOOPS, Flavors, CLOS, KRL, KEE, FRL, ... uses closures for their implementation. Even in 'Object Lisp', which is relatively close to Javascript's objects, they don't use closures:

http://www.unlambda.com/lispm/lmi-source/extract/dj_full/l/o...

In

http://www.unlambda.com/lispm/lmi-source/extract/dj_full/l/o...

you can see that objects in Object Lisp were implemented by using structures (aka records), not closures.


Lisp had CLOS in the 1980's, and before that, precursors to CLOS.


Despite writing ES6 with arrow functions, I find that I prefer writing `const self = this` than relying arrow-function lexical scoping. Maybe it will change over time, but for now that way seems to make he intent far clearer and less likely to mess up in a future refactoring.


To make it more clear, you can use names. For example:

  function Car() {
    const car = this;
    function foo() {
       car.engine = "v8"; // vs self.engine
    }
  }


Not much clearer, if not less.

var self = this; and var that = this; are the standard way and the intent is understood right away.


That's like, your opinion, man.


Yup. All the stuff I say is definitely my opinion.

I'm not the one who invented JavaScript or anything like that.


I try to omit this convention by promises or bind() when possible, but sometimes when using 3rd party libraries it's a necessary evil.


Is there a single instance in real JS code where it's this binding is actually useful?


Yes - if you want to use this inside a callback within your function.


Oh, I wasnt being clear. I meant the default binding behaviour, not using .bind().


One common example would be to refer to instance properties of an object from a method that is attached to the object's prototype.

Actually I think using bind() would be a very unusual thing, but that could just be my style of writing code (I don't think I've ever used it in any code I have written over the years).


It depends on what the meaning of the word "it's" is.


this should never be that complicated.


I use var _this = this


Nicely done!

Thank you for sharing!


It means JavaScript was a poorly designed language.


Not sure I'd go that far but it definitely has its warts, like all languages, and developers need to understand what they are.


Don't get me wrong: I love JavaScript, I write piles of it all the time, and I said "was" not "is" because it's been vastly improved since it was originally badly designed, but I still get screwed by accidentally using "this" in the wrong context.

It's such an easy accident to make, and it's so hard to see, because when you're looking at code you wrote, you see what you meant to write, instead of what's actually there. Programming languages are user interfaces, and "this" is a user interface dark pattern, an unforced design mistake that doesn't make the language any more powerful, but lays a deadly trap for beginners that also bites pros.

It's tricky to understand and hard to explain (this is actually a dynamically bound keyword, not a lexically bound variable), so it's fodder for the thousands of blog posting explaining it like the one we're discussing.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: