10

代码是这样的(语法可能看起来很奇怪,但据我所知,它没有任何问题。或者有吗?)

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()被声明为函数。因此,当我将参数传递给它时,它也应该返回结果。

那么,为什么我没有收到第二个警报框?

4

9 回答 9

23

您正在看到一个命名函数表达式 (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.

于 2013-05-19T05:39:54.540 回答
5

问题

您正在使用命名函数表达式- 函数表达式的名称在该函数范围之外不可用:

// 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泄漏到封闭范围内。将命名函数表达式分配给变量只是这种情况的一种特殊情况,它恰好看起来像函数语句声明。

于 2013-05-19T05:37:15.083 回答
4

addNums在新定义的函数范围内可用

很明显,当一个函数表达式有一个名字(技术上——标识符)时,它被称为命名函数表达式。您在第一个示例中看到的内容 — var bar = function foo(){}; — 就是这样 — 一个以 foo 为函数名的命名函数表达式。要记住的一个重要细节是,这个名称只 在新定义的函数范围内可用;规范要求标识符不应该对封闭范围可用。

阅读本文的更多详细信息。

于 2013-05-19T05:34:52.657 回答
1

您应该声明为命名函数:

function addNums(){

}

或将函数分配给变量:

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

addNum() 不返回任何内容的原因是因为它没有以您声明它的方式添加到全局范围。

于 2013-05-19T05:29:47.127 回答
1

演示

function addNums(a, b) {
   return a+b;
}
var add = addNums;
alert("add: "+ add(2,3));
alert("addNums: "+addNums(2,3));
于 2013-05-19T05:34:06.560 回答
1

我稍微修改了您的代码:

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)

通常,分配了内联匿名方法的变量在使用Here[Function]调用时会打印出来,这会导致函数的名称也被打印出来。console.log(var);console.log(add);

因此,这不像您的 addNums 声明无效或未使用,它的作用域只是绑定到变量 add。

于 2013-05-19T05:57:13.593 回答
1

我已在我的测试网络应用程序中添加了您的代码,并且对我来说效果很好。这是代码。您能否分享您的代码/应用程序的更多详细信息?

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

干杯!!!

于 2013-05-19T05:42:02.093 回答
1

考虑以下代码:

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));
于 2013-05-19T05:47:02.607 回答
0

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..            
于 2013-05-19T05:27:05.173 回答