0

我正在看书。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 相比没有任何大的优势。如果您有一些差异,并且其中一个是优越的,我想听听。

谢谢

4

5 回答 5

6
var test1 = function test2(ex) {
    console.log(test2);
};

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

test2test2仅对及其子作用域(函数)可见(如果有)。

于 2013-06-18T01:03:21.740 回答
5

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

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

于 2013-06-18T01:02:17.367 回答
2

您所指的语法称为命名函数表达式。它主要用于支持匿名函数中的递归。

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

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


补充回答:

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

(function foo () { foo })()

你问的是:

var bar = function foo () { foo }

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

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

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

!function foo(){ foo };

0==function foo(){ foo };

0?0:function foo(){ foo };
于 2013-06-18T01:51:26.930 回答
1

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

一些旧浏览器(例如 IE8)曾经将名称作为变量泄漏,请参阅命名函数表达式揭秘

于 2013-06-18T01:22:09.903 回答
-1

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

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

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

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

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

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

于 2013-06-18T01:22:52.997 回答