Reputation: 127
Passing a function expression as an argument
Example:
var greeting = function(first,last) {
return "Hello " + first + last;
};
function greet(frst,lst,word) {
var result = word(frst,lst);
console.log(result);
}
greet("Joe","Bob",greeting);
I understand that var greeting
is being assigned the anonymous function and this function is being passed as an expression.
I understand that in the global execution context, that variable greeting is set aside some memory space, but not the function inside of it.
I know that function greet , is set aside memory space and when we invoke the function greet, it creates memory space for the local variable result. Now the variable result is assigned to word(frst,lst)
does this make it a function? meaning is word(frst,lst)
a function expression?
What I do not understand is...
How is it that when we invoke the function with:
greet("Joe","Bob",greeting);
that the browser is able to take the argument "Joe" and "Bob" and place them into word(frst,lst)
and then use the parameter greeting which is a variable that runs a function to add it's two parameters, when the parameters from the variable and the function greet have different names? I do not understand how the arguments are being passed into that to give us the result of "Hello Joebob"
.
Please correct me if I am wrong in any of my statements and I do appreciate all your help.
Please help!!
thank you!
Upvotes: 3
Views: 130
Reputation: 2052
If you would analyse this step by step (dry run this) , then this is what happens when you call greet("Joe","Bob",greeting);
STEP-1
first| lst | word
================================================
Joe | Bob | function(first,last) {
| | return "Hello " + first + last;
| | };
STEP-2
var result = word(frst,lst);
what happens here, is the function that the varible word is refering to in step-1 gets called with the value of the first and lst variable.
ie. word('Joe', 'Bob');
so dry running this function we get
var greeting = function(first,last) {
return "Hello " + first + last;
};
first | last | return value = ("Hello " + first + last) | result
================================================================
Joe | Bob | Hello JoeBob | Hello JoeBob
So, console.log(result);
= Hello JoeBob
Upvotes: 1
Reputation: 2176
Let's run through the evaluation process together:
// Def 1
var greeting = function(first, last) {
return "Hello " + first + last;
};
// Def 2
function greet(frst, lst, word) {
var result = word(frst, lst);
console.log(result);
}
// Call
greet("Joe", "Bob", greeting);
When the execution reaches (Def 1), the right hand side, which is a function expression, is evaluated in the global context to produce a closure, a data structure that contains a pointer to a compiled function and a pointer to the global context (since that's where this function is being defined). The result of this evaluation is associated with the identifier greeting
in this toplevel.
Next the execution reaches (Def 2), where similarly, a closure is created and the result stored in greet
.
Interesting things begin at (Call). To evaluate greet("Joe", "Bob", greeting)
, the compiler adds a new stack frame/activation record on top of the topmost one that's used at the top level with slots for greet
's three formal parameters (namely frst
, lst
, and word
) and its one local variable (namely result
). Then, "Joe"
, "Bob"
, and greeting
are all evaluated and their values are assigned to those slots. "Joe"
and "Bob"
evaluate to some string representations of those names, and greeting
we know from Def 1 evaluates to a closure. Then in that stack frame the evaluation of greet
, which from Def 2 we know is a closure, begins.
word
, which is now assigned the value of the closure named by greeting
, is going to be applied to the values of frst
and lst
, which, in this stack frame the compiler has assigned the strings "Joe"
and "Bob"
.
greeting
, the compiler creates the third stack frame with two slots for its 2 formal parameters first
and last
, assigns "Joe"
and "Bob"
to those respectively, and begins executing the body of greeting
. The body of greeting
concatenates "Joe" and "Bob" and prepends them with "Hello", returning the string "Hello JoeBob".result
.console.log
(the story is very similar to the other calls, so I won't go into the details).greet
returns undefined
to its call site, which doesn't do anything with that value. The program then finishes executing.Upvotes: 1
Reputation: 1138
Well, let's take it one by one.
1. Functions as first class objects in JS
In JS, functions are treated as first class objects that means you can store, pass it as arguments, receive in function parameters in the same way you do with other objects or variables.
In your case, the anonymous function is assigned to variable greeting
. This function/function reference can be passed to any other function as normal variables.
When you pass any function to another function, it is passed by reference and in order to execute this you have to invoke it with pair of parenthesis greeting(..)
.
2. Passing of arguments in function references
JS functions do not perform type checking or number of arguments passed to a function when they are invoked. The passed parameters maintained the same order when they are received as arguments in the function definitions.
such as -
function dummy(x, y, x){}
if invoked as dummy(1,2,3)
will receive x
as 1
, y
as 2
and so on. If some of the parameters are not passed such as dummy(1, 3)
, the respective argument will be set as undefined
by JS itself. These are done implicitly by JS engine.
JS function arguments
object
JavaScript functions have a built-in object called the arguments object. The argument object contains an array of the arguments used when the function was called (invoked). With every function invocation, this object is set with the passed parameters and can be retrieved within the function. For eg.
x = findMax(1, 123, 500, 115, 44, 88);
function findMax() {
var i;
var max = -Infinity;
for (i = 0; i < arguments.length; i++) {
if (arguments[i] > max) {
max = arguments[i];
}
}
return max;
}
In the above example, since arguments to the findMax
are dyanmic ie. we are not sure with how many numbers it will get invoked, it is better to retrieve the arguments from the arguments
object instead of as direct function parameters.
Good read - http://bonsaiden.github.io/JavaScript-Garden/#function http://bonsaiden.github.io/JavaScript-Garden/#function.arguments
Upvotes: 1