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?
Share
Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.
Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.
Lost your password? Please enter your email address. You will receive a link and will create a new password via email.
Please briefly explain why you feel this question should be reported.
Please briefly explain why you feel this answer should be reported.
Please briefly explain why you feel this user should be reported.
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
var(function scope),let(block scope), andconst(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:
Some of the ways identifiers can be declared:
var,letandconstvarin non-strict mode)importstatementsevalSome of the locations identifiers can be declared:
Declaration Styles
var
Identifiers declared using
varhave 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 inevalfunctions.let and const
Identifiers declared using
letandconsthave block scope, apart from when they are declared directly in the global context, in which case they have global scope.Note:
let,constandvarare all hoisted. This means that their logical position of definition is the top of their enclosing scope (block or function). However, variables declared usingletandconstcannot 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 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
evalstrings, variables declared usingvarwill be placed in the current scope, or, ifevalis used indirectly, as properties on the global object.Examples
The following will throw a ReferenceError because the names
x,y, andzhave no meaning outside of the functionf.The following will throw a ReferenceError for
yandz, but not forx, because the visibility ofxis not constrained by the block. Blocks that define the bodies of control structures likeif,for, andwhile, behave similarly.In the following,
xis visible outside of the loop becausevarhas function scope:…because of this behavior, you need to be careful about closing over variables declared using
varin loops. There is only one instance of variablexdeclared here, and it sits logically outside of the loop.The following prints
5, five times, and then prints5a sixth time for theconsole.logoutside the loop:The following prints
undefinedbecausexis block-scoped. The callbacks are run one by one asynchronously. New behavior forletvariables means that each anonymous function closed over a different variable namedx(unlike it would have done withvar), and so integers0through4are printed.:The following will NOT throw a
ReferenceErrorbecause the visibility ofxis not constrained by the block; it will, however, printundefinedbecause the variable has not been initialised (because of theifstatement).A variable declared at the top of a
forloop usingletis scoped to the body of the loop:The following will throw a
ReferenceErrorbecause the visibility ofxis constrained by the block:Variables declared using
var,letorconstare all scoped to modules:The following will declare a property on the global object because variables declared using
varwithin the global context are added as properties to the global object:letandconstin the global context do not add properties to the global object, but still have global scope:Function parameters can be considered to be declared in the function body:
Catch block parameters are scoped to the catch-block body:
Named function expressions are scoped only to the expression itself:
In non-strict mode, implicitly defined properties on the global object are globally scoped. In strict mode, you get an error.
In non-strict mode, function declarations have function scope. In strict mode, they have block scope.
How it works under the hood
Scope is defined as the lexical region of code over which an identifier is valid.
In JavaScript, every function-object has a hidden
[[Environment]]reference that is a reference to the lexical environment of the execution context (stack frame) within which it was created.When you invoke a function, the hidden
[[Call]]method is called. This method creates a new execution context and establishes a link between the new execution context and the lexical environment of the function-object. It does this by copying the[[Environment]]value on the function-object, into an outer reference field on the lexical environment of the new execution context.Note that this link between the new execution context and the lexical environment of the function object is called a closure.
Thus, in JavaScript, scope is implemented via lexical environments linked together in a "chain" by outer references. This chain of lexical environments is called the scope chain, and identifier resolution occurs by searching up the chain for a matching identifier.
Find out more.