Function Scopes Understanding Unclear - javascript

var a = 1;
function b() {
a = 10;
return;
function a() {}
}
b();
alert(a);
How is the output of 1 displayed for a? What does the
return;
function a() {}
within the function body perform?

You declare a symbol "a" in the function with its last line. That's the "a" affected by the assignment statement.
Function declaration statements are hoisted up to the top of the function and are interpreted first. Thus, the assignment statement effectively happens after you've declared a function (local to the "b" function) named "a". The assignment, therefore affects that symbol, not the global "a".
Remember that variables aren't typed, so the fact that you've bound a name to a function doesn't prevent it from being assigned a numeric value later.

You code is misleading and in a style that makes people think execution order matters. The standard JavaScript engine these days will take that and reformat prior to running it to:
var a = 1,
b = function() {
var a = function() {};
a = 10;
return;
};
b();
alert(a);
Now you can understand what is actually happening. "a" is declared again inside the function "b" so there is actually two "a" variables now. One is "window.a" and the other one is "b var a" but NOT "b.a" because its not accessible outside of the closure or function.
In other words, you get what you code for.
Please make your code readable and don't confuse the point.

Related

How do these interactions btw var and function declarations with the same name work?

Can anybody tell me how it work by step, and why is different result:
Why is there no SyntaxError in the first case:
first:
var a = 'foo';
function a() { };
console.log(a); // foo
second:
// Uncaught SyntaxError: Identifier 'a' has already been declared
{
var a = 'foo';
function a() { };
}
console.log(a);
How the function a() {} overwrites var a?
// **only no use strict!!!**
var a = 'foo';
console.log(a); // foo
{
console.log(a); // function a() {} - i guess that is the result of hoisting inside the block but on this step the global variable a is still 'foo'
function a() {} // on this step - the global variable a = function a() {}. How to explain that?
a = "bar"; // on this step - overwrites only the local variable a
console.log(a); // bar
}
console.log(a); // function a() {}
and if i write so:
// **only no use strict!!!**
var a = 'foo';
console.log(a); // foo
{
console.log(a); // function a() {}
a = "bar";
function a() {} // on this step - the global variable a = bar. Why is not function a() {} ?
console.log(a); // bar
}
console.log(a); // bar
TL;DR Don't do that. 😃 The semantics for it are complicated and (as you noted) they're different in strict mode vs. loose mode.
Why is there no SyntaxError in the first case
Because that's just how JavaScript's var and function declarations were designed back in 1995. Both create a "binding" (effectively a variable) in the function or global scope where they appear. If you use the same name for both, that same binding is reused. The function is assigned to it first (because function declarations are hoisted), but then when the step-by-step execution of the code occurs the a = 'foo' part of var a = 'foo' runs and overwrites the binding's value with 'foo'.
second
Because you're declaring that function in a block, and the semantics are that are much newer (ES2015); prior to that, every JavaScript engine was free to handle that however it liked (and they handled them differently, and even the same engine would change how it handled them from one version to another).
The semantics there are that a let-style binding is created at the top of the block and the function is assigned to it. Even though var doesn't have block scope, you're not allowed to declare a var variable and a let variable with the same name in a block:
{
// Not allowed
let a = 1;
var a = 2;
}
When let-style declarations were added, this was disallowed, even though (again) the var isn't contained to the block.
With that in mind, here's roughly how the JavaScript engine interprets your "second" code:
// Uncaught SyntaxError: Identifier 'a' has already been declared
{
let a = function a() { };
var a = 'foo';
}
console.log(a);
Since that's the same situation (a var-style declaration and a let-style declaration in the same block), you're just not allowed to do that.
How the function a() {} overwrites var a?
It's that implicit local let declaration again. 🙂 Here's roughly how the JavaScript engine interprets that function declaration:
// **only no use strict!!!**
var a = 'foo';
console.log(a); // foo
{
// Block-local binding and function creation are hoisted
let a = function a() { };
console.log(a); // function a() {}
a<outer> = a<local>; // <======== Where the declaration was (not real syntax)
a = "bar"; // only the local is set
console.log(a); // bar
}
console.log(a); // function a() {}
Note that weird bit where the function declaration originally was:
a<outer> = a<local>; // Where the declaration was
The location of the declaration in the block controls when the value is assigned to the outer var. Yes, this is weird. So the declaration and function creation are hoisted, and then assignment to the outer variable is done where the declaration appeared in the code (even though normally, the location of a function declaration relative to step-by-step code is irrelevant). Importantly, that assignment is from the local's current value as of where that code is reached in the step-by-step execution.
on this step - the global variable a = bar. Why is not function a() {}
Because the assignment is before the declaration in the block, and the local a is copied to the outer a where the declaration was. Here's roughly how the JavaScript engine handles that:
// **only no use strict!!!**
var a = 'foo';
console.log(a); // foo
{
let a = function a() { }; // Hoisted
console.log(a);
a = "bar";
a<outer> = a<local>; // <======== Where the declaration was (not real syntax)
console.log(a); // bar
}
console.log(a); // bar
Again, though, just don't do that. 🙂 It's really complicated and arcane. I wrote an entire section on it for my recent book JavaScript: The New Toys (Chapter 3), and yet to answer your question I had to go back to that chapter and remind myself how this worked. Save those brain cells for something important. 😃
1st Case Works because you can make Empty Functions in JavaScript
2nd Case causes error because of the new ES6
This is an EcmaScript 6 change. From ES6 onwards it's no longer allowed to have duplicate bindings within a block scope. Read more
3rd Case I don't know

How does an empty function declaration work with hoisting in javascript?

