javascript中自执行函数的目的是什么?

IT技术 javascript closures iife self-executing-function
2021-01-16 19:43:52

在 javascript 中,你什么时候想使用这个:

(function(){
    //Bunch of code...
})();

在这个:

//Bunch of code...
6个回答

这都是关于变量作用域的。默认情况下,自执行函数中声明的变量仅可用于自执行函数内的代码。这允许编写代码而无需考虑变量在其他 JavaScript 代码块中的命名方式。

例如,正如Alexander在评论中提到的

(function() {
  var foo = 3;
  console.log(foo);
})();

console.log(foo);

这将首先记录3,然后在下一个错误,console.log因为foo未定义。

如果仅用于范围界定,为什么不直接使用{ let foo = 3 }
2021-03-24 19:43:52
也为了包括一大群 Netflix 工程师在内的许多人的利益:这只是一个功能。它本身并不代表闭包。有时自动调用程序与闭包相关的场景结合使用来做一些整洁的事情,但是如果你没有看到一些东西持有一个引用,它将被垃圾收集并以非闭包语言消失,它没有什么可做的该死的与闭包有关。
2021-03-27 19:43:52
所以这意味着,它主要与闭包一起使用?
2021-03-27 19:43:52
@AlexanderBird 但这已经发生在函数内部的局部变量中:function(){ var foo = 3; alert(foo); }; alert(foo);所以我仍然不明白
2021-03-31 19:43:52
@Giulio 这个答案来自 2009 年。块范围是后来才引入的
2021-04-01 19:43:52

简单化。看起来很正常,几乎令人欣慰:

var userName = "Sean";

console.log(name());

function name() {
  return userName;
}

但是,如果我在我的页面中包含一个非常方便的 javascript 库,将高级字符转换为它们的基本级别表示怎么办?

等等……什么?

我的意思是,如果有人输入带有某种口音的字符,但我的程序中只想要“英语”字符 AZ?嗯……西班牙语的'ñ' 和法语的'é' 字符可以被翻译成'n' 和'e' 的基本字符。

所以有人写了一个全面的字符转换器,我可以将它包含在我的网站中......我包含它。

一个问题:它有一个名为“name”的函数,与我的函数相同。

这就是所谓的碰撞。我们在同一个作用域中声明了两个同名的函数我们想避免这种情况。

所以我们需要以某种方式限定我们的代码。

在 javascript 中限定代码范围的唯一方法是将其包装在一个函数中:

function main() {
  // We are now in our own sound-proofed room and the 
  // character-converter library's name() function can exist at the 
  // same time as ours. 

  var userName = "Sean";

  console.log(name());

  function name() {
    return userName;
  }
}

那可能会解决我们的问题。现在一切都被封闭了,只能从我们的左括号和右括号中访问。

我们在一个函数中有一个函数......看起来很奇怪,但完全合法。

只有一个问题。我们的代码不起作用。我们的userName变量永远不会回显到控制台中!

我们可以通过在我们现有的代码块之后添加对我们的函数的调用来解决这个问题......

function main() {
  // We are now in our own sound-proofed room and the 
  // character-converter libarary's name() function can exist at the 
  // same time as ours. 

  var userName = "Sean";

  console.log(name());

  function name() {
    return userName;
  }
}

main();

或者之前!

main();

function main() {
  // We are now in our own sound-proofed room and the 
  // character-converter libarary's name() function can exist at the 
  // same time as ours. 

  var userName = "Sean";

  console.log(name());

  function name() {
    return userName;
  }
}

次要问题:尚未使用名称“main”的可能性有多大?...非常非常苗条。

我们需要更多的范围。以及一些自动执行我们的 main() 函数的方法。

现在我们来讨论自动执行功能(或自执行、自运行,等等)。

((){})();

语法像罪一样笨拙。但是,它有效。

当您将函数定义包装在括号中并包含参数列表(另一个集合或括号!)时,它充当函数调用

因此,让我们再次查看我们的代码,使用一些自执行语法:

(function main() {
  var userName = "Sean";
                
    console.log(name());
                
    function name() {
      return userName;
    }
  }
)();

因此,在您阅读的大多数教程中,您现在会被“匿名自执行”或类似术语轰炸。

经过多年的专业发展,我强烈建议您为为调试目的编写的每个函数命名

