Javascript - 自执行函数:如果我可以使用非自执行函数创建本地作用域,为什么要使用它们?

时间:2017-09-21 09:04:48

标签: javascript self-executing-function

我知道这里和其他地方有很多关于自我执行功能的帖子,但在阅读帖子后我还有一些问题。

  1. 为什么我会为变量分配一个自执行函数?如果看起来他们仍然执行自己。

    (a = b or a = c) and d = e
    
  2. 我读了很多,使用自执行函数的原因是保持变量私有。如果我有一个不自动执行的功能,我在该功能中定义的所有东西都会是私有的吗?!

    var myFunc=(function() {
     console.log('Hello World');
    })();
    
  3. 所以我不太明白自动执行函数如何保持局部范围(因为你可以使用非自动执行的函数),所以我看到的唯一原因就是当你想自动执行时使用它们,例如on页面加载。

    谢谢!

    还有一个问题:

    (function() {
     var name="my Name"
     console.log(name);
    })();
    
    vs.
    
     function() {
     var name="my Name"
     console.log(name);
     };
     //its the same
    

    - >这里到底发生了什么,因为IIFE我实际上可以执行test.test1()而不是常规函数?

8 个答案:

答案 0 :(得分:1)

  1. 如果那个IIFE没有返回任何东西,那么将它分配给任何东西确实没用。虽然当然可能会有一些IIFE返回你想要使用的东西的例子;在这种情况下,IIFE是设置某个对象的私有范围,例如:

    var foo = (function () {
        var bar = 'something';
        // here be dragons
        return baz;
    })();
    

    这为您提供了一个私有范围来汇集baz,而不会不必要地将临时变量泄漏到全局范围内。

  2. 这些例子没有区别,只是第二个没有执行,因此从不做任何事情。范围界定和范围的目的不变。

答案 1 :(得分:1)

当您想要保持范围时,通常将函数包装在匿名函数中。这也是模块模式的一部分,它仍然很受欢迎:

https://toddmotto.com/mastering-the-module-pattern/

然后,您可以将IIFE的结果分配给变量,这样只能通过调用该变量来访问您的范围。

myScope.myLocallyScopedProperty or myScope[myLocallyScopedProperty]

您的其他功能需要手动调用,也可以从任何地方访问。

我建议阅读Todd Moto的文章,它解释了很多。

答案 2 :(得分:1)

首先,简单地说,这些不是自动执行的功能。 (这将是一个递归函数。)这些是内联调用的函数表达式(IIFE)。 函数不调用自身,表达式调用函数。

  

为什么我要为变量分配一个自执行函数?

这不是代码所做的。它将调用IIFE的结果分配给变量。你想要那个结果时使用它,例如:

var x = (function() {
    var n = 0;
    return {
        increment: function() { return ++n; }
    };
})();
console.log(typeof x); // "object"
console.log(x.increment()); // 1
console.log(x.increment()); // 2

x没有收到IIFE,它会收到IIFE 返回的内容 - 在这种情况下,是一个带有函数的对象。

  

我读了很多,使用自执行函数的原因是保持变量私有。如果我有一个不自动执行的功能,我在该功能中定义的所有东西都会是私有的吗?!

是的,那是真的。当您只需要在IIFE 内执行时,您就可以使用IIFE。否则,绝对地,您定义函数,为其命名,然后在需要的地方重复使用它。函数内部的变量确实是私有的(除非以某种方式暴露),并且特定于每次调用函数。

答案 3 :(得分:1)

  

以IIFE(或立即调用的函数表达式)的形式,它们可以是used to create pluginsused as namespaces并附加到window / jquery /或其他全局级别对象以供稍后使用。

当您为一个变量分配匿名函数这样的函数时,您可以稍后通过使用括号调用变量来使用它,在您的示例中,使用

定义myFunc
var myFunc=(function() {
 console.log('Hello World');
}); 

稍后在代码myFunc()中使用它;

在您的示例中,您将函数的输出直接存储在变量中,通过立即调用它,并且不存储任何输出。

因此,如果您稍后写console.log(myFunc);,则输出undefined

您的代码示例中更好的IIFE示例如下所示。

(function() {
 var name="my Name"
 console.log(name);
})();

执行,执行console.log,然后执行。在您的情况下,不向名称空间或全局对象添加任何内容。

您的最后一个示例定义了一个函数,然后不执行它,并且由于它没有分配命名变量或名称,因此它会出现语法错误,以后不能在代码中使用。所以,下面的例子是没用的。

function() {
 var name="my Name"
 console.log(name);
 };

