Declaring vs Initializing a variable?

怎甘沉沦 提交于 2019-11-28 11:12:28

Edit: @ThisClark said something in the comments, and I went to prove him wrong, and upon reading the spec some more I learned something:

Here's an informative except from the specification:

A var statement declares variables that are scoped to the running execution context’s VariableEnvironment. Var variables are created when their containing Lexical Environment is instantiated and are initialized to undefined when created. [...] A variable defined by a VariableDeclaration with an Initializer is assigned the value of its Initializer’s AssignmentExpression when the VariableDeclaration is executed, not when the variable is created.

Based on my reading of this, the following points describe the behavior (and "correct-ish" usage of the terms) you asked about in your question:

  • A variable declaration (e.g., var foo) causes that variable to be created as soon as the "lexical environment" is instantiated. For example, if that variable were defined within a function body, that function is the "lexical environment", and so variable creation coincides with the instantiation of the function itself.

  • Obviously, variable declarations may or may not be created with an initializer (i.e., the right-hand expression that resolves to the variable's initial value). That's a pretty non-specification usage of the term "initial value", though... let's dig into that a bit more:

  • Technically, per the specification notes here, all variables are initialzed with the value undefined:

    variables are created [...] and are initialized to undefined

    Emphasis on "technically" there, as this is largely academic if an initializer was also provided.

  • Based on what we've already covered, it should be understood that the statement var foo; could exist anywhere within a function body, and moving it anywhere else within the same function would have no effect on the runtime semantics of the function itself (regardless of if/where any actual assignments or other references to foo take place). If that's still confusing, re-read the previous points.

  • The last bit of behavior is the most intuitive part, and that's the assignment of the initializer. This assignment takes place when that line of code is actually executed (which, again, isn't the same point in time when the variable technically got created).

So, to quickly recap:

  • All variable declarations (that use var) are always initialized with undefined upon the initialization of their lexical environment.
  • This initialization probably doesn't count as an assignment, in the technical sense (ha, @ThisClark, you were wrong!!). :)
  • Assignments are the easy part, as they behave the way (and at the point in time) that you expect.

Hope that helps (and that I didn't terribly misinterpret the spec!).

@jmar777's answer is definitely the best explanation and breakdown of the spec. However, I find that for us hands-on learners, a bit of illustrative code is helpful! ;)


The Basic Idea

  • 'Declaration' makes a variable available throughout a given scope.
  • 'Assignment' gives a variable a specific value at that location in the code. If you attempt to assign a value to a variable that has never been declared in that scope or a parent scope, then the variable is implicitly declared on the global scope (equal to typing window.varName = value).
  • 'Initialization' is something that happens 'behind the scenes' or 'under the hood', so to speak. At runtime, all declared variables are initialized with a beginning assignment of undefined (even if they immediately get assigned a different value in the first line of code).

Thus, initialization isn't a term that matters to us. We declare and assign, and the Javascript engine initializes.

So to directly answer the example in your question:

  • var example; declares a variable, which gets assigned a value of undefined during initialization.
  • var example = "hi" declares a variable, which also gets assigned a value of undefined initially, but when that line of code is actually reached during execution, it gets re-assigned to the string "hi".


Illustrative Code

function testVariableDeclaration() {

    // This behaves 'as expected'....

    console.log(test2, 'no value assigned yet'); // --> undefined 'no value assigned yet'

    // ....but shouldn't our actual expectation instead be that it'll throw an error since
    // it doesn't exist yet? See the final console.log() below!


    // As we all know....

    test1 = 'global var'; // ....a variable assignment WITHOUT declaration in the current
                          // scope creates a global. (It's IMPLICITLY declared.)

    // But a little counter-intuitively....

    test2 = 'not global'; // Although this variable also appears to be assigned without
                          // declaration like 'test1', the declaration for 'test2' that
                          // appears *later* in the code gets hoisted so that it's already
                          // been declared in-scope prior to this assignment.

    console.log( test1, window.test1 === test1 ); // --> 'global var' TRUE
    console.log( test2, window.test2 === test2 ); // --> 'not global' FALSE

    var test2; // As shown by the above console.log() outputs, this variable is scoped.

    console.log( test3 ); // Throws a ReferenceError since 'test3' is not declared
                          // anywhere, as opposed to the first console.log() for 'test2'.
}


Effects of 'Scope' on Declaring/Assigning

What makes the difference between declaration and assignment even clearer is that declaring a variable always creates a new variable within the current scope (myVarscopeB), even if a variable of the same name already existed in a parent scope (myVarscopeA). Then we can assign a new value to myVarscopeB at any point in the current scope without re-declaring it. (This assignment does not affect the value of myVarscopeA.) Once the end of scopeB is reached, myVarscopeB will no longer be available for assignment.

On the flip side, if we assign a value to a variable within a given scope without declaring it in that scope, it'll be assigned to the next-highest-up declaration in the 'scope chain' (or a global will be implicitly declared if no higher declaration is found).

Thus, a variable need only be declared once per scope, with each declaration overriding any declarations made in parent scopes (i.e. it creates a distinct variable). But it must be declared in-scope if it's meant to be unique to that scope. Assignment can happen as many times as desired, but only affects the most 'closely-declared' variable (for lack of a better term).

Declaration basically means introducing a new entity to the program. Initialization is giving a variable it's first value. So basically your above example is correct.

Declaring is introduction of a new name in the program.

var test;        // Is this a declaration ?

Initialization refers to the "assignment" of a value.

var test = {first:"number_one"}  // Now that object is initialized with value

The only difference is that the var statement will initialize any declared variables without a value to undefined.

In both examples, you are declaring a variable.

If you assign a value to a variable without the var statement, it will go down the scope chain looking for declared variables, eventually falling back to the global window object.

There is a small thing that you are missing here. An analogy to understand the concept is like this. For each variable there has to be some value assigned to it.

The default value for all the variables (if not explicitly mentioned is undefined)

1) let example; // this is declaring and initializing with undefined

2) example="hi"; // this is assigning the value to hi

3) let example = "hi" // this is declaring and initializing with "hi"

so the 3rd statement is effectively the same as 1+2.

Now, a question may arise that when statement 3rd is possible, why do we need statement 1?

The reason is to expand the scope of variable.

e.g. let us say that a variable is required at line number 8. But the value is not available until late and that too in a code block.

1) {
2)  let a;
3)  try{
4)   a=someFunctionWhichMayThroeException();
5)  }
6)    catch(e){
7)         a=100;
8)  }
9)  someFunctionOnA(a);// the variable is required here
10)
11)  }

By declaring the variable above, we have increased the scope of the variable hence it can be used outside the try block.

PS: this is just a trivial example of the usage.

Taken straight from the MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/undefined :

The global undefined property represents the primitive value undefined. It is one of JavaScript's primitive types.

Simply declaring a variable in Javascript, such as var example initializes it to the primitive value of undefined. That means the following two expressions are equivalent:

//equivalent expressions
var ex1;
var ex2 = undefined;

//true!
alert(ex2 === ex1);

What I don't know and can't test at this time is how far back in web browser history the alert will display true. For example, does this alert work in IE6 or some obscure Blackberry phone? I can't say for certain this is universal but it at least works in the latest versions of Firefox, Chrome, and Safari at the time of writing.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!