About var and this in JavaScript

First of all, always use var to declare your variables. Otherwise the variable will become global variables no matter wherever you 'declare' them. Failing to do so would make weird bugs that takes you lots of time to find them.

There are some differences that JavaScript runs between in browsers and Node.js . There are might other differences among different browsers and versions, but I am going to talk about those here.

In Browser

Note: I use Chrome v42. And don't use jsfiddle like website to try js code. I think they'd wrapped the code in some way to isolate them. So it would behave slightly differently compare with a true native browser environment.

  • In a browser's global scope, this === window. All the code is in the window object in a browser.
  • You can use this.yourVar to refer your global variables.

    var a = 1; //all below statements will print out 1;
    console.log(this.a);
    console.log(window.a);
    console.log(a);
    

In Node.js

Node.js is different because it uses below code to wrap all the code in the js file as similar like IIFE.

    (function(exports, require, module, __filename, __dirname) {
    //the code in the js file/module
     });

So there is a local file/module scope in Node.js. Without a var, the variable still will go to the global, but with var as below

    var a = 1; 
    console.log(this.a); //undefined
    console.log(global.a); //undefined
    console.log(a); //1

a is in the local file/module scope. So global.a doesn't work.

Another thing in this scope to note: this !== global, this in a module is empty {}. But if in a function, this in the function will bind to the outer scope, then this === global is true.

console.log(this); //{}
function afunc(){
    console.log(this === global);//true
};
afunc();

Both Browser and Node.js

Due to a JavaScript design defect, this in a child function will be bound to this variable of the outer scope where the parent function gets invoked, not the this in the parent function. In other words, this will be the outer scope which invoked a non-method function.

myobj = {num: 3};
myobj.double = function(){
  var that = this; //must use that to store this
  function help(){
    that.num *= 2;
  };
  help();
};
myobj.double();
console.log(myobj.num);// 6