这是什么Javascript(function(){})()语法

What is this Javascript (function(){})() syntax

本问题已经有最佳答案,请猛点这里访问。

Javascript中的这种语法究竟是什么? 我经常看到它被使用(或滥用?):

1
(function(){})();

我得到它创建一个匿名函数,然后执行它。 但是,无法弄清楚为什么必须这样。 这不等同于更易读的形式:

1
2
 function initSomething() {}
 initSomething();

编辑:
非常感谢所有帮助我理解Javascript成语的精彩回复。


第二个示例中的函数不再是匿名的...它的名称为initSomething

第一种语法通常用于设置闭包... trapping var x, y, z以及不在其中的内容,以便它们不会与闭包之外具有相同名称的任何其他变量冲突。


在JavaScript中,函数创建新范围。在JavaScript的整个内容周围使用函数包装器将确保您不会污染全局范围。

例如,如果您的HTML文件底部有一些JavaScript:

1
2
3
var test = 'hello';
alert(test);          //'hello'
alert(window.test);   //'hello'

如您所见,test变量实际上成为window对象(window.test)的属性,该对象本质上是JavaScript的全局范围。您不希望在window上设置变量的原因有很多,尤其是未来的兼容性问题(如果更高版本的ECMAScript为window定义了test属性,会怎样?)。此外,始终使用全局变量很慢,因为每当使用test时,解释器都需要在范围链中一路跋涉。

以下功能与上述功能相同,不会污染全局范围。它使用function()声明一个匿名函数,然后使用()立即调用它而不使用参数。这通常称为立即调用的函数表达式或IIFE:

1
2
3
4
5
(function() {
    var test = 'hello';
    alert(test);          //'hello'
    alert(window.test);   //undefined
}());

请注意,这只是一个普通的匿名函数,就像任何匿名函数一样。结束大括号后的一组parens调用匿名函数。围绕整个事物的parens告诉解释器它正在查看值或表达式,而不是函数声明。这个值只是匿名函数运行时的结果。这使得匿名函数的工作就像一个简单的闭包,程序员可以有效地忽略它。

此外,您可以为IIFE使用两种不同的语法:

1
2
(function() {}());
(function() {})();

使用任何一个都不太可能有问题,但是当你的代码中出现一些语法问题时会出现一些差异。 IMO你最好坚持第一个,这也更清楚阅读。

-

至于你的第二个问题:以下两个是等价的吗?

1
(function(){})();

1
2
function initSomething() {}
initSomething();

Errm,wellll,有点儿。你可能会对它们的处理方式相同,因为在大多数情况下它们的工作方式相同。也就是说,在你的程序中,你将得到与任何一个相同的结果(在两种情况下你都定义了一个函数,然后调用它)。

但重要的是要注意匿名函数和函数声明之间的区别。您可以将匿名函数视为可执行文件或代码块,当您不想定义真实的命名函数时,可以将其作为粘合剂传递。因为它们是匿名的,所以它们不存在于作用域链中,例如,您不能将属性添加到匿名函数对象并在以后使用它们 - 除非您首先将它分配给变量,在这种情况下它是不再是匿名的!

声明一个函数是完全不同的。它创建了一个构造函数,您可以反复使用它来创建可以继承原始函数属性的新对象(使用new)。这对许多事情很有用,特别是在使用像AngularJS这样的框架时。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function Friend(likes_you) {
    //private property, only accessible to instances of this object
    this.likes_you = likes_you;
}

//add a function as a property of Friend's prototype -
//instances of the Friend constructor can call this function
Friend.prototype.greet = function(greeting) {
    if (this.likes_you) {
        alert(greeting);
    } else {
        alert("I don't like you");
    }
};

var you = new Friend(true);
you.greet('hello!');          //alerts 'hello!'

var guy = new Friend(false);  //can make as any Friend objects as we want
guy.greet('hello!');          //alerts"I don't like you"

当然,你不需要做这样的事情,但知道JavaScript真正在做什么是很好的。这只是JS兔子洞的开始......


这是一个自我调用的匿名函数。

function(){}是一个匿名函数 - 文字。

(function(){})()调用该文字。

由于这是一个调用自身的匿名函数,因此它是一个自调用的匿名函数。

第一种形式优于第二种形式的优点是它为您提供了一种简单的方法来封装您不希望污染全局命名空间的代码。

你也不是不必要地创建一个现在是全局命名空间一部分的函数initSomething,这可能会破坏别的东西。

如果您对更多信息感兴趣,也可以在这里查看。


这是一个立即调用的函数表达式

1
2
3
(function(){
  /* code */
}());

取自维基百科,因为它得到了很好的解释。

An immediately-invoked function expression (or IIFE, pronounced"iffy") is a JavaScript design pattern which produces a lexical scope using JavaScript's function scoping. Immediately-invoked function expressions can be used to avoid variable hoisting from within blocks, protect against polluting the global environment and simultaneously allow public access to methods while retaining privacy for variables defined within the function.

请参阅此处以获取更详细的说明。

I get that it creates an anonymous function and then executes it. But, can't figure out why it has to be that way. Isn't that equivalent to a more readable form:

1
2
function initSomething() {}
initSomething();

它不一样,因为initSomething仍然可以被引用,因此不是匿名的。


基本上它是一个未命名的(匿名)函数,只要加载函数就会立即执行。

这种方法的原因是尽可能多地保留全局范围,并将变量与可能在其他地方定义的任何其他变量隔离开来,您可以在函数内部定义变量和其他函数,并且不会将所有这些变为垃圾邮件。在您的全球范围内。


你可以两种方式,但第一种情况是匿名函数(它没有名称,所以你避免冲突等)。