Javascript hoisting and variable assignment (with no declaration)

Looking at MDN's introduction to JavaScript, Grammar and Types section - one reads:

Declaring variables

You can declare a variable in three ways:

  • With the keyword var. For example, var x = 42. This syntax can be used to declare both local and global variables.
  • By simply assigning it a value. For example, x = 42. This always declares a global variable. It generates a strict JavaScript warning. You shouldn't use this variant.
  • With the keyword let. For example, let y = 13. This syntax can be used to declare a block scope local variable. See Variable scope below.
  • The following code snippet would seem to fit the "by simply assigning it a value" scenario, meaning the variable should be treated as global.

    (function(){
       console.log(myVar);
       //the following will throw a ReferenceException error
       //myVar = 10;
    
       //the following will not, and I can understand it following the defintion of the behavior of using `var` keyword
       //var myVar = 10;
    })();
    

    But running the code will generate a ReferenceException when myVar is commented, and undefined when not. I would expect it to generate undefined in both cases, since if myVar is a global variable (per definition), than javascript's variable hoisting would make it known before reaching console.log(myVar);

    What is the explanation behind such behavior ? (the behavior I described is what I get when trying it in my firefox's console, but running it in jsfiddle will not throw an error).

    Are self-executing functions an exception to hoisting ?


    the "by simply assigning it a value" scenario

    You are reading the value, not assigning it

    if myVar is a global variable (per definition),

    It isn't.

    myVar is:

  • a variable scoped to the function if the function contains var myVar (or function myVar () { ... } , or it is listed as a parameter in the function definition).
  • a variable scoped to the block if the block contains let myVar
  • a global variable if a value has been assigned to it previously and neither of the above conditions are true.
  • Since you haven't assigned a value, it isn't a global. Since none of the above conditions are true, it isn't any kind of variable, so you get a reference error.


    Regarding your comment:

    I left my var when I meant var in the scenario I am trying to depict. Updated question.

    … and the edit to which you refer:

    Commented out code is not evaluated. Having a comment that uses the keyword var doesn't do anything.


    Regarding your further edits.

    You get a reference error if you try to read a variable before it has been declared.

    var statements (and function declarations) are hoisted so a variable declared with those methods can be read anywhere in the function.

    Assignments are not hoisted. A global variable created implicitly by assignment (which is generally not considered to be best practise and is banned in strict mode) can't be read before the value is assigned.


    Since my comment seemed to help explain it to you, I will turn it into an answer:

    Implicit global variable creation (when you don't actually declare it, but just assign to it) is NOT hoisted. The variable creation happens inline at the moment the assignment occurs.

    Thus, when you try to read the variable, it does not exist yet and that is an error.

    var or let declarations are hoisted to the top of their appropriate scope.


    All of this should hopefully help explain why you should just run in strict mode where implicit global creation is illegal and not allowed and triggers an immediate error. It's basically evil. A simple typo misspelling a variable may not trigger an error when you really want it to.

    链接地址: http://www.djcxy.com/p/96306.html

    上一篇: 函数参数的默认值?

    下一篇: Javascript提升和变量赋值(没有声明)