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

What is the purpose of a self executing function in javascript?

提问人:Ej. 提问时间:2/27/2009 最后编辑:thatpaintingelephantEj. 更新时间:12/26/2022 访问量:226118

问:

在 javascript 中,您希望何时使用它:

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

在此之上:

//Bunch of code...
JavaScript 闭包 IIFE self-executing-function

评论

4赞 Bergi 7/17/2014
还可以查看(技术解释此处。对于语法,请参阅为什么需要括号以及它们应该放在哪里
2赞 Bergi 7/30/2014
参见 将整个 Javascript 文件包装在匿名函数中的目的是什么?
0赞 johnny 12/16/2014
为什么它在分号之前有最后两个括号?
3赞 Ej. 12/17/2014
@johnny最后两个括号前面的部分声明一个(匿名)函数。这两个括号调用该函数。
10赞 Flimm 7/9/2015
“立即调用函数表达式”或 IIFE 是一个更好的名称

答:

21赞 Christoph 2/27/2009 #1

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

评论

10赞 Christoph 10/1/2014
反对票仍然在进来,因为我使用了范围界定命名空间;这是一个定义问题 - 参见例如维基百科: 计算机科学中的命名空间(有时也称为名称范围)是一个抽象容器或环境,用于保存唯一标识符或符号(即名称)的逻辑分组。 以及 命名空间标识符可以为名称提供上下文(计算机科学中的范围),并且这些术语有时可以互换使用。
5赞 Christoph 10/1/2014
Javascript 的函数级作用域提供了变量名称所在的空间,即命名空间;它是一个与命名空间标识符无关的匿名者是无关紧要的......
0赞 Marius 7/9/2023
我认为反对票即将到来,因为您的评论对初学者没有太大帮助。
-4赞 Ólafur Waage 2/27/2009 #2

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

491赞 Ken Browning 2/27/2009 #3

这一切都与变量范围有关。默认情况下,在自执行函数中声明的变量仅可用于自执行函数中的代码。这允许编写代码,而无需担心变量在其他 JavaScript 代码块中的命名方式。

例如,正如亚历山大在评论中提到的:

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

console.log(foo);

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

评论

8赞 Erik Reppen 8/18/2012
也为了许多人的利益,包括一大群 Netflix 工程师:这只是一个功能。它本身并不代表关闭。有时,自动调用器与闭包相关的场景结合使用,以做一些整洁的事情,但是如果你没有看到一些东西保留了一个引用,而这些引用将被垃圾收集并在非闭包语言中消失,那么它与 CLOSURES 无关。
2赞 Pir Abdul 2/13/2013
所以这意味着,它主要用于闭合?
2赞 João Pimentel Ferreira 12/4/2017
@AlexanderBird但这已经发生在函数内部的局部变量中: 所以我还是不明白function(){ var foo = 3; alert(foo); }; alert(foo);
4赞 Giulio 8/20/2020
如果它只是为了范围界定,为什么不直接使用?{ let foo = 3 }
3赞 yunzen 3/1/2021
@Giulio 这个答案来自2009年。块范围是后来才引入的
1赞 James Curran 2/27/2009 #4

由于 Javascript 中的函数是第一类对象,因此通过以这种方式定义它,它有效地定义了一个类似于 C++ 或 C# 的“类”。

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

7赞 chaos 2/27/2009 #5

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

当然,在一半的 JS 实现中,它们无论如何都会。

评论

4赞 Matthew Crumley 2/27/2009
这些会是什么实现?
1赞 Erik Reppen 8/18/2012
任何未以严格模式编写的实现,并包含导致其为全局的隐式 var 声明。
3赞 Guffa 2/27/2009 #6

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

7赞 stesch 2/27/2009 #7

是否有参数并且“一堆代码”返回一个函数?

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

关闭。分配给 的函数使用的值。 可以有一些不同的值(for 循环),并且每次 A 都有一个新函数。somethingasomething

评论

0赞 Christoph 2/27/2009
+1;不过,我更喜欢外部函数中的显式而不是作为参数:imo 这样更具可读性......var x = something;x
0赞 stesch 2/27/2009
@Christoph:如果函数创建后“something”的值发生变化,则它将使用新值,而不是创建时的值。
0赞 Christoph 2/27/2009
@stesch:你从哪里得到的?据我所知,情况并非如此;在 JS 中获取真实引用的唯一方法是使用 arguments-object,但即使这样也不适用于所有浏览器
0赞 stesch 2/27/2009
@Christoph:《JavaScript: The Good Parts》,Douglas Crockford (O'Reilly)
0赞 Christoph 2/27/2009
@stesch:它不像你描述的那样工作:如果你删除变量并直接依赖于词法范围,将使用新值,即......xdocument.write(something)
33赞 M A Hossain Tonu 5/19/2010 #8

自我调用(也称为 auto-invocation) 是当函数 在其 定义。这是一个核心模式和 是许多人的基础 JavaScript 的其他模式 发展。

我是:)的忠实粉丝因为:

  • 它将代码保持在最低限度
  • 它强制将行为与演示分开
  • 它提供了一个闭包,可以防止命名冲突

非常 - (为什么你应该说它好?

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

更多内容请点击此处

评论

44赞 Erik Reppen 8/18/2012
第 1 点。如何?第 2 点。这是来自一个完全不同的最佳实践。第 3 点。什么功能没有?4,5,6,7. 相关性?8. 好吧,我猜 1/8 还不错。
3赞 ICW 3/3/2017
晚了七年,但对于第 1 点。它根本不会减少代码,实际上它在创建函数时至少添加了两行代码。
2赞 pcarvalho 12/19/2018
这里唯一的一点是“它提供了一个防止命名冲突的闭包”,每隔一点都是这个或错误的改写。也许你可以简化你的答案?
14赞 David W. Keith 4/13/2012 #9

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

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

基本上,功能块确保您定义的所有依赖“全局变量”都仅限于您的程序,它不能保护您免受定义隐式全局变量的影响。JSHint 等可以提供有关如何防御此行为的建议。

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

就属性而言,除非您正在创建公共框架或库,否则它们被高估了,但如果您需要实现它们,Douglas Crockford 有一些好主意。private

评论

8赞 Erik Reppen 8/18/2012
严格模式可防止隐含全局变量。这与自动调用器相结合,可以满足您的需求。我从来不理解对私人财产的喧嚣。在 func 构造函数中声明 vars。做。如果忘记使用“new”关键字的想法让您夜不能寐,请编写一个工厂函数。再做一次。
135赞 Sean Holden 5/9/2015 #10

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

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

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

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

因此,在您阅读的大多数教程中,您现在都会受到“匿名自动执行”或类似术语的轰炸。

经过多年的专业发展,我强烈建议您为调试目的而编写的每个函数都命名。

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

评论

4赞 viery365 9/20/2016
谢谢:) 我一直在搜索互联网,试图了解 IIFE 在可变隐私方面相对于正常功能的优势,您的答案简直是最好的。每个人都说,最好的优势之一是,当一个普通函数给你完全相同的东西时,IIFE中的变量和函数“最终”是私有的。最后,我想我通过你的解释过程得到了它。IIFE毕竟只是一个功能,但现在我明白了为什么要使用它。再次感谢!
2赞 MSC 10/1/2016
感谢您抽出宝贵时间解释这一点。
0赞 FireSBurnsmuP 4/7/2017
很好的答案。不过,我对你的最后一点有一个问题 - 当你建议所有函数都命名时,你是说有一种方法可以用自执行函数来做到这一点,还是建议每个人都命名函数然后调用它?编辑:哦,我明白了。这个已经命名了。咄。可能要指出的是,您正在证明使用命名的自执行函数是合理的。
2赞 João Pimentel Ferreira 12/4/2017
好吧,我的朋友,这就是我一直在寻找的答案:)
3赞 Vibhor Dube 6/18/2020
我总是喜欢 2 种类型的答案;(1.) 短小精悍,切中要害。(2.) 一个像解释一样的故事,永远留在你的大脑中。您的属于 (2.)
1赞 Kishor Vitekar 10/20/2015 #11

