Why the first one is ReferenceError,And the second one is TypeError?
This is due to the language feature referred to as hoisting.
In the first example, the function z() is literally never defined - therefore you get a reference error just like this code produces:
b(); // undefined - produces ReferenceError since 'b' cannot be found
In the second example the function declaration for z() is hoisted within its enclosing scope - which is the code block. This is demonstrated here:
{
a();
function a() {
console.log('this is a');
}
}
Finally, the result you are seeing is browser dependent. In Chrome, the variable c will be undefined in the outer scope, but will produce a TypeError because the identifier c has been established. In Safari, c is defined as a function and executes as expected. So in this case, Safari has hoisted the declaration of c() to the outer scope while Chrome does not.
console.log(c);
c();
{
console.log(typeof c);
function c(){ console.log('this is c');}
}
First One:
The function z is not declared that's why you got ReferrenceError.
Second One:
The function z is declared, but inside the If/Else statement. So the scope of the function z is limited only inside the If/Else block. Hence you got the TypeError.
How to make it work?
Call the function z inside the If/Else block like below, it would work without error.
var a = true;
if(a) {
z();
function z() {console.log("a");}
}else{
z();
function z() {console.log("b");}
}
Recommendation:
Use If/Else inside a function, not the other way. See below example:
z();
function z() {
var a = true;
if(a) {
console.log("a");
}else{
console.log("b");
}
}
Related
The below code gives an output of undefined. I was of the impression that all variable and function declarations are hoisted to the top of their scope and so b should now be at the top the scope before calling a(). However, I still get undefined as my output?
a()
var b = 5;
function a() {
console.log(b)
}
You misunderstand how hoisting works. It doesn't hoist the assignment, it only hoists the declaration. Your code is equivalent to the following:
var b; // undefined
function a(){
console.log(b)
}
a();
b = 5;
Yes the variable declaration is hoisted, but the value is not set on b. The code looks like this
var b
function a(){
console.log(b)
}
a()
b = 5;
Hoisting means the variables will be created “at the top” - but it does not change anything about the time the value assignment happens, the b = 5 part still happens when execution reaches the part where it’s written. So if you call a() before that, b exists, but has not gotten any value assigned yet … hence, undefined
You are using a function declaration to create a function. So function declaration is also hoisted so they are being used before declaring.
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);
Consider the following code.
<!DOCTYPE html>
<script>
console.log(a);
function a() {}
</script>
Notice that a is seemingly accessed before it is defined. The console output is: (jsfiddle)
function a() {}
Function and variable names are defined before any other code runs, so the console.log call works here. This is called hoisting.
But this doesn't work if the function is defined as a parameters in a function call. Look at this code.
<!DOCTYPE html>
<script>
function a() {}
a(function b() {});
console.log(b);
</script>
Notice that the function b is defined inside of a call to a. Not inside of a closure, but inside of a call. The console output is: (jsfiddle)
Uncaught ReferenceError: b is not defined
I'm wondering why this happens. Is this the intended behavior? This happens in both Chrome and Firefox.
UPDATE: This jsfiddle shows that names in function expressions are never available in the scope in which they are defined. However, the name is defined inside the scope of the function itself. This means a named function expression can refer to the name, but only inside the function. The name is also stored in the function's name parameter.
<!DOCTYPE html>
<script>
console.log(a); // undefined
var a = function b() {
console.log(b); // function b() { … };
};
a(); // function b() { … };
console.log(a); // function b() { … };
console.log(a.name); // b
console.log(b); // Uncaught ReferenceError: b is not defined
</script>
Inside a(function b() {});, the function is a function expression and not a function declaration (only which are hoisted). You might have a look at var functionName = function() {} vs function functionName() {} for the difference.
EcmaScript §13 (see the paragraph below the NOTE) defines how Function Expressions and Function Declarations are handled.
Function Declarations are instantiated when the EnvironmentRecord is built (§10.5) and thus hoisted, a Function Expression is evaluated later and it's optional Identifier is never visible to the enclosing scope.
As this is a function expression, it's name is not visible to the outer scope. It's the same like
a = function(){}; // valid as it is a function expression
a = function b(){};// also valid
// b is is not accessable here, same as the anonymous function, but a of course is.
both are valid, but b is not visible to the outer scope. Omitting the name in a function declaration however is not valid.
The optional Identifier of the function expression is for reference purposes inside the function body (e.g. to enable recursive calls).
Update to your Update:
The reason why the first console.log yields undefined instead of throwing an error is the hoisting (While the instantiation is hoisted the initialisation isn't):
console.log(a); // undefined
var a = function b() {};
console.log(a); // function b() {}
// equals (hoisted):
var a;
console.log(a); // undefined
a = function b() {};
console.log(a); // function b() {}
function b() doesn't exist until the call a(function b() {}); is executed.
JS doesn't search the code for functions, that way. Also, function b() {} isn't a function declaration, you're merely passing it as a parameter. The only way to access that function would be within function a():
function a() {console.log(arguments[0])}
a(function b() {});
//function b() {}
However, this does not mean that you can actually call b() inside a(), since b() is defined in the scope of a's function call, not in the function itself. Basically, the name b is useless.
Javascript Code
var d = function c() { console.log(c); };
d(); // function c() { console.log(c); };
c(); // Reference Error
I understand the concept of variable hoisting where variable declarations and function definitions are hoisted to top of the existing scope. Also function definition in function expressions are not hoisted.
So, above will be
var d;
d = function c() { console.log(c); };
d();
c();
Hence d is a reference to a named function c
on executing d() the function c is executed in global scope, where there is no variable or property named c. But still console manages to log function definition of c.
When I tried c() I got a reference error. [As I Expected]
Case 2 proves that there is no window property named c available
So, How did d() manage to print the c's definition on execution?
Does every function have its own definition in its local scope as a property?
Yes. A named function expression produces a variable corresponding to the function name within the scope of that function only.
Here's an excellent but lengthy article on the subject: http://kangax.github.com/nfe/
See also the relevant section of the ECMAScript 5 spec. It has a specific note about this.
Say I'm trying to execute this JavaScript snippet. Assume the undeclared vars and methods are declared elsewhere, above, and that something and somethingElse evaluate to boolean-true.
try {
if(something) {
var magicVar = -1;
}
if(somethingElse) {
magicFunction(magicVar);
}
} catch(e) {
doSomethingWithError(e);
}
My question is: what is the scope of magicVar and is it okay to pass it into magicFunction as I've done?
Lots of other good answers about how Javascript handles this with var, but I thought I'd address the let situation...
If a variable is defined with let inside the try block, it will NOT be in scope inside the catch (or finally) block(s). It would need to be defined in the enclosing block.
For example, in the following code block, the console output will be "Outside":
let xyz = "Outside";
try {
let xyz = "Inside";
throw new Error("Blah");
} catch (err) {
console.log(xyz);
}
Javascript has function scope. That means that magicvar will exist from the beginning of the function it's declared in all the way to the end of that function, even if that statement doesn't ever execute. This is called variable hoisting. The same thing happens with functions declarations, which in turn is called function hoisting.
If the variable is declared in global scope, it will be visible to everything. This is part of the reason why global variables are considered evil in Javascript.
Your example will pass undefined into magicFunction if something is false, because magicVar hasn't been assigned to anything.
While this is technically valid Javascript, it's generally considered bad style and will not pass style checkers like jsLint. Extremely unintuitive Javascript like this will execute without any error
alert(a); //alerts "undefined"
var a;
POP QUIZ: What does the following code do?
(function() {
x = 2;
var x;
alert(x);
})();
alert(x);
In javascript only functions create a new context -closure.
Every definition of a variable is really a declaration of the variable at the top of its scope and an assignment at the place where the definition is.
var
function-scoped
hoist to the top of its function
redeclarations of the same name in the same scope are no-ops
You may want to read MDN scope cheat sheet
Due to hoisting You can even do things like this:
function bar() {
var x = "outer";
function foo() {
alert(x); // {undefined} Doesn't refer to the outerscope x
// Due the the var hoising next:
x = 'inner';
var x;
alert(x); // inner
}
foo();
}
bar();
bar();
Demo
So the foo function is converted to something like this:
function foo() {
var x;
alert(x); // {undefined} Doesn't refer to the outerscope x
// Due the the var hoising next:
x = 'inner';
alert(x); // inner
}
My question is: what is the scope of magicVar and is it okay to pass it into magicFunction as I've done?
Define okay..., Yes the code is valid, but it's less readable then if the variables declarations were on the top, that's all.
Due to javascript "hoisting" (MDN description), your variable declaration code gets translated as:
function yourFunction() {
var magicVar;
try {
if(something) {
magicVar = -1;
}
if(somethingElse) {
magicFunction(magicVar);
}
} catch(e) {
doSomethingWithError(e);
}
} //end of your function
"Hoisting" moves all variables declarations to the top of the function. So magicVar is available everywhere in the function, but it's undefined until you give it a value.
Your variable has function scope.
With var, variables exist from the beginning of the function to the end of it, no matter where they are declared, or even if the statement is actually ever reached. They will, however, be undefined until they are assigned another value.
So in your case, if something is false but somethingelse is true, you will call magicFunction with its first argument being undefined.
The let keyword, created in Javascript 1.9 and available (as of today, May 3rd 2012, and as far as I know) only in Firefox, declares variables with the scoped semantics you're probably used to.
I agree with variable hoisting and function hoisting, I would like to emphasis two import points.
Identifier Defined in Catch parameter is i.e. err/e(error) , is scoped to Catch defined block.
Function first hoisting.
example :
b(); // output : 3
var b = 2;
function b(){
return 3;
}