What is the purpose of a self executing function in javascript?
在javascript中,你想什么时候使用它:
1 2 3 | (function(){ //Bunch of code... })(); |
对此:
1 | //Bunch of code... |
一切都与变量范围有关。默认情况下,在自执行函数中声明的变量仅可用于自执行函数中的代码。这允许编写代码而不用考虑如何在其他javascript代码块中命名变量。
例如:
1 2 3 4 5 6 | (function(){ var foo = 3; alert(foo); })(); alert(foo); |
这将首先警告"3",然后在下一个警报上抛出错误,因为未定义foo。
简单化。看起来很正常,几乎让人感到安慰:
1 2 3 4 5 6 7 | var userName ="Sean"; console.log(name()); function name() { return userName; } |
然而。如果我在页面中包含一个非常方便的javascript库,将高级字符转换为基本级别表示,该怎么办?
等等......什么?
我的意思是。如果有人输入带有某种重音的角色(例如法语或西班牙语),但我只想要'英语'字符? A-z在我的程序中?嗯......西班牙语'n~'和法语'e /'字符(我已经为这些字符使用了两个字符,但你可以在表达重音的字符中进行精神跳跃),这些字符可以被翻译成为'n'和'e'的基本字符。
所以有一个好人已经写了一个全面的字符转换器,我可以包括在我的网站...我包括它。
一个问题:它有一个名为'name'的函数,与我的函数相同。
这就是所谓的碰撞。我们在相同的范围内声明了两个具有相同名称的函数。我们想避免这种情况。
所以我们需要以某种方式确定代码的范围。
在javascript中扩展代码范围的唯一方法是将其包装在函数中:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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变量永远不会回显到控制台!
我们可以通过在现有代码块之后添加对函数的调用来解决此问题...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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(); |
或之前!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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()函数的方法。
现在我们来到自动执行功能(或自动执行,自运行,等等)。
((){})();
语法像罪一样尴尬。但是,它的工作原理。
当您将函数定义包装在括号中并包含参数列表(另一组或括号!)时,它将充当函数调用。
所以让我们再看一下我们的代码,使用一些自动执行的语法:
1 2 3 4 5 6 7 8 9 10 | (function main() { var userName ="Sean"; console.log(name()); function name() { return userName; } } )(); |
因此,在您阅读的大多数教程中,您现在将使用"匿名自执行"或类似的术语进行轰炸。
经过多年的专业开发,我强烈建议您为调试目的命名您编写的每个函数。
当出现问题时(它会出现问题),您将在浏览器中检查回溯。当堆栈跟踪中的条目具有名称时,更容易缩小代码问题!
非常啰嗦,我希望它有所帮助!
Self-invocation (also known as
auto-invocation) is when a function
executes immediately upon its
definition. This is a core pattern and
serves as the foundation for many
other patterns of JavaScript
development.
它是一个伟大的粉丝:)因为:
- 它将代码保持在最低限度
- 它强制将行为与表达分开
- 它提供了一个阻止命名冲突的闭包
极大 - (为什么你应该说它好?)
- 它是关于一次定义和执行一个函数。
- 您可以让该自执行函数返回一个值,并将该函数作为参数传递给另一个函数。
- 封装很有用。
- 它也适用于块范围。
- 是的,您可以将所有.js文件包含在自执行功能中,并可以防止全局命名空间污染。 ;)
更多这里。
命名空间。 JavaScript的范围是功能级别的。
我不敢相信没有提到暗示全局的答案。
基本上,功能块确保您定义的所有相关"全局变量"仅限于您的程序,它不会保护您不会定义隐式全局变量。 JSHint等可以提供有关如何防御此行为的建议。
更简洁的
至于
是否有参数和"一堆代码"返回一个函数?
1 | var a = function(x) { return function() { document.write(x); } }(something); |
关闭。
范围隔离,也许。这样函数声明中的变量不会污染外部命名空间。
当然,在那里的JS实现的一半,他们无论如何。
我已经阅读了所有答案,这里缺少一些非常重要的答案,我会亲吻。有两个主要原因,为什么我需要自执行匿名函数,或者更好地说"立即调用函数表达式(IIFE)":
第一个问题已得到很好的解释。对于第二个,请研究以下示例:
1 2 3 4 5 6 7 | var MyClosureObject = (function (){ var MyName = 'Michael Jackson RIP'; return { getMyName: function () { return MyName;}, setMyName: function (name) { MyName = name} } }()); |
注意1:我们没有为
注意2:你还需要了解Javascript中的函数是内部函数可以访问函数的参数和变量,它们是在函数内定义的。
让我们尝试一些实验:
我可以使用
1 2 | console.log(MyClosureObject.getMyName()); // Michael Jackson RIP |
以下巧妙的方法是行不通的:
1 2 | console.log(MyClosureObject.MyName); // undefined |
但我可以设置另一个名称并获得预期的结果:
1 2 3 | MyClosureObject.setMyName('George Michael RIP'); console.log(MyClosureObject.getMyName()); // George Michael RIP |
编辑:在上面的示例中,
这是一个自我调用匿名函数如何有用的可靠示例。
1 2 3 4 5 | for( var i = 0; i < 10; i++ ) { setTimeout(function(){ console.log(i) }) } |
输出:
1 2 3 4 5 6 7 | for( var i = 0; i < 10; i++ ) { (function(num){ setTimeout(function(){ console.log(num) }) })(i) } |
输出:
一个区别是您在函数中声明的变量是本地的,因此当您退出函数时它们会消失,并且不会与其他代码中的其他变量冲突。
javascript中的自调用函数:
自动调用(启动)自调用表达式,而不调用。自动调用表达式在创建后立即调用。这基本上用于避免命名冲突以及实现封装。在此函数外部无法访问变量或声明的对象。为避免最小化问题(filename.min),请始终使用自执行功能。
自执行功能用于管理变量的范围。
变量的范围是程序中定义它的区域。
全局变量具有全局范围;它在JavaScript代码中的任何位置定义,并且可以在脚本中的任何位置进行访问,即使在您的函数中也是如此。另一方面,函数内声明的变量仅在函数体内定义。
它们是局部变量,具有局部范围,只能在该函数中访问。函数参数也算作局部变量,并且仅在函数体内定义。
如下所示,您可以访问函数内部的globalvariable变量,并注意在函数体内,局部变量优先于具有相同名称的全局变量。
1 2 3 4 5 6 7 8 | var globalvar ="globalvar"; // this var can be accessed anywhere within the script function scope() { alert(globalvar); localvar ="localvar" //can only be accessed within the function scope } scope(); |
因此,基本上自执行函数允许编写代码而无需考虑如何在其他javascript代码块中命名变量。
由于Javascript中的函数是第一类对象,通过这种方式定义它,它有效地定义了一个类似于C ++或C#的"类"。
该函数可以定义局部变量,并在其中包含函数。内部函数(实际上是实例方法)可以访问局部变量(实际上是实例变量),但它们将与脚本的其余部分隔离开来。
看起来这个问题已经准备就绪,但无论如何我都会发布我的输入。
我知道什么时候我喜欢使用自动执行功能。
1 2 3 4 5 6 7 | var myObject = { childObject: new function(){ // bunch of code }, objVar1: <value>, objVar2: <value> } |
该函数允许我使用一些额外的代码来定义更清晰代码的childObjects属性和属性,例如设置常用变量或执行数学方程;哦!或错误检查。而不是仅限于嵌套对象实例化语法...
1 2 3 4 5 6 7 | object: { childObject: { childObject: {<value>, <value>, <value>} }, objVar1: <value>, objVar2: <value> } |
编码一般有许多模糊的方法可以做很多相同的事情,让你想知道,"为什么要这么麻烦?"但是,新的情况不断涌现,你不能再单独依赖基本/核心原则了。
1 2 3 4 5 6 7 | (function(){ var foo = { name: 'bob' }; console.log(foo.name); // bob })(); console.log(foo.name); // Reference error |
实际上,上述函数将被视为没有名称的函数表达式。
使用闭括号和左括号包装函数的主要目的是避免污染全局空间。
函数表达式中的变量和函数变为私有(即)它们在函数外部不可用。
IIRC它允许您创建私有属性和方法。