2

I have previously read:

What is the benefit of wrapping angular controller/service/factory declarations in an anonymous function

Are there any benefits to wrapping angular javascript file with the "(function() { ....[js code here]...... })();"

Neither address my question. When it comes to wrapping JavaScript in IIFE blocks, I have seen this:

(function (window, angular, undefined) {
'use strict';

angular.doSomething();

// more code here
})(window, window.angular);

and also this:

(function () {
'use strict';

angular.doSomething();

// more code here
})();

Obviously, angular is defined in the global space, however what are the benefits or drawbacks of the first approach over the second? JavaScript will pass angular by reference anyway. Is there any performance, scope security gains or is it simply beneficial for code minification?

Community
  • 1
  • 1
samazi
  • 1,161
  • 12
  • 24
  • *simply beneficial for code minification*. This. It saves 6 chars per `angular` reference. There's no reason to not do this if IIFE is already being used. – Estus Flask Jul 02 '16 at 14:22
  • @estus great, so we are talking about code optimization. I wonder why all the examples I saw about using IIFE with angular seem to use the second example...Maybe I missed some – samazi Jul 02 '16 at 14:26
  • The second example is easier to follow, I guess it's the reason why it may be used for learning purposes. – Estus Flask Jul 02 '16 at 14:28
  • You'd have to ask the authors of those examples I'm afraid, not us :-). (I'd hazard a guess though that it's because (a) it can be confusing/distracting for newbies, and (b) requires some extra work that's just not worth it in an example.) – Jeroen Jul 02 '16 at 14:29
  • Only real benefit is if somewhere later in other code someone does something wierd like `delete window.angular`. – charlietfl Jul 02 '16 at 14:34
  • Yeah, that makes sense. I definitely prefer the first way for readability, and specificity. – samazi Jul 02 '16 at 14:35
  • @charlietfl can you elaborate a bit? what will the IIFE block be able to see if that action completes? – samazi Jul 02 '16 at 14:38
  • @charlietfl If there is some code that does this, this IIFE is the smallest problem. Third party code relies on `angular` global. – Estus Flask Jul 02 '16 at 14:39
  • It will have already passed in the reference so if it was overwritten or deleted later it wouldn't matter – charlietfl Jul 02 '16 at 14:40
  • @charlietfl so calling delete only deleted it from that object, any existing references will still have access to the object. Nice. – samazi Jul 02 '16 at 14:43
  • @SandorA exactly...or if another version happened to get loaded and overwrite the version you wanted to use – charlietfl Jul 02 '16 at 14:45
  • @charlietfl awesome, so code security is a benefit then. – samazi Jul 02 '16 at 14:47
  • Thats all. minification is irrelevant with these globals which is why using second version will work fine – charlietfl Jul 02 '16 at 14:48

1 Answers1

1

From your list, only code minification purposes are relevant, the other two aren't.

There's one more potential benefit though. Consider a document that loads angular, then your script, and then another script. The final script could change angular in the global namespace (loading a newer version, or something malicious even) at a later time, causing your code to behave erratically.

Here's an example:

////////////////////
// 1. Angular is loaded directly.

////////////////////
// 2. Your code:
(function() {
  'use strict';
  
  window.setInterval(function() {
    console.log(angular.version.full);
    document.write(angular.version.full + "<br>");
  }, 1000);

  // more code here
})();

////////////////////
// 3. Another snippet/library:
window.setTimeout(function() {
  window.angular = { version: { full: "muhahaha!" } };
}, 2500);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>

The "muhahahas" would not appear with the other variant:

////////////////////
// 1. Angular is loaded directly.

////////////////////
// 2. Your code:
(function(window, angular) {
  'use strict';
  
  window.setInterval(function() {
    console.log(angular.version.full);
    document.write(angular.version.full + "<br>");
  }, 1000);

  // more code here
})(window, window.angular);

////////////////////
// 3. Another snippet/library:
window.setTimeout(function() {
  window.angular = { version: { full: "muhahaha!" } };
}, 2500);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
Jeroen
  • 60,696
  • 40
  • 206
  • 339
  • shouldn't you be passing in window.angular in the second example? How is this being isolated? Why don't the two references point to the same object anymore? – samazi Jul 02 '16 at 14:48
  • Ah, yes, I'll update, sending in `window.angular` is probably somewhat better, instead of just assuming it's in the global namespace. - At any rate, in *this* example it still works, as you can tell from the difference between the output from both examples. – Jeroen Jul 02 '16 at 14:55
  • I can see that it works, I am just not sure why it works. I thought JavaScript was pass-by-reference for Objects (angular is an object??) so why in the second example is it not affected? – samazi Jul 02 '16 at 15:00
  • In the second example, the function argument will create a variable within the local function scope with the same name as the "`angular`" variable that is accessible in the global namespace (or more precisely through `window.angular`). The function argument is a variable that *hides* the global one with the same name. – Jeroen Jul 02 '16 at 15:03
  • 1
    Ok, so as in the comments above, this will prevent someone removing or overwriting angular later on since all we are really talking about is the IIFE creating its own reference to the global instelf of relying on the global itself. I think though, if your setTimeout was to run window.angular.version.full = "muhahaha!"; then the change would be seen in the IIFE? – samazi Jul 02 '16 at 15:23
  • Aye. And proper tooling would warn you that the function argument named "`angular`" is unused :-) – Jeroen Jul 02 '16 at 16:09