1
function pickColor() {
    var random = Math.floor(Math.random() * colors.length);
    return colors[random];
}

let pickColor = () => {
    var random = Math.floor(Math.random() * colors.length);
    return colors[random];
}

when I try and call the second one, I get an error that says "Cannot access 'pickColor' before initialization"

Ryan Heaux
  • 11
  • 1
  • 2
    `let` is not hoisted. – Nina Scholz Jun 11 '20 at 20:26
  • 1
    [var functionName = function() {} vs function functionName() {}](https://stackoverflow.com/questions/336859/var-functionname-function-vs-function-functionname) + [Are 'Arrow Functions' and 'Functions' equivalent / exchangeable?](https://stackoverflow.com/questions/34361379/are-arrow-functions-and-functions-equivalent-exchangeable). For further information: [What's the difference between using “let” and “var”?](https://stackoverflow.com/questions/762011/whats-the-difference-between-using-let-and-var) – VLAZ Jun 11 '20 at 20:29

3 Answers3

1

let pickColor = ... acts like a normal variable declaration + assignment.

The assignment = is done only when the actual line of code is executed.

You can call the function defined this way only if the call happens after the declaration, and in a visible scope.

On the contrary, function() definitions are completely 'hoisted', meaning they act like if they were defined on top of the JS block, and may be called "before" their definition.

Example inspired from http://adripofjavascript.com/blog/drips/variable-and-function-hoisting.html :

isItHoisted();

function isItHoisted() {
    console.log("Yes! This function declaration acts the same as if it was declared _before_ the call.");
}


isThisOtherOneHoisted(); // throws an ReferenceError if used before it is  assigned 

let isThisOtherOneHoisted = () => console.log("Javascript sees that the name exists, but the assignment has not been done.");

/**
like :

There is this variable isThisOtherOneHoisted defined later, just so you know.
isThisOtherOneHoisted(); // error, variable does not even containt a function yet
isThisOtherOneHoisted = () => console.log(...)

*/

As additional details, javascript still "see" that it is used before it is intitialized, so that's why the error message is different than if you used a variable that doesn't exist at all.

The declaration is hoisted for any variable, but only the fact that the variable exist. The assignments with = is only executed where it is written.

Pac0
  • 21,465
  • 8
  • 65
  • 74
  • 2
    Every declaration is hoisted. However, with `let` and `const` the variable is not initialised which leads to [the temporal dead zone](https://stackoverflow.com/questions/33198849/what-is-the-temporal-dead-zone) – VLAZ Jun 11 '20 at 20:31
  • @VLAZ yes, thanks for pointing that out. I edited a bit the answer to try to make this point a bit clearer. – Pac0 Jun 11 '20 at 20:34
1

This is due something called "hoisting".

Basically when you use function, JavaScript moves the function to the top of the scope, so you can access it before initialization. Using let does not do this.

func_1();

function func_1() {
    console.log("Thing");
}


func_2(); // will cause an error

let func_2 = () => console.log("Thing");

Details: Everything is technically hoisted, but let and const don't initialise until you get to their line. If you used var, the variable would start off as undefined

console.log(aa); //undefined
var aa = "hello";
console.log(aa); //hello

console.log(bb) // error
let bb = "hello";

Sidenotes (This part is not a solution to the above problem): 1. You should use const instead of let because I don't imagine you will need to change the value of a function. 2. Another difference between these declarations, is the value of the keyword this (it's the same in this situation but it can be different). I won't explain it here, you will probably come across it if you do more Javascript so worth looking into.

QurakNerd
  • 652
  • 4
  • 11
  • I've tried changing the variable assignments on my arrow function to const and it still doesn't work. – Ryan Heaux Jun 11 '20 at 21:14
  • Sorry for the confusion `const` wont fix your problem, the problem is that usinf `function` makes the function available before it is declared. If you want to use `const` or `let` you need to define the function before calling it. I'm simply saying `const` is better for functions in most cases – QurakNerd Jun 11 '20 at 21:27
  • Thank you! This would mean just mean writing the function before calling it in the text editor right? – Ryan Heaux Jun 19 '20 at 01:59
  • @RyanHeaux Yes, just like when you declare a variable. – QurakNerd Jun 19 '20 at 13:03
0

The function declaration

function pickColor(){...}

is moved to the top of the scope (hoisted first) along with any variables declared with var.

where as function expression declared with let is only accessed when the interpreter comes across that line of code.

Example -

let two = () => {
  console.log('something else');
}

var x = 'demo'
let y = 'demo123'

function one() {
  console.log('something');  
};

function three(){
  one();  
}

variable x , function one(){...} , function three(){...} are moved to the top of the scope as soon as the execution starts,

x is undefined until the line x = 'demo' then x is assigned a value of 'demo'.

Variable y is not initiated or assigned any value until the line

let y = 'demo123'

since let is used to initiate the variable, same goes for the function expression initiated with let.

shiva addanki
  • 85
  • 1
  • 10