var, let, or const?

Written by jballin | Published 2017/10/21
Tech Story Tags: javascript | programming | es6 | var | let

TLDRvia the TL;DR App

A Gentle Introduction to ES6

You must understand var to grasp the benefits of let / const. Let’s rewind.

Review: Variable Declarations

It’s important to intentionally declare your variables within a specific scope, using var, to keep your code clear and maintainable.

var x = "outside";function foo() {var x = "inside";console.log(x);}

foo(); // insideconsole.log(x); // outside

Above code properly declares x both outside and inside the function using var. What happens without var in foo?

var x = "outside";function foo() {x = "inside";console.log(x);}

foo(); // insideconsole.log(x); // inside

Uh oh! x outside the function was overwritten by x inside the function because we didn’t specify that x was to be scoped only to foo!

Hoisting Best Practices

Declare variables using var at the top of the current scope.

OK:

console.log('sup')var i = 0;

Better:

var i = 0;console.log('sup')

Review: Hoisting

Variables declared using var are always hoisted to the top of their scope.

console.log(j); // ReferenceError: j is not defined

console.log(i); // undefinedvar i = 0;

The variable j was never declared, so we get an error saying “I’ve never heard of j!”.

i was declared before being logged due to hoisting. Here is how the interpreter executed it:

var i;console.log(i);i = 0;

The interpreter moved (e.g. “hoisted”) the variable declaration to the top of the scope.

However, the variable was not assigned to 0 yet. undefined says “I know i exists, but I don’t know what value i points to because you didn’t assign it to anything”.

Supplement1: What if _var_ refers to a function?Supplement2: Hoisting doesn’t physically “move” your code —MDN

Function Scope

var's are function-scoped: scope is limited to the function it was defined in.

function foo() {var i = 0;}

console.log(i); // ReferenceError: i is not defined

i only exists within foo so we get an error: “I’ve never heard of i!”.

Block Scope

var’s are not block-scoped: scope is not limited to the block it was defined in.

var i = 0if (true) {var i = 1;}

console.log(i); // 1

i was still in the “global scope” within the if block. i's value was overwritten, which may have not been the intention.

let

let variables are block-scoped! Specific scope = less mistakes.

let i = 0;if (true) {let i = 1;}

console.log(i); // 0

Even though i was assigned to 1 in the if block, that assignment was local to the block and therefore our “global” i was still 0. The if block’s scope was separate from the global scope.

const == Constant

const restricts over-writing variables.

const i = 0;i = 1; // TypeError: Assignment to constant variable.

const doesn’t even let you declare a variable without assigning its (constant) value!

const i; // SyntaxError: Missing initializer in const declaration

const, like let, is block scoped.

if (true) {const i = 0;}

console.log(i); // ReferenceError: i is not defined

const does allow variable mutation (only objects/arrays are mutable in JS).

Array Mutation:

const a = [1];const b = a;console.log(a === b); // trueb.push(2);console.log(a === b); // trueconsole.log(a); /// [ 1, 2 ]

Object Mutation:

const obj = {};obj.i = 1;console.log(obj); // { i: 1 }

let/const Hoisting

let and const declarations are not hoisted!

EDIT: Technically they are hoisted, but they are not initialized to anything (var is initialized to undefined).

console.log(a); // undefinedvar a = 2;

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

console.log(c); // Uncaught ReferenceError: c is not definedlet c = 2;

This protects against variable declarations placed after references to variables.

isEqualTo5 has a bug — it always returns true.

function isEqualTo5(n) {return !(n - five);var five = 5;}console.log(isEqualTo5(4)); // true

The issue is that five isn’t assigned till after it’s referenced. It was declared so when it is referenced in the return statement, its value is undefined.

!(4 - undefined) === !(NaN) === true

This bug may be hard to catch. let/const to the rescue!

function isEqualTo5(n) {return !(n - five);const five = 5;}console.log(isEqualTo5(4)); // ReferenceError: five is not defined

const doesn’t hoist the declaration → error: reference before declaration→ prevents bug.

Specific scope = less errors + improved readability/maintainability.

TLDR: var →🗑, const where you can 🔑, otherwise let's cool too! 🕶


Written by jballin | sup world
Published by HackerNoon on 2017/10/21