Variable declaration and scoping rules
Tags: javascript, scope, variables
Published: 2017-11-06 21:02:27

---
title: Variable declaration and scoping rules
published: true
description: 
tags: javascript, scope, variables
---
<p><a name="intro"></a></p>
<h2>Introduction</h2>
<p>In programming, the scope of a variable determines where that variable can be used within the program, and also what functions and objects have access to that variable.</p>
<p>Usually, a variable can have either local or global scope. A variable declared within a block of code has local scope, and is only accessible by other code within the same block. Once the block within which it is declared is exited, the variable goes out of scope. A global variable, on the other hand, is accessible from anywhere within the currently executing script (or program), and usually lasts the entire lifetime of the program.</p>
<p>In this write up, we wish to examine the various ways in which variables can be declared in JavaScript, and we shall see that the scope of a variable in JavaScript is affected by where and how it is declared.</p>
<p><a name="declaring-variables"></a></p>
<h2>Declaring variables</h2>
<p>There are three keywords available for declaring variables in JavaScript. They are the <tt>var</tt>, <tt>let</tt>, and <tt>const</tt> keywords. JavaScript, being a dynamic and loosely typed language, also allows you to use variables without pre-declaring them, but this is not considered good practice and is highly discouraged.</p>
<p>To declare a variable, we use any of the above listed keywords, followed by the variable name as follows:</p>
<p><tt>var a;</tt></p>
<p><tt>let b;</tt></p>
<p><tt>const c = 5;</tt></p>
<p>When you declare a variable using <tt>const</tt>, you must initialize it with a value -as we have done above - which cannot afterwards be changed. When declaring variables with <tt>var</tt> and <tt>let</tt>, we can optionally initialize the variables at the point of declaration:</p>
<p><tt>var a = 2;</tt></p>
<p><tt>var b = 3;</tt></p>
<p><a name="declaring-variables-with-the-var-keyword"></a></p>
<h3>Declaring variables with the <tt>var</tt> keyword</h3>
<p>When you declare a variable using the <tt>var</tt> keyword, the scope is as follows:</p>
<ul>
<li>
<p>If the variable is declared outside of any functions, the variable is available in the global scope.</p>
</li>
<li>
<p>If the variable is declared within a function, the variable is available from its point of declaration until the end of the function definition.</p>
</li>
</ul>
<p>Unlike what you might be used to from other languages, variables declared with the <tt>var</tt> keyword have no block scope. In concrete terms, this means that if you declare a variable using <tt>var</tt> within a <tt>for</tt>, or any non-function block, the variable's scope extends beyond the block to the end of the block's parent scope. On the other hand, if you declare a variable inside a function with the <tt>var</tt> keyword, the variable is only available within the function definition, and cannot be accessed outside of the function. We, therefore, say that variables declared with <tt>var</tt> are function-scoped.</p>
<p>Let's see some examples to help clarify what we are saying.</p>
<pre class="prettyprint linenums no-list-style code">function varScope() {
   var a = 2;
   console.log(a); // outputs  2
}

