patternjavascriptCritical
What is the scope of variables in JavaScript?
Viewed 0 times
variablesthewhatjavascriptscope
Problem
What is the scope of variables in javascript? Do they have the same scope inside as opposed to outside a function? Or does it even matter? Also, where are the variables stored if they are defined globally?
Solution
TLDR
JavaScript has lexical (also called static) scoping and closures. This means you can tell the scope of an identifier by looking at the source code.
The four scopes are:
Outside of the special cases of global and module scope, variables are declared using
Overview
Scope is the region of the codebase over which an identifier is valid.
A lexical environment is a mapping between identifier names and the values associated with them.
Scope is formed of a linked nesting of lexical environments, with each level in the nesting corresponding to a lexical environment of an ancestor execution context.
These linked lexical environments form a scope "chain". Identifier resolution is the process of searching along this chain for a matching identifier.
Identifier resolution only occurs in one direction: outwards. In this way, outer lexical environments cannot "see" into inner lexical environments.
There are three pertinent factors in deciding the scope of an identifier in JavaScript:
Some of the ways identifiers can be declared:
Some of the locations identifiers can be declared:
Declaration Styles
var
Identifiers declared using
let and const
Identifiers declared using
Note:
Function parameter names
Function parameter names are scoped to the function body. Note that there is a slight complexity to this. Functions declared as default arguments close over the parameter list, and not the body of the function.
Function declarations
Function declarations have block scope in strict mode and function scope in non-strict mode. Note: non-strict mode is a complicated set of emergent rules based on the quirky historical implementations of different browsers.
Named function expressions
Named function expressions are scoped to themselves (e.g., for the purpose of recursion).
Implicitly defined properties on the global object
In non-strict mode, implicitly defined properties on the global object have global scope, because the global object sits at the top of the scope chain. In strict mode, these are not permitted.
eval
In
Examples
The following will throw a ReferenceError because the names
The following will throw a ReferenceError for
In the following,
`for(var x = 0; x
..
JavaScript has lexical (also called static) scoping and closures. This means you can tell the scope of an identifier by looking at the source code.
The four scopes are:
- Global - visible by everything
- Function - visible within a function (and its sub-functions and blocks)
- Block - visible within a block (and its sub-blocks)
- Module - visible within a module
Outside of the special cases of global and module scope, variables are declared using
var (function scope), let (block scope), and const (block scope). Most other forms of identifier declaration have block scope in strict mode.Overview
Scope is the region of the codebase over which an identifier is valid.
A lexical environment is a mapping between identifier names and the values associated with them.
Scope is formed of a linked nesting of lexical environments, with each level in the nesting corresponding to a lexical environment of an ancestor execution context.
These linked lexical environments form a scope "chain". Identifier resolution is the process of searching along this chain for a matching identifier.
Identifier resolution only occurs in one direction: outwards. In this way, outer lexical environments cannot "see" into inner lexical environments.
There are three pertinent factors in deciding the scope of an identifier in JavaScript:
- How an identifier was declared
- Where an identifier was declared
- Whether you are in strict mode or non-strict mode
Some of the ways identifiers can be declared:
var,letandconst
- Function parameters
- Catch block parameter
- Function declarations
- Named function expressions
- Implicitly defined properties on the global object (i.e., missing out
varin non-strict mode)
importstatements
eval
Some of the locations identifiers can be declared:
- Global context
- Function body
- Ordinary block
- The top of a control structure (e.g., loop, if, while, etc.)
- Control structure body
- Modules
Declaration Styles
var
Identifiers declared using
var have function scope, apart from when they are declared directly in the global context, in which case they are added as properties on the global object and have global scope. There are separate rules for their use in eval functions.let and const
Identifiers declared using
let and const have block scope, apart from when they are declared directly in the global context, in which case they have global scope.Note:
let, const and var are all hoisted. This means that their logical position of definition is the top of their enclosing scope (block or function). However, variables declared using let and const cannot be read or assigned to until control has passed the point of declaration in the source code. The interim period is known as the temporal dead zone.function f() {
function g() {
console.log(x)
}
let x = 1
g()
}
f() // 1 because x is hoisted even though declared with let!
Function parameter names
Function parameter names are scoped to the function body. Note that there is a slight complexity to this. Functions declared as default arguments close over the parameter list, and not the body of the function.
Function declarations
Function declarations have block scope in strict mode and function scope in non-strict mode. Note: non-strict mode is a complicated set of emergent rules based on the quirky historical implementations of different browsers.
Named function expressions
Named function expressions are scoped to themselves (e.g., for the purpose of recursion).
Implicitly defined properties on the global object
In non-strict mode, implicitly defined properties on the global object have global scope, because the global object sits at the top of the scope chain. In strict mode, these are not permitted.
eval
In
eval strings, variables declared using var will be placed in the current scope, or, if eval is used indirectly, as properties on the global object.Examples
The following will throw a ReferenceError because the names
x, y, and z have no meaning outside of the function f.function f() {
var x = 1
let y = 1
const z = 1
}
console.log(typeof x) // undefined (because var has function scope!)
console.log(typeof y) // undefined (because the body of the function is a block)
console.log(typeof z) // undefined (because the body of the function is a block)
The following will throw a ReferenceError for
y and z, but not for x, because the visibility of x is not constrained by the block. Blocks that define the bodies of control structures like if, for, and while, behave similarly.{
var x = 1
let y = 1
const z = 1
}
console.log(x) // 1
console.log(typeof y) // undefined because y has block scope
console.log(typeof z) // undefined because z has block scope
In the following,
x is visible outside of the loop because var has function scope:`for(var x = 0; x
..
Context
Stack Overflow Q#500431, score: 2688
Revisions (0)
No revisions yet.