Why JavaScript Function Declaration (And Expression)

Why is it called a function expression and not a function declaration?

Interesting question. Wording can have soft boundaries, which is partly what causes this confusion.

First, some rough definitions:

  • Expression: I think this is best thought of with an example. 2 * 2 is an expression, because you can continue doing other operations on it, like 2 * 2 - 3. if (...) on the other hand is not an expression in javascript, it does not resolve into a value in which you can do further operations on. It's invalid to do if (...) {...} / 2. This "definition" has some holes, but should be good enough for the purposes of this answer.
  • Declaration: A declaration is just declaring that you're going to use a certain variable name. So, in your example with const foo = 5, It's the const foo part that actually declares, the = 5 is just initializing the declaration.

With that in mind, lets consider two examples of functions, and see how this terminology plays into these examples:

  1. const g = function() {}

There is a declaration going on here, the const g. We also see that there's a function being created and assigned to g. We're doing something with the result of function() {} (we're assigning it to something), which means javascript will interpret this as a function expression.


  1. function f() {}

We're not using this function as an expression (we're not doing any additional operations with it after we create it), so javascript will actually treat this different from our first example. It's going to declare f in the local namespace, and it's going to apply function hoisting. If you simply added a + before function f() {}, then you would cause javascript to interpret this as an expression instead, and these features will be disabled. You can try it in the dev tools - put in +function f(){} or const g = function f(){}, and f will remain undefined.

The fact that javascript treats the function keyword differently in different contexts is at the heart of this language choice. You can almost think of the "function" keyword as having two different meaning, and the chosen meaning depends on the context. Any time the function is used in an expression context or when it's unnamed, then it takes on the "expression" form, and we call it a "function expression". Otherwise, it takes on the alternative form that contains some extra features, like declaring the function name as a local variable. This is probably why we've adopted to call this alternative form a function declaration. However, like the OP rightly pointed out, even with const f = function() {}, a declaration is still happening, it's just not happening by the function keyword.

Footnote: With examples like +function f() {}, f won't be defined in the same scope as g, but it does get defined inside the body of f. In other words, any named function expression declares its name within its own body.

Why do function declarations get hoisted and function expressions don't?

As per MDN,

Conceptually, for example, a strict definition of hoisting suggests that variable and function declarations are physically moved to the top of your code, but this is not in fact what happens. Instead, the variable and function declarations are put into memory during the compile phase, but stay exactly where you typed them in your code.

As you see, in a function expression, actual function is a value assigned to a named variable. So this named variable is hoisted. Even if you have a named function assigned, it still will not be hoisted as it is not a declaration and will be created later.

Sample:

function test() {  console.log(fn, foo);    var fn = function foo() {}}
test();

Why JavaScript function declaration (and expression)?

As mentioned by others, using the first form in your example (a named function expression) can help with debugging, although with the recent improvements in built-in developer tools in browsers, this argument is becoming less persuasive. The other reason for using a named function expression is that you can use the function name as a variable within the body of the function rather than the now-deprecated in ES5 arguments.callee.

However, named function expressions are incorrectly and problematically implemented in Internet Explorer < 9 and should generally be avoided when you're targeting those browsers. See Juriy Zaytsev's excellent article on the subject for more information.

Function expressions vs function declarations: return value

On the other hand, a function expression does return a value.


This is confusing

Yes indeed. What they actually meant was a function expression evaluates to a (function) value - in contrast to a declaration, which is not an expression but a statement and doesn't evaluate to anything. It has nothing do with the value that the function might return from a call.

function declaration and function expression performance difference

With the powerful optimizations JavaScript engines are using these days, Micro-benchmarks like this produce somewhat misleading results. For example, I'm guessing what you were trying to measure is function call overhead. But it looks like the way your code is written, you may be (re)defining the function definition and/or symbol lookup once for every 10 times you execute it; I'm guessing that wasn't the intent.

In this alternative test, I've arranged things to avoid repeated definition of the function, and added a few other ways of invoking the functions. This reduces the difference in performance to something I'd consider dominated by experimental noise. While this there may sometimes be apparent differences but I wouldn't consider them statistically significant given the experimental error levels. In other words, it reduces the contest to a virtual tie.

Even in browsers where there's a consistent difference between approaches, caching the function in a local variable seems to minimize the difference between definition and expression.

Advantages to use function expression instead of function declaration?

Along with that very good answer, the only advantage I can see is dynamically changing a function call.

For example this code :

function foo(){
console.log('foo');
}

function bar(){
console.log('bar');
}

var myFn = foo;

myFn();

setInterval(function(){
if(myFn === foo) myFn = bar;
else myFn = foo;
}, 5000);

setInterval(function(){
myFn()
}, 6000);

It will never log the same thing since you reassign a global variable, every innerscope function will change while this code :

function foo(){
console.log('foo');
}

setInterval(function(){
function foo(){
console.log('Changed foo');
}

foo()
}, 5000)

setInterval(function(){
foo()
}, 5000)

Will log 2 different things. You can only change the current scope function, not the global.

Know JavaScript Function Expression vs Function Declaration, but what is this? Named Function Expression?

What happens to abc?

It contains a function object. If you are doing nothing with it, it will be garbage-collected.

Why it works?

Why not? What "works"?

abc can be called but not def, why?

This is only true from outside, and not in IE. See below.

Is it a function declaration or an expression?

It is a function expression. You can easily see that as it is part of an assignment expression; declarations always need to be on top level (of functions or global code)

def is undefined - why?

Only from outside. A function expression does not create variables. "def" is the name of the function, and inside the function it is a reference to the function as well. This allows recursion for example without using any outer variables.

var abc = function def() {
def === abc; // true
def.name; // "def"
}
abc();
def; // undefined

If it is supposed to be, are there memory leaks?

Yes, in Internet Explorer. It creates two distinct functions from that code. For the details, see http://kangax.github.com/nfe/#jscript-bugs

Why is abc.prototype is function def?

It is not. It is just an object. Maybe it is shown with that name in your console, as belongs to a function named "def".



Related Topics



Leave a reply



Submit