【问题标题】:Know JavaScript Function Expression vs Function Declaration, but what is this? Named Function Expression? [duplicate]知道 JavaScript 函数表达式与函数声明,但这是什么?命名函数表达式? [复制]
【发布时间】:2012-12-31 17:31:37
【问题描述】:

可能重复:
JavaScript: var functionName = function() {} vs function functionName() {}
What is the difference between a function expression vs declaration in Javascript?

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

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

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

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

谢谢

【问题讨论】:

  • 这是一个命名函数表达式。 def 可以在 inside 函数时使用 def 引用自身。虽然要注意浏览器怪癖(IE)
  • 您可能还没有阅读过这些问题及其答案:stackoverflow.com/questions/1140089/… stackoverflow.com/questions/336859/…
  • kangax.github.com/nfe 应该为您提供所有答案
  • 我不相信这个问题是一个骗局,因为它专门询问变量名称和函数名称不同的情况(即使它是由其中一个答案之一回答的)其他问题)。
  • 它不是重复的。已添加到“可能重复”的问题是针对声明和表达的差异。这不是这里所要求的。请投票重新开放

标签: javascript oop


【解决方案1】:

这是一个Function Expression2

函数表达式可以也有名字;函数表达式的名称仅在函数体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 时被解析为函数声明,尽管大多数引擎仍会[错误地] 将函数声明解析为Statement。 SourceElement 产生出现在程序的顶级“块”或函数的顶级“块”。

在任何情况下,只要有一个function .. 出现在需要一个Expression 的位置,它被解析为一个函数表达式。 all 被解析为函数表达式的示例:

// 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 () {} () 都是无效语法 - 为什么? ;-)

【讨论】:

    【解决方案2】:

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

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

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

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

    注意 FunctionExpression 中的标识符可以从 在 FunctionExpression 的 FunctionBody 中允许函数 递归调用自身。然而,与 FunctionDeclaration 不同的是, FunctionExpression 中的标识符不能被引用并且确实 不影响包含 FunctionExpression 的范围。

    所有最近的浏览器都能正确处理这个问题,所以你不必担心内存泄漏或其他奇怪的东西(不正确的处理只在旧的 IE

    【讨论】:

      【解决方案3】:

      abc 会发生什么?

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

      为什么有效?

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

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

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

      是函数声明还是表达式?

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

      def 未定义 - 为什么?

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

      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”的函数。

      【讨论】:

      • +1 用于涵盖“实际”实施问题(我知道存在一些问题,但没有那么多 :-/)
      【解决方案4】:

      这是一个named function expression。可能的用途是:

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

      但是beware.

      【讨论】:

      • 您的 beware 链接提供了更多信息,并让我清楚地了解了差异。所以接受这个答案
      【解决方案5】:

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

      两者的区别在于浏览器加载它们的方式。

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

      这意味着:

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

      【讨论】:

        猜你喜欢
        • 2010-11-04
        • 1970-01-01
        • 2017-09-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多