What does declaring default parameters in a function do under the hood? - javascript

This is not a debugging question or a how-to question. This is a conceptual question.
I was finding it hard to wrap my head around what this "second scope" thing is, but overlooking the details I came up with this explanation:
If a function is stored (in some way) like this:
{
// function body written using undefined parameters.
// When the function is called the arguments are assigned to the parameters.
}
Declaring default parameters does this:
{ // Second scope
parameter1 = "something"
parameter2 = 5
{
// function body written using the above parameters.
// When the function is called the arguments or default values get assigned to the parameters.
}
}
Is this what really happens under the hood? If not, then what happens in there? The ECMAScript docs are way above my level. Maybe someone could provide the explanation in layman's terms? Thanks!

That's a pretty good explanation! Yes, the parameter list has its own scope. Let me expand on your explanation a bit and then explain why the additional scope there.
When you call a function without default parameter values, a new scope is created for the body of the function, and the parameters are created in that scope like top-level variables in the function. So, conceptually:
<<
let param1 = /*...the argument value provided for param 1 if any */;
let param2 = /*...the argument value provided for param 2 if any */;
// Start of function code
var variable1;
let variable2;
// End of function code
>>
(I'm using <</>> delimiters instead of {/} because the scopes aren't just block scopes, they isolate var as well; so I picked an arbitrary delimiter.)
When there are default parameter values, as you've described, there's an additional scope involved:
<<
let param1 = /*...the argument value provided for param 1 if any */;
let param2 = /*...the argument value provided for param 2 if any */;
<<
// Start of function code
var variable1;
let variable2;
// End of function code
>>
>>
The reason is that default parameter values are expressions, not just literals. For example:
function example(a = 1, b = a + 1) {
// ^^^^^−−−−−−−−−−−−− expression, not just literal
return a + b;
}
console.log(example()); // 1 + (1 + 1) = 3
console.log(example(2)); // 2 + (2 + 1) = 5
One reason that matters is that if there were just one scope for the parameter list and the function body, that would mean an expression in the parameter list could refer to hoisted variables and functions declared in the function body. The hoisted variables would just have the value undefined, so that wouldn't have been useful, but the hoisted functions would be initialized with their function bodies, leading to a situation like this:
// Doesn't work because of the additional scope
function example(a, b = blarg()) {
function blarg() {
return 42;
}
// ...
}
That causes a ReferenceError because the function body's scope isn't available in the parameter list's scope.
IIRC there were arguments for and against and a fair bit of discussion, but in the end the decision was to put the parameter list in its own scope to prevent that and other oddities.

Related

How does Javascript declare function parameters?

