像“var foo = function bar() ...”这样的Javascript函数?

Posted

技术标签:

【中文标题】像“var foo = function bar() ...”这样的Javascript函数?【英文标题】:Javascript functions like "var foo = function bar() ..."? 【发布时间】:2019-02-08 09:28:11 【问题描述】:

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

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

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

【问题讨论】:

在我看来这不是有效的 javascript @Matthew,以什么方式? 可能是因为 addNums() 是在运行时而不是在解析时定义的,并且它在其范围之外不可见 另见JavaScript - Why is this function declaration created in a function expression “undefined”? 【参考方案1】:

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..            

【讨论】:

【参考方案2】:

您应该声明为命名函数:

function addNums()


或将函数分配给变量:

var add= function()// your code 

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

【讨论】:

@c 2 我也不认为这种声明有什么问题。【参考方案3】:

Demo

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

var add = addNums;
alert("add: "+ add(2,3));
alert("addNums: "+addNums(2,3));

【讨论】:

【参考方案4】:

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

很明显,当函数表达式有名字时(从技术上讲—— 标识符),它被称为命名函数表达式。你有什么 在第一个例子中看到 - var bar = function foo(); - 曾是 正是这样 - 一个命名函数表达式, foo 是一个函数 姓名。要记住的一个重要细节是此名称仅 在新定义的函数范围内可用;规范要求 标识符不应该对封闭范围可用。

阅读更多详细信息表单this article

【讨论】:

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

【讨论】:

【参考方案6】:

您看到的是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.");

函数的名称仅在函数本身中可用。这使您能够使用递归而不必知道函数的“外部名称”——甚至不必一开始就设置一个(想想回调函数)。

您选择的名称 shadows 是一个现有名称,因此如果在其他地方定义了另一个 addNums,它将不会被覆盖。这意味着您可以使用您喜欢的任何名称,而不必担心范围界定问题或破坏任何内容。

在过去,您会使用arguments.callee 来引用自身内部的函数,但不知道其名称。但是 JavaScript2 正在删除对此的支持,因此 NFE 是当今实现这一目标的正确方法。

这里有很多关于该主题的内容:http://kangax.github.io/nfe/


1 没有必要将它分配给变量,它只是作为一个示例来区分它与普通函数声明。它可以是 JS 期望表达式(例如函数参数)的任何其他上下文。

2 如果您有strict mode 生效并尝试使用arguments.callee,您将收到错误消息。

【讨论】:

+1 用于解释为什么以及在何处使用命名函数表达式。 @Tomalak 你的回答很有帮助。也感谢您的链接:)【参考方案7】:

我已将您的代码添加到我的测试网络应用程序中,并且对我来说运行良好。这是代码。您能否分享您的代码/应用程序的更多详细信息?

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

干杯!!!

【讨论】:

这段代码有效吗?好吧,对我来说不是,对这里的其他人也是如此!【参考方案8】:

考虑以下代码:

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

【讨论】:

【参考方案9】:

我稍微修改了你的代码:

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。

【讨论】:

以上是关于像“var foo = function bar() ...”这样的Javascript函数?的主要内容,如果未能解决你的问题,请参考以下文章

D3 示例:看起来像一个 javascript 变量,但调用起来像一个函数

为啥vs2005调试突然慢得像乌龟?

像字符一样打印,但在 Shiny 和 DataTable 中像数字一样排序

像存储过程一样慢,像查询一样快 - 不是参数嗅探

我啥时候使用像 Paxos 这样的共识算法而不是使用像 Vector Clock 这样的东西?

GameViewController.swift 像控制器,GameScenes.swift 像视图(Swift 游戏)吗?