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

时间:2009-02-26 20:53:52

标签: javascript closures iife self-executing-function

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

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

对此:

//Bunch of code...

20 个答案:

答案 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模式   发展。

我很喜欢它因为:

  • 将代码保持在最低限度
  • 强制执行行为与呈现分离
  • 它提供了一个阻止命名冲突的闭包

极其 - (为什么你应该说它好?)

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

更多here

答案 3 :(得分:19)

命名空间。 JavaScript的范围是功能级别。

答案 4 :(得分:12)

我无法相信没有提到暗示全局的答案。

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

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

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

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

  1. 更好的命名空间管理(避免命名空间污染 - &gt; JS模块)
  2. 闭包(模拟私人类成员,如OOP所知)
  3. 第一个问题得到了很好的解释。对于第二个,请研究以下示例:

    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,现在有关此点

  • 这是立即调用的函数表达式。因此,当您的JavaScript文件从HTML调用时,此函数会立即调用。
  • 这可以防止在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它允许您创建私有属性和方法。