What happens when JavaScript variable name and function name is the same? - javascript

I have the following code, where I declare a function and after it, a variable with the same name as the function:
function a(x) {
return x * 2;
}
var a;
alert(a);
I expected this to alert undefined, but if I run it, the alert will display the following:
function a(x) {
return x * 2
}
If I assign a value to the variable (like var a = 4), the alert will display that value (4), but without this change a will be recognized as a function.
Why is this happening?

Functions are a type of object which are a type of value.
Values can be stored in variables (and properties, and passed as arguments to functions, etc).
A function declaration:
Creates a named function
Creates a variable in the current scope with the same name as the function (unless such a variable already exists)
Assigns the function to that variable
Is hoisted
A var statement:
Creates a variable in the current scope with the specified name (unless such a variable already exists)
Is hoisted
Doesn't assign a value to that variable (unless combined with an assignment operator)
Both your declaration and var statement are hoisted. Only one of them assigns a value to the variable a.

In JavaScript both function declaration and variable declarations are hoisted to the top of the function, if defined in a function, or the top of the global context, if outside a function. And function declaration takes precedence over variable declarations (but not over variable assignment).
Function Declaration Overrides Variable Declaration When Hoisted
First you declare a variable:
var a; // value of a is undefined
Second, the value of a is a function because function declaration takes precedence over variable declarations (but not over variable assignment):
function a(x) {
return x * 2;
}
And that is what you get when you call alert(a);.
But, if instead of declaring a variable you make variable assignment: var a = 4; then the assigned value 4 will prevail.

If you use a function name as variable name, its value is replaced by function body. So var a becomes your function a and thus your alert displays function a.
Edit But if you assign value to a like var a = "xya";. Then it function will be replaced by variable. As per Order of precedence
Variable assignment takes precedence over function declaration
Function declarations take precedence over variable declarations

You should also remember that var a is hoisted, which makes it more like this
var a; // placed
function a(x) {
return x * 2;
};
var a; // removed
alert (a); // a is replaced by function body
Remember that var a is hoisted, so if you assign 4 to a:
var a; // placed
function a(x) {
return x * 2;
};
var a = 4; // removed
a = 4 // added
alert (a); // a is now 4

First hoisting takes place. Function declaration takes precedence over variable declaration during hoisting.
During execution of the code, if variable is assigned at any point, then it is replaced, otherwise it remains the same function.
(Note: First read the code from Line 4 to Line 8. Then again read from beginning to end.)
console.log(a); // f a(){...} - Executed just after hoisting
console.log(b); // f b(){...} - Executed just after hoisting
var a = 100; // here variable is assigned
function a(x) {...};
function b(x) {...};
var b; // only a declaration here
console.log(a); // 100
console.log(b); // f b(){...}

ES6 comes with a better solution by defining SyntaxError: Identifier (?) has already been declared when using let / const instead of var.
let
function foo () {}
let foo;
// => SyntaxError: Identifier 'foo' has already been declared
const
function foo () {}
const foo = 1;
// => SyntaxError: Identifier 'foo' has already been declared
Note that const foo; does not work. It will cause SyntaxError: Missing initializer in const declaration

Related

In the block scope even after initialisation with undefined var type of variable logs out unexpected value

function show() {
var x = 10;
if (true) {
var x = 20;
}
console.log(x); // 20
}
show();
But when I not initialise the 'x' manually which is inside the 'if-statement', it initialise with undefined and hoisted to the top and should log the most recent value which is undefined , as 20 is logs out in the above example. But it logs out 10.Why?
function show() {
var x = 10;
if (true) {
var x;
}
console.log(x); // 10
}
show();
From MDN - var:
Duplicate variable declarations using var will not trigger an error,
even in strict mode, and the variable will not lose its value, unless
another assignment is performed.
So, unless you re-assign any value to x, variable declared with var will keep its value.
Re-declaring x inside the if block does not create a new variable; x is created only once.
From the Ecmascript spec - 14.3.2 Variable Statement:
A var statement declares variables that are scoped to the running
execution context's VariableEnvironment. Var variables are created
when their containing Environment Record is instantiated and are
initialized to undefined when created. Within the scope of any
VariableEnvironment a common BindingIdentifier may appear in more than
one VariableDeclaration but those declarations collectively define
only one variable.
That is why x in the following statement
var x;
doesn't implicitly gets initialized with undefined; this re-declaration statement didn't re-create the variable x.
function show() {
var x = 10;
if (true) {
var x = undefined; // re-assigned
}
console.log(x);
}
show();
Note on hoisting: Unless you know this already, variables are NOT literally hoisted/moved to the top of the scope in which they are declared; variable declarations are processed before the code execution, this is why they appear to have moved to the top of the scope.
For more details, see: MDN - var hoisting
So if you are trying to relate above both example, you might confused. see both examples in different way, you will get the answer.

Does a function's name act as a variable?

