简体   繁体   中英

Need an explanation on how a function expression is being passed as an argument in a function declaration

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!

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

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.

  • First, 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" .
    • To evaluate the value of 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".
  • Next, that result is stored in the slot called result .
  • Next, a new stack frame is going to be allocated to make the call to the build-in function console.log (the story is very similar to the other calls, so I won't go into the details).
  • Lastly, greet returns undefined to its call site, which doesn't do anything with that value. The program then finishes executing.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM