在javascript中自我执行函数的目的是什么?

在javascript中,什么时候你想使用这个:

(function(){
//Bunch of code...
})();

在这:

//Bunch of code...
211053 次浏览

命名空间。JavaScript的作用域是函数级的。

IIRC允许你创建私有属性和方法。

这都是关于变量作用域的。默认情况下,在自执行函数中声明的变量仅可用于自执行函数中的代码。这允许编写代码时不考虑变量在其他JavaScript代码块中的命名方式。

例如,正如亚历山大注释中提到的:

(function() {
var foo = 3;
console.log(foo);
})();


console.log(foo);

这将首先记录3,然后在下一个console.log上抛出错误,因为foo没有定义。

由于Javascript中的函数是一等对象,通过这样定义它,它有效地定义了一个类似于c++或c#的“类”。

该函数可以定义局部变量,并在其中包含函数。内部函数(实际上是实例方法)可以访问局部变量(实际上是实例变量),但它们将与脚本的其余部分隔离。

可能是范围隔离。这样函数声明中的变量就不会污染外部命名空间。

当然,在一半的JS实现中,它们都是如此。

一个区别是,你在函数中声明的变量是局部的,所以当你退出函数时,它们就消失了,并且它们不会与其他或相同代码中的其他变量冲突。

是否有一个参数和“一串代码”返回一个函数?

var a = function(x) { return function() { document.write(x); } }(something);

关闭。something的值被赋给a的函数使用。something可以有一些变化的值(for循环),每次a都有一个新函数。

自我调用(也称为 自动调用)是当一个函数 立即执行 定义。这是一个核心模式 它是许多人的基础 JavaScript的其他模式 发展。< / p >

我是它的超级粉丝:)因为:

  • 它使代码减至最少
  • 它实现了行为与表示的分离
  • 它提供了一个闭包,可以防止命名冲突

(为什么你要说它是好的?)

  • 它是关于一次定义和执行一个函数。
  • 你可以让这个自动执行的函数返回一个值,并将该函数作为参数传递给另一个函数。
  • 它有利于封装。
  • 它也适用于块作用域。
  • 是的,你可以把你所有的.js文件封装在一个自动执行的函数中,并且可以防止全局命名空间污染。;)

更多的在这里

我不敢相信没有一个答案提到隐含的全局变量。

(function(){})()构造不能防止隐含的全局变量,这对我来说是更大的问题,参见http://yuiblog.com/blog/2006/06/01/global-domination/

基本上,函数块确保你定义的所有依赖的“全局变量”都限制在你的程序中,它不保护你不定义隐式全局变量。JSHint或类似的可以提供关于如何防御这种行为的建议。

更简洁的var App = {}语法提供了类似级别的保护,并且在“公共”页面上可以包装在函数块中。(参见Ember.jsSproutCore获取使用此结构的库的真实示例)

private属性而言,它们有点被高估了,除非你正在创建一个公共框架或库,但如果你需要实现它们,道格拉斯Crockford有一些很好的想法。

简单。所以看起来很正常,几乎令人欣慰:

var userName = "Sean";


console.log(name());


function name() {
return userName;
}

但是,如果我在我的页面中包含一个非常方便的javascript库,它可以将高级字符转换为基本级别表示呢?

等待……什么?

我的意思是,如果有人输入一个带有某种口音的字符,但我只想在我的程序中输入“英语”字符a - z ?嗯…西班牙语的“ñ”和法语的“é”可以翻译成基本字符“n”和“e”。

所以有人写了一个全面的字符转换器,我可以包括在我的网站…我把它包括在内。

有一个问题:它有一个名为“name”的函数,与我的函数相同。

这就是所谓的碰撞。我们在同一个范围中声明了两个同名的函数。我们要避免这种情况。

因此,我们需要以某种方式确定代码的范围。

在javascript中作用域代码的唯一方法是将其包装在函数中:

function main() {
// We are now in our own sound-proofed room and the
// character-converter library's name() function can exist at the
// same time as ours.


var userName = "Sean";


console.log(name());


function name() {
return userName;
}
}

那也许能解决我们的问题。现在所有内容都是封闭的,只能从开括号和闭括号内访问。

我们有一个函数中的一个函数。看起来很奇怪,但完全合法。

只有一个问题。我们的代码不能工作。 我们的userName变量永远不会回显到控制台!< / p >

我们可以通过在现有代码块之后添加对函数的调用来解决这个问题…

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;
}
}
)();

所以,在你阅读的大多数教程中,你现在都会被“匿名自动执行”或类似的术语轰炸。

经过多年的专业发展,我强烈敦促你命名你写的每个函数用于调试目的。

当出现错误时(它会出错),您将在浏览器中检查回溯。当堆栈跟踪中的条目有名称时,总是更容易缩小您的代码问题!

