27

可能重复:
JavaScript:var functionName = function() {} vs function functionName() {}
Javascript 中的函数表达式与声明有什么区别?

我知道函数声明和表达式之间的区别,但是遇到了这个涉及函数名称的代码,并想了解当我们运行它时会发生什么:

var abc = function def() {
    console.log("Wait! What??");
}

我知道这不是 JavaScript 的一种方式,但只想知道几件事:

  1. 会发生什么abc?为什么它有效?abc可以调用但不能调用def,为什么?
  2. 它是函数声明还是表达式?
  3. defundefined——为什么?如果应该是,是否存在内存泄漏?
  4. 为什么abc.prototype是函数def

谢谢

4

5 回答 5

11

abc会发生什么?

它包含一个函数对象。如果你什么都不做,它将被垃圾收集。

为什么它有效?

为什么不?什么“有效”?

abc 可以调用,但 def 不行,为什么?

这仅适用于外部,而不适用于 IE。见下文。

它是函数声明还是表达式?

它是一个函数表达式。您可以很容易地看到它是赋值表达式的一部分;声明总是需要在顶层(函数或全局代码)

def 未定义 - 为什么?

只能从外面。函数表达式不会创建变量。“def”是函数的名称,在函数内部也是对该函数的引用。例如,这允许在不使用任何外部变量的情况下进行递归。

var abc = function def() {
    def === abc; // true
    def.name; // "def"
}
abc();
def; // undefined

如果应该是,是否存在内存泄漏?

是的,在 Internet Explorer 中。它从该代码创建两个不同的函数。有关详细信息,请参阅http://kangax.github.com/nfe/#jscript-bugs

为什么 abc.prototype 是函数 def?

它不是。它只是一个对象。也许它在您的控制台中以该名称显示,属于名为“def”的函数。

于 2013-01-17T08:27:05.403 回答
5

这是一个命名函数表达式。一个可能的用途可能是:

var abc = function def() {
    def.test = 'Wait!'; //< sort of a static property
    console.log(def.test+" What??");
}

要小心

于 2013-01-17T08:16:22.660 回答
2

这是一个函数表达式2

函数表达式也可以有名称;函数表达式的名称仅在函数体1的范围内。(由于 ECMAScript 第 5 版弃用arguments.callee了 ,这是编写递归“匿名”函数的唯一简单方法。)

因为它一个函数表达式,所以名称可能不会1在外部范围内引入新的绑定。

此外,所有函数都是 JavaScript 中的对象。在f(..),在它被“调用”之前f被评估; 如果没有对函数求值,则会引发错误。这就是为什么回调,只是函数,可以通过变量命名并作为参数传递。(..)f

另外,检查关于原型的假设/断言:

var abc = function def() {}
abc.prototype === abc // -> false
abc.name              // -> "def"

1见 Bergi 的回答。

2如何轻松分辨哪个是哪个?

语法规则允许function ..在它是SourceElement时将其解析为 Function Declaration ,尽管大多数引擎仍会 [不正确地] 将 Function Declaration 解析为Statement。SourceElement 产生发生在程序的顶级“块”或函数的顶级“块”。

在任何情况下,只要function ..出现在需要Expression的地方,它就会被解析为函数表达式。全部解析为函数表达式的示例:

// Can only assign values: Statements do not have values!
var f = function () {}        
var g = function gName () {}  // see Bergi's answer

// Can only pass values: Statements do not have values!
doIt(function () {})          // callback / "anonymous function"

// IIFE: Immediately-Invoked Function Expression
;(function () {})()           // standard IIFE
;(function () {} ())          // alternative standard IIFE
;+function () {} ()           // curious way to write an IIFE
// basically you can use any unary operator to turn it into an expression not only
//  + but also - ! ~ and so on which will modify the return value accordingly

关键是,在上述一种情况下,都function ..出现在需要表达式的语法位置,因此被解析为函数表达式。(上面行开头的分号避免了与 ASI 的“歧义”,这在像我喜欢的那样以无分号风格编写时是必需的。)

然而。;function () {} ()并且;function f () {} ()都是无效的语法 - 为什么?;-)

于 2013-01-17T08:16:11.843 回答
2

它是一个命名函数表达式。

与函数声明相反,函数表达式的标识符不是强制性的。

您的函数def不会立即被调用 - 整个函数被传递给abc并且需要被显式调用abc()

ES5规范的第 13 节说明了如何构建命名函数表达式。阅读关于如何构建命名函数表达式的第三条产生式规则。

注意 FunctionExpression 中的标识符可以从 FunctionExpression 的 FunctionBody 内部引用,以允许函数递归调用自身。但是,与 FunctionDeclaration 不同,FunctionExpression 中的标识符不能被引用,也不影响包含 FunctionExpression 的范围。

所有最近的浏览器都正确处理了这个,所以你不必担心内存泄漏或其他奇怪的东西(不正确的处理只在旧的 IE <=8 中)。

于 2013-01-17T08:21:49.943 回答
1

您的示例是(命名的)函数表达式。

两者之间的区别在于浏览器如何加载它们。

在执行任何代码之前加载函数声明。仅当解释器到达该代码
时才加载函数表达式。

这表示:

abc();
var abc = function() {
    console.log("Wait! What??");
}

不会工作,但是:

def();
function def() {
    console.log("Wait! What??");
}

将要。

现在在您的示例中,您可以访问def,但只能在函数本身内部访问。

var abc = function def() {
    console.log(def);
}
abc();

// Logs:
//function def() {
//    console.log(def);
//}
于 2013-01-17T08:16:06.587 回答