function func(x = y, y = 2) {
return [x, y];
}
func(); // ReferenceError: y is not defined
func(1); // [1, 2]
As the code above implied, there is a hidden TDZ in the function parameters scope, which explains why the code below fails:
function func(arg) {
let arg = 1; // SyntaxError: Identifier 'arg' has already been declared
}
So function parameters should be declared with let, but what confused me is :
function func(arg) {
var arg = 1;
console.log(arg); // 1
}
this code works fine.
Why you can redeclare variables using var? How does Javascript declare function parameters?
edit:
I know exactly you can't use let to redeclare a variable. The question here is if function parameters is declared using let, so:
function func(arg) {
var arg = 1;
}
is like:
let arg; // arg parameter declares here
var arg = 1; // func body
and why this can run without an exception?
there is a hidden TDZ in the function parameters scope
Yes indeed. Have a look here for some more examples.
How does Javascript declare function parameters?
As parameters - see here for a step-by-step explanation. They're neither the same as let nor the same as var, they have their own semantics. ES6, which introduced default initialisers, gave them the same TDZ limitations as in let to catch more programmer mistakes.
Why you can redeclare variables using var?
Because until ES5, redeclaring a variable was not an error condition, and this behaviour needed to be preserved to not break the web. It could only be introduced for new features, like let and const - or argument lists that use default initialisers, try function x(bar, bar) {} vs function x(bar, bar=1){}.
This isn't necessarily related to the function's arguments.
This will throw an error as well:
function func() {
var arg = 1;
let arg = 2
console.log(arg); // 1
}
func();
You just can't use let to re-declare a variable, while var isn't that strict: var doesn't try to re-declare the variable if it's already declared. It just assigns the new value.
For more information on the specifics of let, see this MDN page on the let statement.
The reason that is, is because of something that people in the JavaScript community refer to as "hoisting" when you do var arg = 1 that gets translated into var arg; arg = 1; however if var has already been defined as is the case here because of the function parameter, then the compiler tries to be helpful and ignores subsequent re-declarations instead of throwing an error... which is probably an unexpected behaviour, and hasn't been followed through with the new let variable declaration, however, it has to stay there for backwards compatibility reasons.
So var is legacy syntax and ideally you probably want to avoid using it.
Instead using let for variables that can be reassigned, and const for constants.
var also has global scope where as let and const are limited to the scope they are in.
let is added more recently and with it, an error throw was introduced that manifests when you try to declare a variable that involves let twice. This does not happen with var which will simply replace the old value, unless the variable has been already declared with let.
function func(arg) {
let arg = 1; // not ok, because `let` knows that `arg` is being redeclared
}
function func(arg) {
var arg = 1; // ok, because `var` will just replace the value of `arg`
}
function func() {
let arg = 0;
var arg = 1; // not ok, because `let` declared `arg` already
}
Here is a link to the MDN for let which explains the feature.
Parameter bindings does not exactly follow the same behavior as the ones declared with let.
1) Parameter bindings get created before var bindings. var doesn't create bindings that already exist, so there's never a problem there. let however creates bindings after var.
2) There's an early error on all productions that create a scope that has it as a rule that no lexical binding can occur when there's already a variable declaration with the same name.
The first example will not throw an error a value if an argument is passed to func call.
var does not have the same scope as let or const.

Why parameters in JavaScript functions doesn't need var as type?

I know it seems silly question but I'm actually confused with following scenario which as follows...
I understood that for every variable we need to specify datatype as var or though it's not a good practice we can go without var as well. For instance
We can either use
var name = "kishore";
or simply
name = "kishore";
But, when it comes to variables that we are passing as parameters in functions, Why doesn't they accept var? If I'm not wrong, I think those are just like other variable which has to store some value that can be accessible in that function. If I specify var it gives error. I just want to know what's going on there..?
var is not a datatype, but a keyword/operator used to declare a variable in the appropriate scope. Function parameters are already scoped to the function for which they are parameters and there is no changing that. Thus the use of var would be redundant and was not required.
Some commented code samples:
// A globally accessible function
var f1 = function (p1) { // p1 automatically scoped to f1 and available to all inner functions (like f2 below)
// A variable available in the scope of f1 and all inner functions (like f2 below)
var v1;
// f1, p1, v1, and f2 can be reached from here
var f2 = function (p2) { // p2 automatically scoped to f2
// A variable available in the scope of f2
var v2;
// f1, p1, v1, f2, p2, and v2 can be reached from here
};
};
The var keyword is for declaring new variables.
Parameters are different. They already exist when the function is called, the declaration in the function header just gives names to the already existing values.
The arguments collection contains the values that are passed to the function, and you can access the parameters there even if they are not declared as parameters in the function header.
Example:
function test1(a, b, c) {
show(a);
show(b);
show(c);
}
function test2() {
show(arguments[0]);
show(arguments[1]);
show(arguments[2]);
}
test1(1, 2, 3);
test2(1, 2, 3);
// show in Stackoverflow snipper
function show(n) { document.write(n + '<br>'); }
The Parameters are already stored in the function scope in the arguments array , so you don't need to use var :
function fun(t){
console.log(arguments)
};
fun('3');
Output is :
["3"]

Why pass in a function parameter via an immediate function?

