In the first example, you are using var
, which is an old way of declaring variables in Javascript. It can be said that there are Hoisting in var
, since the declaration will be elevated to the most internal function in which it was declared, and not to the block.
Consider the example below:
function outer() {
function inner() {
console.log(myVar); // undefined
if (true) {
var myVar = 500;
}
console.log(myVar); // 500
}
inner();
// console.log(myVar); -> Isso lançaria um erro.
}
outer();
One can say, then, which variables declared with var
have the accessible declaration within the innermost function in which they were declared. Therefore, variables var
have the scope of function and not block. They also have the so-called Hoisting. You can learn more about this in this reply from @bfavaretto.
It is also worth noting that the statement was moved to the beginning of inner
, and not to the beginning of outer
, since the variable was declared within the function inner
, and not outer
. In that case, inner
is the nearest internal function.
On the other hand, variables declared using let
or const
have the scope of block. I do not know if I can, however, say that they do not possess Hoisting, since even the Ecmascript specification is a little vague regarding this. See:
let
and const
declarations define variables that are scoped to the running Execution context’s Lexicalenvironment. The variables are created when their containing Lexical Environment is instantiated but may not be accessed in any way until the variable’s Lexicalbinding is evaluated. A variable defined by a Lexicalbinding with an Initializer is Assigned the value of its Initializer’s Assignmentexpression when the Lexicalbinding is evaluated, not when the variable is created. If a Lexicalbinding in a let
declaration does not have an Initializer the variable is Assigned the value Undefined when the Lexicalbinding is evaluated.
Own emphasis. Source.
The above section does not say at any time that let
or const
do not have Hoisting, but makes it clear that, as in the bold section, "the variables are created when their lexical environments are instantiated, but cannot be accessed in any way until their Lexicalbinding is evaluated". This means that the variables that used this declaration cannot be accessed before their value has been evaluated.
So there is a "temporal Dead zone" (see here or here). It prevents variables declared with let
or const
can be read until your value is assigned. This is because if you try to access a variable let
or const
before your value is assigned, you will receive a ReferenceError
. Behold:
console.log(x); // ReferenceError
let x = 10;
console.log(x);
To learn more, read the links placed during this reply.
Reference:
@bfavaretto, I just found a MDN article saying that Hoisting de Let is raised to the block containing https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Block_scoping
– user181348
That was my question.
– user181348
@bfavaretto is perhaps because at the time ES6 was not yet implemented in the browser(?). Now testing the same code as my question the error is another:
Uncaught ReferenceError: Cannot access 'foo' before initialization
. That is, the Hoisting occurs, but the variable is inaccessible before the declaration.– Sam
The Hoisting with
var
is raised to the function containing it. Already variables declared withlet
orconst
the Hoisting will be the block that was set it. At least that’s what I understood :)– user181348
@bfavaretto On the other hand, if ES6 were not available in the browser, it would error the
let
. Then I don’t remember anymore. It may be that I informed the wrong error in the question, I don’t remember. I think this is most likely, because in 2018 Chrome already had ES6 support.– Sam
Debatable is it possible to call Hoisting the recognition of the variable during the "temporal déad zone", as they say, only to make an exception. In practice there is no Hoisting, there is no way to access the variable without initializing.
– bfavaretto
@ledevwd This MDN content in pt_BR is wrong!
– bfavaretto
@bfavaretto, but Hoisting is not Hoisting when the variable is raised to the scope that contains itself and is visible within that scope or necessarily must be possible to access the variable before it has even been declared to be considered Hoisting?
– user181348
This answers your question? How Hoisting Works at ES6?
– Ricardo Pontual
@Sam had already mentioned the link of this question, I read it and also the links of the questions cited in the comments, but it was not clear to me.
– user181348
@ledevwd "Hoisting" is not such a precise term. I don’t see it being used to describe the behavior of
let
, only that ofvar
(and function parameters and function names, see details here). And the fact is that in these cases it is possible to access the variable before the point where it is declared. In the case oflet
, clearly the JS interpreter needs to know that it exists to cast the exception, but me I wouldn’t call it Hoisting, because it’s not the same thing and it might confuse– bfavaretto
@bfavaretto had already reported in feedback on the link to Mozilla but it did not take effect until today.
– ElvisP
@Eliseub. several translations on MDN are outdated or simply wrong, the same happens with the site of microsoft MSDN, in C# some time the Bfavareto even noticed something wrong in my reply, when I checked it was error that I copied from the documentation in Portuguese, in PHP also several pages in Portuguese are outdated or wrong, for this reason I am avoiding as much as possible any content of doc in Portuguese, both in replies and comments on the site.
– Guilherme Nascimento
@Guilhermenascimento and I do not take your reason, you have more experience and know-how and if you made this decision is because it makes a difference, I noticed some incongruities in the documentation of CSS3 of W3C but also did not get back, I am studying PHP and I have a foot behind, there I consult the official documentation, but I get lost there.
– ElvisP