在javascript中,你想什么时候使用它:
(function(){ //Bunch of code... })();
对此:
//Bunch of code...
Ken Browning.. 385
一切都与变量范围有关.默认情况下,在自执行函数中声明的变量仅可用于自执行函数中的代码.这允许编写代码而不用考虑如何在其他javascript代码块中命名变量.
例如:
(function(){ var foo = 3; alert(foo); })(); alert(foo);
这将首先警告"3",然后在下一个警报上抛出错误,因为未定义foo.
一切都与变量范围有关.默认情况下,在自执行函数中声明的变量仅可用于自执行函数中的代码.这允许编写代码而不用考虑如何在其他javascript代码块中命名变量.
例如:
(function(){ var foo = 3; alert(foo); })(); alert(foo);
这将首先警告"3",然后在下一个警报上抛出错误,因为未定义foo.
简单化.看起来很正常,几乎让人感到安慰:
var userName = "Sean"; console.log(name()); function name() { return userName; }
然而.如果我在页面中包含一个非常方便的javascript库,将高级字符转换为基本级别表示,该怎么办?
等等......什么?
我的意思是.如果有人输入带有某种重音的角色(例如法语或西班牙语),但我只想要'英语'字符?Az在我的节目中?嗯......西班牙语'n~'和法语'e /'字符(我为这些字符分别使用了两个字符,但你可以在表达重音的字符中进行精神跳跃),这些字符可以被翻译成为'n'和'e'的基本字符.
所以有一个好人已经写了一个全面的字符转换器,我可以包括在我的网站...我包括它.
一个问题:它有一个名为'name'的函数,与我的函数相同.
这就是所谓的碰撞.我们在相同的范围内声明了两个具有相同名称的函数.我们想避免这种情况.
所以我们需要以某种方式确定代码的范围.
在javascript中扩展代码范围的唯一方法是将其包装在函数中:
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; } }
这可能会解决我们的问题.现在所有东西都是封闭的,只能从我们的开始和结束括号中访问.
我们在函数中有一个函数......这看起来很奇怪,但完全合法.
只有一个问题.我们的代码不起作用.我们的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()函数的方法.
现在我们来到自动执行功能(或自动执行,自运行,等等).
((){})();
语法像罪一样尴尬.但是,它的工作原理.
当您将函数定义包装在括号中并包含参数列表(另一组或括号!)时,它将充当函数调用.
所以让我们再看一下我们的代码,使用一些自动执行的语法:
(function main() { var userName = "Sean"; console.log(name()); function name() { return userName; } } )();
因此,在您阅读的大多数教程中,您现在将使用"匿名自执行"或类似的术语进行轰炸.
经过多年的专业开发,我强烈建议您为调试目的命名您编写的每个函数.
当出现问题时(它会出现问题),您将在浏览器中检查回溯.它总是更容易缩小你的代码的问题时,在堆栈跟踪中的条目有名字!
非常啰嗦,我希望它有所帮助!
自调用(也称为自动调用)是函数在定义时立即执行的.这是一个核心模式,是许多其他JavaScript开发模式的基础.
它是一个伟大的粉丝:)因为:
它将代码保持在最低限度
它强制将行为与表达分开
它提供了一个阻止命名冲突的闭包
极大 - (为什么你应该说它好?)
它是关于一次定义和执行一个函数.
您可以让该自执行函数返回一个值,并将该函数作为参数传递给另一个函数.
封装很有用.
它也适用于块范围.
是的,您可以将所有.js文件包含在自执行功能中,并可以防止全局命名空间污染.;)
更多这里.
命名空间.JavaScript的范围是功能级别的.
我不敢相信没有提到暗示全局的答案.
该(function(){})()
构造不能防止隐含的全局变量,这对我来说是更大的问题,请参阅http://yuiblog.com/blog/2006/06/01/global-domination/
基本上,功能块确保您定义的所有相关"全局变量"仅限于您的程序,它不会保护您不会定义隐式全局变量.JSHint等可以提供有关如何防御此行为的建议.
更简洁的var App = {}
语法提供了类似的保护级别,并且可以在"公共"页面上包含在功能块中.(有关使用此构造的库的真实示例,请参阅Ember.js或SproutCore)
就private
属性来说,除非你要创建公共框架或库,否则它们会被高估,但如果你需要实现它们,Douglas Crockford有一些好主意.
我已经阅读了所有答案,在此遗漏了一些非常重要的内容,我会接吻。有两个主要原因,为什么我需要自执行匿名函数,或者最好说“ 立即调用函数表达式(IIFE) ”:
更好的名称空间管理(避免名称空间污染-> JS模块)
封闭(模拟私有类成员,从OOP已知)
第一个已经很好地解释了。对于第二个,请研究以下示例:
var MyClosureObject = (function (){ var MyName = 'Michael Jackson RIP'; return { getMyName: function () { return MyName;}, setMyName: function (name) { MyName = name} } }());
注意1:我们没有分配功能MyClosureObject
,更何况是调用该功能的结果。请注意()
最后一行。
注意2:您还需要进一步了解Java语言中的函数,即内部函数可以访问内部定义的函数的参数和变量。
让我们尝试一些实验:
我可以MyName
使用了getMyName
,它可以工作:
console.log(MyClosureObject.getMyName()); // Michael Jackson RIP
以下巧妙的方法不起作用:
console.log(MyClosureObject.MyName); // undefined
但是我可以设置另一个名称并获得预期的结果:
MyClosureObject.setMyName('George Michael RIP'); console.log(MyClosureObject.getMyName()); // George Michael RIP
编辑:在上面的示例MyClosureObject
中设计为不带new
前缀使用,因此按照惯例,不应将其大写。
是否有参数和"一堆代码"返回一个函数?
var a = function(x) { return function() { document.write(x); } }(something);
关闭.something
分配给的函数使用的值的值a
.something
可以有一些不同的值(for循环)和每次a有一个新的功能.
范围隔离,也许.这样函数声明中的变量不会污染外部命名空间.
当然,在那里的JS实现的一半,他们无论如何.
这是一个自我调用匿名函数如何有用的可靠示例.
for( var i = 0; i < 10; i++ ) { setTimeout(function(){ console.log(i) }) }
输出: 10, 10, 10, 10, 10...
for( var i = 0; i < 10; i++ ) { (function(num){ setTimeout(function(){ console.log(num) }) })(i) }
输出: 0, 1, 2, 3, 4...