I understand that immediate functions' closures are used to create private variables; but I am not sure of the differences, if any, between the two below patterns:
var fn = function() {
var p = param;
...
};
and
var fn = (function(p) {
...
})(param);
In both cases, p's scope is limited to fn. So why do I sometimes see the second pattern?
Thanks in advance.
The two code snippets you posted do not do the same thing.
In the first one, you are creating a variable fn which stores a reference to a function object. In the second code snippet, you are actually calling the anonymous function, and fn will store the return value.
EDIT
It seems you are unsure of the answers so I'll elaborate. Let's use an example to explain the use of each. I'm going to make up a simple function to demonstrate:
var param = 5;
var fn = function(p) {
return p * 2;
};
When this is done, you will be able to use fn to call the function. So, you could later say:
var someVar = fn(param); // someVar will be equal to 10
On the other hand, your second example:
var param = 5;
var fn = (function(p) {
return p * 2;
})(param);
fn will store the numeric value 10
NOTE
In my answer, I changed your first function to include p as an argument.
I'm not sure if I understand your question, nor if you understand what you are doing?
In your first example, you create an anonymous function, and then store it to the variable fn, but in your second example, you create an anonymous function, run it, and store the output the the variable fn. So unless you're returning p in the second example, it should not be visible at all.
You are free to correct me, if I'm wrong ;)

JavaScript example question: lexical scoping/closure - Eloquent Javascript