非常冗长,我希望它有帮助!

自调用函数在javascript:

自动调用(启动)自调用表达式,而不需要调用。自调用表达式在创建后立即被调用。这主要用于避免命名冲突以及实现封装。变量或声明的对象在此函数之外不可访问。为了避免最小化(filename.min)的问题,总是使用自执行函数。

下面是一个实例,说明了自我调用匿名函数的用处。

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...

看起来这个问题已经有了答案,但我还是会发表我的意见。

我知道什么时候我喜欢使用自动执行函数。

var myObject = {
childObject: new function(){
// bunch of code
},
objVar1: <value>,
objVar2: <value>
}

该函数允许我使用一些额外的代码来定义childObjects的属性和属性,以获得更清晰的代码,例如设置常用的变量或执行数学方程;哦!或者错误检查。而不是局限于嵌套的对象实例化语法…

object: {
childObject: {
childObject: {<value>, <value>, <value>}
},
objVar1: <value>,
objVar2: <value>
}

一般来说,编码有很多晦涩的方法来做很多相同的事情,这让你想知道,“为什么要麻烦呢?”但是新的情况不断出现,您不能再仅仅依赖基本/核心原则。

(function(){
var foo = {
name: 'bob'
};
console.log(foo.name); // bob
})();
console.log(foo.name); // Reference error

实际上,上面的函数将被视为没有名称的函数表达式。

用左右圆括号包装函数的主要目的是避免污染全局空间。

函数表达式中的变量和函数变成私有的(也就是说,它们在函数外部是不可用的)。

我已经阅读了所有的答案,这里缺少了一些非常重要的东西,我将亲吻。有两个主要原因,为什么我需要自执行匿名函数,或更好地说“立即调用函数表达式(IIFE)”:

  1. 更好的命名空间管理(避免命名空间污染-> JS模块)
  2. 闭包(模拟私有类成员,如OOP所示)

第一个已经解释得很好了。对于第二个问题,请学习下面的例子:

var MyClosureObject = (function (){
var MyName = 'Michael Jackson RIP';
return {
getMyName: function () { return MyName;},
setMyName: function (name) { MyName = name}
}
}());

我们不是将函数赋值给MyClosureObject,而是调用该函数的结果。注意最后一行中的()

关于Javascript中的函数,你还需要知道的是,内部函数得到函数的访问参数和变量,它们是在函数中定义的。

让我们做一些实验:

我可以使用getMyName获得MyName,它可以工作:

 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被设计为在没有__abc1前缀的情况下使用,因此按照惯例它不应该大写。

自执行函数用于管理变量的作用域。

变量的作用域是程序中定义变量的区域。

全局变量具有全局作用域;它在JavaScript代码中的任何地方都有定义,并且可以从脚本中的任何地方访问,甚至在函数中。另一方面,在函数中声明的变量只能在函数体中定义。 它们是局部变量,具有局部作用域,并且只能在该函数中访问。函数形参也算作局部变量,只在函数体中定义

如下所示,您可以在函数中访问全局变量变量,并注意在函数体中,具有相同名称的局部变量优先于全局变量。

var globalvar = "globalvar"; // this var can be accessed anywhere within the script


function scope() {
alert(globalvar);
var localvar = "localvar"; //can only be accessed within the function scope
}


scope();

因此,基本上,自执行函数允许编写代码,而无需考虑其他javascript代码块中的变量如何命名。

简单的答案是:以防止全球(或更高)范围的污染。

IIFE(立即调用函数表达式)是用于将脚本编写为插件、附加组件、用户脚本或任何期望与其他人的脚本一起工作的脚本的最佳实践。这可以确保您定义的任何变量都不会对其他脚本产生不良影响。

这是另一种写IIFE表达式的方法。我个人更喜欢以下方法:

void function() {
console.log('boo!');
// expected output: "boo!"
}();

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/void

从上面的例子可以清楚地看出,IIFE也会影响效率和性能,因为预期只运行一次的函数只会被处死一次,然后就永远被扔进虚空吗。这意味着函数或方法声明不会保留在内存中。

首先你必须访问MDN IIFE,现在有一些关于这个的观点

  • 这是立即调用的函数表达式。当你的javascript文件从HTML中调用这个函数时立即调用。
  • 这防止了在IIFE习惯用法中访问变量以及污染全局作用域。

给你一个简单的问题:“在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());

在节点。插入是某种异步操作。

我不能只是调用等待没有异步关键字在我的函数的声明,我不需要一个命名函数以后使用,但需要等待插入调用或我需要一些其他更丰富的功能(谁知道?)。

你可以使用这个函数返回值:

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) );

此方法用于闭包。有关闭包的更多信息,请阅读链接