JavaScript Scope Explained: Difference Between Var and Let

Updated on March 18, 2019
isaacasante profile image

Isaac has a passion for coding, and has knowledge on web design, web development, and programming in general.

One of the challenges JavaScript programmers getting started with ES6 struggle with has to do with the difference between var and let. Both are keywords in JavaScript used to declare variables. Before the let statement was introduced in ES2015, which is what we refer to as ES6, var was the standard way of declaring variables. The availability of a new statement to declare non-constant variables later on therefore came with a bit of confusion.

var firstVariable = "I'm first!" // Declared and initialized
let secondVariable; // Simply declared.

Variables declared both ways can store values, be it primitive values or objects, and may be initialized when created. They may also be null or undefined.

var firstVariable; // Value is undefined.
let secondVariable = null; // This is valid as well.

But now you want to know: what is the difference between var and let? The answer is scope.

Understanding Scope In JavaScript

For starters, JavaScript scope refers to the level of accessibility of variables. In other words, scope determines whence variables are visible in our script. Let’s see an example of what scope is about, with actual code:

var myNumber = 10;

function addTwo(userNum) {
    var numberTwo = 2;
    return numberTwo + userNum; 
}

function subtractTwo(userNum) {
    return userNum - numberTwo;
}

console.log(addTwo(myNumber)); // 12

console.log(subtractTwo(myNumber)); // ReferenceError: numberTwo is not defined

Let’s go through the JavaScript example above. We first create a variable called myNumber and assign the value 10 to it. We then create the function addTwo(), which takes a parameter, userNum. Inside of that function, we declare the variable numberTwo and initialize it with the value 2. We proceed to add it to the value of our function’s parameter and return the result.

In a second function called subtractTwo(), we expect to receive a number as a parameter, from which we intend to deduct 2 and return the result. But we are doing something wrong here. When deducting 2 from the parameter’s value, we use the numberTwo variable that we declared and initialized in our addTwo() function. By doing so, we are incorrectly assuming that the numberTwo variable is accessible outside its function, when in fact it is not.

Notice that this eventually causes our code to have an error. In Line 12, we pass in the value 10, which is stored in our global variable myNumber, to our addTwo() function. The output in the console is as expected, as we get the number 12.

In Line 14, however, when we try to output the result of our subtraction, we get what is known as a reference error in JavaScript. Try running this code in a text editor of your choice and opening your browser console to see the output. You will see an error message pointing to Line 9 of our script: Uncaught ReferenceError: numberTwo is not defined.

The reason for this is clearly stated. The numberTwo variable that we are trying to access in Line 9 is inaccessible. It is thus not recognized, and because we have not declared any variable with the same name in our subtractTwo() function, there is no valid location in memory to reference, hence the error.

That is how scope works in JavaScript. We would have gotten the same erroneous result even if we used the let keyword instead of var. The takeaway here is that scope is the context of execution. Every JavaScript function has its own scope; therefore, variables declared in a function may only be visible and used within that function. Global variables, on the other hand, may be accessed from any part of the script.

Understanding Scope Hierarchy

When writing code in JavaScript, we need to remember that scopes can be hierarchically layered. This means that one scope, or a parent scope, can have yet another scope, or child scope, within it. Variables from the parent scope may be accessed from the child scope, but not the other way around.

var globalVariable = "Hi from global!"; // This is accessible everywhere within this script.