So I'm new to programming and I'm trying to learn JS with the book Eloquent Javascript.
So far so good, until I reached an example with the following code
function makeAddFunction(amount) {
function add(number) {
return number + amount;
}
return add;
}
var addTwo = makeAddFunction(2);
var addFive = makeAddFunction(5);
show(addTwo(1) + addFive(1));
note: show is like alert, only it shows the variables on the screen of a JS console the tutorial has integrated.
The author says this is an example to show how lexical scoping allows to synthesise functions.
Chapter here
What I don't understand is how addTwo and addFive, which supposedly are variables, can send parameters to the functions makeAddFunction and add, and more specifically, how does the function add knows that the parameter the variables are sending is the parameter number.
Thanks for your help guys!
In javascript, a function is a first-class object, that is, it can be passed around, assigned to a variable, etc. The variables addTwo and addFive contain functions. Those functions are generated by the "factory" function makeAddFunction.
The functions that addTwo and addFive contain carry with them the scope that existed when they were created. That is, when addTwo, for example, was created, the parameter "amount" was 2. So addTwo, in essence, is the following function:
function addTwo(number) {
return number + 2;
}
When someone calls addTwo(), it's not passing anything back to makeAddFunction. MakeAddFunction has already run and is finished. However, the scope created within makeAddFunction (in which "amount" equals 2) lingers in the addTwo function.
addTwo and addFive are variables -- but they're function variables. Look at typeof(addTwo) -- it's a function. It's like if you did this:
var addTwo = function(x) { return x + 2; };
It's the same as this:
function addTwo(x) { return x + 2; }
(Edit: As Šime pointed out, they aren't exactly the same. See here for an explanation of the difference between the two.)
The example will hopefully make sense once you understand that. You can even do weird things like this, declaring an anonymous function and invoking it right away:
var seven = function(x) { return x + 2; }(5);
Which is literally, at the physical machine code level, the exact same as: Which is equivalent to for all purposes relevant to this question:
function addTwo(x) { return x + 2; }
var seven = addTwo(5);
Edit:
Perhaps a less confusing "prequel" to this is the following:
function makeTheAddTwoFunction()
{
return function(x) { return x + 2; }
}
var addTwo = makeTheAddTwoFunction();
This is silly, but serves to illustrate functions that make functions. Of course, that sort of function usually will accept arguments so that it can make different functions each time, but there you go.
I think the key to understanding that example is understanding that functions can return other functions (just like any other variable). Documenting that code will go a long way in helping understand that concept.
/**
* Creates an adder function
* #param {number} amount Amount to add
* #return {function} Method that adds 'amount' to its argument.
* See the documentation of add for its signature
*/
function makeAddFunction(amount) {
/**
* Everytime makeAddFunction is called, a new instance of add is created
* (and returned) that holds on to its copy of 'amount' (through the closure)
* #param {number} number value to add to 'amount'
* #return {number} 'amount' + 'number'
*/
return function add(number) {
return number + amount;
};
}
// addTwo now is a reference to a function that when called
// adds 2 to whatever is passed in
var addTwo = makeAddFunction(2);
// addFive Adds 5 to its argument
var addFive = makeAddFunction(5);
// addTwo(1) = 3, addFive(1) = 6, therefore, output is 9
show(addTwo(1) + addFive(1));
Re: What I don't understand is how addTwo and addFive, which supposedly are variables, can send parameters to the functions makeAddFunction?
addTwo and addFive are variables. But their values are not simple scalars (numbers, strings, etc). Rather, their values are functions. Since their values are functions, it is fine to invoke those functions. Eg, addTwo(1)
Re: and more specifically, how does the function add knows that the parameter the variables are sending is the parameter number?
The function add is calling its first parameter number. So later, when you call the function via a variable, eg, addOne, the first parameter given to addOne becomes number.
ps If you're thinking to yourself, "Self, this is pretty tricky!" Then you're right--and that's the entire purpose of the example, to show something tricky. How often you'll use this technique may vary from never to every so often.
The best way to think of a piece of code like this is to substitute values and interpet in your mind
// when this one is invoked
var addTwo = makeAddFunction(2);
// makeAddFunction
// becomes something like
function makeAddFunction(2) {
function add(number) {
return number + 2;
}
// return a function, that adds
// 2 to every number it gets
return add;
}
// therefore this function call
// will add 2 to 1 and return 3
addTwo(1);
As always, here are the Jibbring notes on JavaScript Closures. It discusses scopes, execution contexts, variable/property resolution, etc...
While JavaScript closures are lexical, execution contexts (which may contain properties) are bound (think Python or Ruby) and not just "free variables" (as is the case with C# or Scala). This is the reason why new variables can only be introduced in new function scopes. (Modern Mozilla implementations introduce let).

What are these lines doing?

I'm starting learning javascript for a project, I've found a script that does a part of what I need to do, I'd like to know how it works, both for me and in case it needs to be modified.
Originally it was used inside the page, now I've put it in a file on its own and does not work anymore, so I'm dividing it in parts, because I fail to get the whole thing.
Here is what bother me most for now:
1) Is this a declaration of a function? What is its name? How can it be invoked?
(function() {
//some code
})();
2) No clue of what is going on here
var VARIABLE = VARIABLE || {};
3) Am I defining the implementation of methodCall here? Something like overriding a method in Java?
VARIABLE.methodCall = function(parameter) {
console.log("parameter was: " + parameter);
};
Thank you in advance for your help.
1) creates an unnamed function and executes it. this is useful for creating a scope for local variables that are invisible outside the function. You don't need to invoke it aside from this, the '()' at the end does that for you.
2) if variable is null/undefined, set it to an empty object.
3) yes, that should work as you expect, you can call VARIABLE.methodCall(parameter)
in response to your comment, here is a common example
function foo (VARIABLE) {
var VARIABLE = VARIABLE || {};
}
(function() {
//some code
})();
simply runs //some code, but variables in it will not remain, since the function() { } block introduces a new inner scope.
function() { } notation is called a closure, it allows variables be functions. For example,
(function() { })() is a common JavaScript idiom. After the ), there is (), which invokes the expression before as function, so (callback || function(x) { return x; })(x) is allowed.
var a = function a() { return 1; }
var VARIABLE = VARIABLE || {}; uses the short-circuit OR, If VARIABLE is not defined, VARIABLE will be set to {}, an empty object. (otherwise, if VARIABLE exists, it will not change)
x = A || B means "If A evaluates to TRUE, x is A, otherwise, x is B.".
VARIABLE.methodCall, as you said, adds methodCall to VARIABLE, without erasing other values in VARIABLE

Categories