8

While making a JavaScript class function, I’m using this. A lot. But while using that, it’s making me wonder whether it would’ve made a difference to use var instead.

var MyClass = function() {
  this.x = 4;
  
  return {
    getVal: this.x
  };
}

versus the same thing with the use of var:

var MyClass = function() {
  var x = 4;
  
  return {
    getVal: x
  };
}

What’s the difference and when should I use which?

The same question applies to the class syntax:

class MyClass {
  constructor(){
    const x = 4;
  }
}

versus

class MyClass {
  constructor(){
    this.x = 4;
  }
}
Sebastian Simon
  • 18,263
  • 7
  • 55
  • 75
Kristian
  • 21,204
  • 19
  • 101
  • 176
  • I’ve edited this question and the top answer — maybe a bit too heavily. This question needed an update to be more useful to new devs today. Novices are getting confused by this and are asking why `this.x = 1; console.log(x);` does not work, or why `const x = 1; console.log(this.x);` does not work, or why `class A { constructor(){ const x = 1; } }; console.log((new A()).x);` does not work, etc. One part is [the difference between a property and a variable](/q/26421417/4642212), another part is [scope](/q/500431/4642212), and _this_ question, ideally, nicely combines the two. – Sebastian Simon Dec 15 '22 at 02:49
  • There’s still a lot of context missing, notably how the ["this" keyword works](/q/3127429/4642212), the difference between [strict and sloppy mode](//developer.mozilla.org/en/docs/Web/JavaScript/Reference/Strict_mode), between [scripts and modules](//developer.mozilla.org/en/docs/Web/JavaScript/Guide/Modules), implicit globals, etc. Two examples: `function A(){ this.x = 1; }; const a = A(); console.log(a.x, this.x, window.x, x);` logs `1` `1` `1` `1` because of the missing `new` keyword in sloppy mode; fails in strict mode. `this.x = 1; console.log(x);` logs `1` in scripts, fails in modules. – Sebastian Simon Dec 15 '22 at 02:58

4 Answers4

9

Identifiers with this become public properties, whereas those with var become private variables. Nowadays, const should be used instead of var; if you can’t use const for a specific variable, use let instead. The access semantics are the same.

When using an identifier with the this keyword, like this.x = 4;, you’re setting a property with the key "x" and the value 4 on the object referenced by this. Since this refers to the instance in the context of a class, such properties become instance members of the class, which means they will be available in each newly created instance of that class. When you use this, it means that your intention is to use it in a class, so you need to instantiate it using the new keyword as shown below.

Example

function Foo() {
  // Variables, scoped to the function. Private access.
  const bar = 'I am bar';
  
  // Properties, set on the instance. Public access
  this.baz = 'I am baz';
  this.secretBar = () => `It’s a secret to everybody: ${bar}.`;
}

const f = new Foo();

console.log(f.bar); // undefined
console.log(f.baz); // "I am baz"
console.log("bar" in f); // false; f does not have the property "bar".
console.log(f.secretBar()); // "It’s a secret to everybody: I am baz.";
  // `secretBar` is in the scope of `Foo`, so it has access to its variables.

While making a JavaScript class function, I’m using this. A lot. But while using that, it’s making me wonder whether it would’ve made a difference to use var instead.

There is a significant difference. You should not create variables with the this keyword that you don’t want to appear in instances of your class, unless otherwise needed.

Sebastian Simon
  • 18,263
  • 7
  • 55
  • 75
Blaster
  • 9,414
  • 1
  • 29
  • 25
  • what if, for the sake of argument, I add a return { } like i've done in my example. doesn't that now become the public scope of the function, rather than all of the this.variables? – Kristian Jun 22 '12 at 19:41
  • @Kristian: Yes whatever you want to return using `return` keyword is still available to outside code. It is up to you which private variables or functions you want to return. Public variables are public so they shouldn't be necessarily put in `return` block. In fact you can search for `JavaScript Revealing Pattern` which uses the same method. BTW, your code won't work unless you add `()` at the end like `var myClass = function() { /* code */ }();` – Blaster Jun 22 '12 at 19:46
  • i'm instantiating it. but ya, i use revealing pattern almost always, which seems to take over the regular visibility of this.something... which is why ive never thought to ask this question before – Kristian Jun 22 '12 at 19:50
  • @Kristian: In revealing pattern, everything is creating using `var` keyword, nothing with `this` keyword and finally whatever members you want to make available to outside code, you put them in `return` block. – Blaster Jun 22 '12 at 19:52
1

You can access this.x with myClass.x, but you can't do that for var x case. This is all about encapsulation.

J-16 SDiZ
  • 26,473
  • 4
  • 65
  • 84
1

If you are not going to need to do inheritance, closures (the var case) and objects (the this case) basically do the same thing and are roughly interchangeable.

Differences to keep in mind:

  • When you use "this" the constructor needs to be called with "new" and methods need to be called with .call if you store them on a variable or pass them as a callback.

  • There might be performance differences if you instantiate lots of objects (current engines may with objects better - but only if you put the methods in the prototype instead of setting them in the constructor)

  • Variables declared with "var" are private and cannot be accessed outside the function. Sometimes this is OK but this can stop you from doing inheritance (there is no notion of "protected in Javascript")

hugomg
  • 68,213
  • 24
  • 160
  • 246
  • _“and methods need to be called with .call if you store them on a variable or pass them as a callback”_ — in 2022, consider using arrow functions; also when passing as a callback, `.bind` would need to be used, not `.call`. Related: [How to access the correct `this` inside a callback](/q/20279484/4642212). _“but only if you put the methods in the prototype instead of setting them in the constructor”_ — The reason being that methods set like `this.method = function(){`…`};` are created every time a new instance is created. But this has nothing to do with using `this` _itself_. – Sebastian Simon Dec 15 '22 at 03:11
1

Expressions like this.x refer to properties; they are like instance variables. These variables have public scope. They work as class variables in object oriented programming.

On the other hand, var x; has limited scope. These are variables that behave like private instance variables and are accessible within the local scope.

Sebastian Simon
  • 18,263
  • 7
  • 55
  • 75
Nishu Tayal
  • 20,106
  • 8
  • 49
  • 101