Search code examples
javascriptvariablesfunction-parameter

Why is the function argument not overwritten on creating variable of same name inside the function?


var a = 'why is this not undefined?';
function checkScope(a) {
    var a;
    console.log(a);
}
checkScope(a);

Javascript is functional scope language, right? When I declare a new variable just inside the function that uses the same name as the functional argument, why does the newly defined variable still hold the same data as the argument?

I thought it should be undefined?


Solution

  • var a; is actually a variable declaration statement. When the function is defined, all the variables declared in it, are processed before the code execution and so you can use the variables even before the actual declaration line is executed at runtime. This is called var hoisting. So, no matter how many times you declare a variable, the variable is actually declared only once.

    In your case, you have defined a as one of the parameters to the function, which is scoped to the current function. And then you are declaring a variable with the same name. Since a is already declared in the function, as one of the parameters, the var a; declaration will be ignored.

    That is why you are getting why is this not undefined? in the console.

    Instead of var a;, lets say you had var a = 1;, in this case, the variable is already declared but the assignment expression will be evaluated at runtime and the value 1 will be assigned to a. So, the console.log will print 1.


    This behaviour is explained in the ECMA Script 5.1 Specification, under the section 10.5 Declaration Binding Instantiation,

    1. If code is function code, then

      a. Let func be the function whose [[Call]] internal method initiated execution of code. Let names be the value of func’s [[FormalParameters]] internal property.

      b. Let argCount be the number of elements in args.

      c. Let n be the number 0.

      d. For each String argName in names, in list order do

            i. Let n be the current value of n plus 1.

            ii. If n is greater than argCount, let v be undefined otherwise let v be the value of the n’th element of args.

            iii. Let argAlreadyDeclared be the result of calling env’s HasBinding concrete method passing argName as the argument.

            iv. If argAlreadyDeclared is false, call env’s CreateMutableBinding concrete method passing argName as the argument.

            v. Call env’s SetMutableBinding concrete method passing argName, v, and strict as the arguments.

    ....

    1. For each VariableDeclaration and VariableDeclarationNoIn d in code, in source text order do

      a. Let dn be the Identifier in d.

      b. Let varAlreadyDeclared be the result of calling env’s HasBinding concrete method passing dn as the argument.

      c. If varAlreadyDeclared is false, then

            i. Call env’s CreateMutableBinding concrete method passing dn and configurableBindings as the arguments.

            ii. Call env’s SetMutableBinding concrete method passing dn, undefined, and strict as the arguments.

    As we see in the specification, the arguments and the variables declared in the function, all are actually defined in the execution environment corresponding to the function in which they are defined. So, if the arguments and the variables have the same name, the variable is actually defined only once and the second declaration is ignored.