Answers:
这都是关于变量作用域的。默认情况下,自执行函数中声明的变量仅可用于自执行函数中的代码。这样就可以编写代码,而不必担心在其他JavaScript代码块中如何命名变量。
例如,如亚历山大的评论中所述:
(function() {
var foo = 3;
console.log(foo);
})();
console.log(foo);
这将首先记录日志3
,然后在下一次引发错误,console.log
因为foo
未定义。
var
,是这样的:...function(){ foo=3;}
?它将设置全局变量,对吗?
function(){ var foo = 3; alert(foo); }; alert(foo);
所以我还是不明白这一点
简单化。看起来很正常,几乎令人安慰:
var userName = "Sean";
console.log(name());
function name() {
return userName;
}
但是,如果我在页面中包含一个非常方便的javascript库,该库会将高级字符转换为它们的基本级表示形式,该怎么办?
等等...什么
我的意思是,如果有人输入带有某种重音符号的字符,但是我只想在程序中使用“英语”字符AZ?好吧...西班牙语的“ñ”和法语的“é”字符可以翻译成“ 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”这个名字的机会是什么?...非常非常苗条
我们需要更多的范围界定。还有一些自动执行我们的main()函数的方法。
现在我们来介绍自动执行功能(或自动执行,自动运行等)。
((){})();
语法令人作呕。但是,它起作用。
当您将函数定义包装在括号中并包括参数列表(另一个集合或括号!)时,它将充当函数调用。
因此,让我们使用一些自动执行的语法再次查看我们的代码:
(function main() {
var userName = "Sean";
console.log(name());
function name() {
return userName;
}
}
)();
因此,在您阅读的大多数教程中,您现在都会被术语“匿名自我执行”或类似的东西所吸引。
经过多年的专业发展,我强烈建议您命名为调试目的编写的每个函数。
当出现问题(并且会发生问题)时,您将在浏览器中检查回溯。它总是更容易缩小你的代码的问题时,在堆栈跟踪中的条目有名字!
long之以鼻,希望对您有所帮助!
:)
自调用(也称为自动调用)是指函数在定义后立即执行。这是一种核心模式,并且是许多其他JavaScript开发模式的基础。
我非常喜欢:),因为:
极大地-(为什么要说它的好?)
这里更多。
命名空间。JavaScript的作用域是功能级别的。
我不敢相信所有答案都暗含了全局变量。
该(function(){})()
构造无法防止隐含的全局变量,对我而言,这是一个更大的问题,请参见http://yuiblog.com/blog/2006/06/01/global-domination/
基本上,功能块确保您定义的所有相关“全局变量”都局限于程序中,它不能保护您免受隐式全局变量的定义。JSHint等可以提供有关如何防御此行为的建议。
更为简洁的var App = {}
语法提供了类似的保护级别,并且在“公共”页面上时可以包装在功能块中。(有关使用此构造的库的真实示例,请参见Ember.js或SproutCore)
就private
属性而言,除非您要创建公共框架或库,否则它们会被高估,但是如果您需要实现它们,Douglas Crockford有一些好主意。
我已经阅读了所有答案,在此遗漏了一些非常重要的内容,我会接吻。有两个主要原因,为什么我需要自执行匿名函数,或者最好说“ 立即调用函数表达式(IIFE) ”:
第一个已经很好地解释了。对于第二个,请研究以下示例:
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循环),并且每次具有新功能时。
var x = something;
在外部函数中使用显式而不是x
参数:imo这样更易读……
x
并直接取决于词汇范围,即document.write(something)
...
这是一个自我调用匿名函数如何有用的可靠示例。
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...
let
代替var
就可以了。
javascript中的自调用函数:
自调用表达式将自动调用(启动),而不被调用。自调用表达式创建后立即被调用。基本上,这用于避免命名冲突以及实现封装。在此函数之外无法访问变量或声明的对象。为了避免最小化问题(filename.min),请始终使用自执行函数。
自执行功能用于管理变量的范围。
变量的范围是程序在其中定义的区域。
全局变量具有全局范围;它在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代码块中如何命名变量。
(function(){
var foo = {
name: 'bob'
};
console.log(foo.name); // bob
})();
console.log(foo.name); // Reference error
实际上,以上函数将被视为没有名称的函数表达式。
使用封闭的和开放的括号包装函数的主要目的是避免污染全局空间。
函数表达式内的变量和函数变为私有(即,它们在函数外部将不可用)。
简短的答案是: 防止污染全球(或更高)范围。
IIFE(立即调用函数表达式)是将脚本编写为插件,附加组件,用户脚本或任何希望与其他人的脚本一起使用的脚本的最佳实践。这样可以确保您定义的任何变量都不会对其他脚本产生不良影响。
这是编写IIFE表达式的另一种方法。我个人更喜欢以下方法:
void function() {
console.log('boo!');
// expected output: "boo!"
}();
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/void
从上面的示例可以很明显地看出,IIFE也会影响效率和性能,因为预期仅运行一次的函数将执行一次,然后永久地转储到void中。这意味着函数或方法声明不会保留在内存中。
void
。我喜欢。
看来这个问题已经准备好了,但我还是会发表我的意见。
我知道何时需要使用自我执行功能。
var myObject = {
childObject: new function(){
// bunch of code
},
objVar1: <value>,
objVar2: <value>
}
该函数使我可以使用一些额外的代码来定义更干净代码的childObjects属性和属性,例如设置常用变量或执行数学方程式;哦! 或错误检查。而不是限于...的嵌套对象实例化语法
object: {
childObject: {
childObject: {<value>, <value>, <value>}
},
objVar1: <value>,
objVar2: <value>
}
通常,编码有很多晦涩的方式来做很多相同的事情,这使您想知道“为什么要打扰?” 但是,新的情况不断出现,您将无法再仅依靠基本/核心原则。
给您一个简单的问题:“在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,并且我不需要命名函数供以后使用,而是需要等待插入调用,或者我需要其他一些更丰富的功能(谁知道?) 。
IIRC它允许您创建私有属性和方法。