Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript functions like "var foo = function bar() ..."?

The code goes like this (The syntax may seem odd but as far as I know, there is nothing wrong with it. Or is there?)

var add=function addNums(a, b) {                     
   return a+b;
 }                     
 alert("add: "+ add(2,3));           // produces 5
 alert("addNums: "+addNums(2,3));        // should also produce 5

addNums() is declared as a function. So, when I pass the parameters to it, it should also return the result.

Then, why am I not getting the second alert box?

like image 592
Navneet Saini Avatar asked May 19 '13 05:05

Navneet Saini


People also ask

What are the 3 types of functions in JavaScript?

There are 3 ways of writing a function in JavaScript: Function Declaration. Function Expression. Arrow Function.

What is foo bar in JavaScript?

The terms foobar (/ˈfuːbɑːr/), foo, bar, baz, and others are used as metasyntactic variables and placeholder names in computer programming or computer-related documentation.

Is var a function in JavaScript?

The var statement declares a function-scoped or globally-scoped variable, optionally initializing it to a value.

Does JavaScript code order matter?

So, why exactly does JavaScript function order matter? Well, function order matters a huge amount when a variety of functions exist inside multiple scopes of a program. For a JavaScript program to perform correctly, functions in the inner scope must be able to access functions in the outer scope.


2 Answers

The problem

You are using a named function expression - and a function expression's name is not available outside of that function's scope:

// Function statement
function statement() {
    console.log("statement is a type of " + typeof statement);
}
statement();
console.log("statement is a type of " + typeof statement);

results in:

statement is a type of function
statement is a type of function

whereas:

// Function expression with a name
var expression = function namedExpression() {
    console.log("namedExpression is a type of " + typeof namedExpression);
};

expression();
// namedExpression();  // uncommenting this will cause an exception
console.log("expression is a type of " + typeof expression);
console.log("namedExpression is a type of " + typeof namedExpression);

will produce:

namedExpression is a type of function
expression is a type of function
namedExpression is a type of undefined

The solution

Depending on what you are trying to do, you want do do one of the following:

  • Change your function declaration to use a statement and then alias your function:

    function addNums(a, b) {
        return a + b;
    }
    
    var add = addNums;
    
  • Alias both names to your expression:

    var add = addNums = function addNums(a, b) {
        return a + b;
    };
    

Why does JavaScript do things this way?

Named function expressions are useful because they let you reference a function inside itself and they give you a name to look at in a debugger. However, when you use a function as a value you don't generally want parts of it leaking into the enclosing scope. Consider:

(function setup() {
    var config = retrieveInPageConfig();
    if (config.someSetting) {
        performSomeOtherSetup();
    }
    kickOffApplication();
})();

This is a perfectly licit use of a function expression - in such a case you would not expect the name setup to leak into the enclosing scope. Assigning a named function expression to a variable is just a special case of this, that just happens to look like a function statement declaration.

like image 40
Sean Vieira Avatar answered Oct 20 '22 00:10

Sean Vieira


You are seeing a named function expression (NFE).

An anonymous function expression is where you assign a function without a name to a variable1:

var add = function () {
  console.log("I have no own name.");
}

A named function expression is where you assign a named function to a variable (surprise!):

var add = function addNums() {
  console.log("My name is addNums, but only I will know.");
}

The function's name is only available within the function itself. This enables you to use recursion without necessarily knowing the "outside name" of the function - even without having to set one in the first place (think callback functions).

The name you choose shadows an existing name, so if another addNums is defined elsewhere it will not be overridden. This means you can use any name you like without fear for scoping problems or breaking anything.

In the past you would have used arguments.callee to refer to a function inside itself without knowing its name. But support for that is being removed from JavaScript2, so NFEs are the correct way to do this nowadays.

Here is a lot of stuff to read on the topic: http://kangax.github.io/nfe/


1 Assigning it to a variable is not necessary, it just serves as an example to distinguish it from a plain function declaration. It could be any other context where JS expects an expression (a function argument, for example).

2 You will receive an error if you have strict mode in effect and try to use arguments.callee.

like image 101
Tomalak Avatar answered Oct 20 '22 00:10

Tomalak