Why this logs 1 ? It's confusing to me , can anyone please explain?
(function(){
var hello = () => {
console.log(1);
}
function hello () {
console.log(2);
}
return hello()
})()
CodePudding user response:
Function declarations (statements that start with function functionName( )get hoisted to the top of their enclosing scope, and assign to their function name identifier first, before anything else runs in that scope.. Assignments with = do not.
The fact that it's an arrow function doesn't particularly matter - a function assignment at the same point would produce the same results.
(function(){
var hello = function() {
console.log(1);
}
function hello () {
console.log(2);
}
return hello()
})()
Your code is equivalent to
(function(){
// hello identifier gets created at the very beginning
var hello;
// hoisted function declaration assigns to `hello`:
hello = function hello () {
console.log(2);
}
// assignment with =, not hoisted, assigns to `hello`
hello = () => {
console.log(1);
}
return hello()
})()
I'd recommend using ES2015 syntax at least, which will help prevent you from making these sorts of accidents - it will forbid re-declarations of variables if you use let or const.
(function(){
let hello = () => {
console.log(1);
}
function hello () {
console.log(2);
}
return hello()
})()
CodePudding user response:
Because:
- Function declarations create identifiers (more specifically, "bindings") in the same binding environment that
vardeclarations do - A
vardeclaration for a binding that already exists is not an error - Function declarations are processed upon entry to the function or global scope ("hoisted"), so they assign to the binding first
So your code is creating a binding, assigning a the declared function to it, then overwriting that value with the arrow function. In effect:
(function(){
// Declaration of the var-scoped binding happens first
var hello;
// Then the function declaration is processed, assigning
// the function to the binding
hello = function hello() {
console.log(2);
};
// Then the step-by-step code begins and processes
// the assignment
hello = () => {
console.log(1);
};
return hello();
})();
Side note: var is effectively deprecated, there's no reason to use it in modern code. Instead, use let or const. They have more rational behavior:
- They're block-scoped, not function- or global-scoped (unless they appear at the top level of function or global scope)
- Repeated declarations are an error (including a
letorconstdeclaration that would conflict with avar-style declaration like a function declaration) - At global scope, they live in an inner scope nested inside the global
varscope, and they don't create properties on the global object
Your example would have given you a nice, useful error with let or const:
(function(){
let hello = () => {
console.log(1);
};
function hello () {
console.log(2);
}
return hello();
})()
