Forum Moderators: open

Message Too Old, No Replies

is jQuery's (function($) { . })($); irrelevant now?

         

csdude55

9:17 pm on Dec 11, 2022 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



I have a third party script that includes this at the top:

(function($) {
// do stuff
})($);

I couldn't find this exact thing in the docs, but I found this explanation:

... the interpreter will invoke the function immediately, and will pass jQuery as a parameter, which will be used inside the function as $

[stackoverflow.com...]

I'm not sure that I understand the purpose here. I'm assuming that the script would normally run as soon as it's loaded, anyway. And since I already load jQuery beforehand, I'm not sure if there's a need to pass jQuery as a $ parameter.

Is this something that is no longer necessary? I'm using jQuery version 3.3.1, so maybe this was just something that was needed in older versions?

robzilla

10:24 pm on Dec 11, 2022 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



We mostly have functions because they don't run immediately, but only when called upon. But they have other benefits, for example that variables created inside a function don't exist outside of it. So it can be helpful to use immediately invoked functions, e.g. when you're plugging something into existing websites with varied codebases, as this is a way to prevent overwriting any pre-existing variables.

Not sure of the benefit of passing $ to $, I'm more used to seeing the jQuery object passed to $, which could be a way to ensure that $ is, in fact, jQuery and not some other object or library.

csdude55

4:18 am on Dec 12, 2022 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



In this case, the third party script uses (function($) { ... })($); and then inside of it are a bunch of variables being set and other functions. So I think you're right, it's less about controlling when it runs and more about not accidentally overwriting variables.

Personally, I would have just use variables names that would have been highly unlikely to duplicate (like, instead of "var default" I might have used "var Script.Name.Default"). But I guess this way is actually better, just not as obvious to the less experienced user.

Fotiman

12:41 pm on Dec 12, 2022 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



From the stackoverflow link, you'll notice that the examples on that page pass in `jQuery` to the IIFE (Immediately Invoked Function Expression), as opposed to passing in `$`:

(function($) {
// do stuff
})(jQuery);

vs.

(function($) {
// do stuff
})($);

As robzilla mentioned, this is how you ensure that `$` is an alias to jQuery as opposed to some other library (like Prototype, for example), and might be preceded by `jQuery.noConflict();`. Your 3rd party script is doing it incorrectly if they're passing in `$` instead of `jQuery`, because that `$` may not be an alias to jQuery in the global scope.

And yes, the IIFE is one way to encapsulate variables within a function scope so they don't become global variables.

<!DOCTYPE html>
<body>
<button id="originalCounter">Original Counter</button>
<button id="contaimatingCounter">Contaminate</button>
<button id="safeCounter">Safe Counter</button>
<script>
var counter = 0; // this is going to live at the global scope
function incrementCounter() {
counter = counter + 1;
console.log(`originalCounter: ${counter}`);
}
document.querySelector('#originalCounter').addEventListener('click', incrementCounter);
</script>
<script>
var counter = 1; // this overwrites the value at the global scope
function contaminateCounter() {
counter = counter + 1;
console.log(`contaimatingCounter: ${counter}`);
}
document.querySelector('#contaimatingCounter').addEventListener('click', contaminateCounter);
</script>
<script>
(function () {
var counter = 0; // this is function scoped, not accessible outside of the IIFE
function incrementSafely() {
counter = counter + 1;
console.log(`safeCounter: ${counter}`);
}
document.querySelector('#safeCounter').addEventListener('click', incrementSafely);
})(); // immediately invoke this anonymous function, preventing contamination of the global scope
</script>
</body>

In that example, you'll see that the first 2 buttons both have side effects from the other button (view the console log to see it in action). Imagine these are both 3rd party scripts that you include on your page, intending to provide distinct functionality but not realizing that because they contaminate the global scope, they could break other functionality. The 3rd button has it's behavior defined within an IIFE, and therefore doesn't have the same vulnerability.

csdude55

6:36 pm on Dec 12, 2022 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Makes perfect sense! Thanks for the breakdown. I changed it from ($) to (jQuery), that has to be a logic error on their end.

One other question, they precede the function with a semicolon; eg,

;(function($) {

Is that just a safety net in case the previous code doesn't end with a semicolon? Or does it do something special?

Fotiman

10:26 pm on Dec 12, 2022 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



I believe that has to do with ensuring that concatenation of the code (when combining multiple files) doesn't cause problems if the file before this one contains something invalid. That is, the ; ensures any open statement ends before processing the code in this file.