mdn / sprints

Archived: MDN Web Docs issues are tracked in the content repository.
https://github.com/mdn/content
Creative Commons Zero v1.0 Universal
150 stars 142 forks source link

Javascript let variable creation phase #3915

Closed sujalK closed 3 years ago

sujalK commented 3 years ago

Request type

Details

I saw that in the website, MDN has wrote that let variables are not set to undefied during creation phase of Javascript. As far I know, let variables are also set to undefined before it really gets into execution phase where actual value is assigned to the variable.

But according to ECMA standard, there is specified that, let variable value is set to undefined before setting actual value Please see it here:

https://tc39.es/ecma262/#prod-LexicalBinding

hamishwillee commented 3 years ago

Hi @sujalK

  1. Can you identify the page and section where you see the problem?

    Do you mean here where it says:

    Unlike variables declared with var, which will start with the value undefined, let variables are not initialized until their definition is evaluated.

  2. And the problem is that you think that the note means that the variable is set to undefined ?

    let and const declarations define variables that are scoped to the running execution context's LexicalEnvironment. The variables are created when their containing Environment Record 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.

I don't think the spec says or implies what you think it does. What the spec says (point 2) is that once the LexicalBinding is evaluated, if no initialiser has been set, then the value will be set to undefined. However it doesn't say when the LexicalBinding is evaluated.

I tested this and the javascript is definitely behaving as indicted on MDN - you get the reference error because it is not defined until the definition is evaluated.

sujalK commented 3 years ago

Please see the last sentence:

If a LexicalBinding in a let declaration does not have an Initializer the variable is assigned the value undefined when the LexicalBinding is evaluated.

hamishwillee commented 3 years ago

@sujalK Thanks. I don't think it quite says "let variable value is set to undefined before setting actual value". What it says, precisely is that the variable gets the value of undefined:

My understanding is that declaring a var or let (without assignment) results in the value being set to undefined. The difference is that a var is hoisted and a let is not. That means that var always has a value (even if you declare it after you try and access it), while let will only have that value if you declare it before trying to access it.

So if MDN says let variables are not set to undefined on declaration that would be wrong. Can you point me to where it says that?


FYI I did some experimentation to confirm my understanding:

  1. Declaration using let or var (without assignment) results in undefined
    {
     let foo;
     var bar;
     console.log(foo); // Undefined
     console.log(bar); // Undefined
    }
  2. Declaration using let (without assignment) results in reference error if occurs after access
    {
     console.log(foo); // ReferenceError
     let foo;
    }
  3. But assignment using var after access is still undefined
    {
     console.log(bar); // undefined
     var bar=1;
    }
hamishwillee commented 3 years ago

So the MDN section let > Temporal dead zone is an example which is technically correct but unhelpful

Unlike variables declared with var, which will start with the value undefined, let variables are not initialized until their definition is evaluated. Accessing the variable before the initialization results in a ReferenceError.

Because it implies that let variables do not start with the value undefined when in fact they do (if no value is assigned). Perhaps this would be better:

Unlike variables declared with var, accessing a let variable before it has been declared will result in a ReferenceError (let variables are not hoisted (initialized before other code is run, regardless of declaration order).

@chrisdavidmills What do you think (at least on this specific case). I think the whole term "Temporal dead zone" is horrible. Perhaps "Using Uninitialized Variables"? "Using Undeclared Variables" would be better?

Again, the only difference between let and var is that all var variables get initialised before anything else runs.

sujalK commented 3 years ago

In my opinion, the let variables is set to undefined in creation phase but Javascript engine is not allowing to access before code execution reaches to the line: For example:- where let someVar=1; is reached during execution phase.

hamishwillee commented 3 years ago

"but Javascript engine is not allowing to access before code execution reaches to the line: For example:- where let someVar=1; is reached during execution phase."

Yes, a let variable is set to undefined in the creation phase, which occurs when the variable is declared - i.e. let somevar. Once the variable has been initialised though you can access it because it exists. Prior to that you get a reference error because it does not exist.

So this text is not quite correct - the engine allows you to try access the variable at any time. It's just that before the variable is declared it does not exist - hence the reference error because it does not exist. This isn't a matter of opinion - you can test it.

But in any case, you still haven't pointed to specific text with an error in MDN. That makes it hard for me to fix anything. Can you please point to the specific error text?

chrisdavidmills commented 3 years ago

@chrisdavidmills What do you think (at least on this specific case). I think the whole term "Temporal dead zone" is horrible. Perhaps "Using Uninitialized Variables"? "Using Undeclared Variables" would be better?

I think it is some kind of official term, but I agree it is still horrible ;-)

