“Scope” is a name given to an environment that contains variables. If you can access a variable, we say the variable is within scope. If you cannot access a variable, we say the variable is not in scope.
There are five kinds of scopes in JavaScript:
- Global scope
- Function scope
- Block scope
- Lexical scope
- Closure scope
In this lesson, you’ll learn the first four kinds of scope. We’ll cover closures in a later module.
Global scope
You create a variable in the global scope if you declare the variable outside all functions and curly braces ({}). These variables are called global variables.
const globalVariable = 'some value'Global variables can be used everywhere in your code. They can be used in any functions.
const hello = 'Hello world!'
function sayHello() { console.log(hello)}
console.log(hello) // 'Hello world!'sayHello() // 'Hello world!'If you hear the term local scope, it means the variable is not in a global scope. Local scope can mean function scope, block scope, or even lexical scope.
Function scope
If you create a variable in function, the variable is in a function scope.
function someFunction() { const functionVariable = 'some value'}You can use a function-scoped variable anywhere inside the function.
function someFunction() { const functionVariable = 'some value' console.log(functionVariable) // This will log 'some value'}
someFunction()But you cannot use the variable outside the function.
function someFunction() { const functionVariable = 'some value' console.log(functionVariable) // This will log 'some value'}
console.log(functionVariable) // ReferenceError: functionVariable is not definedBlock scope
A block is a set of code contain within curly braces ({}). If you create a variable inside curly braces, that variable is scoped to the block.
Examples of blocks include:
forloopsifstatement- A pair of curly brackets
// For loopfor (const item of items) { // item is block-scoped}
// if statementif (time === '12pm') { const chimeCount = 12 // chimeCount is block-scoped}
// A block{ const name = 'Zell' // name is block-scoped}Block scope only applies to variables created with const and let. It does not apply to variables created with var.
var is function-scoped
Variables created with var are always scoped to its nearest function. In the example below, you can see that hello ignores the block scope.
{ var hello = 'Hello world!' console.log(hello) // 'Hello world!'}
console.log(hello) // 'Hello world!'This is why you should not create variables with var anymore. Always use const or let.
Lexical scope
You can use a variable after you created it. But you cannot use the variable before you created it.
This behavior is called lexical scope.
console.log(laugh) // ReferenceError: can't access lexical declaration `laugh' before initializationconst laugh = 'haha'Nested scopes
You can have functions in functions. When do this, you create a nested scope.
// Global scopefunction outerFunction() { // outerFunction scope function innerFunction() { // innerFunction scope }}- Variables created in the global scope can be used in both
outerFunctionandinnerFunction - Variables created in
outerFunctioncan be used ininnerFunction, but not in the global scope - Variables created in
innerFunctioncan only be used in inner function
It’s easy to visualize scopes with a one-way glass—you can see the outside, but people from the outside cannot see you.
If you have scopes within scopes, visualize multiple layers of one-way glass.
Same-name variables in different scopes
You can use variables with the same name if they exist in different scopes. If this happens, JavaScript uses the variable closest to the current scope.
function sayName(name) { console.log(name)}
const name = 'Zell'sayName('Vincy') // VincyScopes are not transferable
Each function you create has their own scope. Variables declared in one function cannot be transferred to another function.
In the example below, two does not have access to varOne, even though two called one.
function one() { const varOne = `I'm part of one`}
function two() { one() console.log(varOne) // Error, varOne is not defined}Managing scopes
Here are three rules for managing scopes:
First: Avoid having too many global variables. If you have too many global variables, you may get a variable-name collision (where two variables use the same name).
If variables are declared with let or const, you’ll get an error. If variables are declared with var, the second variable overwrites the first variable (which generates hard-to-find bugs).
Second: Keep variables scoped to the function they need.
// Don't do thisconst prize = 'playstation'function announceWinner(name) { console.log(name + ' won a ' + prize)}// Do thisfunction announceWinner(name) { const prize = 'playstation' console.log(name + ' won a ' + prize)}Third: Don’t be afraid to hoist variables to a higher scope if needed.
Let’s say you have this:
function sayName(name) { console.log(name)}
function shoutName(name) { console.log(name + '!')}
sayName('Zell') // ZellshoutName('Zell') // Zell!Normally, you’d want to keep name variable within each of these functions. But sometimes, you will want to hoist name to a higher scope.
const name = 'Zell'
function sayName() { console.log(name)}
function shoutName() { console.log(name + '!')}
sayName() // Zell!shoutName() // Zell!This one is hard to explain with simple examples. You’ll see why I create this rule when you create dots for the carousel later (next module).
Ordering your code
Here’s a simple order I follow:
- Variables required by multiple functions
- Functions
- Code for execution
Welcome! Unfortunately, you don’t have access to this lesson. To get access, please purchase the course or enroll in Magical Dev School.
Unlock this lesson