Javascript函数如“var foo = function bar()...”?

时间:2013-05-19 05:23:33

标签: javascript function

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

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 个答案:

答案 0 :(得分:23)

您看到的是named function expression (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 如果strict mode生效并尝试使用arguments.callee,您将收到错误。

答案 1 :(得分:5)

问题

您正在使用named function expression - 并且函数表达式的名称在该函数的范围之外不可用:

// 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泄漏到封闭范围中。将命名函数表达式赋给变量只是一个特殊情况,就像函数语句声明一样看起来

答案 2 :(得分:4)

addNums 仅在新定义的功能范围内可用

  

很明显,当一个函数表达式有一个名字时(技术上 -   标识符),它被称为命名函数表达式。你有什么   在第一个例子中看到 - var bar = function foo(){}; - 是的   确切地说 - 一个命名函数表达式,其中foo是一个函数   名称。要记住的一个重要细节是此名称仅    在新定义的功能范围内可用;规格强制要求   标识符不应对封闭范围可用。

详细了解 this article

答案 3 :(得分:1)

您应该声明为命名函数:

function addNums(){

}

或将函数赋值给变量:

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

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

答案 4 :(得分:1)

Demo

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

答案 5 :(得分: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>

干杯!!!

答案 6 :(得分: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));

答案 7 :(得分: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)

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

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

答案 8 :(得分: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..