console.log(a); // ReferenceError, a is not accessible outside the function.
</pre>
<p>Let's see another example.</p>
<pre class="prettyprint linenums no-list-style code">function varScope() {
   var a = 2;
   if(true) {
      var a =  "Jamie"; //change the value of a inside the "if" block
      console.log(a); //prints "Jamie"
   }
   console.log(a); //prints "Jamie": outside the "if" block, a still maintains the updated value 
   //a being function scoped, the (re-) declaration inside the if statement overwrote the previous value of a
   //when we assigned it a new value inside the conditional statement
}
console.log(a); // ReferenceError, again, a is not accessible outside the function.
</pre>
<p>Finally, let's look at this one.</p>
<pre class="prettyprint linenums no-list-style code">function forScope() {
   for(var i = 0; i &lt; 5; i++) {
      console.log(i); //prints the values 0 through 4;
   }
   console.log(i); //prints 5;
}
</pre>
<p>What just happened? Inside the <tt>for</tt> header, we declare and initialize the <tt>i</tt> variable. Then inside the loop, we iterate from 0 while the value of <tt>i</tt> is less than <tt>5</tt>, bumping <tt>i</tt> on each iteration. When the value of <tt>i</tt> equals <tt>5</tt>, the condition <tt>i &lt; 5</tt> evaluates to false, terminating our loop. However, since <tt>i</tt> is declared using <tt>var</tt>, its scope extends from its point of declaration to the end of the function. Hence, even after the loop, we can access the up-to-date value of <tt>i</tt>, which, in this case is 5.</p>
<p><a name="declaring-variables-with-the-let-keyword"></a></p>
<h3>Declaring variables with the <tt>let</tt> keyword</h3>
<p>variables declared using the <tt>let</tt> keyword have three important characteristics.</p>
<ul>
<li>They are <strong>block scoped</strong></li>
<li>They are <strong>not</strong> accessible before they are assigned</li>
<li>They <strong>cannnot</strong> be re-declared within the same scope</li>
</ul>
<p>Let's see what this means using some examples.</p>
<pre class="prettyprint linenums no-list-style code">function  letScope() {
   let a = 5;

   if  (true) {
      let a = "Jamie";  // using let creates a new a variable inside the "if" block
      console.log(a); //  prints "Jamie"
   }

   console.log(a); // 5,  outside the <tt>if</tt> block, the outer a shines through
}
console.log(a); // ReferenceError, <tt>a</tt> is not accessible outside the function.
</pre>
<p>Here's what happens in this function.</p>
<ol>
<li>
<p>Inside the function, we create an <tt>a</tt> variable using <tt>let</tt>, this variable exists throughout the scope of this function.</p>
</li>
<li>
<p>Inside the <tt>if</tt> block, we create another <tt>let</tt> -declared <tt>a</tt> variable. Being block scoped, we just created a new a variable.</p>
</li>
<li>
<p>This variable is totally different from, and independent of, the outer <tt>a</tt> variable.</p>
</li>
<li>
<p>This variable is only available within the <tt>if</tt> block, and not accessible outside this block.</p>
</li>
</ol>
<p>In addition, you can't re-declare a <tt>let</tt> variable:</p>
<pre class="prettyprint linenums no-list-style code">let a = 2;
let a = 3// SyntaxError, cannot re-declare the a variable
</pre>
<p><a name="declaring-variables-with-the-const-keyword"></a></p>
<h3>Declaring variables with the <tt>const</tt> keyword</h3>
<p>Variables declared with the <tt>const</tt> keyword share all the characteristics of variables declared using the <tt>let</tt> keyword, plus one important distinguishing characteristic:</p>
<ul>
<li>
<p>They can't be reassigned</p>
</li>
</ul>
<pre class="prettyprint linenums no-list-style code">const a = 2;
a = 3 // Error, reassignment is not allowed
</pre>
<pre class="prettyprint linenums no-list-style code">const a = 2;
const a = 3 // Error, re-declaration is not allowed
</pre>
<p><a name="variable-mutability"></a></p>
<h2>Variable Mutability</h2>
<p>Regardless of how you declare a variable, using any of the keywords we have discussed, the variable is mutable. Mutability must not be confused with reassignment. This difference is highlighted when working with arrays or objects. An example or two will clarify what this means.</p>
<p><a name="object-example"></a></p>
<h3>Object example:</h3>
<pre class="prettyprint linenums no-list-style code">const person = {
  name: 'Michael'
};
person.name = 'Jamie' // OK! person variable mutated, not completely re-assigned
console.log(person.name); // "Jamie"
person = "Newton" // Error, re-assignment is not allowed with const declared variables
</pre>
<p><a name="array-example"></a></p>
<h3>Array example:</h3>
<pre class="prettyprint linenums no-list-style code">const person = [];
person[0] = 'Michael'; // OK! person variable only mutated, not completely re-assigned
console.log(person[0]) // "Michael"
person = "Newton" // Error, re-assignment is not allowed with const declared variables
</pre>
<p><a name="accessing-a-variable-before-its-declaration"></a></p>
<h2>Accessing a variable before its declaration</h2>
<p>In the section on <a href="#declaring-variables-with-the-let-keyword">declaring variables with <tt>let</tt></a>, we noted that one of the characteristics of <tt>let</tt> declared variables is that they are not accessible before they are declared. What does this mean? Let's see.</p>
<p>Consider this piece of code:</p>
<pre class="prettyprint linenums no-list-style code">console.log(a); // undefined, but no error raised
var a = 2;
</pre>
<p>In the above snippet, we attempt to read the value of the <tt>a</tt> variable before its declaration. Instead of getting an error, we get <tt>undefined</tt>. Why is that? The answer is that <tt>var</tt> declared variables are moved to the top of the scope at execution.</p>
<p>At runtime, this code is interpreted as:</p>
<pre>var a;
console.log(a); // undefined: a is declared, but hasn't been assigned a value, hence no errors raised
a = 2;
</pre>
<p>This phenomenon is what is referred to as hoisting.</p>
<p>If we try to do a similar thing with a variable declared using <tt>let</tt> or <tt>const</tt>, we will get a reference error thrown.</p>
<pre class="prettyprint linenums no-list-style code">console.log(a); // ReferenceError
let a = 2;
</pre>
<p><a name="conclusion"></a></p>
<h2>Concluding thoughts</h2>
<p>Mastering scope in JavaScript can seem tricky, and may take some time to&nbsp;getting used to.&nbsp; But with practice the various ways of declaring variables in JavaScript and how these affect scope become second nature.</p>
<p><a name="further-reading"></a></p>
<h2>Further reading</h2>
<ol class="no-list-style">
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let" target="_blank" rel="external">MDN let</a></li>
<li><a href="https://github.com/mbeaudru/modern-js-cheatsheet#variable-declaration-var-const-let" target="_blank" rel="external">Modern Javascript Cheatsheet</a></li>
</ol>