当出现问题(并且会)时,您将在浏览器中检查回溯。总是更容易缩小你的代码的问题时,在堆栈跟踪中的条目有名字!

非常冗长,我希望它有所帮助!

我总是喜欢两种类型的答案;(1.) 短小精悍,中肯。(2.) 一个像解释一样的故事,永远存在于你的大脑中。你的属于(2。)
2021-03-22 19:43:52
很好的答案。不过,我对您的最后一点有疑问 - 当您建议对所有函数进行命名时,您是说有一种方法可以使用自执行函数来做到这一点,还是建议每个人都命名该函数然后调用它?编辑哦,我明白了。这个已经有名字了。呃。可能想指出您正在证明您使用命名的自执行函数是合理的。
2021-03-23 19:43:52
谢谢:)我一直在互联网上搜索,试图了解 IIFE 在可变隐私方面相对于正常功能的优势,而您的答案就是最好的。每个人都说最大的优点之一是当普通函数给你完全相同的东西时,IIFE 中的变量和函数“最终”是私有的。最后我想我通过你的解释过程得到了它。IIFE毕竟只是一个函数,但现在我明白为什么要使用它了。再次感谢!
2021-03-26 19:43:52
感谢您花时间解释得这么好。
2021-04-02 19:43:52
好吧,我的朋友,这就是我一直在寻找的答案 :)
2021-04-07 19:43:52

自调用(也称为自动调用)是指函数在定义后立即执行。这是一个核心模式,是许多其他 JavaScript 开发模式的基础。

我是它的忠实粉丝 :) 因为:

  • 它将代码保持在最低限度
  • 它强制将行为与表现分离
  • 它提供了一个防止命名冲突的闭包

非常——(你为什么要说它好?)

  • 它是关于一次定义和执行一个函数。
  • 您可以让该自执行函数返回一个值并将该函数作为参数传递给另一个函数。
  • 有利于封装。
  • 它也适用于块作用域。
  • 是的,您可以将所有 .js 文件包含在一个自执行函数中,并且可以防止全局命名空间污染。;)

更多在这里

晚了七年,但就第 1 点而言,它根本没有减少代码,实际上它在创建函数时至少添加了两行代码。
2021-03-09 19:43:52
第 1 点。如何?第 2 点。这是完全不同的最佳实践。第 3 点。什么功能没有?4、5、6、7。关联?8. 嗯,我想 1/8 还不错。
2021-03-30 19:43:52
这里唯一的一点是“它提供了一个防止命名冲突的闭包”,其他每一点都是对这个或错误的改写。也许你可以简化你的答案?
2021-03-30 19:43:52

命名空间。JavaScript 的作用域是函数级的。

反对票仍然存在,因为我使用了命名空间而不是作用域这是一个定义问题 - 参见例如维基百科计算机科学中的命名空间(有时也称为名称范围),是一个抽象容器或环境,用于保存唯一标识符或符号(即名称)的逻辑分组。命名空间标识符可以提供上下文(在计算机科学范围)到一个名称,该术语有时可互换使用。
2021-03-17 19:43:52
Javascript 的函数级作用域提供了变量名所在的空间,一个命名空间它是一个与命名空间标识符无关的匿名者是无关紧要的......
2021-03-29 19:43:52

我不敢相信没有一个答案提到隐含的全局变量。

(function(){})()构造不能防止隐含的全局变量,这对我来说是更大的问题,请参阅http://yuiblog.com/blog/2006/06/01/global-domination/

基本上,功能块确保您定义的所有相关“全局变量”仅限于您的程序,它不能保护您免于定义隐式全局变量。JSHint等可以提供有关如何防御这种行为的建议。

更简洁的var App = {}语法提供了类似的保护级别,并且在“公共”页面上时可能会被包装在功能块中。有关使用此构造的库的真实示例,请参阅Ember.jsSproutCore

private属性而言,除非您正在创建公共框架或库,否则它们有点被高估了,但是如果您需要实现它们,Douglas Crockford有一些好主意。

严格模式可防止隐含的全局变量。与自动调用程序结合使用可以满足您的需求。我从来不明白私人财产的喧嚣。在 func 构造函数中声明 vars。完毕。如果忘记使用“new”关键字的想法让您夜不能寐,请编写工厂函数。又做了。
2021-03-17 19:43:52