【问题标题】:where in javascript is this kind of function assignment to variable useful?在javascript中,这种对变量的函数赋值有用吗?
【发布时间】:2013-06-18 00:56:31
【问题描述】:

我正在看书。 Javascript,Douglas Crokford 的优秀部分。书中提供了一些例子,但我无法理解这些例子在哪里以及如何在实践中有用。为了简单起见,我在这里修改了代码。 这里有两种方法,我可以对变量进行函数赋值。

例子1:

var test= function(ex) {
    alert(ex);
};
test(5);

这会产生值为 5 的警报框

例子2:

var test1 = function test2(ex) {
    alert(ex);
};
test1(7); //this produces alert box with value of 7
test2(8)//this does not give a alert box

我已经定义了函数 test2,但将它分配给了 test1。为什么我不能通过调用 test2(8) 直接访问 test2。 此外,我认为示例 2 与示例 1 相比没有任何大的优势。如果您有一些差异,并且其中一个更出色,我想听听。

谢谢

【问题讨论】:

标签: javascript function object


【解决方案1】:
var test1 = function test2(ex) {
    console.log(test2);
};

命名函数使其能够从其主体中引用自身。

test2 仅对 test2 及其子作用域(函数)可见。

【讨论】:

  • 请注意,当arguments.callee 被逐步淘汰(我相信HTML 5 已经淘汰了arguments.callee)时,这种语法在将来会更加突出和有用。这样做的好处是它不仅向前兼容,而且向后兼容旧浏览器。
  • @finishingmove:你能给我一个简单的例子吗?它可以用来在自身内部引用。这将有助于我更好地理解
  • @bfavaretto:真的吗?我在像 Netscape 4 和 IE 5 一样古老的浏览器中使用过它。关于它在哪里不起作用的任何参考/链接?
【解决方案2】:

您基本上是在为test1 分配一个具有名称的函数,即所谓的“命名函数表达式”。调试代码很有用,因为函数的名称将出现在调用堆栈跟踪中,而不是“匿名函数”中。

JavaScript中的函数也是对象,所以函数的标识符是test1(函数对象),但是函数本身的名字是test2,所以test1.name == 'test2'

【讨论】:

  • 谢谢。函数 test2 存在吗?为什么调用 test2(7) 不会发出警报。 test1 被分配了一个 test2 的功能。但是 test2 不应该不复存在吗?
  • 我在上面解释过...函数test2 函数test1,名称为test2,所以不,test2 作为标识符不不存在。不过,您正在做的事情很麻烦;您想为变量 函数分配相同的名称:test2 = function test2(){}
【解决方案3】:

您所指的语法称为named function expression。它主要用于支持匿名函数中的递归。

在 ECMASCRIPT 5 之前的 javascript 中,当函数是匿名的时,有两种方法可以进行递归。

  1. 使用 arguments.callee:

    (function(x){
        alert(x);
        if (x) {
            arguments.callee(x-1);
        }
    })(10);
    
  2. 使用命名函数表达式:

    (function countdown (x){
        alert(x);
        if (x) {
            countdown(x-1);
        }
    })(10);
    

在 ECMASCRIPT 5 中,当启用严格模式时,arguments.callee 不再受支持。因此,在 ECMASCRIPT 5 严格模式和未来版本的 javascript 中,您应该使用命名函数表达式来编写递归匿名函数。


补充答案:

现在您可能想知道,这不是您要询问的语法。该语法如下所示:

(function foo () { foo })()

你问的是:

var bar = function foo () { foo }

实际上,它们是相同的。命名函数表达式语法适用于函数表达式。这只不过是在表达式上下文中声明的函数。

在 javascript 中,表达式上下文只是计算数学的任何地方。基本上,表达式上下文是大括号() 之间的任何内容,= 符号右侧的任何内容。以及任何需要操作员评估的内容。

除了上述两种形式,以下也是有效的命名函数表达式:

!function foo(){ foo };

0==function foo(){ foo };

0?0:function foo(){ foo };

【讨论】:

    【解决方案4】:

    您希望它的行为方式违反规范。函数声明必须有名字,它们的名字代表当前作用域中的变量。但是函数表达式,当命名时,不应该用它们的名字创建一个变量。相反,它们的名称仅在函数内部可用。

    一些旧浏览器(例如 IE8)曾经将名称作为变量泄漏,请参阅 Named function expressions demystified

    【讨论】:

    • 能否请您提供一个简单的示例以便更好地理解。这对我有很大帮助
    • 你不明白哪一部分? slebetman 给出了一些函数表达式的例子,你看到那个答案了吗?
    【解决方案5】:

    您的示例 2 并不是真正的正确 JavaScript 示例。定义函数有两种方式:

    • var foo = function(x) { console.log(x);返回 x; }

    • 函数 foo(x) { console.log(x);返回 x; }

    请注意,在第一个示例中,您首先有效地创建了一个匿名 函数,然后然后 为该匿名函数对象附加了一个名称('foo')。然而,在第二个示例中,您将立即创建一个命名函数对象“foo”。

    另外,如果您转到控制台并首先按照您的方式定义 test2,然后在定义后输入var test1 = test2 行,那么您将同时使用这两个函数。

    您可以在另一个 S/O 答案中看到更深层次的技术差异的解释,非常赞成:var functionName = function() {} vs function functionName() {}

    【讨论】:

    • 这是正确的javascript。具体来说,它是 ecmascript 5 严格模式下递归匿名函数的唯一有效语法,因为不再支持 arguments.callee
    • 不确定我是否理解...var test1 = function test2(ex) {...} 是一个匿名函数吗?不是 test2 是名称(然后 test1 是 test2 的别名)吗?
    • @alexakarpov 这不是匿名函数,而是命名函数表达式。
    • 我就是这么想的;但是@slebetman 说这种语法(我认为这是不正确的)——即var test1 = function test2(x) {...}——是递归匿名函数的正确语法。因此我的问题是——这个例子中的匿名函数在哪里?我只是想了解我哪里错了……我自己也在学习 JavaScript,也和 OP 读同一本书 =)
    • @alexakarpov:见我的回答和 bfavaretto 的回答。在这种语法中,函数名称应该被视为匿名的,并且只能在其内部可见(对其余代码隐藏)。但是,如果您阅读 bfavaretto 的答案,您会发现一些较旧的浏览器将函数名称作为局部变量泄漏。对于所有现代浏览器,它应该是匿名的。
    猜你喜欢
    • 2016-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-27
    • 1970-01-01
    • 1970-01-01
    • 2016-03-27
    相关资源
    最近更新 更多