【问题标题】:Javascript Function Definition ExplanationJavascript函数定义说明
【发布时间】:2017-06-08 10:50:57
【问题描述】:

谁能解释一下 JS 文件中的以下函数

function Init()
{
  (function set()
     {
       -----code---
       print "hello";
      }
   )();
}

如果我调用函数 Init ,它会自动运行函数集还是我需要调用 set() 来运行它?

【问题讨论】:

  • 是的,因为它是一个定义代码范围的 IIFE。在您的情况下,它没有任何区别,因为 Init 已经创建了一个范围。

标签: javascript function


【解决方案1】:

您需要调用Init 来运行其中的任何代码。现在,里面的代码只是普通的 JavaScript 代码,但很有趣。让我们看看为什么。


如何

你的内部函数是所谓的IIFE。为了更容易阅读外部函数 (Init),您可以做的是将内部函数替换为 IIFE 调用的结果。

这里有几个例子:

var x = undefined; // x === undefined
x = (undefined); // again
x = 3;      // x === 3
x = (3);   // again the same
x = 'some string'; // some string
x = ('some string'); // the same

所以可以将() 放在一个对象周围,你会得到相同的对象。函数也一样

x = function() {};   // x is that function now.
x = (function() {}); // the same.

但是如果你说x = 3;,你能打电话给x吗?

x = 3;
x(); // syntax error
x = (3);
x(); // again error. can't call a number.

但是,如果你的 x 是一个函数,你可以调用它:

x = function() { console.log('Hi'); }; // you can call x now.
x(); // logs 'Hi'!

所以如果你对括号做同样的事情,它是一样的:

x = (function() { console.log('Hi'); }); // again, the same.
x(); // no error, function called again!

所以你可以跳过作业部分:

// instead of x = (...); and the x(), you replace the x part right away.

(function() { console.log('Hi'); })()
// function body       up to here ^^ now the call part.

请注意,如果没有第一对括号,它将无法工作:

function() { console.log('Hi'); }(); // syntax error.

因此,您放置外部括号 () 只是为了将该函数表达式就地转换为对象。


为什么

这就是它的工作原理。 但是为什么呢?因为你想确保没有其他人调用你的函数!如果你这样做:

var x = function() {};
x();

现在至少有两件事可能会发生而您可能不希望发生:

  1. 可能存在名称冲突。您可能不知道是否已经在要调用外部函数的位置定义了“x”,例如你bind 初始化某个在范围内有 x 的对象。

  2. 有人可以“窃取”你的 x 并再次调用它。不一定要窃取,你只是泄漏它(一个微妙的错误)和其他一些代码调用 x,期望找到它自己的 x,但实际上,它现在是你的 x,因为它是可访问的。而你不希望这样。

因此,您可以轻松地将其锁定在立即执行的匿名函数中。

希望这能让事情变得更清楚。

【讨论】:

  • "因此,您将外部括号 () 只是为了将该函数 def 就地转换为对象。"。实际上,外括号将可能是函数声明的内容更改为函数表达式。可以使用在语句开头允许的任何标点符号,例如+-!,如 !function(){}()。 ;-)
  • @RobG 太棒了! TIL !function() { console.log('a'); }()twitter.com/zladuric/status/823632051572248577
  • 是的,在 (function(){}()) 上节省了一个字符。 ;-)
【解决方案2】:

当你这样做时

(function set() { /*code here*/ })();

,它非常接近

var set = function () { /*code here*/ };
set();

所以当你调用 Init() 的时候,set 函数就会被调用。

【讨论】:

  • 我想说这在技术上并不相等。在第一个示例中,调用后当前范围内没有任何对象。在第二个示例中,您在上面的代码中有一个 set 变量,并在调用下面(下面甚至没有未定义)。
  • @Zlatko In the first example, there are no objects left at the current scope 这是错误的。在第一个示例中,您可以在函数 Init 中的任何位置调用 set() 并且它将起作用,而在第二个示例中,您只能在分配后调用 set()。即使在匿名函数的情况下,在 Init 作用域的环境中为它创建了一个内部名称,甚至在它开始解释函数 Init 的第一行之前。
  • 不,set 在外部函数范围或set 本身之外的任何地方都不可用。看看这个:gist.github.com/zladuric/dae9dc89297921f4f4023dee53e667fd 还是我理解错了?
  • @Zlatko 我错了。我在规范中找到了参考:... unlike in a FunctionDeclaration, the Identifier in a FunctionExpression cannot be referenced from and does not affect the scope enclosing the FunctionExpression.
【解决方案3】:

您需要调用Init(); 来执行该函数。

(function () {console.log('IIFE') }());

您所指的语法是immediately-invoked function expression

【讨论】:

  • 还是有错别字
【解决方案4】:

这是 js 中的一个基本函数闭包(另一个函数内部的内部函数)。

也是..它是匿名函数..意思是......您只能使用该函数一次(这就是函数调用附加到函数减速的原因)。所以……

function regular()
{
    function regular_closure()
    {

    }

    (function () // this is anonymous
    {

    })(); // call the anonymous function.. which is also a closure

    regular_closure(); // call the function
}

有关此主题的更多信息:

MDN - js closures in depth

When to use js closure

【讨论】:

  • 我认为将其称为闭包是一种误导。每个函数在其外部执行上下文中都有一个闭包,而不仅仅是立即调用的函数。每次调用 regular 时都会执行该函数,因此实际上并非只使用一次,它是一个函数表达式,而不是一个声明。
  • 是的,这是一个闭包,但我认为这个问题本身并没有涉及到闭包。闭包没有访问任何内容,因此它不那么相关。
  • 这实际上是我从 MDN 附加链接的原因 :)
  • 链接是关闭。我想说,闭包不是其中的相关部分,我认为@RobG 会同意吗?
猜你喜欢
  • 1970-01-01
  • 2011-02-26
  • 2023-03-08
  • 2014-01-17
  • 1970-01-01
  • 2013-12-23
  • 2017-12-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多