Antes de que saliera ES6 (ES2015) las variables se declaraban con var, despues con la llegada de ES6 se introdujeron let y const para definir nuestras variables.

Variables var

Primero necesitamos entender como funcionan las var y el hoisting. Las variables que declaramos con var no tienen un "scope" de bloque  y son redeclaradas en la parte superior del entorno de ejecución, lo cual podemos ver en los siguientes ejemplos.

El resultado de este código seria:

Perro
Mi mascota es un: Gato
Gato

Nada que no esperaramos de una variable, pero ahora veamos otro ejemplo.

Lo que resulta en:

Perro
Mi mascota es un: Gato
Gato

El resultado es el mismo sin importar que la variable la declaramos despues de usarla, esto es lo que se conoce como hoisting.

Basicamente las variables declaradas con var se redeclaran en la parte superior del contexto de ejecución, por esta razon este código no genera un error.

Variables let

Las variables declaradas usando let tienen un scope de bloque, lo cual significa que si las declaramos dentro de llaves "{ }" estaran contenidas dentro de esas llaves y no podremos acceder a ellas por fuera de ese bloque. Por ejemplo:

Resultado:

Perro
Mi mascota es un: Gato
Y es de: Colombia
Gato
Uncaught ReferenceError: origen is not defined

En este ejemplo podemos ver como al intentar acceder a la variable origen por fuera del bloque de la función nos encontramos con un error ya que una variable let declarada dentro de un bloque solo se puede acceder dentro del mismo.

Variables const

Con variables const podemos declarar lo que en la mayoria de casos es una constante, lo cual nos sirve para definir variables que no queremos que sean modificadas durante la ejecución.

En este caso el resultado sera un error ya que estamos intentando modificar una "constante".

Uncaught TypeError: Assignment to constant variable.

En su mayoria las variables declaradas con const son constantes, pero hay pequeñas excepciones a esto.

Por ejemplo, un objecto o un array declarado con const no puede ser reasignado pero su contenido si puede ser modificado.

Conclusión

var es para variables globales y usa hoisting. Lo ideal es no usarlas a menos que requiramos compatibilidad con navegadores antiguos.

let es el tipo de variable ideal si requerimos que esta cambie por alguna razon durante la ejecución.

const la usaremos para definir constantes que no requiren cambios durante la ejecución del código. Sin embargo debes tener en cuenta las exepciones con objectos y arrays.