javascript 中的自调用函数:

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

6赞 sg.cc 11/20/2015 #12

下面是一个关于自我调用匿名函数如何有用的可靠示例。

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

评论

0赞 radio_head 11/30/2017
您能否解释一下第一组代码的情况
2赞 Vitaly Zdanevich 9/21/2018
代替第一种情况就可以了。letvar
0赞 Garrett 12/18/2016 #13

看起来这个问题已经准备好了,但我还是会发布我的意见。

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

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

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

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

一般来说,编码有很多晦涩难懂的方式来做很多同样的事情,让你想知道,“何必呢?但是,新的情况不断出现,您不能再仅依靠基本/核心原则。

1赞 Madhankumar 3/31/2017 #14
(function(){
    var foo = {
        name: 'bob'
    };
    console.log(foo.name); // bob
})();
console.log(foo.name); // Reference error

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

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

函数表达式中的变量和函数变为私有(即,它们在函数外部不可用。

13赞 user3025289 12/5/2017 #15

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

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

第一个已经解释得很好。对于第二个,请学习以下示例:

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

注意事项1:我们没有将函数赋值给 ,而是将函数赋值给 ,更不是函数赋值给 。请注意最后一行。MyClosureObject()

注意事项2:关于 Javascript 中的函数,您还需要了解的是,内部函数可以访问函数的参数和变量,它们是在内部定义的。

让我们尝试一些实验:

我可以开始使用并且它有效:MyNamegetMyName

 console.log(MyClosureObject.getMyName()); 
 // Michael Jackson RIP

以下巧妙的方法行不通:

console.log(MyClosureObject.MyName); 
// undefined

但是我可以设置另一个名称并获得预期的结果:

MyClosureObject.setMyName('George Michael RIP');
console.log(MyClosureObject.getMyName()); 
// George Michael RIP

编辑:在上面的示例中,它被设计为不带前缀使用,因此按照惯例,它不应该大写。MyClosureObjectnew

评论

1赞 Angela P 8/17/2021
你的回答是我第一次意识到可以 ( function(){ }( ) ) 代替问题的语法 (function(){ })();他们似乎取得了同样的结果。
2赞 Adeojo Emmanuel IMM 4/24/2018 #16

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

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

全局变量具有全局作用域;它在 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 代码块中的命名方式。

3赞 Donovan P 12/20/2019 #17

简短的回答是:防止全球(或更高)范围的污染。

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

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

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

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

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

评论

0赞 Ej. 12/21/2019
很好,我以前从未见过这种用法。我喜欢。void
2赞 SayAz 3/11/2020 #18

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

  • 这是立即调用的函数表达式。因此,当您的 javascript 文件从 HTML 调用此函数时,会立即调用。
  • 这样可以防止访问 IIFE 习语中的变量,也可以防止污染全局范围。
1赞 zentechinc 4/6/2020 #19

鉴于您的简单问题:“在 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,而且我不需要命名函数供以后使用,但需要等待该插入调用,或者我需要一些其他更丰富的功能(谁知道呢?

2赞 borma425 7/28/2021 #20

您可以使用此函数返回值:

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

评论

0赞 CodeGust 10/24/2023
我们可以把它用作库命名空间吗?
0赞 srt 9/13/2022 #21

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

评论

1赞 user16217248 9/18/2022
虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。- 来自评论