您已使用var test = function myFunc添加了两个示例。第一个可以与test.test1()一起使用。对于第二个,您需要首先将test评估为函数,然后调用其函数,如test().test1()

答案 4 :(得分:1)

1:将IIFE分配给局部变量对于类似的东西是有意义的:

var getID = (function () {
  var id = 0;
  return function () { return id++; };
})();

通过这种方式,除了通过重新声明变量之外,您可以获得新ID,而不会冒险从代码中的任何其他位置重置内部计数器。

2:基本上你通过创建一个函数来创建Scope。但如果你不执行它,那么它就什么都不做。所以如果你有:

function () { return 'foo' };

如果未分配给变量或没有名称,您想如何调用它?它本身不会做任何事情,因为它没有被调用。像这样的东西是死代码,可以安全地删除。

答案 5 :(得分:1)

你的第一件事没有任何意义:

var myFunc = =(function() {
       console.log('Hello World');
    })();

myFunc不是函数,而是undefined

正如我所看到的,自我执行功能的意义是打包一些必须立即执行的代码。

var p1=1, p2=2, obj = {
   prop: (function(x,y){ return x+y;})(p1, p2)
}

如果你喜欢,你的脚本将插入已经存在的应用程序并创建一种私有方法,避免覆盖已经定义的函数/对象:



function aFunction() {
  console.log('a code');
}
(function(w) {
  function aFunction() {
    console.log('b code');
  }
  w.run = function() {
    aFunction();
  };
})(window)
aFunction();
run();




答案 6 :(得分:1)

使用自执行函数仅显示范围内所需的内容。我想我有一个明显的例子:

let myObject = (function(){
  let privateVariable = "I'm private";
  function privateMethod() {
    //private method
  };
  function methodToExpose() {
    //this method I will expose
  }

  //what is returned here, is what is public
  return {
    PublicMethod: methodToExpose
    //other public properties
  }
}());

因此,该函数立即执行,发生的事情是我有一个由我从函数返回的对象定义的对象。

我可以给你的另一个例子是在闭包内保留当前作用域的变量,但你不会真正使用它,因为我们现在有let。一个实际的例子:

<span id="1">old</span>
<span id="2">old</span>
<span id="3">old</span>
<span id="4">old</span>
<script>
var toPrint = "";
for (var i = 1; i <= 4; i++) {
  toPrint = "new: " + i;
  document.getElementById(i.toString()).addEventListener('click', function(event){ event.target.innerHTML = toPrint; })
}

</script>

单击某个范围时,该值将替换为值“... new:4”! 那是因为当你完成执行时,这就是toPrint的价值。分配给click事件的函数检索toPrint,并在检索它时,它是“new:4”。我们用闭包来解决这个问题:

<span id="1">old</span>
<span id="2">old</span>
<span id="3">old</span>
<span id="4">old</span>
<script>
var toPrint = "";
for (var i = 1; i <= 4; i++) {
  toPrint = "new: " + i;
  document.getElementById(i.toString()).addEventListener('click', function(event){ 
    var currPrint = toPrint;
    return function(event){ event.target.innerHTML = currPrint ; };
  }())
}

</script>

通过使用自执行功能,我们将toPrint的当前值保存在本地范围内的currPrint变量中。当我们稍后点击一个跨度时,分配给click的函数甚至会使用变量currPrint,它包含toPrint在分配函数时所具有的值,而不是toPrint在完成执行时的值。

请注意,这也是通过使用let而不是var来解决的,但它仍然是自执行函数的一个示例:)

答案 7 :(得分:0)

我猜你错过了什么。只是为了使基本的事情清楚 - 如果你将一个自执行的函数赋给变量,那么当执行时函数的实际return value被赋给变量而不是函数本身。

var myFunc = (function() {
    console.log('Hello World');
})();
myFunc(); // will throw error: TypeError: myFunc is not a function
myFunc === undefined

var myFunc = (function() {
    console.log('Hello World');
    return 'japp';
})();
myFunc(); // will throw error: TypeError: myFunc is not a function
myFunc === 'japp'

那么为什么这种模式会出现?

IIFE对

非常有用
  • 限制范围 如果你宣布

    var test = 'test'; // var test actually will be assigned as a property of the current context (this)
    window.test = 'test'; // so you pollute the global namespace which is not a good practice
    

    所以这将是更好的

    (function() {
        var test = 'test';
    })();
    
  • IIF的另一个非常好的方法是你可以用&#34; privates&#34;

    来实现设计
    var myFunc;
    (function() {
        var i = 0; // i is available for myFunc with private access
        myFunc = function() { console.log( ++i ) };
    })();
    myFunc(); // logs 1
    myFunc(); // logs 2