Why can't we use function variables

let greeting = "hi"

outside(greeting)
  
let outside = function(x){

    document.getElementById("myH1").innerHTML = x
}




let inside = function(x){console.log(x)}


It says in console: Cannot access ‘outside’ before initialization
at functionexpression.js:23:1
(anonymous) @ functionexpression.js:23

The error tells you what the issue is. You have to define the function before you can use it. Just moving the call to outside will make it work.

let greeting = "hi"
 
let outside = function(x){
    document.getElementById("myH1").innerHTML = x
}
outside(greeting);

Javascript is not a compiled language, so things work from top down. Things must be defined (meaning they have to be higher in the document) before they can be used

Getting a bit deeper into the topic, the issue of vertical ordering of the lines exists when using let and const, because they help us to write better code.

When using older techniques such as var, or a function declaration, those are pre-processed before the code is run, so when using those the order was of less importance. But still, even when using those it’s important to program defensively, and ensure that things are defined first before you attempt to use them.

The term to be aware of is hoisting, which is when variables and function declarations are moved to the top of their scope before code execution. E.g.

console.log(greeting);
var greeting = 'Hi';

This will log undefined (instead of a ReferenceError), as this is what the code above looks like to the interpreter:

var greeting;
console.log(greeting);
greeting = 'Hi';

Which technically means that we can use variables before they are declared, just likely not with the desired result.

ES6 introduced something called the temporal dead zone, which makes accessing a let/const variable before its declaration throw an error:

console.log(greeting);
const greeting = 'Hi';
// ReferenceError

@Growly if this is new to you, it might be an idea to give these two articles a quick read:

3 Likes

I see, I forgot about that

Also, How come when you put the console above the functions but not for function variables?



let text = "gg"

Inconsole(text)

function out(x){
    console.log(x)
}

function Inconsole(x){
    document.getElementById("myH1").innerHTML = x


}

Function declarations are hoisted like variables. Unlike variables (vars) which are hoisted to the top and given a value of undefined in the case of function declarations the entire definition is hoisted to the top.

This is why you can call or invoke the function ahead of it’s position in code

Try and picture hoisting as variables being put into an object connected to the code. When we want these variables or function declarations that is where javascript is going to look.

Consider the following:

   1. const x = 2
   2. var y = 5
   3. let z = 10
   4. function log(val) {
   5.   console.log(val)
   6. }

When we execute line 1 --> 1. const x = 2 the variable object looks a bit like this.

// variable object
{
  x: 2,
  y: undefined
  z:
  log: function(val) { // whole function has been put here from the get go.
    console.log(val)
  }  
}

When we execute line 2 --> 2. var y = 5

// variable object
{
  x: 2,
  y: 5
  z:
  log: function(val) {
    console.log(val)
  }  
}

And execute line 3 --> 3. let z = 10 and so on …

// variable object
{
  x: 2,
  y: 5
  z: 10
  log: function(val) {
    console.log(val)
  }  
}
1 Like

When thinking about it, function declarations are side effects. Procedural Programming is highly dependent on order of execution to avoid possible side effects. Since function declarations hoists to the top of the execution context, it can possibly change the program meaning if the order is changed.

3 Likes

Hm… not sure about that, they are local to the current scope as any variable declarations after all. Compare this to PHP, where (for reasons I fail to comprehend) function declarations certainly are side effects:

function foo() {
    function bar() {
        echo 'bar';
    }

    echo 'foo';
}

// This would throw a fatal error: 
// Call to undefined function bar()
bar();
foo();

// However, this would actually work
// and echo "foobar"
foo();
bar();

The JS equivalent OTOH would have to be explicit about global definitions:

function foo () {
  function bar () {
    console.log('bar')
  }

  globalThis.bar = bar
  console.log('foo')
}

// ReferenceError: bar is not defined
bar()
foo()

// Logs "foo\nbar"
foo()
bar()
2 Likes

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.