【问题标题】:Immediately invoked function expression without using grouping operator不使用分组运算符立即调用函数表达式
【发布时间】:2023-03-07 02:01:01
【问题描述】:

我试图在不使用 IIFE 模式的情况下立即调用一个函数(将函数定义括在括号内)。这里我看到了两种情况:

  1. 当立即调用函数声明时:给出SyntaxError

  2. 当立即调用函数表达式时:执行成功

示例 1: 给出SyntaxError

//gives `SyntaxError`
function() {
    console.log('Inside the function');
}();

示例 2:执行没有任何错误

// Executes without any error
var x = function() {console.log('Inside the function')}(); // Inside the function

所以,我有这些疑问:

  • 使用这种方法,为什么函数声明会报错,而函数表达式却不会报错?
  • 有没有一种方法可以在不使用 IIFE 模式的情况下立即调用函数声明

【问题讨论】:

  • 快速提问。 IIFE 立即调用代码并创建一个范围。那么您对不使用 IIFE 模式立即调用函数声明有什么期望?
  • +function(){console.log('done')}()new function(){console.log('done')}() 似乎有效。我想知道,这里的引擎盖下发生了什么。
  • "JavaScript 是否提供了任何方法让我们立即调用函数声明而不用括号括起来?" - 是的 - 它只需要消除它是函数表达式而不是函数声明的歧义,这可以通过例如以任何运算符为前缀(例如!function() { .... })。 “为什么它给函数声明一个错误,而不是函数表达式?”你有没有注意到 IIFE 是什么意思? “立即调用函数表达式。”它不是 IIFD/E。函数调用是一个表达式 - 您不能在表达式中使用语句。
  • @AadityaSharma 什么是“IIFE 模式”? IIFE 表示立即调用的函数表达式。如果你有一个函数表达式并立即调用它,那就是 IIFE。您的第二个示例正是如此 - 您调用的函数表达式。与 +function(){} 相同,尽管它更 hacky - 它只是强制将其作为表达式而不是声明来计算。

标签: javascript function iife


【解决方案1】:

在您的代码中,您没有导致语法错误的函数名称。即使你有名字,它也会抛出错误。

function func(){
  console.log('x')
}();

原因是函数声明不返回函数的值,但是当您将函数声明包装在 () 中时,它会强制它成为返回值的函数表达式。

在第二个示例中,function() {console.log('Inside the function')} 被视为表达式,因为它位于 RightHandSide。所以它执行没有错误。

有没有一种方法可以在不使用 IIFE 模式的情况下立即调用函数声明

您可以使用+,这将使函数声明成为一个表达式。

+function(){
  console.log('done')
}()

如果您不想使用+(),可以使用new 关键字

new function(){
  console.log('done')
}

额外

@cat 在 cmets 中提出了一个非常有趣的问题。我试着回答一下,分三种情况

+function(){} //returns NaN
(+function(){return 5})() //VM140:1 Uncaught TypeError: (+(intermediate value)) is not a function
+function(){return 5}() //5

+function(){} 返回NaN

+ 在这里充当一元加号,它将旁边的值解析为数字。由于Number(function(){}) 返回NaN,所以它也返回NaN

(+function(){return 5;})() 返回错误

通常 IIFE 是使用 () 创建的。 () 用于使函数声明成为表达式 + 是一种简短的方法。现在+function(){} 已经是一个返回NaN 的表达式。所以调用NaN 会返回错误。代码与

相同
Number(function(){})()

+function(){return 5;}() 返回5

在上面的行中,+ 用于使语句成为表达式。在上面的例子中,第一个函数被调用,然后+ 用于将其转换为数字。所以上面的行与

相同
Number(function(){return 5}())

在声明的证明中“+在函数被调用后运行”考虑下面的sn-p

console.log(typeof +function(){return '5'}());

所以在上面的sn-p中你可以看到返回值是字符串'5'但是因为+被转换为数字

【讨论】:

  • ...但请注意,像这样使用new 会产生使用提供的函数作为构造函数构造对象的副作用(然后立即垃圾收集它,因为你不保存返回值)。尝试例如let foo = new function() { console.log("in function") }; console.log(foo); console.log(foo.constructor); 明白我的意思。
  • 你能说一下为什么+function(){}是(正确地)NaN,而(+function(){ return 5 })()(+ (intermediate value)) is not a function,而+function(){ return 5 }()5吗?
  • @cat 您的问题值得用原始答案而不是 cmets 来回答。我已经添加了详细的答案。看看这个。如果有任何困惑问我
  • @MaheerAli 这很有帮助 - 在第二个示例中,function() {console.log('Inside the function')} 被视为表达式,因为它位于 RightHandSide。
  • @AadityaSharma 绝对是。
