Skip to main content Accessibility Feedback

How scope works in JavaScript

As part of back-to-basics series this week, yesterday we looked at the difference between var, let, and const. Today, we’re going to look at scope in JavaScript.

Let’s dig in.

What is scope?

Scope is the context in which a function or variable is accessible. There are four types of scope: global, local, lexical, and block.

At a high level, functions have access to variables and other functions set outside themselves, but not variables set inside other functions.

We’re going to learn about global, local, and lexical scope today, and we’ll dig into the block scope tomorrow.

Global Scope

A variable or function in the global scope is accessible inside other functions.

// this is in the global scope
let sandwich = 'tuna';

function logSandwich () {
	// Will log `tuna` in the console
	// It can access sandwich because it's in the global scope
	console.log(sandwich);
}
logSandwich();

// Will also log `tuna` in the console
console.log(sandwich);

Local Scope

A variable or function that’s only accessible in a part of your code base has local scope.

function logSandwich () {
	// this has variable local scope
	let sandwich = 'tuna';

	// Will log `tuna` in the console
	// It can access sandwich because it's scope is local to the function
	console.log(sandwich);
}
logSandwich();

// returns "Uncaught ReferenceError: sandwich is not defined"
// `sandwich` is local to the logSandwich() function, and not accessible here
console.log(sandwich);

Lexical Scope

If you nest your functions, variables and other functions defined in the parent function have lexical scope and can be accessed by the inner functions.

The parent function cannot access variables or functions defined within the inner functions.

function sandwiches () {

	// this is in the lexical scope
	let sandwich = 'tuna';

	function logSandwich () {

		// Will log `tuna` in the console
		// It can access sandwich because it's in the lexical scope
		console.log(sandwich);

	}
	logSandwich();

	// Will also log `tuna` in the console
	console.log(sandwich);

}
sandwiches();

// returns "Uncaught ReferenceError: sandwich is not defined"
// `sandwich` is lexical to the sandwiches() function, and out of scope
console.log(sandwich);

Defining and updating variables in different scopes

You can define a variable in a function that has the same name as a global or lexical variable without modifying that variable.

let sandwich = 'tuna';

function logSandwich () {
	// logs "turkey"
	// Does NOT update the global `sandwich` variable
	let sandwich = 'turkey';
	console.log(sandwich);

}
logSandwich();

// logs "tuna"
console.log(sandwich);

If you omit the leading variable declaration, you can update a variable in the global or lexical scope from within a function.

let sandwich = 'tuna';

// logs "tuna"
console.log(sandwich);

let logSandwich = function () {

	// logs "tuna"
	console.log(sandwich);

	// Updates `sandwich` in the global scope
	sandwich = 'turkey';

	// logs "turkey"
	console.log(sandwich);

};
logSandwich();

// logs "turkey"
console.log(sandwich);

Keeping code out of the global scope

There are times you may want to expose a function or variable to the global scope (for example, a lightweight framework you want other scripts to be able to use).

But generally speaking, you want to keep your functions and variables out of the global scope. Otherwise, if another script or developer defines a variable or function that has the same name as the ones in your script, it will override them or introduce conflicts.

You can move your code into a lexical scope by wrapping it in a function.

// Wrapper for your code
let myScripts = function () {
	// Your codes goes here...
};

// Run your scripts
myScripts();

If you want your code to run immediately when the file runs without having to call your function, you can use something called an Immediately Invoked Function Expression (or IIFE). An IIFE is an anonymous (as in, unnamed) function that runs immediately.

(function () {
	// Your code goes here...
	// It will be scoped and run immediately
})();