I have a question about this code below:
function myfunc () {
return 2 + 2;
}
console.log(myfunc);
Does anyone know why, when we log 'myfunc' to the console, we get the entire function itself back? Or in other words, is 'myfunc' acting as a variable that holds the function's contents, or is it just referencing that function?
Because if I go ahead & add this to the code...
myfunc = undefined; //or any other value like myfunc = 20;
...then since myfunc's value is changed, I can no longer use it to invoke the function. So what is 'myfunc' really?
The answer is yes, a function declaration creates a symbol in the local function scope (or global scope if the declaration is in that context) that works exactly like a variable declared with var (though function declarations are hoisted above var declarations).
Now, a function expression like this:
var x = function helloWorld() { return "hello world"; };
does not create a local "helloWorld" symbol (except when it does). The value of a function expression is a reference to the created function, and that can be assigned to a variable just like any other value.

Why doesn't this assignment throw a ReferenceError?

Consider three cases, where both a and k are undefined:
if (a) console.log(1); // ReferenceError
and
var a = k || "value"; // ReferenceError
seems reasonable, but...
var a = a || "value"; // "value"
Why doesn't the last case throw a ReferenceError? Isn't a being referenced before it's defined?
This is because of one of var's "features" called hoisting. Per the link:
Because variable declarations (and declarations in general) are processed before any code is executed, declaring a variable anywhere in the code is equivalent to declaring it at the top. This also means that a variable can appear to be used before it's declared. This behavior is called "hoisting", as it appears that the variable declaration is moved to the top of the function or global code. (emphasis mine)
So, for example:
console.log(a);
var a = "foo";
Instead of throwing a ReferenceError as you might expect, since a is referenced before it is defined, it logs undefined. This is because, as mentioned earlier, the declaration is processed first and essentially happens at the top, which means it's the same as:
var a;
console.log(a);
a = "foo";
The same goes for functions as mentioned earlier:
function foo() {
console.log(a);
var a = "foo";
}
That's the same as:
function foo() {
var a;
console.log(a);
a = "foo";
}
To see why, look into the ECMAScript 2015 Language Specification:
13.3.2 Variable Statement
NOTE
A var statement declares variables that are scoped to the running execution context’s VariableEnvironment. Var variables are created when their containing Lexical Environment is instantiated and are initialized to undefined when created.
[...]
A variable defined by a VariableDeclaration with an Initializer is assigned the value of its Initializer’s AssignmentExpression when the VariableDeclaration is executed, not when the variable is created. (emphasis mine)
From this, we can gather that the var declarations are created before any code is executed (in their lexical environment) and are scoped to the containing VariableEnvironment, which is either in the global scope, or in a function. They are initially given the value undefined. The next part explains that the value that the var is assigned to is the value of the right hand side when the declaration is executed, not when the variable is created.
This applies to your situation because in your example, a is referenced like it is in the example. Using the information earlier, your code:
var a = a || "value";
Can be rewritten as:
var a;
a = a || "value";
Remember that all declarations are processed before any code is executed. The JavaScript engine sees that there's a declaration, variable a and declares it at the top of the current function or global scope. It is then given the value undefined. Since undefined is falsey, a is assigned to value.
In contrast, your second example throws a ReferenceError:
var a = k || "value";
It can also be rewritten as:
var a;
a = k || "value";
Now you see the problem. Since k is never a declared anywhere, no variable with that identifier exists. That means, unlike with a in the first example, k is never declared and throws the ReferenceError because it is referenced before declaration.
But how do you explain var a = "123"; var a = a || "124"; // a = "123"?
From the ES2015 Language Specification again:
Within the scope of any VariableEnvironment a common BindingIdentifier may appear in more than one VariableDeclaration but those declarations collective define only one variable.
To put it plainly: variables can be defined in the same function or global scope more than once, but always define the same variable. Thus, in your example:
var a = "123";
var a = a || "124";
It can be rewritten as:
var a;
a = "123";
a = a || "124";
Declaring a in the same function or global scope again collectively only declares it once. a is assigned to "123", then it is assigned to "123" again because "123" is truthy.
As of ES2015, you should, in my opinion, no longer use var. It has function scoping and can cause unexpected assignments like those mentioned in the question. Instead, if you still want mutability, try using let:
let a = a || "value";
This will throw a ReferenceError. Even though all variables are hoisted, no matter which declarator you use (var, let, or const), with let and const it is invalid to reference an uninitialized variable. Also, let and const have block scope, not function scope. This is more clear and normal regarding other languages:
function foo() {
{
var a = 3;
}
console.log(a); //logs 3
}
Versus:
function foo() {
{
let a = 3;
}
console.log(a); //ReferenceError
}
var a = k || 'value';
var a = a || 'value';
a is declared when you call var a but k is not, that why first line is ReferenceError and second line is 'value'
if (a) console.log(1); // ReferenceError
in this case i think there is no doubt as a is not declared anywhere before using it so refrence error
var a = k || "value"; //ReferenceError
same case here k is not declared and we are trying to use it
var a = a || "value"; //"value"
now in this case when we are trying use a (a in r.h.s) that time a is already declared before using it and hence no error
Adding to this if you want to know difference between reference error and undefined
refrence error -indicate variable is not declared yet whereas
undefined - it is special value in javascript assigned to any variable as soon as it is declared undefined indicates that variable is declared but has not taken any value

