在javascript中,你想什么时候使用它:
(function(){
//Bunch of code...
})();
对此:
//Bunch of code...
答案 0 :(得分:369)
关于变量范围的全部内容。默认情况下,在自执行函数中声明的变量仅可用于自执行函数中的代码。这样就可以编写代码而无需考虑如何在其他javascript代码块中命名变量。
例如:
(function(){
var foo = 3;
alert(foo);
})();
alert(foo);
这将首先警告“3”,然后在下一个警报上抛出错误,因为未定义foo。
答案 1 :(得分:78)
简单化。看起来非常正常,几乎让人感到安慰:
var userName = "Sean";
console.log(name());
function name() {
return userName;
}
然而。如果我在我的页面中包含一个非常方便的javascript库,将高级字符转换为基本级别表示,该怎么办?
等等......什么?
我的意思是。如果有人输入带有某种重音的角色(例如法语或西班牙语),但我只想要'英语'字符? A-z在我的程序中?嗯......西班牙语' 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;
}
}
)();
因此,在您阅读的大多数教程中,您现在将被称为“匿名自我执行”这一术语。或类似的东西。
经过多年的专业发展,我强烈敦促您将您编写的所有功能命名为以进行调试。
当出现问题(并且会出现问题)时,您将在浏览器中检查回溯。当堆栈跟踪中的条目具有名称时,总是更容易缩小代码问题!
非常啰嗦,我希望它有所帮助!
答案 2 :(得分:33)
自我调用(也称为 自动调用)是一个函数 立即执行 定义。这是一个核心模式和 是许多人的基础 其他JavaScript模式 发展。
我很喜欢它因为:
极其 - (为什么你应该说它好?)
更多here。
答案 3 :(得分:19)
命名空间。 JavaScript的范围是功能级别。
答案 4 :(得分:12)
我无法相信没有提到暗示全局的答案。
(function(){})()
构造不能防止隐含的全局变量,对我来说这是一个更大的问题,请参阅http://yuiblog.com/blog/2006/06/01/global-domination/
基本上,功能块确保您定义的所有相关“全局变量”仅限于您的程序,它不会保护您不会定义隐式全局变量。 JSHint等可以提供有关如何抵御此行为的建议。
更简洁的var App = {}
语法提供了类似的保护级别,并且可以在“公共”页面上包含在功能块中。 (有关使用此构造的库的真实示例,请参阅Ember.js或SproutCore)
就private
属性而言,除非您要创建公共框架或库,否则它们会被高估,但如果您需要实现它们,Douglas Crockford有一些好主意。
答案 5 :(得分:7)
是否有参数并且“一串代码”返回一个函数?
var a = function(x) { return function() { document.write(x); } }(something);
封闭。 something
的值被分配给a
的函数使用。 something
可以有一些不同的值(for循环),每次a都有一个新函数。
答案 6 :(得分:6)
范围隔离,也许。这样函数声明中的变量就不会污染外部名称空间。
当然,在那里的JS实现的一半,他们无论如何都会。
答案 7 :(得分:5)
以下是自我调用匿名函数如何有用的一个很好的例子。
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...
答案 8 :(得分:3)
一个区别是你在函数中声明的变量是本地的,所以当你退出函数时它们会消失,而不会与其他代码中的其他变量冲突。
答案 9 :(得分:3)
我已经阅读了所有答案,这里缺少一些非常重要的东西,我会吻。有两个主要原因,为什么我需要自我执行匿名函数,或者更好地说&#34; 立即调用函数表达式(IIFE)&#34;:
第一个问题得到了很好的解释。对于第二个,请研究以下示例:
var MyClosureObject = (function (){
var MyName = 'Michael Jackson RIP';
return {
getMyName: function () { return MyName;},
setMyName: function (name) { MyName = name}
}
}());
注意1:我们没有为MyClosureObject
分配功能,更多调用该功能的结果。请注意最后一行中的()
。
注意2:您还需要了解Javascript中的函数,内部函数可以访问函数的参数和变量,它们是定义的内。
让我们尝试一些实验:
我可以使用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
前缀的情况下使用,因此按照惯例,它不应大写。
答案 10 :(得分:2)
javascript中的自我调用函数:
自动调用(启动)自调用表达式,而不会被调用。自动调用表达式在创建后立即调用。这基本上用于避免命名冲突以及实现封装。在此函数外部无法访问变量或声明的对象。为了避免最小化问题(filename.min),总是使用自执行函数。
答案 11 :(得分:1)
由于Javascript中的函数是第一类对象,通过这种方式定义它,它有效地定义了一个类似C ++或C#的“类”。
该函数可以定义局部变量,并在其中包含函数。内部函数(实际上是实例方法)可以访问局部变量(实际上是实例变量),但它们将与脚本的其余部分隔离开来。
答案 12 :(得分:1)
首先,您必须访问MDN IIFE,现在有关此点
答案 13 :(得分:1)
自执行功能用于管理变量的范围。
变量的范围是程序中定义它的区域。
全局变量具有全局范围;它在JavaScript代码中的任何位置定义,并且可以在脚本中的任何位置进行访问,即使在您的函数中也是如此。另一方面,函数内声明的变量仅在函数体内定义。 它们是局部变量,具有局部范围,只能在该函数中访问。函数参数也算作局部变量,仅在函数体内定义。
如下所示,您可以访问函数内部的globalvariable变量,并注意在函数体内,局部变量优先于具有相同名称的全局变量。
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代码块中命名变量。
答案 14 :(得分:1)
最简单的答案是:防止全球(或更高)范围的污染。
IIFE(立即调用函数表达式)是将脚本编写为插件,附加组件,用户脚本或任何希望与其他人的脚本一起使用的脚本的最佳实践。这样可以确保您定义的任何变量都不会对其他脚本产生不良影响。
这是编写IIFE表达式的另一种方法。我个人更喜欢以下方法:
void function() {
console.log('boo!');
// expected output: "boo!"
}();
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/void
从上面的示例可以很明显地看出,IIFE也会影响效率和性能,因为预期仅运行一次的功能将执行一次,然后永久地转储到void 。这意味着函数或方法声明不会保留在内存中。
答案 15 :(得分:0)
您可以使用此函数返回值:
var Test = (function (){
const alternative = function(){ return 'Error Get Function '},
methods = {
GetName: alternative,
GetAge:alternative
}
// If the condition is not met, the default text will be returned
// replace to 55 < 44
if( 55 > 44){
// Function one
methods.GetName = function (name) {
return name;
};
// Function Two
methods.GetAge = function (age) {
return age;
};
}
return methods;
}());
// Call
console.log( Test.GetName("Yehia") );
console.log( Test.GetAge(66) );
答案 16 :(得分:0)
给出一个简单的问题:“在javascript中,什么时候您想使用它:...”
我喜欢@ken_browning和@sean_holding的答案,但这是我看不到的另一个用例:
let red_tree = new Node(10);
(async function () {
for (let i = 0; i < 1000; i++) {
await red_tree.insert(i);
}
})();
console.log('----->red_tree.printInOrder():', red_tree.printInOrder());
其中Node.insert是一些异步操作。
在函数声明时,我不能只在没有async关键字的情况下调用await,并且我不需要命名函数供以后使用,但需要等待插入调用,或者我需要其他一些更丰富的功能(知道吗?)。
答案 17 :(得分:0)
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js">
</script>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
</head>
<body>
<div id="myDiv" style="width: 480px; height: 400px;"><!-- Plotly chart will be drawn inside this DIV --></div>
<script>
var trace1 = {
x: ['2013-10-04 22:23:00', '2016-10-06 22:23:00', '2013-11-04 22:23:00', '2013-11-07 22:23:00','2013-12-04 22:23:00', '2013-12-08 22:23:00'],
y: [1, 3, 6,9, 4, 5],
fill: 'tozeroy',
fillcolor: 'red',
text: server1,
hoverinfo: "x+y+text",
name:"Server 1",
type: 'scatter',
mode:"markers",
marker:
{
size:5,
color:"gray"
},
uid:"c2e171"
};
var layout = {
margin: {
l: 35,
r: 40,
b: 50,
t: 10
},
legend: {
"orientation": "h"
},
yaxis : {
fixedrange: true
},
};
var data = [trace1];
Plotly.newPlot('myDiv', data,layout);
var plotDiv = document.getElementById('myDiv');
</script>
</body>
</html>
实际上,上述函数将被视为没有名称的函数表达式。
使用close括号和左括号包装函数的主要目的是避免污染全局空间。
函数表达式中的变量和函数变为私有(即)它们在函数外部不可用。
答案 18 :(得分:0)
看起来这个问题已经准备就绪,但我还是会发布我的输入。
我知道什么时候我喜欢使用自动执行功能。
var myObject = {
childObject: new function(){
// bunch of code
},
objVar1: <value>,
objVar2: <value>
}
该函数允许我使用一些额外的代码来定义更清晰代码的childObjects属性和属性,例如设置常用变量或执行数学方程;哦!或错误检查。而不是仅限于...的嵌套对象实例化语法。
object: {
childObject: {
childObject: {<value>, <value>, <value>}
},
objVar1: <value>,
objVar2: <value>
}
编码通常有许多模糊的方法来做很多相同的事情,让你好奇,&#34;为什么要打扰?&#34;但是新的情况不断涌现,你不能再单独依赖基本/核心原则了。
答案 19 :(得分:-2)
IIRC它允许您创建私有属性和方法。