About scoping in JavaScript - javascript

I need to have some information about the scoping in JavaScript. I know that it supports lexical (static) scoping, but, does not it support dynamic scoping as well?

I think you're confused because Javascript uses static scoping but at function-level, not at block level like usual structured languages.
var foo = "old";
if (true) {var foo = "new";}
alert (foo == "new")
So be careful, blocks don't make scope!
That's why you sometimes see loops with functions inside just to enable variables whose scope is inside an iteration:
functions = [];
for(var i=0; i<10; i++) {
(function(){
var local_i = i;
functions[local_i] = function() {return local_i;}
})();
}
functions[2]() // returns 2 and not 10

As far as I understood; Javascript has two kinds of variables which are global and local variables. But, suppose we have a variable called x, which is defined as global, and defined in the static parent of the scope of place where x is referenced. In this case, x takes the value of the global variable. Thus, global variable has higher priority than local ones. And, when there is no any global variables, x finds the declaration through the static chain which makes me think that Javascirpt is staticaly scoped language.
Am I right at above?

Related

Does top level functions makes closure in JavaScript?

I am learning closure and have basic doubt.
function makeCounter() {
let count = 0;
return function() {
return count++;
};
}
let counter = makeCounter();
Here when we are returning function it has closure with outer scope. so it has a closure with count.
var x = 1;
function func() {
console.log(x); // does func has closure with x ??
}
func();
So my question is , only nested function makes closure ??
or top level func has also closure with x ??
Closures in JavaScript are implemented using the [[OuterEnv]] internal field of the [[EnvironmentRecord]] internal field of function declarations. The [[OuterEnv]] value is then copied to the execution context created any time a function is called. This value is then used to create the scope chain, enabling the closure behavior.
Functions declared in the global context are no different in this regard and maintain a link to their surrounding environment, the Global Environment Record.
In the global context, variables declared using var and function declarations behave subtly differently to those declared inside other functions, in that they end up as properties on the global object, but this is an implementation detail.
For the sake of conversation, lets say that every closure creates a "scope" where variables are defined - everything within the closure/scope can access variables, anything outside cannot. With that said, there are two different types of implied closures you should be aware of.
This is not an exhastive description of how closures work, but more of description of the basic practical concepts as they relate to this question. There is much more going on with how call stacks are created, lexical scoping, "global" scope within NodeJS, iframes, sandboxing, var vs const/let, block vs function scopes, and other concepts which I will leave to the reader to discover on their own.
The browser/window/global scope
In the browser, you have the top-level scope (basically window, often referred to as the "global" scope). This kind of acts as a closure in that all "non-enclosed" variables are defined as part of the window scope and are available to most other code running on that page. For example, if you include the following script in the browser, x is part of the global/window scope, whereas y and z are enclosed inside their own nested scopes.
// basic-script.js
// x becomes part of the global/window scope
const x = 10;
(() => {
// y is enclosed in a separate, nested closure
const y = 20;
// x is available in this nested scope/closure
console.log('The sum of x and y is', x + y);
function foo() {
// z is enclosed in a separate, nested closure
const z = 5;
// x and y are both available in this nested scope/closure
console.log('The sum of x y and z is', x + y + z);
}
foo();
// z is not available to the parent scope
console.log(z); //-> undefined
})();
// y is not available to the parent scope
console.log(y); //-> undefined
<script src="basic-script.js"></script>
<script>
// this works because x is not enclosed
console.log('The value of x is', x);
// y and z are not available as they are inside a separate closure
console.log(y, z); //-> undefined, undefined
</script>
JavaScript modules
When you write JavaScript which is imported or required by other modules, every module is automatically wrapped in its own closure. For example, if you were to import/require the above basic-script.js into another JavaScript file, the above would be automatically enclosed like this:
(function() {
var x = 10;
// ... other code removed for brevity
})();
There is some other magic going on for exposing exports and so forth, but that's beyond the scope of this answer (pun intended). If JS modules were not wrapped in their own closure, then you would have a mess of naming collisions and reference issues, as well as a security nightmare.
So to answer your question, yes - your second example shares a closure with "x" - the closure is implicitly created depending on your environment.
Don't know, if you are still searching for the answer or not.
What is you meant by top level, I think you are talking about the global scope. To understand closure one should understand scope better.
And No, Closure in not work in global scope. The main reason of closure is to create a function that return a function with specific variables/calculations with it so that you can reuse that value again. I have a detailed blog in scope, closure and lexical environment. You can check it out https://shimulhsn.hashnode.dev/lexical-environment-and-scope-chain
A practical use of closures is creating a "scope" of protection around variables and functions declared within that function from outside interference. The top scope is "global", accessed using the window variable (an object). Everything, regardless what scope it was declared in, has access to it.
A function declared in global scope creates its own scope that no expression in the global scope and other "sub-global" scopes has access to. Functions declared in the global scope or declared inside other functions create their own scope, that even its immediate parent scope doesn't have access to.
Any variable declared—var, let, const—inside a function block is accessible in that function scope and any sub-scope created within that function scope—i.e., nothing outside that function scope can access it, (except a mechanism the function creating the scope may provide).
The second example in the question, where x is declared in the global scope, means everything has access to x. If x is later changed it is changed in all scopes. x is wide-open to interference anywhere in the code.
var x = 1; <-- declared outside func()
function func() {
// ...etc., etc., etc.
In the first example:
function makeCounter() {
let count = 0;
return function() {
return count++;
};
}
...makeCounter() creates a scope that includes count and an anonymous function, and that has access to them. Sub-scopes within this scope also have access to them. However, any expression in the global scope or other sub-global scopes do not have access to them.
Regarding the description that closures give access to an outer function's scope from an inner function—that scope access travels "up", accessing every parent scope, all the way to global scope, regardless how far "down" the "scope-chain" it goes. For example:
const can_i_reach_global = 'yes';
topLevel();
function topLevel () {
console.log('topLevel func, can_i_reach_global:', can_i_reach_global);
oneDeep();
function oneDeep () {
console.log('oneDeep func, can_i_reach_global:', can_i_reach_global);
twoDeep();
function twoDeep () {
console.log('twoDeep func, can_i_reach_global:', can_i_reach_global)
}
}
}
So, as far as practical definitions go, simply stating function closure "...gives you access to an outer function's scope from an inner function..." doesn't describe the usefulness of this programming construct.

what is local scope in JavaScript? How is local scope different to function scope?

I'm quite new to coding and am confused about the differences between a local scope with a function scope and block scope.
I understand that global scope is when a variable is declared outside of a function so it can be accessed anywhere. A function scope is when a variable can be accessed anywhere within the function and a block scope is when a variable can be accessed within a set of braces e.g. {let a = block scope},
However, I'm confused. What is a local scope? Is local scope the same thing as function scope?
Any help will be much appreciated
"Local scope" is a catch-all term for any scope that isn't global, so it includes both function scope and block scope (and module scope).
It used to be that JavaScript had only function scope and global scope. As of ES2015, it also has block scope for let, const, and class declarations, as well as "module scope" (the top-level scope for a module) and for scope (details below).
Here's an example:
// Assume this code is not in a module and is at the top level
let a; // Global scope
function example() {
let b; // function scope (a kind of local scope)
for (let n = 0; n < 2; ++n) { // `n` is in local scope for the `for` (a kind of local scope)
let c = n * 2; // block scope (a kind of local scope)
}
// This is a freestanding block, they don't *have* to be attached to anything
{
let d; // block scope (a kind of local scope)
}
}
It would be just the same if that were in a module except that the let a wouldn't be at global scope, it would be at module scope.
It's probably worth calling out the scope containing a let declaration within a for loop initializer isn't quite the same as the scope attached to any block that the for has; the former is the parent scope of the latter, and sometimes a for doesn't have a block attached to it:
for (let n = 0; n < 0; ++n)
console.log(n);
The scope of n above is non-obvious. It's scoped to the for loop, but in a very interesting way: A new n is created for each loop iteration. So for the first interation, there's an n whose value is 0. Then, a new n is created, gets a copy of the old n's value, and is then incremented; then that new n is used for the next loop iteration. This is handy for closures in loops.
It's a good question. Under most of circumstances, function scope is local scope.
However, consider the following code:
function foo(){
const sum = 0
someArray.forEach(function(item){
var plusOne = item + 1
sum = sum + 1
})
}
This function contains an inner function (called a closure) that defines its own scope. While the inner function is being executed, plusOne is in the local scope. sum is not in the local scope, but it's not really in the "global" scope either; it's in the scope of its parent. (You'll see this described in Chrome Dev Tools as the "closure" scope.) Scopes are nested, so your inner function/closure can see and modify variables in the parent scope (sum in this case).
There's another possibility if you're using CommonJS/ES6 modules. This might be a file:
var foo = 1
export function bar() {
return foo
}
You can write this (ES6) code to access bar:
import {bar} from "thefile"
console.log(bar())
You can't write this code:
import {foo} from "thefile"
foo looks "global"-ish, but it's really local to the module, and thus is in scope only for that module. It's not exported, so it isn't accessible outside that module.
(Aside: A "transpiler" will take JavaScript written for one platform/version and translate it to another. So, for example, it's common to transpile modern ES6 like I've written above to the lowest-common-denominator such as a web browser. Browsers don't generally support modules, so a transpiler will wrap the original module code in a function, thus converting "module scope" to "function scope".)

Is a variable declaration the same as a variable's binding?

MDN documentation states:
let bindings are created at the top of the (block) scope containing
the declaration, commonly referred to as "hoisting". Unlike variables
declared with var, which will start with the value undefined, let
variables are not initialized until their definition is evaluated.
Accessing the variable before the initialization results in a
ReferenceError. The variable is in a "temporal dead zone" from the
start of the block until the initialization is processed.
Is the "let binding" referrred to (the hoisting of let and const) just the keyword let, or is it just the creation of storage space (which doesn't have to do with the keyword)?
Previously I thought the variable keyword and variable name together comprised a declaration, but in a question I asked recently, the answerer said they are actually an initialization.
I'm sorry for using two different terms when writing that MDN paragraph. For all purposes in that article, "variable" and "binding" should be understood as the same thing. But let's go into details.
A variable declaration creates the variable (as an abstract entity). It tells the compiler that it should introduce a new variable, and also can tell it about a name, a type to be held, an initial value, a scope etc. (depending on the language). In JS, there are different kinds of declarations that do different things, for example
var has a name, an optional initialiser and scoping rules specific to var
function has a (sometimes optional) name, the value is always given and known to be a function
const has a name, a required initialiser, should be immutable, and has lexical scoping
…
A binding is the association of a variable name with the variable entity, for example "x refers to the variable declared with class x". Such bindings depend on the scope, i.e. in every different scope there are different bindings and so the identifier x might refer to different things in different scopes.
Given the scoping rules of JavaScript, a variable declaration also causes bindings for itself to be created in the respective scopes.
So the binding is what makes the name available to be used. That's what I referred to as "the let binding is created at the top of the scope". It has nothing to do with the variable existing, having memory allocated for it, or being initialised.
A declaration just says that something exists. In JavaScript you can declare variables, functions and (more recently) classes.
In some languages (e.g. C, C++) it's possible to declare something without defining it. For example:
// this declares a function exists with a given signature, but doesn't define its implementation
void someFunction();
someFunction(); // here we call the function, since we know it exists
// here we define the function, which we have to do at some point
void someFunction() { /* ... */ }
This pattern is less common in modern languages, where the declaration and the definition tends to be combined, but it's useful to understand the distinction seeing as your question seems largely about terminology.
Variables can be declared, however they don't have definitions.
let b; // we declare that there's a variable 'b'
Instead you can assign a variable:
b = 5; // assignment
let c = 6; // declaration and assignment in one statement
The concept of binding in computer science has many forms. For example, when you type foo in your code, binding is the act of working out which variable/function/type/... should be used. In JavaScript this is pretty straightforward, but in some languages it can get pretty hairy (due to things like overload resolution and so forth).
However I don't believe that's what MDN means when they talk about let bindings. I believe it's a shorthand for "let declaration and assignment", as we saw above.
Regardless, I wouldn't worry too much about that term. The most important bit to understand from the paragraph you've quoted is that let and const are tighter versions of var, introduced in recent versions of the language to address pitfalls and surprises that came from the way var works.
Previously I thought the variable keyword and variable name together comprised a declaration
You're right.
var a;
var b = 1;
let c;
let c = 2;
const d = 3;
These are all declarations of variables (even though const technical variables can't vary, or more precisely, they cannot be reassigned).
It's just that var is a bit sloppy and surprising.
You could declare a var more than once within the same scope:
var a = 1;
var a = 2;
This won't work with let:
let a = 1;
let a = 2; // SyntaxError: Identifier 'a' has already been declared
Scoping on var can be surprising too:
for (var i = 0; i < 10; i++)
{
var inner = 1;
}
console.log(inner); // prints 1 even though you might think this would be an error
Or worse:
for (var i = 0; i < 10; i++)
{
for (var i = 0; i < 10; i++)
{
console.log('hello');
}
}
At a glance you might think this would print hello 100 times (10*10), but actually it is only printed 10 times because both loops use the same variable. This is a type of programmer error that the language should really prevent. If that code used let i instead, it would produce a syntax error.
As for hoisting you can think of it as though all the var declarations were moved to the top of the containing function.
function foo()
{
doThing();
var i = 0;
doSomethingElse();
for (var j = 0; j < 10; j++)
{
var k = 10;
}
}
Even though that's how you might write the code, it behaves as though you had written:
function foo()
{
var i; // all declarations hoisted to top of containing function scope
var j;
var k;
doThing();
i = 0;
doSomethingElse();
for (j = 0; j < 10; j++)
{
k = 10;
}
}
This is why you can write:
i = 10;
var i;
The var is moved up in the code, so it behaves as:
var i;
i = 10;
You can think of let as not being moved. Therefore it is an error to reference it before it is declared.
The main thing to understand here is that the js engine actually visits a let statement inntwo different situations (as well as every other statement, but it particularily matters here). It is visited once during parsing, when it generates an AST and also analyzes the scopes and the variables. It also creates a list of variables for each scope. Now when the code gets executed, the engine visits the statement a second time (or more often if its inside a loop / function / whatever) and now finally initializes the variable and assigns a value to it. So "hoisting" is basically just caused because of the parsing / executing stages, the engine knows that a variable exists before it reaches the declaration statement during execution as it has already parsed it before.
Is the "let binding" referrred to (the hoisting of let and const) just the keyword let, or is it just the creation of storage space (which doesn't have to do with the keyword)?
The keyword actually causes an entry in the scope record, which will then get turned into a storage space during execution. On the other hand the statement itself causes an initialization during execution. So its actually hard to say when a declaration happens, thats a question of words. Its common to say
That variable was declared at line 10
Its declared in that block
so wether "declaration" refers to the statement or the scope assignment is up to you :)
the answerer said they are actually an initialization.
Actually the answerer prefered to call it "initialization" and not "declaration" to not confuse readers, but well in reality its confusing as human languages are not as clearly defined as machine ones.

JavaScript loop variable scope

Just a quick question about the scoping of JavaScript variables.
Why does the alert() function print the value of i instead of returning undefined?
$(document).ready(function () {
for(var i = 0; i < 10; i += 1){
}
alert("What is 'i'? " + i);
});
I'm fairly new to JS, and in nearly all other languages I've dabbled, a declaration in the scope of the for loop would contain the value to that said loop, but not in this case, why?
i.e. What is 'i'? 10' is printed.
See the MDN for the "initialization parameters" of a for-loop:
An expression (including assignment expressions) or variable declaration. Typically used to initialize a counter variable. This expression may optionally declare new variables with the var keyword. These variables are not local to the loop, i.e. they are in the same scope the for loop is in. The result of this expression is discarded.
JavaScript didn't have block scope until const and let were introduced, just var which is function scoped. Since the initialization of i is within one function, that variable is accessible anywhere else in that same function.
From MDN:
Important: JavaScript does not have block scope. Variables introduced with a block are scoped to the containing function or script, and the effects of setting them persist beyond the block itself. In other words, block statements do not introduce a scope. Although "standalone" blocks are valid syntax, you do not want to use standalone blocks in JavaScript, because they don't do what you think they do, if you think they do anything like such blocks in C or Java.
The javascript folks are trying to fix this!
EcmaScript6 (aka EcmaScript 2015) is the latest version of javascript that was passed last summer and browsers are just starting to support its features.
One of those features is block-scope local variables with the "let" expression. As of right now (April 2016), most of the current versions of the major browsers support this except Safari. Few mobile browsers support this.
You can read more about it here (in particular, see the section "let-scoped variables in for loops"):
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
You can check current browser support here (look for the row Bindings -> let):
https://kangax.github.io/compat-table/es6/
Unlike other languages (for example: Java, C++, C), JavaScript doesn't support block scope. Once you declare a variable in a loop or in a function it's scope is within the function body if you do
for(i=0; i<arr.length; i++) {
var j=0;
// ...
}
here your i becomes a global variable and j become local to the function or script in which the loop is.
for(i=0; i<arr.length; i++) {
var j=0;
// ...
}
it is not correct to state that the above creates a global variable i. I believe you should always use var to declare variables (unless you are intentionally wanting a 'property' rather than a 'variable' -which is pretty unlikely in 99.99% of JS coding scenarios ...)
Omitting var when assigning an initial value to i isn't creating a local or even a global variable, it is creating a property i for the global object (which may seem/behave mostly like a global variable - but they have some subtle differences).
better would be:
var i;
for(i=0; i<arr.length; i++) {
var j=0;
// ...
}
now the loop is using a global variable i (or function local variable i, if this code appears in a function)
see more about this at what is function of the var keyword and variables vs. properties in Javascript
--
note, what is a little confusing is that you can re-declare a variable, for example in a second loop
for(var i=0; i<9; i++){
document.write('i = ' + i + '<br>');
}
for(var i=0; i<9; i++){
document.write('i = ' + i + '<br>');
}
this seems to be valid (no errors when I test). It seems that you CAN re-declare variables in JavaScript - but it probably isn't every a good idea, unless a special case - see this related question mentioning how [Google Analytics makes use of the 'safe' redeclaration of a variable] (Redeclaring a javascript variable)
there is some discussion about re-declaring variables in JS (and also loop variables like i) in this related SO question: declare variables inside or outside the loop
There is event a JavaScript pattern for single declaration of variables

Will I have any problems if I declare the same variable multiple times?

So lets say I have some code:
//Javascript
var elements = [];
function addNumbah1(){
var i = 1;
elements.push(i);
}
function addNumbah2(){
var i = 2;
elements.push(i);
}
And that goes on up to addNumbah999(), is it bad form to declare the i variable every time? Will that break anything? Should I do:
//Javascript
var elements = [];
var i
function addNumbah1(){
i = 1;
elements.push(i);
}
function addNumbah2(){
i = 2;
elements.push(i);
}
Short answer: NO, JS hoists all variable declarations to the top of the scope, regardless of how many times you've declared them:
var i = 0
for (var i=0;i<10;i++)
{
var j = i%2;//declared 10 times, on each iteration
}
Will be translated to
var i, j; //i is undefined at this point in the code.
for (i = 0;i<10;i++)
{
j = i%2;//declared 10 times, on each iteration
}
In your first example, you're declaring i as a variable in a function's scope, which is what you must do to avoid cluttering the global scope. The memory these variables use is allocated when the function is called, and deallocated when the function returns (roughly, closures form an exception, but that would take us to far). Consider this:
var i = 10;
function someF()
{
var i = 1;
alert(i);
}
someF();//alerts 1 <-- value of i, local to someF
alert(i);//10, global i is unchanged
But if you were to omit the var:
function someF()
{
i = 1;
alert(i);
}
You'll see that 1 is alerted twice. If JS can't find a variable declaration in the current scope, it will look in the higher scopes until a var is found. If no variable is found, JS will create one for you in the highest scope (global). Check my answer here on how implied globals work for a more detailed example, or read the MDN pages, especially the section on Name conflicts
Lastly, I'd like to add that globals, especially implied globals, are evil. Also know that the ECMA6 standard is clearly moving away from global variables and introduces support for true block-scopes. As you can see here
Oh, and if you want to check if a function uses implied globals: 'use strict'; is a great thing:
(function()
{
'use strict';
var localVar = 123;//ok
impliedGlobal = 123;//TypeError!
}());
As you can see, implied globals are not allowed. See MDN on strict mode for the full explanation
The second form, with global i might actually be a bit slower because it's defined in a higher scope, and variables defined in a higher scope take longer to resolve.
Aside from any performance considerations just stick with common guidelines unless performance is really an issue. In this case: scope your variables as narrowly as possible.
I would strongly advise you to use the first form.
The first way you did it is fine. Each instance of i would have no knowledge of the other i in the other functions.
You should read this tutorial on global versus local variables
Also, could I suggest an optimization. Why can't you just do the following to cover any number (instead of separate functions for each number)?
var elements = [];
function addNumbah(number){
elements.push(number);
}
It is okay to declare variables with same name in different functions.
Variables declared inside a function only exist in the scope of that function, so having the same variable name across different functions will not break anything.
In fact, it is good form to keep variables in as small of a scope as possible! Global variables can be difficult to manage and can create really bad bugs, especially if one function isn't done using the variable when another function tries to access it.
Specifically for simple variables, declaring
var i = 0;
every time is perfectly fine.
You can declare a variable multiple times..In your code you are declaring Variable i in different scopes here:
//Here you are declaring variable i local to addNumbah1,2 functions
var elements = [];
function addNumbah1(){
var i = 1;
elements.push(i);
}
function addNumbah2(){
var i = 2;
elements.push(i);
}
//Here v /variable i has been declared globally
var elements = [];
var i
function addNumbah1(){
i = 1;
elements.push(i);
}
function addNumbah2(){
i = 2;
elements.push(i);
}
Note that although you can declare a variable multiple times but generally its not a good programming practice as it may cause bugs/problems in your application

Categories

Resources