So we should probably use some kind of language along the lines of "Using Undeclared Variables (creating what is sometimes known as a "temporal dead zone")" ... ?

sujalK commented 3 years ago

on this text: Unlike variables declared with var, which will start with the value undefined, let variables are not initialized until their definition is evaluated.

On this link:

https://wiki.developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Temporal_dead_zone

hamishwillee commented 3 years ago

@sujalK Thanks. I have updated the text in https://wiki.developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Temporal_dead_zone_TDZ to make this more clear:

let variables cannot be read/written until they have been fully initialized, which happens when they are declared (if no initial value is specified on declaration, the variable is initialized with a value of undefined). Accessing the variable before the initialization results in a ReferenceError.

This is strictly correct according to the spec.

@chrisdavidmills Can you give my changes a quick look? I also took the time to explain why this is a Temporal DZ and not just "using undeclared identifiers", and tidied up some of the description.

I also added the note below. Strictly speaking this is always "good advice" - define and assign your values for all variables before you use them. I put this here because for let you get the reference error. IMO it is a pity you don't also get one for var :-)

image

sujalK commented 3 years ago

As we know var variables in creation phase sets it's value to undefined, Is is not that let variables are set to undefined in creation phase of an Execution context ? I mean the ReferenceError is generated due to JS engine not allowing us to access the let variable before it's defined with some value in it ?

Screen Shot 2020-11-27 at 23 40 43
hamishwillee commented 3 years ago

I'm sorry but I don't understand your question, or how it affects the updated documentation. But let me have a try at answering anyway.

As we know var variables in creation phase sets it's value to undefined,

The main point to take away here is that for a var variable creation phase happens before any code is executed due to hoisting. That means the order of declaration of the var does not matter in the sense that when code is executed the var aways has a value.

Is is not that let variables are set to undefined in creation phase of an Execution context ?

"The variables are created when their containing Environment Record is instantiated".

The let value only gets assigned when the variable is declared and/or initialised with a value, at which point it will have a value of undefined OR the initialiser.

I mean the ReferenceError is generated due to JS engine not allowing us to access the let variable before it's defined with some value in it ?

Is the reference error because the JS engine won't allow us access the variable until after declaration, OR is it because the variable has no value you get a reference error. The spec seems to indicate the former, but it doesn't matter - the rule is you can't access a variable that hasn't been initialised.

chrisdavidmills commented 3 years ago

I think we can close this one now. @hamishwillee has clarified the point on the page, and there is no point debating this round in circles.

Blade2187 commented 3 years ago

I also added the note below. Strictly speaking this is always "good advice" - define and assign your values for all variables before you use them. I put this here because for let you get the reference error. IMO it is a pity you don't also get one for var :-)

image

I happened upon this note, which ended up in my finding it was a recent addition mentioned in this issue discussion.

I disagree; where is that codified as a good practice? The opposite is generally considered good practice, to declare variables close to where they are needed.

chrisdavidmills commented 3 years ago

I disagree; where is that codified as a good practice? The opposite is generally considered good practice, to declare variables close to where they are needed.

I don't think you are in disagreement here — but "scope" here could mean the global scope, or it could mean the top of the part of the code that uses the variables. So the note should maybe be rewritten to make it clearer. Do you fancy having a go at rewriting it, @Blade2187 ?

hamishwillee commented 3 years ago

Bah, I knew I'd have problems with that note. @Blade2187, you're right about what I meant, and yes this is an arguable practice.

I have modified as shown, which I think is probably less of a trigger :-)

image

As @chrisdavidmills suggests, open to you proposing something better! I find JavaScript so easy to screw up in subtle ways.