Javascript - self-executing functions : why to use

2019-06-10 04:36发布

问题:

I know there are a lot of posts here and elsewhere about selfexecuting functions but I still have some questions after reading posts.

  1. why would I ever assign a self-executing function to a variable? If seems that they execute themselves anyways.

    var myFunc=(function() {
     console.log('Hello World');
    })();
    
  2. I read a lot that the reason to use self-executing functions is to keep variables private. If I have a not self-executing function, everything I define inside that function is gonna be private anyways?!

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

So I dont quite understand how self-executing functions are to keep local scope (as you can do that using not self-executing functions) so the only reason I see is to use them when you want to execute automatically for example on page load.

Thanks!

just one more question:

var test=(function myFunc(){
      var name="Hello World"
      return {
        test1: function(){
          return name;
        },
        test2:function(){
          return name+"1"
        }
      }
    })()

    test.test1()

vs

    var test=function myFunc(){
      var name="Hello World"
      return {
        test1: function(){
          return name;
        },
        test2:function(){
          return name+"1"
        }
      }
    }

    test.test1()

--> what exactly happens here that because of IIFE I can actually execute test.test1() and not with a regular function?

回答1:

You usually wrap your functions in a anonymous function when you want to keep your scope contained. This is also part of the module pattern which is still pretty popular:

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

Then you can assign the outcome of that IIFE to a variable so your scope can only be accessed by calling that variable.

myScope.myLocallyScopedProperty or myScope[myLocallyScopedProperty]

Your other function needs to be called manually and it also accessible from anywhere.

I suggest reading the article by Todd Moto it explains a lot.



回答2:

  1. If that IIFE doesn't return anything, then there's indeed absolutely no use to assign it to anything. Though there may of course be examples of IIFEs returning something you want to use later; in that case the IIFE is a private scope to set up some object for example:

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

    This gives you a private scope to assemble baz without unnecessarily leaking temporary variables into the global scope.

  2. There's no difference in those examples, except that the second one doesn't execute and therefore never does anything. Scoping and the purpose for the scoping are unchanged.



回答3:

First, briefly, these are not self-executing functions. (That would be a recursive function.) These are inline-invoked function expressions (IIFEs). The function doesn't call itself, the expression calls the function.

why would I ever assign a self-executing function to a variable?

That's not what that code does. It assigns the result of calling the IIFE to the variable. You'd use it when you want that result, for instance:

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 doesn't receive the IIFE, it receives what that IIFE returns — in this case, an object with a function on it.

I read a lot that the reason to use self-executing functions is to keep variables private. If I have a not self-executing function, everything I define inside that function is gonna be private anyways?!

Yes, that's true. You use an IIFE when you only need to do what's inside the IIFE once. Otherwise, absolutely, you define the function, give it a name, and then reuse it wherever you need it. The variables inside the function are indeed private to it (unless exposed in some way), and are specific to each call to the function.



回答4:

1: To assign an IIFE to a local Variable makes sense for something like that:

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

This way you can get new IDs without running the risk to reset the internal counter from anywhere else in the code, except by redeclaring the variable.

2: Basically you create Scope by creating a function. But if you do not execute it, well, it doesn't do anything. So if you have that:

function () { return 'foo' };

How do you want to call it if it is not assigned to a variable or does not have a name? By itself it wont do anything, since it is not called. Something like that is dead code and can safely be removed.



回答5:

your first thing has no sense whatsoever:

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

myFunc is not a function and it is undefined.

The sense, as I see it, for a self executing function is to package some code that has to be executed right away.

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

OR avoiding overwriting already defined functions/objects in the case your script will be inserted in a already existing application and also creating a kind of private methods, if you like:

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



回答6:

You use self executing functions to expose only what you need out of a scope. I think I have a somewhat clear example:

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

So, the function gets executed immediately, and what happens is I have an object that is defined by what I returned from the function.

Another example I could give you is to retain variables of the current scope inside a closure, but you wouldn't really use it that much, since we now have let. A practical example:

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

When you click on a span, the value will be replaced with the value... "new: 4"! That's because when you finished executing, that's the value that toPrint has. The function assigned to the click event retrieves that toPrint, and at the time it retrieves it, it is "new: 4". We solve this with closures:

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

By using a self executing function, we save the current value of toPrint in the currPrint variable inside a local scope. When we later click on a span, the function assigned to the click even will use the variable currPrint, which contains the value that toPrint had at the time the function was assigned, not the value that toPrint has at finished execution.

Note that this is solved also by using let instead of var, but still, it's an example of self-executing functions :)



回答7:

In the form of IIFE (or immediately invoked function expressions), they can then be used to create plugins or used as namespaces and attached to window / jquery / or other global level object for use later.


When you name a function like assigning anonymous function to a variable, you can use it later by calling the variable with parentheses, in your example, defined myFunc with

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

Use it later in code as myFunc();

In your example, you are storing the output of function directly in variable, by calling it immediately, and there is no output to be stored.

So, if you later write console.log(myFunc);, there is undefined as output.


Better IIFE example from your code samples is the one mentioned below.

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

It executes, does a console.log and that's it. Adds nothing to namespace or the global object in your case.


The last of your examples defines a function, does not execute it then, and since it does not have a named variable assigned, or a name, it gives syntax error and cannot be used later in code. So, below example is useless.

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

You have added two more examples with var test = function myFunc. First one will work fine with test.test1(). For the second one, you need to evaluate test as a function first and then call its function, like test().test1().



回答8:

I guess you miss something here. Just to make basic things clear - if you assign a self executed function to a variable the actual return value of the function when executed at this time is assigned to the variable and not the function itself.

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'

So why is this pattern around?

IIFEs are very useful to

  • limit the scope if you declare

    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
    

    so this would be mouch better

    (function() {
        var test = 'test';
    })();
    
  • another very good thigs with IIFs is that you can achieve a design with "privates"

    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