Looking at the hoisting example from this site, I don't get why the below alters 1 even after the hoisting:
var a = 1;
function b() {
a = 10;
return;
function a() {}
}
b();
alert(a); // alerts 1
is actually
var a = 1;
function b() {
function a() {}
a = 10;
return;
}
b();
alert(a);
Shouldn't it alter 10 because a is still assigned to 10 before b function returns? Why does calling an empty a function cause this? On a related note, why does the below not alert function but still alter 1? Doesn't a get reassigned to a function with the declaration?
var a = 1;
function a() {}
alert(a);
Let's take it line by line,
Here, b(); you call the function b. What has the function b in its body? The declaration of a new function whose name is a. When you access a inside the b, you actually don't access the global variable a, but the function you just declared. So the 10 will be set to the pointer that points to function called a and not the global variable called a
But why does the first block of code alerts 1? I am confused
Because when the JavaScript engine goes to execute the assignment:
a = 10;
checks where a has been defined. Since in the current scope, where you try to set 10 to a, there is a function declaration, whose name is a, Then will happen that I described above. But you would say why? The function declaration is below the assignment. The reason why this is happening is the fact the JavaScript engine first process the declarations in your script and then proceeds to the execution of your script. So when the engine would questioned about a, where a is defined, as always it will look first at the current scope. If there isn't there then it will look in the scope where the current scope is enclosed. In your case this is the global scope, as I can infer from your code. So if you hand't defined this function, the the second step I mentioned before would have been done and since there is variable called a, would had alter it's value. If there isn't there any variable then a would have been defined on the global scope and it's value would have been 10.
var a = 1;
function b() {
a = 10;
return;
// I renamed the function from a to c to notice the hoisting
function c() {}
}
b();
console.log(a);

Difference in declaring variable

Please let me know the difference between the below two codes.
var a = 1;
function b() {
a = 10;
return;
}
b();
console.log(a);
This prints 10 in console.
whereas the below code prints 1 in console
var a = 1;
function b() {
var a = 10;
return;
function a() {}
}
b();
console.log(a);
Thanks for help.
In the first code there is one global variable 'a' which can be modified by any function and that change would be permanent.
But in the second code, there are two 'a' variable. Lets call them ag (a global) and al (a local). In second code b() function is modifying al (local variable a) not the global variable. But we are printing global variable in console.
Thats why results are varying in both the codes.
It's a metter of scope. In the first a is declared only out of function b, so when you edit a inside function b you are referencing the "outer" a.
In the second snippet you are re-declaring var a inside the function, so when you edit a variable inside the b function you are referencing the latest leaving untouched the "outer" a variable.
You have declared a in your second code inside the function hence the scope(availability) of your variable a persists only till function execution.
Once we return back from the function, local variable a is no more hence outer global a's value is printed.
when you are using var ,its scope will be local to its function.
and without var it will be a global function.
The first example is quite straight-forward: You declare an a variable which your b function closes over. So b sets a to 10.
Your second example is deliberately complex and confusing. You declare an a variable that b closes over, but then shadow it with an a variable inside b. To make matters worse, there's also a function declaration of a that is also in scope in b. The var wins over the function declaration, because function declarations are processed before var statements are. The outer a is completely unaffected by b, so the console.log at the end logs 1.
That's easier to describe with a diagram of sorts:
var a = 1; // <== The declaration `b` closes over
function b() {
var a = 10; // <== The inner `a` variable
return; // <== Returns from `b`
function a() {} // <=== Declaration that was processed immediately
// upon entering `b` (the `return` doesn't affect it
// at all), but which is then superceded by `var a`
}
b();
console.log(a); // Logs 1

Javascript function

there is such javascript code:
function a() {
a = 3;
return a;
}
console.log(a());
console.log(a());
After execution it prints out: 3, Type error. Could anybody explain why, please
You have a scope issue
Because you didn't use "var" you are overriding the global "a" variable (used to be your function) with a number (3).
When you try to execute it a second time, it's no longer a function but a number, which throws the type error.
function a() {
a = 3; // you just over-wrote a()
return a;
}
console.log(a()); // 3, but now "a" === number, not function
console.log(a()); // ERROR, you treated "a" as a function, but it's a number
what you want
function a() {
var a = 3; // using var makes "a" local, and does not override your global a()
return a;
}
console.log(a()); // 3
console.log(a()); // 3
Using var is recommended almost always inside a function, otherwise you're polluting, or worse overriding, global variables.
In JS, var enforces your variable into the local scope (your function).
Note that using var in the global scope still creates a global variable
If you were trying to set a as a variable, then var is needed in front. Because you didn't do so, it is exposed to the global scope, in which it is part of the window object, and you can access it with window.a. So, the best thing to do is to change the first body line of your function to say: var a = 3.

JavaScript scope gets changed? Why does this happen?

The value of 'a' seems to lose global scope when the constructor a is called.
var a = 6;
function b() {
a = 10;
function a() {}
console.log(a); //10
}
b();
console.log(a); //6
The order is interpreted as shown below due to variable hoisting. Note that as #ShadowCreeper correctly points out, function a(){} is actually creating a local variable a inside of function b which is hoisted as shown below.
var a;
var b;
a = 6;
b = function() {
var a;
a = function(){};
a = 10;
console.log(a); //10
}
b();
console.log(a); //6
Because you are creating a local variable (the function a) then replacing that local variable's value (the function) with 10.
One way to avoid things like this is to precede all local variables and functions with "_" (underscore).
This answer has a really nice explanation of what is going on here.
The summary is that Javascript is processed in two phases, compilation and then execution. The function definitions occur during the compilation step, so inside of b the compiler sees the definition function a() {} and the local variable a is created within the scope of b. Later on when the code is executed, the scope of b already contains the local variable a before any code is executed, so the line a = 10; is just giving the local variable a new value. The function definition was already processed during compilation so that will not happen during execution, so console.log(a) will output 10.

Categories