web developer | musician | venue booker

var, let, const, hoisting, scope, and functions


Javascript has three ways of defining variables: var, let, and const. They have sometimes subtle, other times dramatic differences. Below I will explain the basic functionality of each.

var is the oldest method of defining variables in Javascript. It is able to be redefined and updated. For example, if you define var name = "john" and later define name = "tim", and then console.log(name), the result should be tim.
var variables are also scoped to the function they are initially declared in. Meaning, if you declare this function

function createName() { 
    var name = "john"; 

, and later in your code write console.log(name), you will get an error because the variable name is only defined within the scope of the function it was declared in. The only way for that example to work would be if you declared the variable name outside of any function, therefore making it global, and then accessible via any scope, like this:

var name = "john"
function createName() {
createName(); //log: 'john'
console.log(name) //log: 'john'

This can sometimes create some unexpected problems though, as var variables are not “block scoped”. For example, in this code

var name = "john"; 
if (name === "john") {
    var lastName = "smith"; 
    console.log(`${name} ${lastName})

, your last console.log statement would return “smith”. This is because the var variable is not block scope. Enter let

let is the newer variety of variable declaration in Javascript. It serves a similar purpose as var, but has a few advantages, one of which being that it is “block-scoped”. Another interesting thing about let, is that if you declare the same variable name with let, but define them in different scopes, it will actually create two separate variables (because it is block scoped), whereas let will re-assign the already declared variable.

const is the newest of the three types of variables. Const is short for, you guessed it, constant. Meaning, it can’t be changed. However, one aspect to note is that if you define a const variable and assign it the value of an object, the properties within that object can change. So in that sense, const is changeable, but it’s value still can’t be re-assigned.


[W3Schools.com] https://www.w3schools.com/js/js_hoisting.asp defines hoisting as:

Hoisting is JavaScript's default behavior of moving all declarations to the top of the current scope (to the top of the current script or the current function)

Meaning that no matter where the function is defined within the document, it will be “hoisted to the top”. Note that this only hoists the function declaration, not the function initialization.
This allows you to do something like this (not advised though!)


function myFunc () {
  return 'Hello, world!';

//returns 'Hello, world'

This works because the function declaration was hoisted to the top. However, if we do something like this:

function myFunc () {
    var name = 'john'

myFunc();  //undefined

It will return undefined. This is because even the though function was hoisted to the top, the variable declaration didn’t happen until after the console.log statement. The solution would be to move the var variable to the top of the function declaration, or to take it out of the function and instead make it global. However, the best method would be to use let or const instead.

Named functions, anonymous functions, and arrow functions

Before ES6, there were essentially two ways to define a function: Function declarations and function expressions. A function declaration is like this:

function functionDeclaration() {

And a function expression is like this:

var functionExpression = function () {

The biggest difference between the two is that a function declaration will be hoisted to the top, whereas a function expression will not.

Arrow Functions

ES6 introduced a new way to create functions: the arrow function. It looks a little different, and also behaves slightly different as well. An ES6 function is written like this:

const helloWorld = () => 'Hello World!';

Besides being more concise, and easier to read, there are some key differences, mainly, with the this keyword. Because we so often use nested functions (functions within functions), it is necessary to make sure the this keyword gets carried over to the lower function. In previous versions of javascript, this was done using the .bind() method, and binding to self. Because arrow functions now allow you to retain the scope of the calling function, that is no longer needed, which makes things like making api calls more clearer and more concise.