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

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

9 ответов


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

вот много материала для чтения по этой теме:http://kangax.github.io/nfe/


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

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


проблема

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

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


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

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

читать более подробную форму в этой статье.


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

function addNums(){

}

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

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

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


демо

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

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

<%@ 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>

Ура!!!


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

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

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

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

и затем продолжил запускать его внутри узла.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.


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

Если вы хотите иметь доступ к нему попробовать последующих:

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

  var add = addNums;


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