This question already has answers here:
What happens when JavaScript variable name and function name is the same?
(6 answers)
Closed 8 months ago.
I want to know the difference between the following two block of codes:
function foo() {
var a = 'private variable';
return function a(){
console.log(a)
}
}
foo()(); // output: function a(){...}
vs
function foo() {
var a = 'private variable';
function a(){};
return () => {console.log(a)}
}
foo()(); // output: private variable
In the first block of code, based on the hoisting, the function a definition should be hoisted, and then var a = 'private variable' rewrite the a, but why the console.log(a) output the function definition?
It's not about hoisting. The first variant does not actually declare a function, it is merely a function expression (i.e., a 'lambda' or a 'closure') which doesn't declare anything within it's own lexical scope. What the 'a' does in that expression is assign the 'name' property of the resulting function object, and make it available to it's body's lexical scope:
e.g. in node:
> const f = function a() {console.log(a);}
undefined
> a
Thrown:
ReferenceError: a is not defined
> f
[Function: a]
> f()
[Function: a]
undefined
See also https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function
I hope below code could help you understand what is happening.
When you use return function a() { ... } it will not considered as function declaration but will be treated as Variable assignment like a = function () { ... }; return a;. And return will execute later a will hold value as function.
As below code you can be sure that assignment want take place until it reaches that line. So when we use foo(1)(); it outputs private variable.
function foo(returnString) {
var a = 'private variable';
if (returnString)
return function() { console.log(a); };
return function a() { console.log(a); };
}
foo()(); // output: function a() { console.log(a); }
foo(1)(); // output: private variable
In your second case it is quite simple. As per Order of precedence
Variable assignment takes precedence over function declaration
Function declarations take precedence over variable declarations
function foo() {
var a = 'private variable';
function a() {};
return () => { console.log(a); }
}
foo()(); // output: private variable
In the first case when you are referencing a in console.log you are actually referencing the function a and it already shadowed over the var = a so you don't have access to it.
On the second option, function a() {} actually moves above the var a = 'private variable' so the code would look like this:
function a() {};
var a;
a = 'private variable';
That is why when you call foo()() your var a = 'private variable'; is shadowing over the function a and you see private variable in terminal.
Related
For example:
(function foo() {
var a = 3;
console.log(a);
});
var obj = {
a: (function foo() {
var a = 2;
console.log(a);
})
};
obj.a(); // 2
foo(); // ReferenceError: Not Defined
How is that I can access a function expression within obj, but not in the global object?
Edits: for cohesion and clarity
You're confusing a couple of different things here.
Your first statement is a function expression, not a function declaration:
(function foo() {
var a = 3;
console.log(a);
});
This happens to be a named function expression ("foo"), but it does not introduce a variable foo in this scope. If you wanted to introduce foo so that it can be called again, you need either a function declaration...
function foo() {
var a = 3;
console.log(a);
}
foo();
or, you need to assign the function expression to a variable:
var foo = function () {
var a = 3;
console.log(a);
}
foo();
Your next bit of code, the object declaration, effectively does this by assigning the function expression to a variable, obj.a:
var obj = {
a: (function foo() {
var a = 2;
console.log(a);
})
};
The error in your thinking here is due to confusion around foo. In both cases, foo is the name of the function, but it's not actually relevant to invoking the function. You should drop the foo because it's only confusing things.
In essence, your first snippet is equivalent to:
(function () { alert('x'); });
This line of code defines an anonymous function, but does nothing with it. The function exists briefly, is never invoked, and then is lost, because it is not assigned to anything.
Your second snippet is equivalent to:
var x = function () { alert('y') };
This code defines a variable, x, and assigns a function to it. The function can then be invoked with x(), and the function remains available as long as x is in scope.
Your original question is:
How can an object access function expression?
Which doesn't really make sense. The object can't "access the function expression", it just contains a property to which a function has been assigned, while the snippet outside the object did not retain the function in a way that would allow you to invoke it.
I have a problem with a local scope. The second console.log doesn't show "a" value, but shows undefined. Why so?
"use strict"
console.log(a); //undefined
var a = "a";
function b(){
console.log(a); // why is undefined here?
var a = "a1";
console.log(a); // here is "a1"
}
b();
JS will process your code like:
"use strict"
var a; // undefined
console.log(a); //undefined
a = "a";
function b(){
var a; // undefined
console.log(a); // all is clear, LOCAL variable a is undefined.
a = "a1";
console.log(a); // here is "a1"
}
b();
read more about hoisting here.
Also you can read about Function declaration hoisting, this is an important part of JavaScript fundamentals too.
Object-Oriented JavaScript, 2nd Edition: When your JavaScript program execution enters a new function, all the variables declared
anywhere in the function are moved (or elevated, or hoisted) to the
top of the function. This is an important concept to keep in mind.
Further, only the declaration is hoisted, meaning only the presence of
the variable is moved to the top. Any assignments stay where they are.
In the preceding example, the declaration of the local variable a was
hoisted to the top.
var a = 123;
function f() {
var a; // same as: var a = undefined;
alert(a); // undefined
a = 1;
alert(a); // 1
}
Hoisting is JavaScript's default behavior of moving declarations to the top. You have an a variable in your function scope. This is how it looks like when you're executing it:
"use strict"
console.log(a); //undefined
var a = "a";
function b(){
var a;
console.log(a); // Undefined because a is not set
a = "a1";
console.log(a); // here is "a1"
}
b();
Because you have another variable a defined in function b, so it' like this:
function b() {
var a;
console.log(a);
a = "a1";
console.log(a);
}
Can anyone explain why
function x() {
console.log("Hello!");
}
var a = x;
a();
x();
produces
Hello!
Hello!
but this
var a = function x() {
console.log("Hello!");
}
a();
x();
throws an error when you try to call function x? Is the second x function not considered a hoisted function? I tried this in both nodejs and a browser.
What you have in the second example is what's called a named function expression.
Its name is not added to the containing scope, but is accessible within the scope of the function itself:
var a = function x() {
alert(x);
};
a();
This is useful in writing recursive functions or functions that otherwise reference themselves, as it ensures that the name won't get clobbered due to anything that happens outside the function's scope.
It also allows you to create self-referencing functions in places where you can't use a function declaration, such as in an object literal:
var myFavoriteFunctions = {
factorial: function f(n) {
return n === 1 ? 1 : n * f(n);
},
identity: function (v) { return v; }
};
console.log(myFavoriteFunctions.factorial(10));
Your first example is a function statement, which declares a name in its containing scope.
Your second example is a named function expression, which does not.
For more information, see here.
One of my friends was taking an online quiz and he asked me this question which I could not answer.
var global = false;
function test() {
global = true;
return false;
function global() {}
}
console.log(global); // says false (As expected)
test();
console.log(global); // says false (Unexpected: should be true)
If we assume that functions are hoisted at the top along with var variables, let's try this one.
var foo = 1;
function bar() {
return foo;
foo = 10;
function foo() {}
var foo = 11;
}
bar();
console.log(foo); //says 1 (But should be 11) Why 1 this time ??
Here is a JSBin Demo and JSBIN Demo2 to play with.
PS: If we remove function global() {} from test(), then it runs fine. Can somebody help me understand why is this happening ?
var statements and function declaration statements are "hoisted" to the top of their enclosing scope.
Therefore, the function global(){} in your function creates a local global name.
Assigning to global inside your functions binds to this local name. Here's how you can "rewrite" it using hoisting to understand how the compiler sees it:
function test() {
var global = function() {}; // hoisted; 'global' now local
global = true;
return false;
}
I'll answer the second part of your question,
If we assume that functions are hoisted at the top along with var variables
bar();
console.log(foo); //says 1 (But should be 11) Why 1 this time ??
You should try console.log(bar()); console.log(foo); instead. However, what hoisting does to your function is this:
function bar() {
var foo;
function foo() {}
return foo;
foo = 10;
foo = 11;
}
So you should expect to get the function returned, since your variable assignments are after the return statement. And both the var and the function declaration make foo a local variable, so the global foo = 1 is never changed.
This question already has answers here:
What is the difference between a function expression vs declaration in JavaScript? [duplicate]
(5 answers)
var functionName = function() {} vs function functionName() {}
(41 answers)
Closed 8 years ago.
What is the difference between
var a = function() {}
and
var a = function b() {}
The latter, b is undefined?
The second one is a named anonymous function - the name will appear in a stacktrace (otherwise in the stacktrace you''ll see just "anonymous function")
The first is an anonymous function expression and the second a named function expression, both valid in Javascript.
For example, it can be used for recursion without arguments.callee (deprecated and not permitted in strict mode), because it refers to itself, no matter where. The scope of the reference is local only to inside the function, that is it isn't accessible globally:
var a = function b(){
return b;
};
function c() {
return c;
}
var d = function e() {
return e();
};
d(); // maximum call stack size exceeded :P
var f = c;
c = null;
f(); // null
a(); // function
b();// undefined not a function
b; // not defined
a()(); // same function again
var a = function() {}
Function name can be omitted. In this case function name is omitted. These functions are called anonymous functions.
Read about javascript scope and anonymous function advantages and disadvantages for details.