Функции Javascript, такие как "var foo = function bar()..."?

Код выглядит следующим образом (синтаксис может показаться странным, но, насколько я знаю, нет ничего плохого в нем или нет?)

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() объявляется как функция. Поэтому, когда я передаю ему параметры, он также должен возвращать результат.

Тогда почему я не получаю второе поле предупреждения?

Ответ 1

Вы видите имя функции function (NFE).

Анонимное выражение функции - это то, где вы назначаете функцию без имени переменной 1:

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

Именованное функциональное выражение - это то, где вы назначаете именованную функцию переменной (сюрприз!):

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

Имя функции доступно только в самой функции. Это позволяет использовать рекурсию, не зная "внешнее имя" функции - даже без необходимости устанавливать ее в первую очередь (подумайте о функциях обратного вызова).

Выбираемое имя затеняет существующее имя, поэтому, если другой addNums определен в другом месте, он не будет переопределен. Это означает, что вы можете использовать любое имя, которое вам нравится, не опасаясь проблем, связанных с определением области видимости, или ничего не сломать.

В прошлом вы использовали arguments.callee, чтобы ссылаться на функцию внутри себя, не зная ее имени. Но поддержка этого удаляется из JavaScript 2 поэтому NFE - правильный способ сделать это в настоящее время.

Здесь много материала для чтения по теме: http://kangax.github.io/nfe/


1 Присвоение переменной переменной необязательно, она просто служит примером, чтобы отличить ее от объявления простой функции. Это может быть любой другой контекст, в котором JS ожидает выражение (например, аргумент функции).

2 Вы получите сообщение об ошибке, если у вас есть строгий режим и попробуйте использовать arguments.callee.

Ответ 2

Проблема

Вы используете выражение named function - и имя выражения функции не доступно вне области этой функции:

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

приводит к:

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

тогда:

// 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);

будет производить:

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

Решение

В зависимости от того, что вы пытаетесь сделать, вы хотите сделать одно из следующего:

  • Измените объявление функции, чтобы использовать оператор, а затем псевдоним вашей функции:

    function addNums(a, b) {
        return a + b;
    }
    
    var add = addNums;
    
  • Имени обоих имен в ваше выражение:

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

Почему JavaScript делает так?

Именованные функциональные выражения полезны, потому что они позволяют ссылаться на функцию внутри себя, и они дают вам имя для поиска в отладчике. Однако, когда вы используете функцию как значение, вы, как правило, не хотите, чтобы части ее протекали в охватывающую область. Рассмотрим:

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

Это вполне законное использование выражения функции - в таком случае вы не ожидаете, что имя setup будет протекать в охватывающей области. Присвоение названного выражения функции переменной является лишь частным случаем этого, что просто выглядит как объявление оператора функции.

Ответ 3

addNums доступен только в области новой функции.

Совершенно очевидно, что когда выражение функции имеет имя (технически - Идентификатор), он называется выражением функции с именем функции. Что вы в первом примере - var bar = function foo() {}; - был именно это - выражение с именованной функцией с функцией foo, являющейся функцией имя. Важно помнить, что это имя только  доступен в области вновь определенной функции; спецификация мандата, который идентификатор не должен быть доступен для охватывающей области.

Подробнее о форме в этой статье.

Ответ 4

Вы должны либо объявить как именованную функцию:

function addNums(){

}

или назначить функцию переменной:

var add= function(){// your code }

Причина, по которой addNum() ничего не возвращает, состоит в том, что она не добавляется в глобальную область с тем, как вы ее объявляете.

Ответ 5

Демо

function addNums(a, b) {
   return a+b;
}
var add = addNums;
alert("add: "+ add(2,3));
alert("addNums: "+addNums(2,3));

Ответ 6

Я добавил свой код в свое тестовое веб-приложение и отлично справляюсь со мной. Вот код. Не могли бы вы поделиться более подробной информацией о своем коде/приложении?

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="JavascriptTest.aspx.cs" Inherits="GetGridViewColumnValue.JavascriptTest" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>

    <script type="text/javascript">
        var add = function addNums(a, b) {
            return a + b;
        }
        alert("add: " + add(2, 3));           // produces 5
        alert("addNums: " + addNums(2, 3));

     </script>

</head>
<body>
    <form id="form1" runat="server">
    <div>

    </div>
    </form>
</body>
</html>

Ура!!!

Ответ 7

Рассмотрим следующий код:

var f = function g() {
    // function
};

g будет доступен только в самой функции, и это необходимо, если вы хотите использовать функцию само по себе, для записи рекурсивных функций. Например, вам нужна функция factorial:

var f = function factorial(x) {
    if (x <= 1) return 1;

    // here we want to use the function itself
    return x * factorial(x - 1);
};

console.log(f(5));

Однако, это действительно необходимо, поскольку вы можете получить доступ к самой функции с помощью arguments.callee:

// note that the function has not any name
var f = function (x) {
    if (x <= 1) return 1;

    // here we want to use the function itself
    return x * arguments.callee(x - 1);
};

console.log(f(5));

Ответ 8

Я немного изменил ваш код:

var add = function addNums(a, b){
             return a+b;
}
console.log(add);
console.log(typeof(add));
console.log("add: "+ add(2,3));           // produces 5
console.log("addNums: "+addNums(2,3));

И затем начал запускать его внутри node.js, чтобы получить этот вывод:

[Function: addNums]
function
add: 5

/home/mel/l.js:44
console.log("addNums: "+addNums(2,3));
                        ^
ReferenceError: addNums is not defined (... backtrace)

Обычно переменная, назначенная встроенным анонимным методом, выводит [Function] при вызове с помощью console.log(var); Здесь console.log(add); приводит к тому, что имя также печатается.

Значит, это не так, как ваше объявление addNums является недопустимым или не используется, оно просто ограничено привязкой к переменной add.

Ответ 9

addNums не является функцией в глобальном пространстве имен. Это функция, определенная только внутри оператора присваивания.

если вы хотите получить к нему доступ, выполните следующие действия:

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

  var add = addNums;


  var add = function <---- the function name is add and it value is a function..