0

I thought before that function expression can be any function that is store in some variable. For example, this is function expression, because function is stored in func variable.

let func = function() {
   console.log(5);
};

And here's function expression, because callback function is stored in function's paremeter callback.

function func(callback) {
   callback();
};
func(function() {
   console.log(5);
});
//That's what I mean:
//let callback = function() {...}

But... recently I've found out that this callback function can also be considered as function expression. Why? This function isn't stored in some variable.

let arr = [18, 50];
let obj = {
    name: 'Karina',
};
arr.forEach(function func(value) {
    console.log(`${this.name} is ${value} years old`);
}, obj);

So, my question is...What exactly make function function expression?

Heaven
  • 41
  • 4
  • Why would the third not be one while the second one _is_ a function expression? I don't really see the difference between the two. – Ivar Sep 30 '21 at 15:31
  • What is special about that function expression? The name? The name is optional. Just read the [docs](//developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/function). See [Why JavaScript function declaration (and expression)?](/q/9667148/4642212), [Why use named function expressions?](/q/15336347/4642212), [var functionName = function() {} vs function functionName() {}](/q/336859/4642212). – Sebastian Simon Sep 30 '21 at 15:31
  • Why do you think the second and the third one are different? `forEach` is also just a function like `func`? – t.niese Sep 30 '21 at 15:34
  • A function declaration is always on its own and must have a name. An expression can be part of a bigger expression, not just an assignment, and doesn't need a name. See https://astexplorer.net/#/gist/ef3e38fbc933703e9cf24d05e88e34ef/757f8906774cf58d3f92b958723a2ee442434dd3 – Ruan Mendes Sep 30 '21 at 15:34
  • Consider an expression "any unit of code that can be evaluated to a value". So yes, the latest example is still a function expression. The only functions that are not "expressions" are those declared as standalone statements by using the `function` keyword without any kind of assignment. Final note: I hate people that closes questions just because they seem similar in title to another one. Funny thing is that the other question is still a duplicate of another question and none of them answers specifically this question. Sometimes I want to close my account. Cheers. – Ernesto Stifano Sep 30 '21 at 15:47
  • @Ernesto Stifano yeah, that's true:) So, you're telling that the third example contains `function expression` because **every function expects to get value as a parameter.** And considering your phrase about expressions that _"any unit of code that can be evaluated to a value"_, we can say that any callback function is a function expression. Do I get u right? – Heaven Sep 30 '21 at 16:04
  • Mmm, not necessarily, because I can instantiate a function like `function myFunction() {}` inside a block, which is a function declaration (not expression), and use it as a callback elsewhere like `someFunction(myFunction)`. – Ernesto Stifano Sep 30 '21 at 16:27
  • The third example contains a function expression because it is being evaluated in place. In fact, it is the most simple expression, because it has only one term and no operators. `1 + 1` is an expression, just like `2`. You could do `array.forEach(someVariable || function myCallback() {});` and maybe now it seems more like an expression. – Ernesto Stifano Sep 30 '21 at 16:30
  • Following my latest example, it is the same as doing `const arg = someVariable || function myCallback() {};` and then `array.forEach(arg)`. Maybe in the first case `arg` is not an explicit variable (although inside the called function it will be accessible through a local variable), but every expression result must be at least temporarily stored somewhere. – Ernesto Stifano Sep 30 '21 at 16:34
  • @Ernesto Stifano So, if I got u right... Firstly, expression is some piece of code that returns only 1 value as a result. Secondly, function started to be a function expression from the moment it's put in the piece of code where something expects a value. For example, function expects to get a value as a parameter. So, callback function becomes a function expression here. And other example, every variable expects to get a value during the assignment. So, in this case `let func = function(){..}` function becomes a function expression too. Correct? – Heaven Sep 30 '21 at 17:28
  • 1
    Everything you wrote is absolutely correct! – Ernesto Stifano Sep 30 '21 at 17:51

2 Answers2

1

I thought before that function expression can be any function that is store in some variable.

No. The variable to store to does not matter. The let func = …; is not part of the function expression, the function expression is only the part (expression) that comes in the middle.

  let func = function() {
//           ^^^^^^^^^^^^
     console.log(5);
//^^^^^^^^^^^^^^^^^^
  };
//^

This function isn't stored in some variable.

Actually there's no difference between your second and third snippet. You're passing the function constructed from the expression to a function, regardless how that function is declared (with parameters, with rest syntax, without parameters, or as a builtin like forEach).

But yes, you can have function expressions completely without variables, like in

  !function() {…}();
// ^^^^^^^^^^^^^^
  void function() {…};
//     ^^^^^^^^^^^^^^
  (function() {…})();
// ^^^^^^^^^^^^^^

Basically, function expressions are just the literal syntax (as in: object literal, string literal) for function objects.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
-1

I'm also learning about functional programming and found out that using a function as a value is indeed a function expression, as you said, by assigning an anonymous function to a variable. But I think the main difference relies on the function declaration being hoisted right? So context comes to play and all of that fun stuff :)

  • 1
    Please don't write answers that are guesses. – Ruan Mendes Sep 30 '21 at 15:36
  • _“using a function as a value is indeed a function expression”_ isn’t accurate. Given `const foo = () => {};`, `foo` is a function “as a value”. But `(function foo(){})` is a function expression, `foo` is not. Also, being anonymous has absolutely nothing to do with being a function expression. The final point is more correct: function _declarations_ are hoisted to their function or global scope, whereas function expressions are not. – Sebastian Simon Sep 30 '21 at 15:36
  • @SebastianSimon both `const foo = () => {};` and `const foo = function [name]() {};` contain a [array] function expressions. As soon as a [arrow] function is part of of an expression you talk about a [arrow] function expression. – t.niese Sep 30 '21 at 15:39
  • You are indeed correct that only function declarations get hoisted. The following does not work `doIt(); const x = function doIt(){};` – Ruan Mendes Sep 30 '21 at 15:40
  • @t.niese No, `const foo = () => {};` is a lexical declaration. I wasn’t talking about that, anyway. I was comparing `foo` and `(function foo(){})`, which are an identifier and a function expression (within a parenthetical for clarity), respectively. – Sebastian Simon Sep 30 '21 at 15:44
  • @JuanMendes Note that there are _two_ things at play here: even replacing `doIt();` by `x();` won’t work, and flipping the order of the two statements won’t work. One cause is that `function doIt(){}` isn’t hoisted, but the other cause is that the binding identifier of a function expression only is in scope _inside_ the function. – Sebastian Simon Sep 30 '21 at 15:46
  • @SebastianSimon the `() => {}` part of `const foo = () => {};` is an arrow function expression, in the same way as `function foo(){}` in `(function foo(){})` is a function expression. – t.niese Sep 30 '21 at 15:48
  • @t.niese Yes, that is true, but that wasn’t what my comment was about. _“Given `const foo =`…`;`”_ was just for context so I could use `foo` as something concrete. – Sebastian Simon Sep 30 '21 at 15:49
  • Wow! amazing to learn from you guys, thanks for pointing out my mistakes! – Camilo Vega Sep 30 '21 at 15:55
  • @SebastianSimon yes the auto correction seems to have kicked in. But if you say `Given const foo = () => {};, foo is a function “as a value”. But (function foo(){}) is a function expression,` is a bit misleading, both are expressions which contain a [arrow] function expression. For someone struggling to understand what a [arrow] function expression is it reads as if `const foo = () => {}` does not contain one, but `(function foo(){})` does. But I understand what you want to say. – t.niese Sep 30 '21 at 16:09
  • @t.niese I see now… yes, both `foo` and `(function foo(){})` are expressions _and_ functions. But only the second is what is commonly referred to as a “function expression”. I was thinking more in terms of syntax and grammar terminology, but it is indeed useful to be aware of these differences. – Sebastian Simon Sep 30 '21 at 16:13
  • @SebastianSimon That's true, I didn't remember that named function expressions only make its name available within the function itself. Named function expressions were a later addition to make recursive calls easier. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function#named_function_expression – Ruan Mendes Sep 30 '21 at 17:27
  • Sorry to bother, but isn't then the function foo(){} a named function declaration rather than a function expression? I'm a bit confused – Camilo Vega Sep 30 '21 at 20:34
  • @Camilo, it depends on context. If it stands on a statement on its own, it's a declaration which must always be named. If it's part of a larger expression, it's an expression and may or may not be named but its name is not available to the outer scope, just within the function (and provides a `Function.name`) – Ruan Mendes Oct 01 '21 at 12:59