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?
This question is related to
javascript
function
variables
scope
var
I really like the accepted answer but I want to add this:
Scope collects and maintains a look-up list of all the declared identifiers (variables), and enforces a strict set of rules as to how these are accessible to currently executing code.
Scope is a set of rules for looking up variables by their identifier name.
Variables declared globally have a global scope. Variables declared within a function are scoped to that function, and shadow global variables of the same name.
(I'm sure there are many subtleties that real JavaScript programmers will be able to point out in other answers. In particular I came across this page about what exactly this
means at any time. Hopefully this more introductory link is enough to get you started though.)
Javascript uses scope chains to establish the scope for a given function. There is typically one global scope, and each function defined has its own nested scope. Any function defined within another function has a local scope which is linked to the outer function. It's always the position in the source that defines the scope.
An element in the scope chain is basically a Map with a pointer to its parent scope.
When resolving a variable, javascript starts at the innermost scope and searches outwards.
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>
You'll want to investigate closures, and how to use them to make private members.
There are ALMOST only two types of JavaScript scopes:
So, any blocks other than functions do not create a new scope. That explains why for-loops overwrite outer scoped variables:
var i = 10, v = 10;
for (var i = 0; i < 5; i++) { var v = 5; }
console.log(i, v);
// output 5 5
Using functions instead:
var i = 10, v = 10;
$.each([0, 1, 2, 3, 4], function(i) { var v = 5; });
console.log(i,v);
// output 10 10
In the first example, there was no block scope, so the initially declared variables were overwritten. In the second example, there was a new scope due to the function, so the initially declared variables were SHADOWED, and not overwritten.
That's almost all you need to know in terms of JavaScript scoping, except:
So you can see JavaScript scoping is actually extremely simple, albeit not always intuitive. A few things to be aware of:
So this code:
var i = 1;
function abc() {
i = 2;
var i = 3;
}
console.log(i); // outputs 1
is equivalent to:
var i = 1;
function abc() {
var i; // var declaration moved to the top of the scope
i = 2;
i = 3; // the assignment stays where it is
}
console.log(i);
This may seem counter intuitive, but it makes sense from the perspective of a imperative language designer.
Just to add to the other answers, scope is a look-up list of all the declared identifiers (variables), and enforces a strict set of rules as to how these are accessible to currently executing code. This look-up may be for the purposes of assigning to the variable, which is an LHS (lefthand-side) reference, or it may be for the purposes of retrieving its value, which is an RHS (righthand-side) reference. These look-ups are what the JavaScript engine is doing internally when it's compiling and executing the code.
So from this perspective, I think that a picture would help that I found in the Scopes and Closures ebook by Kyle Simpson:
Quoting from his ebook:
The building represents our program’s nested scope ruleset. The first floor of the building represents your currently executing scope, wherever you are. The top level of the building is the global scope. You resolve LHS and RHS references by looking on your current floor, and if you don’t find it, taking the elevator to the next floor, looking there, then the next, and so on. Once you get to the top floor (the global scope), you either find what you’re looking for, or you don’t. But you have to stop regardless.
One thing of note that is worth mentioning, "Scope look-up stops once it finds the first match".
This idea of "scope levels" explains why "this" can be changed with a newly created scope, if it's being looked up in a nested function. Here is a link that goes into all these details, Everything you wanted to know about javascript scope
In EcmaScript5, there are mainly two scopes, local scope and global scope but in EcmaScript6 we have mainly three scopes, local scope, global scope and a new scope called block scope.
Example of block scope is :-
for ( let i = 0; i < 10; i++)
{
statement1...
statement2...// inside this scope we can access the value of i, if we want to access the value of i outside for loop it will give undefined.
}
There are two types of scopes in JavaScript.
Global scope: variable which is announced in global scope can be used anywhere in the program very smoothly. For example:
var carName = " BMW";
// code here can use carName
function myFunction() {
// code here can use carName
}
Functional scope or Local scope: variable declared in this scope can be used in its own function only. For example:
// code here can not use carName
function myFunction() {
var carName = "BMW";
// code here can use carName
}
ECMAScript 6 introduced the let and const keywords. These keywords can be used in place of the var keyword. Contrary to the var keyword, the let and const keywords support the declaration of local scope inside block statements.
var x = 10
let y = 10
const z = 10
{
x = 20
let y = 20
const z = 20
{
x = 30
// x is in the global scope because of the 'var' keyword
let y = 30
// y is in the local scope because of the 'let' keyword
const z = 30
// z is in the local scope because of the 'const' keyword
console.log(x) // 30
console.log(y) // 30
console.log(z) // 30
}
console.log(x) // 30
console.log(y) // 20
console.log(z) // 20
}
console.log(x) // 30
console.log(y) // 10
console.log(z) // 10
My understanding is that there are 3 scopes: global scope, available globally; local scope, available to an entire function regardless of blocks; and block scope, only available to the block, statement, or expression on which it was used. Global and local scope are indicated with the keyword 'var', either within a function or outside, and block scope is indicated with the keyword 'let'.
For those that believe there is only global and local scope, please explain why Mozilla would have an entire page describing the nuances of block scope in JS.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
Javascript uses scope chains to establish the scope for a given function. There is typically one global scope, and each function defined has its own nested scope. Any function defined within another function has a local scope which is linked to the outer function. It's always the position in the source that defines the scope.
An element in the scope chain is basically a Map with a pointer to its parent scope.
When resolving a variable, javascript starts at the innermost scope and searches outwards.
const
' and 'let
'You should be using block scoping for every variable you create, just like most other major languages. var
is obsolete. This makes your code safer and more maintainable.
const
should be used for 95% of cases. It makes it so the variable reference can't change. Array, object, and DOM node properties can change and should likely be const
.
let
should be be used for any variable expecting to be reassigned. This includes within a for loop. If you ever change value beyond initialization, use let
.
Block scope means that the variable will only be available within the brackets in which it is declared. This extends to internal scopes, including anonymous functions created within your scope.
In "Javascript 1.7" (Mozilla's extension to Javascript) one can also declare block-scope variables with let
statement:
var a = 4;
let (a = 3) {
alert(a); // 3
}
alert(a); // 4
I found that many people new to JavaScript have trouble understanding that inheritance is available by default in the language and that function scope is the only scope, so far. I provided an extension to a beautifier I wrote at the end of last year called JSPretty. The feature colors function scope in the code and always associates a color to all variables declared in that scope. Closure is visually demonstrated when a variable with a color from one scope is used in a different scope.
Try the feature at:
See a demo at:
View the code at:
Currently the feature offers support for a depth of 16 nested functions, but currently does not color global variables.
In EcmaScript5, there are mainly two scopes, local scope and global scope but in EcmaScript6 we have mainly three scopes, local scope, global scope and a new scope called block scope.
Example of block scope is :-
for ( let i = 0; i < 10; i++)
{
statement1...
statement2...// inside this scope we can access the value of i, if we want to access the value of i outside for loop it will give undefined.
}
The key, as I understand it, is that Javascript has function level scoping vs the more common C block scoping.
Traditionally, JavaScript really only has two types of scope :
I will not elaborate on this, since there are already many other answers explaining the difference.
The most recent JavaScript specs now also allow a third scope :
Traditionally, you create your variables like this :
var myVariable = "Some text";
Block scope variables are created like this :
let myVariable = "Some text";
To understand the difference between functional scope and block scope, consider the following code :
// 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
Here, we can see that our variable j
is only known in the first for loop, but not before and after. Yet, our variable i
is known in the entire function.
Also, consider that block scoped variables are not known before they are declared because they are not hoisted. You're also not allowed to redeclare the same block scoped variable within the same block. This makes block scoped variables less error prone than globally or functionally scoped variables, which are hoisted and which do not produce any errors in case of multiple declarations.
Whether or not it is safe to use today, depends on your environment :
If you're writing server-side JavaScript code (Node.js), you can safely use the let
statement.
If you're writing client-side JavaScript code and use a browser based transpiler (like Traceur or babel-standalone), you can safely use the let
statement, however your code is likely to be anything but optimal with respect to performance.
If you're writing client-side JavaScript code and use a Node based transpiler (like the traceur shell script or Babel), you can safely use the let
statement. And because your browser will only know about the transpiled code, performance drawbacks should be limited.
If you're writing client-side JavaScript code and don't use a transpiler, you need to consider browser support.
These are some browsers that don't support let
at all :
For an up-to-date overview of which browsers support the let
statement at the time of your reading this answer, see this Can I Use
page.
(*) 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.
Global variables are exactly like global stars (Jackie Chan, Nelson Mandela). You can access them (get or set the value), from any part of your application. Global functions are like global events (New Year, Christmas). You can execute (call) them from any part of your application.
//global variable
var a = 2;
//global function
function b(){
console.log(a); //access global variable
}
If you are in the USA, you may know Kim Kardashian, infamous celebrity ( she somehow manages to make the tabloids). But people outside of the USA will not recognize her. She is a local star, bound to her territory.
Local variables are like local stars. You can only access them (get or set the value) inside the scope. A local function is like local events - you can execute only (celebrate) inside that scope. If you want to access them from outside of the scope, you will get a reference error
function b(){
var d = 21; //local variable
console.log(d);
function dog(){ console.log(a); }
dog(); //execute local function
}
console.log(d); //ReferenceError: dddddd is not defined
In JavaScript there are two types of scope:
The Below function has a local scope variable carName
. And this variable is not accessible from outside of the function.
function myFunction() {
var carName = "Volvo";
alert(carName);
// code here can use carName
}
The Below Class has a Global scope variable carName
. And this variable is accessible from everywhere in the class.
class {
var carName = " Volvo";
// code here can use carName
function myFunction() {
alert(carName);
// code here can use carName
}
}
There are two types of scopes in JavaScript.
Global scope: variable which is announced in global scope can be used anywhere in the program very smoothly. For example:
var carName = " BMW";
// code here can use carName
function myFunction() {
// code here can use carName
}
Functional scope or Local scope: variable declared in this scope can be used in its own function only. For example:
// code here can not use carName
function myFunction() {
var carName = "BMW";
// code here can use carName
}
JavaScript have only two type of scope :
var
keyword has functional scope.Whenever a function is called, a variable scope object is created (and included in scope chain) which is followed by variables in JavaScript.
a = "global";
function outer(){
b = "local";
console.log(a+b); //"globallocal"
}
outer();
Scope chain -->
a
and outer
function are at top level in scope chain.variable scope object
(and included in scope chain) added with variable b
inside it.Now when a variable a
required it first searches for nearest variable scope and if variable is not there than it move's to next object of variable scope chain.which is in this case is window level.
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>
You'll want to investigate closures, and how to use them to make private members.
A very common issue not described yet that front-end coders often run into is the scope that is visible to an inline event handler in the HTML - for example, with
<button onclick="foo()"></button>
The scope of the variables that an on*
attribute can reference must be either:
querySelector
as a standalone variable will point to document.querySelector
; rare)Otherwise, you'll get a ReferenceError when the handler is invoked. So, for example, if the inline handler references a function which is defined inside window.onload
or $(function() {
, the reference will fail, because the inline handler may only reference variables in the global scope, and the function is not global:
window.addEventListener('DOMContentLoaded', () => {_x000D_
function foo() {_x000D_
console.log('foo running');_x000D_
}_x000D_
});
_x000D_
<button onclick="foo()">click</button>
_x000D_
Properties of the document
and properties of the element the handler is attached to may also be referenced as standalone variables inside inline handlers because inline handlers are invoked inside of two with
blocks, one for the document
, one for the element. The scope chain of variables inside these handlers is extremely unintuitive, and a working event handler will probably require a function to be global (and unnecessary global pollution should probably be avoided).
Since the scope chain inside inline handlers is so weird, and since inline handlers require global pollution to work, and since inline handlers sometimes require ugly string escaping when passing arguments, it's probably easier to avoid them. Instead, attach event handlers using Javascript (like with addEventListener
), rather than with HTML markup.
function foo() {_x000D_
console.log('foo running');_x000D_
}_x000D_
document.querySelector('.my-button').addEventListener('click', foo);
_x000D_
<button class="my-button">click</button>
_x000D_
On a different note, unlike normal <script>
tags, which run on the top level, code inside ES6 modules runs in its own private scope. A variable defined at the top of a normal <script>
tag is global, so you can reference it in other <script>
tags, like this:
<script>_x000D_
const foo = 'foo';_x000D_
</script>_x000D_
<script>_x000D_
console.log(foo);_x000D_
</script>
_x000D_
But the top level of an ES6 module is not global. A variable declared at the top of an ES6 module will only be visible inside that module, unless the variable is explicitly export
ed, or unless it's assigned to a property of the global object.
<script type="module">_x000D_
const foo = 'foo';_x000D_
</script>_x000D_
<script>_x000D_
// Can't access foo here, because the other script is a module_x000D_
console.log(typeof foo);_x000D_
</script>
_x000D_
The top level of an ES6 module is similar to that of the inside of an IIFE on the top level in a normal <script>
. The module can reference any variables which are global, and nothing can reference anything inside the module unless the module is explicitly designed for it.
ES5
and earlier:Variables in Javascript were initially (pre ES6
) lexically function scoped. The term lexically scoped means that you can see the scope of the variables by 'looking' at the code.
Every variable declared with the var
keyword is scoped to the function. However, if other function are declared within that function those functions will have access to the variables of the outer functions. This is called a scope chain. It works in the following manner:
// global scope
var foo = 'global';
var bar = 'global';
var foobar = 'global';
function outerFunc () {
// outerFunc scope
var foo = 'outerFunc';
var foobar = 'outerFunc';
innerFunc();
function innerFunc(){
// innerFunc scope
var foo = 'innerFunc';
console.log(foo);
console.log(bar);
console.log(foobar);
}
}
outerFunc();
_x000D_
What happens when we are trying to log the variables foo
, bar
, and foobar
to the console is the following:
innerFunc
itself. Therefore, the value of foo is resolved to the string innerFunc
.innerFunc
itself. Therefore, we need to climb the scope chain. We first look in the outer function in which the function innerFunc
was defined. This is the function outerFunc
. In the scope of outerFunc
we can find the variable bar, which holds the string 'outerFunc'.ES6
(ES 2015) and older:The same concepts of lexically scope and scopechain still apply in ES6
. However a new ways to declare variables were introduced. There are the following:
let
: creates a block scoped variableconst
: creates a block scoped variable which has to be initialized and cannot be reassignedThe biggest difference between var
and let
/const
is that var
is function scoped whereas let
/const
are block scoped. Here is an example to illustrate this:
let letVar = 'global';
var varVar = 'global';
function foo () {
if (true) {
// this variable declared with let is scoped to the if block, block scoped
let letVar = 5;
// this variable declared with let is scoped to the function block, function scoped
var varVar = 10;
}
console.log(letVar);
console.log(varVar);
}
foo();
_x000D_
In the above example letVar logs the value global because variables declared with let
are block scoped. They cease to exist outside their respective block, so the variable can't be accessed outside the if block.
1) There is a global scope, a function scope, and the with and catch scopes. There is no 'block' level scope in general for variable's -- the with and the catch statements add names to their blocks.
2) Scopes are nested by functions all the way to the global scope.
3) Properties are resolved by going through the prototype chain. The with statement brings object property names into the lexical scope defined by the with block.
EDIT: ECMAAScript 6 (Harmony) is spec'ed to support let, and I know chrome allows a 'harmony' flag, so perhaps it does support it..
Let would be a support for block level scoping, but you have to use the keyword to make it happen.
EDIT: Based on Benjamin's pointing out of the with and catch statements in the comments, I've edited the post, and added more. Both the with and the catch statements introduce variables into their respective blocks, and that is a block scope. These variables are aliased to the properties of the objects passed into them.
//chrome (v8)
var a = { 'test1':'test1val' }
test1 // error not defined
with (a) { var test1 = 'replaced' }
test1 // undefined
a // a.test1 = 'replaced'
EDIT: Clarifying example:
test1 is scoped to the with block, but is aliased to a.test1. 'Var test1' creates a new variable test1 in the upper lexical context (function, or global), unless it is a property of a -- which it is.
Yikes! Be careful using 'with' -- just like var is a noop if the variable is already defined in the function, it is also a noop with respect to names imported from the object! A little heads up on the name already being defined would make this much safer. I personally will never use with because of this.
The idea of scoping in JavaScript when originally designed by Brendan Eich came from the HyperCard scripting language HyperTalk.
In this language, the displays were done similar to a stack of index cards. There was a master card referred to as the background. It was transparent and can be seen as the bottom card. Any content on this base card was shared with cards placed on top of it. Each card placed on top had its own content which took precedence over the previous card, but still had access to the prior cards if desired.
This is exactly how the JavaScript scoping system is designed. It just has different names. The cards in JavaScript are known as Execution ContextsECMA. Each one of these contexts contains three main parts. A variable environment, a lexical environment, and a this binding. Going back to the cards reference, the lexical environment contains all of the content from prior cards lower in the stack. The current context is at the top of the stack and any content declared there will be stored in the variable environment. The variable environment will take precedence in the case of naming collisions.
The this binding will point to the containing object. Sometimes scopes or execution contexts change without the containing object changing, such as in a declared function where the containing object may be window
or a constructor function.
These execution contexts are created any time control is transferred. Control is transferred when code begins to execute, and this is primarily done from function execution.
So that is the technical explanation. In practice, it is important to remember that in JavaScript
Applying this to one of the previous examples (5. "Closure") on this page, it is possible to follow the stack of execution contexts. In this example there are three contexts in the stack. They are defined by the outer context, the context in the immediately invoked function called by var six, and the context in the returned function inside of var six's immediately invoked function.
i) The outer context. It has a variable environment of a = 1
ii) The IIFE context, it has a lexical environment of a = 1, but a variable environment of a = 6 which takes precedence in the stack
iii) The returned function context, it has a lexical environment of a = 6 and that is the value referenced in the alert when called.
In JavaScript there are two types of scope:
The Below function has a local scope variable carName
. And this variable is not accessible from outside of the function.
function myFunction() {
var carName = "Volvo";
alert(carName);
// code here can use carName
}
The Below Class has a Global scope variable carName
. And this variable is accessible from everywhere in the class.
class {
var carName = " Volvo";
// code here can use carName
function myFunction() {
alert(carName);
// code here can use carName
}
}
Global variables are exactly like global stars (Jackie Chan, Nelson Mandela). You can access them (get or set the value), from any part of your application. Global functions are like global events (New Year, Christmas). You can execute (call) them from any part of your application.
//global variable
var a = 2;
//global function
function b(){
console.log(a); //access global variable
}
If you are in the USA, you may know Kim Kardashian, infamous celebrity ( she somehow manages to make the tabloids). But people outside of the USA will not recognize her. She is a local star, bound to her territory.
Local variables are like local stars. You can only access them (get or set the value) inside the scope. A local function is like local events - you can execute only (celebrate) inside that scope. If you want to access them from outside of the scope, you will get a reference error
function b(){
var d = 21; //local variable
console.log(d);
function dog(){ console.log(a); }
dog(); //execute local function
}
console.log(d); //ReferenceError: dddddd is not defined
A very common issue not described yet that front-end coders often run into is the scope that is visible to an inline event handler in the HTML - for example, with
<button onclick="foo()"></button>
The scope of the variables that an on*
attribute can reference must be either:
querySelector
as a standalone variable will point to document.querySelector
; rare)Otherwise, you'll get a ReferenceError when the handler is invoked. So, for example, if the inline handler references a function which is defined inside window.onload
or $(function() {
, the reference will fail, because the inline handler may only reference variables in the global scope, and the function is not global:
window.addEventListener('DOMContentLoaded', () => {_x000D_
function foo() {_x000D_
console.log('foo running');_x000D_
}_x000D_
});
_x000D_
<button onclick="foo()">click</button>
_x000D_
Properties of the document
and properties of the element the handler is attached to may also be referenced as standalone variables inside inline handlers because inline handlers are invoked inside of two with
blocks, one for the document
, one for the element. The scope chain of variables inside these handlers is extremely unintuitive, and a working event handler will probably require a function to be global (and unnecessary global pollution should probably be avoided).
Since the scope chain inside inline handlers is so weird, and since inline handlers require global pollution to work, and since inline handlers sometimes require ugly string escaping when passing arguments, it's probably easier to avoid them. Instead, attach event handlers using Javascript (like with addEventListener
), rather than with HTML markup.
function foo() {_x000D_
console.log('foo running');_x000D_
}_x000D_
document.querySelector('.my-button').addEventListener('click', foo);
_x000D_
<button class="my-button">click</button>
_x000D_
On a different note, unlike normal <script>
tags, which run on the top level, code inside ES6 modules runs in its own private scope. A variable defined at the top of a normal <script>
tag is global, so you can reference it in other <script>
tags, like this:
<script>_x000D_
const foo = 'foo';_x000D_
</script>_x000D_
<script>_x000D_
console.log(foo);_x000D_
</script>
_x000D_
But the top level of an ES6 module is not global. A variable declared at the top of an ES6 module will only be visible inside that module, unless the variable is explicitly export
ed, or unless it's assigned to a property of the global object.
<script type="module">_x000D_
const foo = 'foo';_x000D_
</script>_x000D_
<script>_x000D_
// Can't access foo here, because the other script is a module_x000D_
console.log(typeof foo);_x000D_
</script>
_x000D_
The top level of an ES6 module is similar to that of the inside of an IIFE on the top level in a normal <script>
. The module can reference any variables which are global, and nothing can reference anything inside the module unless the module is explicitly designed for it.
ECMAScript 6 introduced the let and const keywords. These keywords can be used in place of the var keyword. Contrary to the var keyword, the let and const keywords support the declaration of local scope inside block statements.
var x = 10
let y = 10
const z = 10
{
x = 20
let y = 20
const z = 20
{
x = 30
// x is in the global scope because of the 'var' keyword
let y = 30
// y is in the local scope because of the 'let' keyword
const z = 30
// z is in the local scope because of the 'const' keyword
console.log(x) // 30
console.log(y) // 30
console.log(z) // 30
}
console.log(x) // 30
console.log(y) // 20
console.log(z) // 20
}
console.log(x) // 30
console.log(y) // 10
console.log(z) // 10
1) There is a global scope, a function scope, and the with and catch scopes. There is no 'block' level scope in general for variable's -- the with and the catch statements add names to their blocks.
2) Scopes are nested by functions all the way to the global scope.
3) Properties are resolved by going through the prototype chain. The with statement brings object property names into the lexical scope defined by the with block.
EDIT: ECMAAScript 6 (Harmony) is spec'ed to support let, and I know chrome allows a 'harmony' flag, so perhaps it does support it..
Let would be a support for block level scoping, but you have to use the keyword to make it happen.
EDIT: Based on Benjamin's pointing out of the with and catch statements in the comments, I've edited the post, and added more. Both the with and the catch statements introduce variables into their respective blocks, and that is a block scope. These variables are aliased to the properties of the objects passed into them.
//chrome (v8)
var a = { 'test1':'test1val' }
test1 // error not defined
with (a) { var test1 = 'replaced' }
test1 // undefined
a // a.test1 = 'replaced'
EDIT: Clarifying example:
test1 is scoped to the with block, but is aliased to a.test1. 'Var test1' creates a new variable test1 in the upper lexical context (function, or global), unless it is a property of a -- which it is.
Yikes! Be careful using 'with' -- just like var is a noop if the variable is already defined in the function, it is also a noop with respect to names imported from the object! A little heads up on the name already being defined would make this much safer. I personally will never use with because of this.
I found that many people new to JavaScript have trouble understanding that inheritance is available by default in the language and that function scope is the only scope, so far. I provided an extension to a beautifier I wrote at the end of last year called JSPretty. The feature colors function scope in the code and always associates a color to all variables declared in that scope. Closure is visually demonstrated when a variable with a color from one scope is used in a different scope.
Try the feature at:
See a demo at:
View the code at:
Currently the feature offers support for a depth of 16 nested functions, but currently does not color global variables.
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>
You'll want to investigate closures, and how to use them to make private members.
JavaScript have only two type of scope :
var
keyword has functional scope.Whenever a function is called, a variable scope object is created (and included in scope chain) which is followed by variables in JavaScript.
a = "global";
function outer(){
b = "local";
console.log(a+b); //"globallocal"
}
outer();
Scope chain -->
a
and outer
function are at top level in scope chain.variable scope object
(and included in scope chain) added with variable b
inside it.Now when a variable a
required it first searches for nearest variable scope and if variable is not there than it move's to next object of variable scope chain.which is in this case is window level.
Try this curious example. In the example below if a were a numeric initialized at 0, you'd see 0 and then 1. Except a is an object and javascript will pass f1 a pointer of a rather than a copy of it. The result is that you get the same alert both times.
var a = new Date();
function f1(b)
{
b.setDate(b.getDate()+1);
alert(b.getDate());
}
f1(a);
alert(a.getDate());
Variables declared globally have a global scope. Variables declared within a function are scoped to that function, and shadow global variables of the same name.
(I'm sure there are many subtleties that real JavaScript programmers will be able to point out in other answers. In particular I came across this page about what exactly this
means at any time. Hopefully this more introductory link is enough to get you started though.)
Try this curious example. In the example below if a were a numeric initialized at 0, you'd see 0 and then 1. Except a is an object and javascript will pass f1 a pointer of a rather than a copy of it. The result is that you get the same alert both times.
var a = new Date();
function f1(b)
{
b.setDate(b.getDate()+1);
alert(b.getDate());
}
f1(a);
alert(a.getDate());
The key, as I understand it, is that Javascript has function level scoping vs the more common C block scoping.
const
' and 'let
'You should be using block scoping for every variable you create, just like most other major languages. var
is obsolete. This makes your code safer and more maintainable.
const
should be used for 95% of cases. It makes it so the variable reference can't change. Array, object, and DOM node properties can change and should likely be const
.
let
should be be used for any variable expecting to be reassigned. This includes within a for loop. If you ever change value beyond initialization, use let
.
Block scope means that the variable will only be available within the brackets in which it is declared. This extends to internal scopes, including anonymous functions created within your scope.
Variables declared globally have a global scope. Variables declared within a function are scoped to that function, and shadow global variables of the same name.
(I'm sure there are many subtleties that real JavaScript programmers will be able to point out in other answers. In particular I came across this page about what exactly this
means at any time. Hopefully this more introductory link is enough to get you started though.)
I really like the accepted answer but I want to add this:
Scope collects and maintains a look-up list of all the declared identifiers (variables), and enforces a strict set of rules as to how these are accessible to currently executing code.
Scope is a set of rules for looking up variables by their identifier name.
My understanding is that there are 3 scopes: global scope, available globally; local scope, available to an entire function regardless of blocks; and block scope, only available to the block, statement, or expression on which it was used. Global and local scope are indicated with the keyword 'var', either within a function or outside, and block scope is indicated with the keyword 'let'.
For those that believe there is only global and local scope, please explain why Mozilla would have an entire page describing the nuances of block scope in JS.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
There are ALMOST only two types of JavaScript scopes:
So, any blocks other than functions do not create a new scope. That explains why for-loops overwrite outer scoped variables:
var i = 10, v = 10;
for (var i = 0; i < 5; i++) { var v = 5; }
console.log(i, v);
// output 5 5
Using functions instead:
var i = 10, v = 10;
$.each([0, 1, 2, 3, 4], function(i) { var v = 5; });
console.log(i,v);
// output 10 10
In the first example, there was no block scope, so the initially declared variables were overwritten. In the second example, there was a new scope due to the function, so the initially declared variables were SHADOWED, and not overwritten.
That's almost all you need to know in terms of JavaScript scoping, except:
So you can see JavaScript scoping is actually extremely simple, albeit not always intuitive. A few things to be aware of:
So this code:
var i = 1;
function abc() {
i = 2;
var i = 3;
}
console.log(i); // outputs 1
is equivalent to:
var i = 1;
function abc() {
var i; // var declaration moved to the top of the scope
i = 2;
i = 3; // the assignment stays where it is
}
console.log(i);
This may seem counter intuitive, but it makes sense from the perspective of a imperative language designer.
ES5
and earlier:Variables in Javascript were initially (pre ES6
) lexically function scoped. The term lexically scoped means that you can see the scope of the variables by 'looking' at the code.
Every variable declared with the var
keyword is scoped to the function. However, if other function are declared within that function those functions will have access to the variables of the outer functions. This is called a scope chain. It works in the following manner:
// global scope
var foo = 'global';
var bar = 'global';
var foobar = 'global';
function outerFunc () {
// outerFunc scope
var foo = 'outerFunc';
var foobar = 'outerFunc';
innerFunc();
function innerFunc(){
// innerFunc scope
var foo = 'innerFunc';
console.log(foo);
console.log(bar);
console.log(foobar);
}
}
outerFunc();
_x000D_
What happens when we are trying to log the variables foo
, bar
, and foobar
to the console is the following:
innerFunc
itself. Therefore, the value of foo is resolved to the string innerFunc
.innerFunc
itself. Therefore, we need to climb the scope chain. We first look in the outer function in which the function innerFunc
was defined. This is the function outerFunc
. In the scope of outerFunc
we can find the variable bar, which holds the string 'outerFunc'.ES6
(ES 2015) and older:The same concepts of lexically scope and scopechain still apply in ES6
. However a new ways to declare variables were introduced. There are the following:
let
: creates a block scoped variableconst
: creates a block scoped variable which has to be initialized and cannot be reassignedThe biggest difference between var
and let
/const
is that var
is function scoped whereas let
/const
are block scoped. Here is an example to illustrate this:
let letVar = 'global';
var varVar = 'global';
function foo () {
if (true) {
// this variable declared with let is scoped to the if block, block scoped
let letVar = 5;
// this variable declared with let is scoped to the function block, function scoped
var varVar = 10;
}
console.log(letVar);
console.log(varVar);
}
foo();
_x000D_
In the above example letVar logs the value global because variables declared with let
are block scoped. They cease to exist outside their respective block, so the variable can't be accessed outside the if block.
Just to add to the other answers, scope is a look-up list of all the declared identifiers (variables), and enforces a strict set of rules as to how these are accessible to currently executing code. This look-up may be for the purposes of assigning to the variable, which is an LHS (lefthand-side) reference, or it may be for the purposes of retrieving its value, which is an RHS (righthand-side) reference. These look-ups are what the JavaScript engine is doing internally when it's compiling and executing the code.
So from this perspective, I think that a picture would help that I found in the Scopes and Closures ebook by Kyle Simpson:
Quoting from his ebook:
The building represents our program’s nested scope ruleset. The first floor of the building represents your currently executing scope, wherever you are. The top level of the building is the global scope. You resolve LHS and RHS references by looking on your current floor, and if you don’t find it, taking the elevator to the next floor, looking there, then the next, and so on. Once you get to the top floor (the global scope), you either find what you’re looking for, or you don’t. But you have to stop regardless.
One thing of note that is worth mentioning, "Scope look-up stops once it finds the first match".
This idea of "scope levels" explains why "this" can be changed with a newly created scope, if it's being looked up in a nested function. Here is a link that goes into all these details, Everything you wanted to know about javascript scope
In "Javascript 1.7" (Mozilla's extension to Javascript) one can also declare block-scope variables with let
statement:
var a = 4;
let (a = 3) {
alert(a); // 3
}
alert(a); // 4
Traditionally, JavaScript really only has two types of scope :
I will not elaborate on this, since there are already many other answers explaining the difference.
The most recent JavaScript specs now also allow a third scope :
Traditionally, you create your variables like this :
var myVariable = "Some text";
Block scope variables are created like this :
let myVariable = "Some text";
To understand the difference between functional scope and block scope, consider the following code :
// 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
Here, we can see that our variable j
is only known in the first for loop, but not before and after. Yet, our variable i
is known in the entire function.
Also, consider that block scoped variables are not known before they are declared because they are not hoisted. You're also not allowed to redeclare the same block scoped variable within the same block. This makes block scoped variables less error prone than globally or functionally scoped variables, which are hoisted and which do not produce any errors in case of multiple declarations.
Whether or not it is safe to use today, depends on your environment :
If you're writing server-side JavaScript code (Node.js), you can safely use the let
statement.
If you're writing client-side JavaScript code and use a browser based transpiler (like Traceur or babel-standalone), you can safely use the let
statement, however your code is likely to be anything but optimal with respect to performance.
If you're writing client-side JavaScript code and use a Node based transpiler (like the traceur shell script or Babel), you can safely use the let
statement. And because your browser will only know about the transpiled code, performance drawbacks should be limited.
If you're writing client-side JavaScript code and don't use a transpiler, you need to consider browser support.
These are some browsers that don't support let
at all :
For an up-to-date overview of which browsers support the let
statement at the time of your reading this answer, see this Can I Use
page.
(*) 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.
The idea of scoping in JavaScript when originally designed by Brendan Eich came from the HyperCard scripting language HyperTalk.
In this language, the displays were done similar to a stack of index cards. There was a master card referred to as the background. It was transparent and can be seen as the bottom card. Any content on this base card was shared with cards placed on top of it. Each card placed on top had its own content which took precedence over the previous card, but still had access to the prior cards if desired.
This is exactly how the JavaScript scoping system is designed. It just has different names. The cards in JavaScript are known as Execution ContextsECMA. Each one of these contexts contains three main parts. A variable environment, a lexical environment, and a this binding. Going back to the cards reference, the lexical environment contains all of the content from prior cards lower in the stack. The current context is at the top of the stack and any content declared there will be stored in the variable environment. The variable environment will take precedence in the case of naming collisions.
The this binding will point to the containing object. Sometimes scopes or execution contexts change without the containing object changing, such as in a declared function where the containing object may be window
or a constructor function.
These execution contexts are created any time control is transferred. Control is transferred when code begins to execute, and this is primarily done from function execution.
So that is the technical explanation. In practice, it is important to remember that in JavaScript
Applying this to one of the previous examples (5. "Closure") on this page, it is possible to follow the stack of execution contexts. In this example there are three contexts in the stack. They are defined by the outer context, the context in the immediately invoked function called by var six, and the context in the returned function inside of var six's immediately invoked function.
i) The outer context. It has a variable environment of a = 1
ii) The IIFE context, it has a lexical environment of a = 1, but a variable environment of a = 6 which takes precedence in the stack
iii) The returned function context, it has a lexical environment of a = 6 and that is the value referenced in the alert when called.
Javascript uses scope chains to establish the scope for a given function. There is typically one global scope, and each function defined has its own nested scope. Any function defined within another function has a local scope which is linked to the outer function. It's always the position in the source that defines the scope.
An element in the scope chain is basically a Map with a pointer to its parent scope.
When resolving a variable, javascript starts at the innermost scope and searches outwards.
There are only function scopes in JS. Not block scopes! You can see what is hoisting too.
var global_variable = "global_variable";
var hoisting_variable = "global_hoist";
// Global variables printed
console.log("global_scope: - global_variable: " + global_variable);
console.log("global_scope: - hoisting_variable: " + hoisting_variable);
if (true) {
// The variable block will be global, on true condition.
var block = "block";
}
console.log("global_scope: - block: " + block);
function local_function() {
var local_variable = "local_variable";
console.log("local_scope: - local_variable: " + local_variable);
console.log("local_scope: - global_variable: " + global_variable);
console.log("local_scope: - block: " + block);
// The hoisting_variable is undefined at the moment.
console.log("local_scope: - hoisting_variable: " + hoisting_variable);
var hoisting_variable = "local_hoist";
// The hoisting_variable is now set as a local one.
console.log("local_scope: - hoisting_variable: " + hoisting_variable);
}
local_function();
// No variable in a separate function is visible into the global scope.
console.log("global_scope: - local_variable: " + local_variable);
Javascript uses scope chains to establish the scope for a given function. There is typically one global scope, and each function defined has its own nested scope. Any function defined within another function has a local scope which is linked to the outer function. It's always the position in the source that defines the scope.
An element in the scope chain is basically a Map with a pointer to its parent scope.
When resolving a variable, javascript starts at the innermost scope and searches outwards.
run the code. hope this will give an idea about scoping
Name = 'global data';
document.Name = 'current document data';
(function(window,document){
var Name = 'local data';
var myObj = {
Name: 'object data',
f: function(){
alert(this.Name);
}
};
myObj.newFun = function(){
alert(this.Name);
}
function testFun(){
alert("Window Scope : " + window.Name +
"\nLocal Scope : " + Name +
"\nObject Scope : " + this.Name +
"\nCurrent document Scope : " + document.Name
);
}
testFun.call(myObj);
})(window,document);
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>
You'll want to investigate closures, and how to use them to make private members.
run the code. hope this will give an idea about scoping
Name = 'global data';
document.Name = 'current document data';
(function(window,document){
var Name = 'local data';
var myObj = {
Name: 'object data',
f: function(){
alert(this.Name);
}
};
myObj.newFun = function(){
alert(this.Name);
}
function testFun(){
alert("Window Scope : " + window.Name +
"\nLocal Scope : " + Name +
"\nObject Scope : " + this.Name +
"\nCurrent document Scope : " + document.Name
);
}
testFun.call(myObj);
})(window,document);
Source: Stackoverflow.com