I am learning JavaScript. I understood that variables created by 'let' are hoisted (as variables created by 'var') but those are not available to use until control hits the initialization statement because of temporal dead zone. If we can't use the variables, what is the need of hoisting those variables?
There is no need to hoist it, it is just something to be aware of.
If you had, as a ridiculous example:
var x = 10;
function if_x_is_10() {
if (x === 10) {
console.log('It was 10!');
}
let x = 10;
console.log('Now it is 10!');
}
if_x_is_10(); // Uncaught ReferenceError: x is not defined
You just need to be able to realize, "oh, even though there is an x outside the function, since there is a let x inside the function, I can't access x until I am past that line, and I can't access the outer x inside of the function".
Related
I am new to javascipt as I have started learning js now, I am pretty confused with var that is said to be function scoped and block scoped;
If so then how do we access them outside of that function!? lets say i want to use it from another class (I don't know maybe by creating some object or whatever) (I guess we can't create objects here! because as it is a functional programming based language I guess!:( )
var y = "global";
if (y === "global") {
var y = "block-scoped";
console.log(y); // expected output: block-scoped
}
console.log(y); // expected output: block-scoped
var is not said to be function scoped.
Variables declared with var can either be function or Global scoped.
If the declaration occurs within a function, then the variable is
scoped to that function.
If the declaration occurs outside of a function, then the variable is
scoped Globally.
If a variable is declared with let or const, then it has block level scope. A block is delimited by {} or if those symbols are not present, the enclosing function or, if not in a block or a function, then Global.
I've written another post that discusses scope and the scope chain in much greater detail and should help in answering your coding scenario.
I'm learning JS by reading a book (Learning JavaScript by Ethan Brown) where author writes:
Lexical scoping means whatever variables are in scope where you define
a function from (as opposed to when you call it) are in scope in the
function. Consider this example:
const x = 3;
function f() {
console.log(x); // this will work
console.log(y); // this will cause a crash
}
const y = 3;
f();
The variable x exists when we define the function f , but y doesn’t.
Then we declare y and call f , and see that x is in scope inside the
body of f when it’s called, but y isn’t. This is an example of lexical
scoping: the function f has access to the identifiers that
were available when it was defined, not when it was called
When I run it in VS Code debugger, there doesn't seem to be any errors.
I see
3
3
without any exceptions. Can this depend on ES version that I'm using or something else?
Though I think the author simply chose a poor (well, incorrect) piece of code to illustrate the point, the code is interesting as a way to illustrate something related but different. Because y is declared with const, it is visible inside the function because its declaration is hoisted to the nearest enclosing block (which is not explicitly visible in the posted code, but it must be there somewhere). However, if the function call is moved to before that declaration, you will see an error because the reference to y will happen in the somewhat weirdly-named "temporal dead zone". References to declared but uninitialized variables created with let or const are runtime errors.
If the declaration of y is changed to a var declaration, then moving the function call to before variable declaration does not cause an error because the variable is defined and in scope but is simply (old-school) uninitialized, and therefore simply undefined.
This works because const y=3 is declared before f() is called. If you move the declaration of y after f() then it will work as "expected"
As I understand it, Javascript doesn’t compile, it only runs. So there should be no compile-time errors, only runtime errors. So why doesn’t this code work?
function show() { console.log(x); }
(function () {
var x = 42;
show();
})()
My question isn’t on how to make this code better; I realize it is bad code and I already know how to fix it (see below).
My question is, why am I getting an Uncaught ReferenceError? If Javascript only throws errors at runtime, it should know that x == 42 at the time it calls show(), which is inside the anonymous function, correct?
working code:
(function () {
var x = 42;
function show() { console.log(x); }
show();
})()
working code, best option:
function show(y) { console.log(y); }
(function () {
var x = 42;
show(x);
})()
Note:Below description is as of ES5, NOT ES6 since in ES6 scoping rules have been changed(due to introduction of let).
Javascript does compile. It's just that like other languages such as c++/c# there is NO intermediate thing like exe/IL code that need to be clicked to start execution. In JS execution starts after compile phase.
So, when the compilation happens the compiler looks for function declaration and var declaration for variables. Therefore for this IIFE,
(function () {
var x = 42;
show();
})();
It does find one var declaration and the variable x is registered in the scope of the IIFE. This is called variable hoisting and x is available at the function level, in this case IIFE.
Later at execution time, the IIFE looks like this(conceptually):
(function () {
//registration of x in this function's scope has already happened at
//compile time. Notice absence of `var`
x = 42;
show();
})();
Now, at this time the engine talks to scope and asks for lvalue reference of x. Since x was registered in IIFE, engine gets one and then 42 is assigned to it.
Now for this part:
function show() { console.log(x); }
When show is called, engine first asks scope of show function for x, since it doesn't have any variable registered with the name x, global scope is asked( rvalue reference) for x, since it was never registered with global scope either during compilation phase, it cannot be found in any of the scope and we get reference error.
it should know that x == 42 at the time it calls show(), which is inside the anonymous function, correct?
Because of scoping rules, variables in outer scopes are visible in inner scope but not vice-versa. x inside IIFE is visible at the IIFE level and not outside in outer scope.
Variable hoisting in JS is fun.
It's saying giving you the Reference Error because you've defined x inside of a closure (a function defined inside another function), meaning it's not available in the global scope and the show() method doesn't know it exists. If you defined it first, globally, it would of course work.
That said, scoping has been significantly improved in ES6+ with the use of let and const, so unless you're stuck with vanilla JS you'll probably find those to give a much more consistent and predictable coding experience.
This is a useful read on the subject: How do JavaScript closures work?
show function gets scope where it's declared, not invoked.
I was playing with some code and ran into a situation where I couldn't identify why 'let' is behaving the way it does.
For the below block of code:
var x = 20; // global scope
function f() {
let x = x || 30;
}
f(); // VM3426:1 Uncaught ReferenceError: x is not defined(…)
I get the error 'x is not defined' on executing f(). I do understand 'let' variables are not hoisted but since 'x' has a global copy, why isn't the line inside function 'f' defaulting to global copy instead of throwing an error?
Does 'let' set the variable to undeclared (instead of 'undefined' with var because of hoisting) at the beginning of the function?
Is there any way to get the global copy of 'x' within the function?
The exception is about the right side x - when you are initializing block-scope x variable the global one is already "forgotten" however the new one is still not being declared and cannot be used during initialization
Compare with explicit calling global one
function f() {
let x = window.x || 30;
}
Also take a look at this MDN article about let dead zones
let allows you to declare variables that are limited in scope to the block, statement, or expression on which it is used. This is unlike the var keyword, which defines a variable globally, or locally to an entire function regardless of block scope.
Here in your case, an exception is thrown because you are defining let with the same name.
For More Info
you can use this keyword to access global scope
var x= 20; // global scope
function f() {
let x =this.x || 30;
}
f();
but In strict mode this will default undefined
Read it https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/this
The declaration of the local x is shadowing the global one and new one is still not declared first and cannot be used during initialization. It is same situation like following :
var foo = 5;
function do_something() {
console.log(foo); // ReferenceError
let foo = 2;
}
do_something();
For reference MDN
As suggested by #m.antkowicz you can use window.x in your case.
Is this a variable definition or declaration? And why?
var x;
..and is the memory reserved for x after this statement?
EDIT:
In C extern int x; is a declaration, int x = 5; is a definition. What's the analog in JS? Wikipedia says a declaration allocates memory and the definition assigns a value to this allocated memory.
SECOND EDIT:
I think the explanation of #Deryck sounds great, but there's some output that disagrees with his explanation:
> var x;
undefined
> x
undefined // now it looks like x is defined to the value undefined
> y
ReferenceError: y is not defined
If the ReferenceError output would say y is not declared it would make sense. But often I read that JS has two non-values: null and undefined. So var x would be a definition with the value undefined.
var x is a declaration because you are not defining what value it holds but you are declaring its existence and the need for memory allocation.
var x = 1 is both declaration and definition but are separated with x being declared in the beginning while its definition comes at the line specified (variable assignments happen inline).
I see that you already understand the concept of hoisting but for those that don't, Javascript takes every variable and function declaration and brings it to the top (of its corresponding scope) then trickles down assigning them in order.
You seem to know most of this already though. Here's a great resource if you want some advanced, in-depth exploration. Yet I have a feeling you've been there before.
Javascript Garden
PS - your analogy between C variable dec/def and JS was spot on. What you read on Wikipedia was correct.
Declaring a variable is like telling the (javascript) compiler that this token x is something I want to use later. It does point to a location in memory, but it does not yet contain a value. ie. it is undefined
var x;
defining it means to give it a value which you can either do it like:
x = 10; // defining a variable that was declared previously
or like this:
var y = 20; // declaring and defining a variable altogether.
http://msdn.microsoft.com/en-us/library/67defydd(v=vs.94).aspx
http://www.w3schools.com/js/js_variables.asp
I will give you a long answer for better explanation.
When the javascript engine is not able to find a particular variable in memory, it will throw an error. To be more specific, when the javascript engine (Execution Context) is not able to "reference" a variable in memory, it will throw a ReferenceError. This is not exactly the same as a Declaration Error, at least in javascript.
There is a deference between a not defined error and the value undefined.
So doing
var a = undefined;
and
var a;
will both log the same result i.e. undefined. This is because, when you simply do a var a; the javascript engine allocates memory for the variable and automatically sets it's value to undefined, which is different from saying that a doesn't exist at all - in which case it will throw a ReferenceError.
Hoisting
console.log(a); // undefined
var a = 'something';
will log undefined because, the javascript engine knows there's a variable declared somewhere in the code - which means to say that the javascript engine actually does something before it executes the code - one of the thing it does is hoists variables. To put it simply, the above code is the same as
var a; // hoisted (declared and defined the value `undefined`)
console.log(a); // undefined
a = 'something' // update the defined value to `something`
So, yes, declaration and definition happen together in javascript (automatically - if you don't do it yourself) and the default defined value is undefined.
ES6
Just an additional note
const a;
will throw a SyntaxError where a initializer (definition) is necessary. const is the only time when you need to declare and define manually.
> var x;
undefined
> x
undefined // now it looks like x is defined to the value undefined
> y
ReferenceError: y is not defined
Although it is usually said that Javascript is an interpreted language, but there is also a compilation step that happens very fast just before the interpreter runs. The job of this compilation step is to create scope chains, where variables are declared(no read/write operation here, just simple name-keeping) in their respective scopes. These variables will point to some memory location but value in it will be undefined until some execution is carried out by the interpreter.
> Compiler run:
When compiler sees var x;, it will simply book-keep this variable in its respective scope.
The next x; and y; are simply ignored in the compilation step as they are execution statements.
> Interpreter run:
When interpreter sees var x;, it will skip this as there is no read/write operation here.
Now when interpreter sees x;(execution statement), "x" will already be declared in the scope, and it will hold value "undefined", which is what you get on the console.
But when interpreter sees y; similarly, there has been no previous declaration or name-keeping for it in the compilation step, and thus we get the ReferenceError as expected.
Hope someone finds this comment useful.
var x, y, z;
var x;
var h = 4;
i = 4;
all the above are global variables if placed at the top, (outside any functions)
Lets say that the javascript has a function start
function start() {
x = 5*5;
}
the global variable x is now equal to 25
Where as if the var x; was not placed outside of any functions, that variable x would just be local to that function.
You declare JavaScript variables with the var keyword:
var carname;
After the declaration, the variable is empty (it has no value).
To assign a value to the variable, use the equal sign
var carname="Volvo";
In computer programs, variables are often declared without a value. The value can be something that has to be calculated, or something that will be provided later, like user input. Variable declared without a value will have the value undefined.
The variable carname will have the value undefined after the execution of the following statement:
var carname;
var hoisting
In JavaScript, a variable can be declared after being used.
bla = 2
var bla;
// ...
// is implicitly understood as:
var bla;
bla = 2;
For that reason, it is recommended to always declare variable at the top of functions. Otherwise, it may lead to confusing cases
When declaring a variable without assigning a value to it, there still needs to be some memory available for it, otherwise you cannot make a reference to the variable later in the program. I don't think it's a noticeable amount of memory being used and won't make a difference.
var x;
This is a variable declaration. In Js if you don't assign any value to variable in declaration. It will get undefined by default.
var x; // declaring x
console.log(x); // output: undefined
But if you have not even declared the variable in you try to access it. It says that the variable is not defined.
console.log(y); // Output: ReferenceError: y is not defined
If you need access to objects between JS files, it's good practice to expose one object to the global namespace and declare fields and methods on that object.
File 1:
var myObject;
myObject.myField = "Field!";
File 2:
myObject.prototype.myFunction = function () {
return this.myField;
};
I have taken from a really good discussion on : Equivalent of C extern declaration in JavaScript
https://github.com/ganqqwerty/123-Essential-JavaScript-Interview-Questions
Various trivia regarding the difference between undefined and null completely aside, the short answer is: there is no equivalence in Javascript. There are no bare "forward declarations". Javascript variable declarations are definitions. Variables that have been defined but not explicitly initialized will contain the value 'undefined'. There is no "external linkage".
If you refer to an identifier that is not in any accessible scope (perhaps because it doesn't exist the first place), you will get your "ReferenceError: y is not defined". This has nothing to do with variable value or storage.
In simple terms,
undefined means value to the variable is not defined.
not defined means the variable itself is not defined.
var x; //value is not defined. So,
x //undefined
//y variable is not declared or defined. So,
y // y is not defined