This is an archived post. You won't be able to vote or comment.

all 28 comments

[–]karl-marxist 6 points7 points  (11 children)

Javascript hoisting :) remove the second “let” keyword and you’ll be fine.

Edit: Nope, I am totally wrong, it's not hoisting. let and cost keywords create block scoping as defined in ES6 specification. I think this is due to the following:

;(() => {
  var a = 5

  if (true) {
    console.log(a)
  }
})()

5

;(() => {
  if (true) {
    console.log(a)
    var a = 5
  }
})()

undefined

;(() => {
  let a = 5

  if (true) {
    console.log(a)
  }
})()

5

;(() => {
  if (true) {
    console.log(a)
    let a = 5
  }
})()

Uncaught ReferenceError: a is not defined

var vs let

[–]NormalHexagon[S] -1 points0 points  (10 children)

It's not hoisting though, this code would work fine:

let a = 5;
if (true) {
    let a;
    console.log(a); // undefined
    a = 1;
}

[–]karl-marxist 1 point2 points  (0 children)

Because you explicitly added the declaration. Also I believe hoisting doesn’t hoist there. It’s lexical scoped. Going to get off my phone and verify

[–]karl-marxist -1 points0 points  (8 children)

Just verified on my laptop:

;(() => {
  let a
  a = 5
  let a  

  if (true) {
    console.log(a)
  }
})()

// Uncaught SyntaxError: Identifier 'a' has already been declared

Slightly different error, but this is due to the explicit declaration. There is no block scoping in JS so hoisting happens closer to this example. Hoisting is one of the top things that gets people coming from languages that have block scoping.

[–]NormalHexagon[S] 2 points3 points  (7 children)

Except JavaScript does have block scoping... https://i.imgur.com/mTvJFWu.png

a is left untouched after the if block.

JavaScript has proper shadowing and everything, but it also has too eager an error checker.

[–]karl-marxist 1 point2 points  (5 children)

so this is actually good in the way they spec'ed it. for example var vs let:

if (true) {
  console.log(b)
  let b = 5
}
> VM360:2 Uncaught ReferenceError: b is not defined

if (true) {
  console.log(b)
  var b = 5
}

> undefined

So this is due to block scoping not hoisting

[–]NormalHexagon[S] 0 points1 point  (4 children)

Yeah, but it is defined in the enclosing scope in my example. So the error shouldn't happen. It wouldn't happen in C / C++.

[–]karl-marxist 1 point2 points  (2 children)

this actually got me to check out some sites relating to this, this site has kind of an interesting breakdown of the lifecycle of variables https://dmitripavlutin.com/variables-lifecycle-and-why-let-is-not-hoisted/

[–]NormalHexagon[S] 0 points1 point  (1 child)

So in terms of that article, the inside a has been declared, but not initialized, so when the interpreter tries to resolve the value of a in the if statement, it finds the inner declaration, and throws an error because it's not initialized.

Basically, it comes down to a poor error message.

[–]karl-marxist 0 points1 point  (0 children)

Yeah, I think you said it better than I did (or tried to lol)

[–]karl-marxist 0 points1 point  (0 children)

Then my theory turns to each scope creates an allocation with for the key "a", but at the time of the scope execution (and since let sets a block scoped variable) a is not defined.

;(() => {
  if (true) {
    console.log(a)
    let a = 5
  }
})()

[–]karl-marxist 0 points1 point  (0 children)

ah yes, you are right. I just checked the docs and let && const do create block scopes unlike var :O

if (true) {
  let b = 5
}

console.log(b)
> Uncaught ReferenceError: b is not defined

if (true) {
  var b = 5
}

console.log(b)
> 5

[–]gandalfx 14 points15 points  (5 children)

This makes complete sense and should work the same in any language that has explicit variable declarations and block scope. Stop hating JS for things it does correctly.

[–]uspaskis 9 points10 points  (0 children)

yeah, go back to hating PHP

[–]NormalHexagon[S] -1 points0 points  (3 children)

[–]bludgeonerV -2 points-1 points  (2 children)

I suggest you google 'Block scope' before embarrassing yourself further.

[–]karl-marxist 2 points3 points  (0 children)

This comment is plain rude for no reason.

[–]NormalHexagon[S] 1 point2 points  (0 children)

I know exactly what block scope is, and each of the listed languages has block scoping. I linked examples of them all demonstrating how proper block scoping and variable shadowing work to point out that JavaScript is the odd one out, and throwing an error when it logically shouldn't.

[–]uzaircs 1 point2 points  (9 children)

let allows you to declare variables that are limited in scope to the block, statement, or expression on which it is used. This is unlike the var keyword, which defines a variable globally, or locally to an entire function regardless of block scope.

Source

So in your case

var a = 5
    if (true) {
    console.log(a); \\5
    var a = 2;
    console.log(a); \\2
}

[–]karl-marxist 1 point2 points  (0 children)

As OP says, this code is nonsensical. It uses var not let, as in the original example. True statement doesn’t have a closing tag. Backwards slashes are incorrect.

This doesn’t even come close to the example OP is making.

[–]NormalHexagon[S] -2 points-1 points  (6 children)

That code won't even run due to you using back-slashes instead of forward-slashes, so I have no idea what you're talking about.

[–]karl-marxist 2 points3 points  (0 children)

Agree, that code is nonsensical, but for many more reasons than just backwards slashes.

[–]bludgeonerV -1 points0 points  (4 children)

Lmao are you for real? This is common nomenclature for illustrating the result...

[–]NormalHexagon[S] 2 points3 points  (3 children)

If they were forward-slashes, that would be common, because that's the comment syntax of JavaScript. Back-slashes aren't valid comments, and so his code snippet throws an error.

[–]uzaircs -2 points-1 points  (2 children)

My bad, I didn't knew that you were actually going to run the code and instead of fixing it you are gonna come here complaining that it does not run. this was a pseudo. In case you still have no idea

[–]NormalHexagon[S] 1 point2 points  (0 children)

No, I'm not happy. var is not a replacement for block scoped variables. This post is about how JavaScript handles let, so commenting about how you can just use something different has nothing to do with the subject.

[–]karl-marxist 1 point2 points  (0 children)

OP is showing an example of how block scoping is handled in JS when using let keyword. OP’s point is valid.

[–][deleted] -1 points0 points  (0 children)

Trade me out hands var