Javascript 中的这种语法到底是什么?我经常看到它被使用(或滥用?):
(function(){})();
我知道它创建了一个匿名函数然后执行它。但是,无法弄清楚为什么必须这样。这不等同于更易读的形式:
function initSomething() {}
initSomething();
编辑:感谢所有帮助我理解 Javascript 习语的伟大回应。
Javascript 中的这种语法到底是什么?我经常看到它被使用(或滥用?):
(function(){})();
我知道它创建了一个匿名函数然后执行它。但是,无法弄清楚为什么必须这样。这不等同于更易读的形式:
function initSomething() {}
initSomething();
编辑:感谢所有帮助我理解 Javascript 习语的伟大回应。
第二个示例中的函数不再是匿名的......它有一个名字,initSomething
.
第一种语法通常用于设置闭包...捕获var x, y, z
以及不在其中的内容,以便它们不会与闭包之外的任何其他同名变量发生冲突。
这是一个自我调用的匿名函数。
function(){}
是一个匿名函数字面量。
(function(){})()
调用该文字。
由于这是一个调用自身的匿名函数,因此它是一个自调用匿名函数。
第一种形式相对于第二种形式的优势在于它为您提供了一种简单的方法来封装您不想污染全局名称空间的代码。
您现在也不必不必要地创建一个initSomething
作为全局名称空间一部分的函数,这可能会破坏其他东西。
如果您对更多信息感兴趣,也可以查看此处。
在 JavaScript 中,函数创建了新的作用域。在 JavaScript 的全部内容周围使用函数包装器将确保您永远不会污染全局范围。
例如,如果您有一个底部带有一些 JavaScript 的 HTML 文件:
<script>
var test = 'hello';
alert(test); //'hello'
alert(window.test); //'hello'
</script>
如您所见,test
变量实际上变成了window
对象 ( window.test
) 的属性,它本质上是 JavaScript 的全局范围。您不想在 上设置变量的原因有很多window
,尤其是未来的兼容性问题(如果更高版本的 ECMAScript 为 定义了test
属性window
怎么办?)。此外,一直使用全局变量很慢,因为每当您使用test
.
以下在功能上与上述相同,不会污染全局范围。它使用 声明一个匿名函数function()
,然后立即使用 不带参数地调用它()
。这通常称为立即调用函数表达式或IIFE:
<script>
(function() {
var test = 'hello';
alert(test); //'hello'
alert(window.test); //undefined
}());
</script>
请注意,这只是一个普通的匿名函数,就像任何匿名函数一样。右花括号后的一组括号调用匿名函数。整个事物周围的括号告诉解释器它正在查看一个值或表达式,而不是函数声明。该值只是匿名函数运行时的结果。这使得匿名函数像一个简单的闭包一样工作,程序员可以有效地忽略它。
此外,您可以对 IIFE 使用两种不同的语法:
(function() {}());
(function() {})();
使用任何一个都不太可能出现问题,但是当您的代码中出现一些语法问题时,就会出现一些差异。IMO你最好坚持第一个,这也更清晰易读。
--
至于你的第二个问题:以下两个是等价的吗?
(function(){})();
和
function initSomething() {}
initSomething();
嗯,嗯,有点。您可能会以同样的方式对待它们而侥幸,因为在大多数情况下,它们的工作方式相同。也就是说,在您的程序中,您将获得与其中任何一个相同的结果(在这两种情况下,您都在定义一个函数,然后调用它)。
但重要的是要注意匿名函数和函数声明之间的区别。您可以将匿名函数视为可执行文件,或者当您不想定义真正的命名函数时,您可以将其作为胶水传递的代码块。因为它们是匿名的,所以它们不存在于作用域链中,例如,你不能将属性添加到匿名函数对象并在以后使用它们——除非你先将它分配给一个变量,在这种情况下它是不再匿名!
声明一个函数是完全不同的。它创建了一个构造函数,您可以一次又一次地使用它来创建new
可以继承原始函数属性的新对象(使用)。这对很多事情都很有用,尤其是在使用像 AngularJS 这样的框架时。
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(){
/* code */
}());
取自维基百科,因为它解释得很好。
立即调用的函数表达式(或 IIFE,发音为“iffy”)是一种 JavaScript 设计模式,它使用 JavaScript 的函数作用域生成词法作用域。立即调用的函数表达式可用于避免从块内提升变量,防止污染全局环境,同时允许公共访问方法,同时保留函数内定义的变量的隐私。
有关更详细的说明,请参见此处。
我知道它创建了一个匿名函数然后执行它。但是,无法弄清楚为什么必须这样。这不等同于更易读的形式:
function initSomething() {}
initSomething();
它不一样,因为initSomething
仍然可以引用,因此不是匿名的。
两种方法都可以,但第一种情况是匿名函数(它没有名称,因此可以避免冲突等)。
基本上它是一个未命名(匿名)的函数,一旦加载该函数就会立即执行。
这种方法的原因是尽可能远离全局范围,并将您的变量与可能在其他地方定义的任何其他变量隔离开来,您可以在函数内部定义变量和其他函数,它不会垃圾邮件所有这些在您的全球范围内。