Hacker News new | ask | show | jobs
by Meegul 3530 days ago
It's spelled out pretty well in the article. But if you want another example, consider these two code blocks:

  var foo;
  var bar;
  { 
    let foo = "hello";
    var bar = "world";
  }
  console.log(foo);
  console.log(bar);
This produces:

  undefined
  world
The reason being that the `let` statement restricted that variable to the block it was in (defined by the { and }). `var` declares the variable globally, allowing it to be accessed outside of the {}.

We prefer now to use `let` and `const` over `var` because it doesn't pollute the global namespace. With the asynchronous nature of Javascript, it's theoretically possible for you to declare a variable with `var`, assign it a value, then immediately use that value and find that it's different than what you expected because of another function using the same variable name. This isn't possible with `let`.

5 comments

> `var` declares the variable globally"

Not quite. var's are hoisted to the top of their most local function.

  (function(){
    (function(){
      var x = 123;
    })();
    {
      var y = 123;
    }
    // Here, x is not defined, but y is
  })();
  // Here, neither x nor y are defined
The above code essentially gets translated to the following:

  (function(){
    var y;
    (function(){
      var x;
      x = 123;
    })();
    {
      y = 123;
    }
    // Here, x is not defined, but y is
  })();
  // Here, neither x nor y are defined
From the article--

let x = 'outer';

function test(inner) {

  if (inner) {

    let x = 'inner';

    return x;

  }

  return x; // gets result from line 1 as expected
}

test(false); // outer

test(true); // inner

This makes it seem like let creates global variables. Why would you want to return a variable from outside the function? Doesn't that create massive overhead in terms of keeping track where variables are initially set? Easy to understand in this example, but what if let x = 'outer'; is defined at the top of a 5000 line script and this function appears near the bottom?

Edit: Turns out I don't know how to format code. This is in the first example of section 3.1 Block Scope Variables.

If you were to then reference 'x' from another block of code, say in another <script> element in the case of web development, 'x' would not be a defined variable, whereas with 'var', it would be.

This is mostly just a case of 'let' restricting a variable to the block it is in, and the child blocks. In your example, `let x = 'outer';` is sort of acting like a global variable, but the importance is that if another script were to be running, it could not access that instance of 'x'.

Ehw. Yeah, I sort of assumed that you had a top level function / IIFE (in a .js file, FWIW) in which the var's were nested.

Somebody writing stuff, into the global namespace, directly in <script> tags, has bigger problems :-)

Ahh, I get it, Thank you! In the same way var scopes to window if defined outside of a function, let scopes it to the current script block. That is very neat.

I'll read more into uses of let over var. Function level scoping a la var feels like less mental overhead, but as I read more I'm sure my opinion will change.

Javascript (in browser) is async, but not concurrent (like say, threads). JS will run the code in an event handler to completion (or not - while(1){}) before starting the code for the next event. Thus, code from one execution path cannot update variables in another path "immediately".

You could use a variable in a callback for an event that was assigned on the line above, and it since has changed, but it's important to remember that the callback (or promise, etc) does not actually run until an arbitrary time "later".

"var" declares function scope, not global scope. If you really want global scope, declare the variable with no keyword preceding it (e.g. "foo = 3").
Close. Assigning "foo" without var will look up the lexical scope stack from most nested to global. If nothing exists, it will indeed make a new global. However, if there is a "foo" somewhere in that scope stack, it will update that variable.

    var a = function () {
      var foo
      var b = function () {
        foo = 3
      }
      b()
    }
    a()
    console.log( foo )  // undefined
In the code above, the "foo" in function a is set to 3, rather than creating a global. (changing the "vars" to "lets" would do the same thing, FWIW)

Also, "use strict" mode will not let you make a global that way. If in strict mode, you have to put the "var" outside of any function, then assign it (either on that line, or later) to make a global.

> With the asynchronous nature of Javascript, it's theoretically possible for you to declare a variable with `var`, assign it a value, then immediately use that value and find that it's different than what you expected

Can you give an example ? My understanding is that the closure freeze the variable in the time the function was called. It can happen if you do not use a closure (function) though.

Here's a post on Stackoverflow that can explain it better than I can: http://stackoverflow.com/questions/21363295/understanding-ja...
Here's how you should do it:

  for(var i=0; i<=3; i++) count(i);

Or a real world example:

  for(var i=0; i<texture.length; i++) createPattern(i);

  function createPattern(i) {
    texture[i].onload = function() {
      pattern[i] = ctx.createPattern(texture[i], 'repeat');
    }
  }
I've made a blog post about closures: http://www.webtigerteam.com/johan/en/blog/closure_en.htm

It would be cool to write like this (but you cant):

  pattern = texture.map(t => t.onload => ctx.createPattern(t, 'repeat'))
Javascript closures are like Ruby blocks and closures: you get to "touch", as well as "look" - and also see "touches" that happened in between times elsewhere.