Problem
In javascript, what is the scope of variables? Do they have the same scope inside a function as they do outside? Is it even relevant? Also, if the variables are defined globally, where are they stored?
Asked by lYriCAlsSH
Solution #1
Closures and lexical (also known as static) scoping are features of JavaScript. This means that by looking at the source code, you can determine the scope of an identifier.
The four scopes are as follows:
Variables are declared using var (function scope), let (block scope), and const (const) outside of the exceptional circumstances of global and module scope (block scope). In strict mode, most other types of identifier declarations have block scope.
The scope of an identifier is the area of the codebase over which it is valid.
A lexical environment is a relationship between the names of identifiers and the values that go with them.
Scope is made up of a linked nesting of lexical environments, with each level representing a lexical environment from an ancestor execution context.
A scope “chain” is formed by these linked lexical environments. The process of looking for a matched identifier along this chain is known as identifier resolution.
There is just one way to resolve an identifier: outwards. Outer lexical contexts cannot “look” into inner lexical environments in this sense.
In JavaScript, there are three important elements to consider when determining the scope of an identifier:
Identifiers can be stated in a variety of ways, including:
Some of the identifiers for locations can be declared:
Apart from when they are declared directly in the global context, in which case they are placed as properties on the global object and have global scope, identifiers declared with var have function scope. Their use in eval functions is governed by various regulations.
Except when they are declared explicitly in the global context, where they have global scope, identifiers declared using let and const have block scope.
It’s worth noting that let, const, and var are all hoisted. This means that the top of their enclosing scope is their logical place of definition (block or function). Variables declared with let and const, on the other hand, cannot be read or assigned to until control has passed the declaration point in the source code. The temporal dead zone is the term for the intermediate interval.
The names of function parameters are limited to the function body. It’s worth noting that this is a little more complicated than it appears. Functions with default parameters close over the parameter list rather than the function body.
In strict mode, function declarations have block scope, but in non-strict mode, they have function scope. Note that non-strict mode is a convoluted set of emerging rules based on the peculiar historical implementations of many browsers.
The scope of named function expressions is limited to themselves (e.g., for the purpose of recursion).
Because the global object is at the top of the scope chain, implicitly specified properties on it have global scope in non-strict mode. These are not permitted in rigorous mode.
Variables declared with var in eval strings will be stored in the current scope, or as properties on the global object if eval is used indirectly.
The following will throw a ReferenceError because the namesx, y, and z have no meaning outside of the function f.
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. Similarly, blocks that define the bodies of control structures such as if, for, and while behave.
Because var has function scope, x is visible outside of the loop in the following:
…as a result of this behavior, you must be cautious when using var to declare variables in loops. There is just one declaration of variable x here, and it is logically outside the loop.
For the console, the following prints 5 five times and then 5 a sixth time. outside the loop log:
Because x is block-scoped, the following prints undefined. Asynchronously, the callbacks are executed one by one. Because of the new behavior for let variables, each anonymous function closed over a distinct variable named x (rather than var), and therefore integers 0 through 4 are printed.
Because the visibility of x is not bound by the block, the following will not throw a ReferenceError; rather, it will print undefined because the variable has not been initialized (because of the if statement).
A variable declared using let at the top of a for loop is scoped to the loop body:
Because the visibility of x is confined by the block, the following will throw a ReferenceError:
Variables declared with the var, let, or const keywords are all module-scoped:
// module1.js
var x = 0
export function f() {}
//module2.js
import f from 'module1.js'
console.log(x) // throws ReferenceError
Because variables created with var within the global context are added as properties to the global object, the following will declare a property on the global object:
In the global context, let and const do not add attributes to the global object, but they do have global scope:
The following are examples of function parameters that are declared in the function body:
The parameters of the catch-block body are scoped:
The scope of named function expressions is limited to the expression itself:
Implicitly declared attributes on the global object are globally scoped in non-strict mode. You’ll get an error if you’re using strict mode.
Function declarations have function scope in non-strict mode. They have block scope in strict mode.
The scope of an identifier is defined as the lexical region of code over which it is valid.
Every function-object in JavaScript contains a hidden [[Environment]] reference to the lexical environment of the execution context (stack frame) in which it was produced.
The secret [[Call]] method is called when you call a function. This method makes a link between the new execution context and the function-lexical object’s environment by creating a new execution context. It accomplishes this by duplicating the function-[[Environment]] object’s value onto an outer reference field on the new execution context’s lexical environment.
It’s worth noting that this connection between the new execution context and the function object’s lexical environment is referred to as a closure.
Scope is implemented in JavaScript by using lexical environments that are linked together in a “chain” by outside references. The scope chain is a collection of lexical environments, and identifier resolution is accomplished by looking up the chain for a matched identifier.
Find out more.
Answered by Triptych
Solution #2
Scope chains are used in Javascript to define the scope of a function. There is usually only one global scope, with each declared function having its own nested scope. The local scope of any function defined within another function is related to the outer function. The scope is always defined by the position in the source.
A scope chain element is essentially a Map with a pointer to its parent scope.
When resolving a variable, javascript searches outwards from the innermost scope.
Answered by krosenvold
Solution #3
Variables with a global scope are those that are declared worldwide. Variables declared within a function are scoped to that function and are shadowed by global variables with the same name.
(I’m sure real JavaScript programmers will be able to point out many intricacies in alternative replies.) I came across one page in particular that explains what this means at any given time. However, hopefully this more introductory link will suffice to get you started.)
Answered by Jon Skeet
Solution #4
JavaScript has traditionally only had two sorts of scope:
I won’t go into detail because there are already a plethora of other replies that explain the difference.
The most recent JavaScript specs now also allow a third scope :
Traditionally, variables are created in the following manner:
var myVariable = "Some text";
The following is how block scope variables are created:
let myVariable = "Some text";
Consider the following code to see the difference between functional and block scope:
// i IS NOT known here
// j IS NOT known here
// k IS known here, but undefined
// l IS NOT known here
function loop(arr) {
// i IS known here, but undefined
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
for( var i = 0; i < arr.length; i++ ) {
// i IS known here, and has a value
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
};
// i IS known here, and has a value
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
for( let j = 0; j < arr.length; j++ ) {
// i IS known here, and has a value
// j IS known here, and has a value
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
};
// i IS known here, and has a value
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
}
loop([1,2,3,4]);
for( var k = 0; k < arr.length; k++ ) {
// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS NOT known here
};
for( let l = 0; l < arr.length; l++ ) {
// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS known here, and has a value
};
loop([1,2,3,4]);
// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS NOT known here
Our variable j is only known in the first for loop, but not before or after that. Despite this, our variable I is known throughout the method.
within the same block, to redeclare the same block scoped variable Block scoped variables are therefore less prone to errors than globally or functionally scoped variables, which are hoisted and do not create any problems when numerous declarations are made.
Whether it is safe to use now depends on the following factors:
This Can I Use page has an up-to-date list of which browsers support the let statement at the time you’re reading this answer.
(*) Globally and functionally scoped variables can be initialized and used before they are declared because JavaScript variables are hoisted. This means that declarations are always much to the top of the scope.
Answered by John Slegers
Solution #5
Here’s an example:
<script>
var globalVariable = 7; //==window.globalVariable
function aGlobal( param ) { //==window.aGlobal();
//param is only accessible in this function
var scopedToFunction = {
//can't be accessed outside of this function
nested : 3 //accessible by: scopedToFunction.nested
};
anotherGlobal = {
//global because there's no `var`
};
}
</script>
Closures and how to use them to create private members are something you should look into.
Answered by geowa4
Post is based on https://stackoverflow.com/questions/500431/what-is-the-scope-of-variables-in-javascript