basic javascript function syntax [duplicate]

This question already has answers here:
What is the (function() { } )() construct in JavaScript?
(28 answers)
Closed 6 years ago.
from MDN, just wondering why the () around the function, why the extra () after it, and why the var b inside the function doesn't replace the value of the first var b, given it doesn't use the keyword let, which would keep b local to that function, thanks
var a = 1;
var b = 2;
(function() {
var b = 3;
a += b;
})();
a; // 4
b; // 2
When you write var b inside a function, the var keyword makes it a local variable. So, var b inside the function is a local variable and var b at the top which is outside the function is in global scope. You can read more about scoping in MDN. Also, the () after the function is called immediate function invocation which means that the function is given a call soon after it is defined. Also, since a inside the function has no var before its declaration, it will take the global a which is 1 and add 3, local variable b's value it.
The function is simply called immediately. That’s what the last parentheses are for. The extra parentheses around the function declaration are because
function() {
var b = 3;
a += b;
}();
would create a syntax error as the function keyword would not be interpreted as an expression here.
and why the var b inside the function doesn't replace the value of the first var b, given it doesn't use the keyword let, which would keep b local to that function,
You may have heard that the special thing about let is that it is block-scoped. That’s true. But var has always been scoped to the function and since the second var b is inside its own function it’s scoped to that function and does not affect the b from the top scope here.
The template
(function(){})();
Is a template of an anonymous function.
To explain it, let's create a function x() that alerts 'hello':
function x() {
alert('hello');
}
To call x, we will:
x();
Now, it's clear that if we replace an object's name with it's value, the statememt will stay the same (take for example var k = 5; alert(k); alert(5) - the two alerts are the same because variable's name was replaced with it's value).
In our case, x's value is:
function () {
alert('hello');
}
So if we replace x with it's value in the statement x(); ->
(function () {
alert('hello');
})();
And that's the source of the syntax. The result of that will be an immediate call to the specified function. Of course, this syntax works also for functions with parameters and functions with return types.

Global variable override with a local one

The following test is a success, and prints 1 and 1:
function test1() {
a = 1;
console.log(a); // prints "1"
}
function test2() {
console.log(a); // prints "1"
}
test1();
test2();
And the following test fails, because a local variable overrides the previously created global one:
function test1() {
a = 1;
var a = 2;
console.log(a); // prints "2"
}
function test2() {
console.log(a); // throws an error
}
test1();
test2();
Why does the second example remove the global variable permanently? What purpose/logic does such functionality serve in JavaScript?
EDITED: For those who marked it as a duplicate of Strange Behavior on Global and Local Variable in JavaScript
Hoisting refers to the scenario when a later declared local variable is moved up the function scope, overriding the previously visible variable. But in our case the function first creates a global variable, and then deletes it completely/globally.
However, it is probably related, as we can see in the following test:
function test1() {
a = 1;
console.log(a); // prints "1"
}
function test2() {
console.log(a); // prints "undefined"
var a = 2;
}
function test3() {
console.log(a); // prints "1"
}
test1();
test2();
test3();
In your second case, no global variable named a ever exists.
a = 1 generally does not create a global variable. The statement a = 1 stores the value 1 in a variable called a. If the variable environment of any containing local scope has a variable called a, the nearest scope with an a variable will have that variable set to 1.
As a special case, if a variable called a does not exist in any containing scope (and if you are not in strict mode), then the JavaScript engine will create a global variable called a.
In your second case, var a creates an a variable in the local scope. Due to hoisting, that modification to the scope's variable environment happens before any code runs. Thus, by the time a = 1 is executed, that local scope does have a variable called a, so that local variable is used.
In your third case, test2 logs the local variable a (created by the var a). At the time the log call is made, the local a has not yet been assigned a value.
Hoisting refers to the scenario when a later declared local variable is moved up the function scope, overriding the previously visible variable.
Hoisting simply means that all var declarations are treated as if they happen at the top of their containing function. It has nothing to do (directly) with overriding variable visibility.
Note that declarations with an assignment will have only the declaration hoisted, not the assignment. The assignment stays in place wherever it is in the function.
Javascript moves variable declarations to the top. So in this example the compiler reads you code as:
function test1() {
var a;
a = 1;
a = 2;
console.log(a); // prints "2"
}
function test2() {
console.log(a); // throws an error
}
test1();
test2();

Categories

Resources