4

function foo(a,b){
  return a + b;
}

foo(1,2);

Are function parameters hoisted?

Does the variableEnvirnoment at the creation phase of the function execution context looks something like that :

VE = {
        { 0 : undefined , 1: undefined, length: 2 },
        {a : undefined, b: undefined},
        outer: refToGlobalLE
     }
Abdou Bestmood
  • 465
  • 4
  • 14
  • 1
    What do you mean "hoisted" in this context? – jonrsharpe May 09 '20 at 13:50
  • Yes , in the function foo context. – Abdou Bestmood May 09 '20 at 13:52
  • 4
    That doesn't really clarify anything. – jonrsharpe May 09 '20 at 13:54
  • Are the parameters a and b of the function foo hoisted to its execution context? Does the creation of the argument object enough to say that they have been hoisted? – Abdou Bestmood May 09 '20 at 14:04
  • 1
    What would that even *mean*? It doesn't make sense to refer to anything as being hoisted here. The *function itself* would get hoisted, so it would still work if you moved the call above the definition. – jonrsharpe May 09 '20 at 14:05
  • I am not referring to the function itself as it is hoisted to the global context. I am referring to its parameters. They make part of the arguments object and the variable environment too? – Abdou Bestmood May 09 '20 at 14:17
  • 3
    The earliest point at which you can refer to the function parameters is at the beginning of the function body. So talking about hoisting does not make any sense for parameters. – t.niese May 09 '20 at 14:19
  • adding : console.log(funcX.arguments); console.log(a,b) to the top of the function has clarify my confusion. Thanks anyway. – Abdou Bestmood May 09 '20 at 14:21

2 Answers2

3

Yes, parameters are hoisted.

When a function is called, each declaration in the function body (var, let, const, and function declarations) is instantiated in the environment record for that execution context. Each formal parameter is also added to the environment record in the same way ([9.2.10 21.c.i and 9.2.10 28.e.i.2]). The full process is described in section 9.2.10 of the spec.

Formal parameters and function declarations are both initialised (note: not "instantiated") during the abstract operation called FunctionDeclarationInstantiation. All other bindings are initialized during evaluation of the function body.

This means that formal parameter bindings are added into the same logical location, in the same way, as those of function body declarations ie. var, let, const, and function declarations (all of which are hoisted, by the way). And it means that formal parameter bindings are initialized in the same way as function declarations (ie. that their corresponding value is set at the top of the function).

Hoisting is a function of the time and place an identifier binding is instantiated. Formal parameter bindings are instantiated (and initialized) in the same way as function declarations. We know function declarations are hoisted, therefore parameter bindings are hoisted. QED.

Prior to ES2015 this hoisting was, as far as I know, invisible, because function parameters are already at the very top of a function. However, parameter default value initializer syntax was added in ES2015, making the hoisting visible in userland.

If formal parameters were not hoisted then the following code would not throw "Uncaught ReferenceError: Cannot access 'x' before initialization" because the default parameter value for z would refer to the outer x:

var x = 'global'
(function(y, z = x, x) {}()) // "Uncaught ReferenceError: Cannot access 'x' before initialization"

Your comment says that 'assuming that parameters are hoisted, x would [be initialized to] "undefined", and as a result the error would not occur as x is already initialized'. Your implication is that hoisting could also be used to explain the absence of an error. This is true, but it does not therefore follow that if an error is observed, hoisting cannot be occurring. Indeed, we can see hoisting is occurring because, as specified in the error message, x in z = x is taken to refer to formal parameter x which is declared later in the program text. The only way this is possible is for hoisting to have occurred.

Ben Aston
  • 45,997
  • 54
  • 176
  • 303
  • Thanks for your answer, but as far as I know. Hoisting is the process setting variable declarations (only var) to undefined and function declarations to the functions as a string in the variable environment. Then, the Lexical environment would be just a copy of the variable environment at the beginning. So, assuming that parameters are hoisted, x would get "undefined", and as result the error wouldn't occur as x is already initialized. However, I feel like parameters are a special case and they are initialized with the provided args at the phase of creation. Do we still call that hoisting? – Abdou Bestmood May 12 '20 at 15:23
  • I have updated my answer with reference to the spec. – Ben Aston May 13 '20 at 10:29
2

No, The functions parameters are not hoisted in JavaScript.

function foo(a,b){
  return a + b;
}

foo(1,2);

To explain you in brief about the whole process, I would like to explain about how the function itself gets called. So since you are speaking about the variable environment(which in this case would be the global execution context), the JavaScript thread of execution which basically executes the code line by line would store the function definition code as a value to the foo variable in the memory and it does not executes it yet (it just saves the definition as is). It moves to the next execution line which apparently makes a function call(using parenthesis) to that foo function definition.

Now, when that function gets called foo(1,2), first a new execution context gets created inside the global execution for that foo function. You can imagine this as a box abstracted inside. The arguments 1 and 2 gets mapped with the 'a' and 'b' parameters of the function as variables inside the foo execution context and not the global execution context. Then, the function just returns the value of a+b to the global execution context through the call stack.

Okay, so to check this, if you would have just called the function and then after that defined it like below

foo(1,2);

function foo(a,b){
  return a + b;
}

You would probably get an error since the foo function definition is not present in the global execution context and would basically result into a REFERENCE ERROR.

Now, talking about the parameters itself, whether they get hoisted or not. Then No! Those are itself created when the function gets called and a new execution context is created. These variables are block scoped to the function and are not visible to the outer/global execution context. So as and when the function gets returned to the callee, the variable inside of it are just garbage collected.

Hope that answers your question.

Tethys0
  • 896
  • 1
  • 7
  • 14