在 JavaScript 中,函数创建了新的作用域。在 JavaScript 的全部内容周围使用函数包装器将确保您永远不会污染全局范围。
例如,如果您有一个底部带有一些 JavaScript 的 HTML 文件:
<script>
var test = 'hello';
alert(test); //'hello'
alert(window.test); //'hello'
</script>
如您所见,test 变量实际上变成了 window 对象 (window.test) 的属性,这本质上是 JavaScript 的全局范围。您不想在window 上设置变量的原因有很多,尤其是未来的兼容性问题(如果更高版本的ECMAScript 为window 定义了test 属性怎么办?)。此外,始终使用全局变量很慢,因为每当您使用 test 时,解释器都需要一直沿作用域链向上移动。
以下在功能上与上面相同,不会污染全局范围。它使用function() 声明一个匿名函数,然后立即使用() 不带参数地调用它。这通常称为立即调用函数表达式或 IIFE:
<script>
(function() {
var test = 'hello';
alert(test); //'hello'
alert(window.test); //undefined
}());
</script>
请注意,这只是一个普通的匿名函数,就像任何匿名函数一样。右花括号后的一组括号调用匿名函数。整个事物周围的括号告诉解释器它正在查看一个值或表达式,而不是函数声明。该值只是匿名函数运行时的结果。这使得匿名函数像一个简单的闭包一样工作,程序员可以有效地忽略它。
此外,您可以对 IIFE 使用两种不同的语法:
(function() {}());
(function() {})();
使用任何一个都不太可能出现问题,但是当您的代码中出现一些语法问题时,会出现some differences。 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 兔子洞的开始……