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

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

本文关键字:function bar foo var like functions quot Javascript      更新时间:2023-09-26

代码如下(语法可能看起来很奇怪,但据我所知,它没有任何问题。还是有?)

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

那么,为什么我没有得到第二个警告框?

您看到的是一个命名函数表达式(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的支持被删除了,所以nfe是现在做这件事的正确方法。

这里有很多关于这个话题的资料: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 仅在新定义的函数作用域中可用。

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

阅读更多细节形式这篇文章

应该声明为命名函数:

function addNums(){
}

或将函数赋值给变量:

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

addNum()不返回任何东西的原因是因为它没有以声明它的方式添加到全局作用域。

Demo

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

我在我的测试web应用程序中添加了您的代码,并为我工作得很好。下面是代码。您能分享一下您的代码/应用程序的更多细节吗?

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

然后继续在node.js中运行它,得到如下输出:

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

通常,内联匿名方法赋值的变量在调用console.log(var);时会输出[Function],这里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..