function parentScope() {
    var accessEverywhere = "Hi from parent"; // This is accessible everywhere within the parentScope function.

    function childScope() {
        var accessHere = "Hey from child";
        console.log(accessHere); // This is accessible within this childScope function only.
    }

    console.log(accessEverywhere); // Hi from parent

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

parentScope();
console.log(globalVariable);

The JavaScript example above provides an illustration of the hierarchical nature of scopes. For now, we are only using the var keyword. We have one global variable at the top of our script, which we should be able to access anywhere within it. We then have a function called parentScope(), which contains the local variable accessEverywhere.

The latter is visible anywhere within the function. Finally, we have another function called childScope(), which has a local variable called accessHere. As you might have guessed by now, that variable can only be accessed in the function within which it is declared.

But our code generates an error, and that is because of a mistake in Line 13. On Line 16 when we call the parentScope() function, the console logging statements in both Line 11 and Line 13 get executed. Though the accessEverywhere variable gets logged without any issue, the execution of our code stops when we try to output the value of the accessHere variable in Line 13. The reason for that is that the variable in question was declared in the childScope() function and is therefore not visible to the parentScope() function.

Thankfully, there is an easy solution to that. We simply need to call the childScope() function without our parentScope() function definition.

var globalVariable = "Hi from global!"; // This is accessible everywhere within this script.

function parentScope() {
    var accessEverywhere = "Hi from parent"; // This is accessible everywhere within the parentScope function.

    function childScope() {
        var accessHere = "Hey from child";
        console.log(accessHere); // This is accessible within this childScope function only.
    }

    childScope(); // Call the function instead of accessing its variable directly
    
    console.log(accessEverywhere); // Hi from parent
}

parentScope();
console.log(globalVariable);

Here, I am saving this code into a JavaScript file called tutorialscript.js and linking it to an index.html file on my local server. When I run my script, I see the following in my Chrome console.

All the variable values we are expecting are being logged to the console without any errors.
All the variable values we are expecting are being logged to the console without any errors.

We now understand how scope in JavaScript works. Let’s concentrate once again on the var and let keywords. The main difference between these two is that variables declared with var are function scoped, whereas those declared with let are block scoped.

You have seen examples of function-scoped variables above. Block scoped, nevertheless, means that the variable is only visible within the block of code within which it is declared. A block can be anything within curly brackets; take if/else statements and loops, for instance.

function fScope() {
    if (1 < 10) {
        var hello = "Hello World!"; // Declared and initialized inside of a block
    }
    console.log(hello); // Available outside the block. It is function scoped.
}

fScope();

The piece of code above, with its comments, is self-explanatory. Let’s replicate it and make a couple of changes. In Line 3, we will use the let keyword, then try to access the hello variable in Line 4. You will see that our code will generate an error because of Line 6, as accessing a variable declared with let outside of its block scope is not allowed.

function fScope() {
    if (1 < 10) {
        let hello = "Hello World!"; // Declared and initialized inside of a block. Block scoped.
        console.log("The value is: " + hello); // Variable is visible within the block.
    }
    console.log(hello); // Uncaught ReferenceError: hello is not defined
}

fScope();

Should I use var or let?

Before ES6, there was no block scope in JavaScript; but its introduction helps in making one’s code more robust. Personally, I prefer to use let as it makes it easier for me to debug and fix unexpected behavior caused by reference errors.

When working on a large program, reducing the scope as best as you can is always a good recommendation. Having said that, if your script only consists of a dozen lines of codes, you probably should not worry too much about which keyword you use, so long as you know the difference between global scope, function scope and block scope in JavaScript and are able to avoid errors.

Questions & Answers

    Comments

      0 of 8192 characters used
      Post Comment

      No comments yet.

      working

      This website uses cookies

      As a user in the EEA, your approval is needed on a few things. To provide a better website experience, owlcation.com uses cookies (and other similar technologies) and may collect, process, and share personal data. Please choose which areas of our service you consent to our doing so.

      For more information on managing or withdrawing consents and how we handle data, visit our Privacy Policy at: https://owlcation.com/privacy-policy#gdpr

      Show Details
      Necessary
      HubPages Device IDThis is used to identify particular browsers or devices when the access the service, and is used for security reasons.
      LoginThis is necessary to sign in to the HubPages Service.
      Google RecaptchaThis is used to prevent bots and spam. (Privacy Policy)
      AkismetThis is used to detect comment spam. (Privacy Policy)
      HubPages Google AnalyticsThis is used to provide data on traffic to our website, all personally identifyable data is anonymized. (Privacy Policy)
      HubPages Traffic PixelThis is used to collect data on traffic to articles and other pages on our site. Unless you are signed in to a HubPages account, all personally identifiable information is anonymized.
      Amazon Web ServicesThis is a cloud services platform that we used to host our service. (Privacy Policy)
      CloudflareThis is a cloud CDN service that we use to efficiently deliver files required for our service to operate such as javascript, cascading style sheets, images, and videos. (Privacy Policy)
      Google Hosted LibrariesJavascript software libraries such as jQuery are loaded at endpoints on the googleapis.com or gstatic.com domains, for performance and efficiency reasons. (Privacy Policy)
      Features
      Google Custom SearchThis is feature allows you to search the site. (Privacy Policy)
      Google MapsSome articles have Google Maps embedded in them. (Privacy Policy)
      Google ChartsThis is used to display charts and graphs on articles and the author center. (Privacy Policy)
      Google AdSense Host APIThis service allows you to sign up for or associate a Google AdSense account with HubPages, so that you can earn money from ads on your articles. No data is shared unless you engage with this feature. (Privacy Policy)
      Google YouTubeSome articles have YouTube videos embedded in them. (Privacy Policy)
      VimeoSome articles have Vimeo videos embedded in them. (Privacy Policy)
      PaypalThis is used for a registered author who enrolls in the HubPages Earnings program and requests to be paid via PayPal. No data is shared with Paypal unless you engage with this feature. (Privacy Policy)
      Facebook LoginYou can use this to streamline signing up for, or signing in to your Hubpages account. No data is shared with Facebook unless you engage with this feature. (Privacy Policy)
      MavenThis supports the Maven widget and search functionality. (Privacy Policy)
      Marketing
      Google AdSenseThis is an ad network. (Privacy Policy)
      Google DoubleClickGoogle provides ad serving technology and runs an ad network. (Privacy Policy)
      Index ExchangeThis is an ad network. (Privacy Policy)
      SovrnThis is an ad network. (Privacy Policy)
      Facebook AdsThis is an ad network. (Privacy Policy)
      Amazon Unified Ad MarketplaceThis is an ad network. (Privacy Policy)
      AppNexusThis is an ad network. (Privacy Policy)
      OpenxThis is an ad network. (Privacy Policy)
      Rubicon ProjectThis is an ad network. (Privacy Policy)
      TripleLiftThis is an ad network. (Privacy Policy)
      Say MediaWe partner with Say Media to deliver ad campaigns on our sites. (Privacy Policy)
      Remarketing PixelsWe may use remarketing pixels from advertising networks such as Google AdWords, Bing Ads, and Facebook in order to advertise the HubPages Service to people that have visited our sites.
      Conversion Tracking PixelsWe may use conversion tracking pixels from advertising networks such as Google AdWords, Bing Ads, and Facebook in order to identify when an advertisement has successfully resulted in the desired action, such as signing up for the HubPages Service or publishing an article on the HubPages Service.
      Statistics
      Author Google AnalyticsThis is used to provide traffic data and reports to the authors of articles on the HubPages Service. (Privacy Policy)
      ComscoreComScore is a media measurement and analytics company providing marketing data and analytics to enterprises, media and advertising agencies, and publishers. Non-consent will result in ComScore only processing obfuscated personal data. (Privacy Policy)
      Amazon Tracking PixelSome articles display amazon products as part of the Amazon Affiliate program, this pixel provides traffic statistics for those products (Privacy Policy)
      ClickscoThis is a data management platform studying reader behavior (Privacy Policy)