【解决方案2】:

函数声明,如

function foo() {
}

将变量名称foo 定义(并提升)为当前范围内的函数。函数声明不会评估为值;它只是某事,有点像if 做某事(而不是评估一个值)。

您只能调用作为函数的值,例如

<somevalue>()

其中somevalue 是引用函数的变量名。

请注意,函数声明需要函数名,否则没有变量名可分配给函数 - 您原来的

//gives `SyntaxError`
function() {
    console.log('Inside the function');
}();

不是因为末尾的 () 而抛出,而是因为缺少名称。

可以将括号放在函数声明的末尾,只要括号内有内容 - 但这些括号不会调用函数,它们会计算出一个值:

function x() {
    console.log('Inside the function');
}(console.log('some expression inside parentheses'));

解释器将这些视为两个单独的语句,例如

function x() {
    console.log('Inside the function');
}
// completely separate:
(console.log('some expression inside parentheses'));

括号的内部被评估然后被丢弃,因为它没有被分配给任何东西。

(空括号是被禁止的,因为它们不能被评估为一个值,类似于const foo = ()被禁止)

【讨论】:

  • 可能有助于让最后一个没有() 的例子显示它抛出。
  • 它也给出了一个命名函数的错误function kaka() {console.log('Inside the function');}();
  • @CertainPerformance - 这个例子只是执行了最后一组括号中的内容,忽略了函数声明。 (console.log('some expression inside parentheses'));
  • 您的答案缺乏,除了 iife 之外,没有任何替代方法可以立即调用函数。
  • @AadityaSharma 函数声明不会被忽略 - 变量名称 x 在当前范围内被分配(并提升)给该函数。但是x 永远不会被调用,所以你看不到Inside the function
【解决方案3】:

IIFE 中的 E 代表表达式,如果没有环绕括号,您的函数不会被评估为表达式,因此会出现语法错误。

创建表达式是一种欺骗解释器并能够立即调用函数的方法

(function() {
    console.log('Inside the function');
})();

在您的示例中,您有一个函数语句,后跟grouping operator,但由于两个原因,它在语法上不正确,首先它没有名称,其次是因为分组运算符内部必须有一个表达式,事实上如果你添加一个有效的错误会消失,但你仍然不会得到你想要的结果。

function foo() {
    console.log('Inside the function');
}();

function foo() {
    console.log('Inside the function');
}(1+2);

【讨论】:

    【解决方案4】:

    为了调用某些东西,它必须是一个函数值,一个声明只是声明一个名称,而不是对函数值本身求值,因此你不能调用它。

    由于上述原因,不能调用声明。您必须以某种方式通过分配或分组(IIFE)以某种方式结束表达式。所以这是一个不。

    如果您向我们提供有关您为什么要这样做的更多背景信息,也许我们可以提供建议。

    【讨论】:

      【解决方案5】:

      不知道你为什么要这样做,但是:

      有没有一种方法可以在不使用 IIFE 模式的情况下立即调用函数声明?

      好吧,如果对于函数声明,您的意思是使用关键字function,如:

      function name() { return this.name; }
      

      据我所知,没有。如果我理解正确的话,您需要额外的括号来告诉运行时不要将函数分配给 name 变量。

      现在,您实际上可以做的是使用Function,如:

      new Function('console.log("ey there")')();
      

      这将执行console.log 代码。这里不需要IIFE。但我不明白这怎么能比 IIFE 更好。

      【讨论】:

        【解决方案6】:

        您可以通过以下方式拨打电话 -

        ~function(){console.log("hi")}()
        !function(){console.log("hi")}()
        +function(){console.log("hi")}()
        -function(){console.log("hi")}()
        (function(){console.log("hi")}());
        var i = function(){console.log("hi")}();
        true && function(){ console.log("hi") }();
        0, function(){ console.log("hi") }();
        new function(){ console.log("hi") }
        new function(){ console.log("hi") }()
        

        【讨论】:

          猜你喜欢
          • 2013-01-26
          • 1970-01-01
          • 2018-01-07
          • 2012-12-28
          • 2017-04-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-05-04
          相关资源
          最近更新 更多