Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improve IIFE docs #37361

Merged
merged 2 commits into from
Jan 4, 2025
Merged

improve IIFE docs #37361

merged 2 commits into from
Jan 4, 2025

Conversation

kirkwaiblinger
Copy link
Contributor

Description

Added examples of IIFE use cases, and made changes to confusing and misleading information.

Motivation

I was pointing a github user to the docs for IIFEs, since they were in a position where they were absolutely required to use multiple statements in a position that only accepted one, which is perfect use case for an IIFE, see marilari88/zod-playground#130 (comment) (and also marilari88/zod-playground#81). But when I looked at the docs page I had linked... I found it to be extremely difficult to understand, and didn't really address the use case I was referring to at all.

Additional details

Related issues and pull requests

@github-actions github-actions bot added Content:JS JavaScript docs Content:Glossary Glossary entries labels Dec 24, 2024
@kirkwaiblinger kirkwaiblinger changed the title lots of iife writeup improve IIFE docs Dec 24, 2024
@github-actions github-actions bot added the size/m [PR only] 51-500 LoC changed label Dec 24, 2024
Copy link
Contributor

github-actions bot commented Dec 24, 2024

Preview URLs

Flaws (18)

Note! 1 document with no flaws that don't need to be listed. 🎉

URL: /en-US/docs/Web/JavaScript/Reference/Operators/function
Title: function expression
Flaw count: 6

  • macros:
    • Wrong xref macro used (consider changing which macro you use). Error processing path /en-US/docs/Learn/Getting_started_with_the_web/JavaScript_basics
    • Wrong xref macro used (consider changing which macro you use). Error processing path /en-US/docs/Learn/JavaScript/First_steps
    • Wrong xref macro used (consider changing which macro you use). Error processing path /en-US/docs/Learn/JavaScript/Building_blocks
    • Wrong xref macro used (consider changing which macro you use). Error processing path /en-US/docs/Learn/JavaScript/Objects
    • Wrong xref macro used (consider changing which macro you use). Error processing path /en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks
    • and 1 more flaws omitted

URL: /en-US/docs/Web/JavaScript/Reference/Operators/async_function
Title: async function expression
Flaw count: 6

  • macros:
    • Wrong xref macro used (consider changing which macro you use). Error processing path /en-US/docs/Learn/Getting_started_with_the_web/JavaScript_basics
    • Wrong xref macro used (consider changing which macro you use). Error processing path /en-US/docs/Learn/JavaScript/First_steps
    • Wrong xref macro used (consider changing which macro you use). Error processing path /en-US/docs/Learn/JavaScript/Building_blocks
    • Wrong xref macro used (consider changing which macro you use). Error processing path /en-US/docs/Learn/JavaScript/Objects
    • Wrong xref macro used (consider changing which macro you use). Error processing path /en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks
    • and 1 more flaws omitted

URL: /en-US/docs/Web/JavaScript/Reference/Operators/Comma_operator
Title: Comma operator (,)
Flaw count: 6

  • macros:
    • Wrong xref macro used (consider changing which macro you use). Error processing path /en-US/docs/Learn/Getting_started_with_the_web/JavaScript_basics
    • Wrong xref macro used (consider changing which macro you use). Error processing path /en-US/docs/Learn/JavaScript/First_steps
    • Wrong xref macro used (consider changing which macro you use). Error processing path /en-US/docs/Learn/JavaScript/Building_blocks
    • Wrong xref macro used (consider changing which macro you use). Error processing path /en-US/docs/Learn/JavaScript/Objects
    • Wrong xref macro used (consider changing which macro you use). Error processing path /en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks
    • and 1 more flaws omitted
External URLs (1)

URL: /en-US/docs/Glossary/IIFE
Title: IIFE

(comment last updated: 2025-01-03 22:23:28)

@kirkwaiblinger kirkwaiblinger force-pushed the iife-docs branch 2 times, most recently from d2ffb51 to 3e917eb Compare December 24, 2024 22:01
@kirkwaiblinger kirkwaiblinger marked this pull request as ready for review December 24, 2024 22:03
@kirkwaiblinger kirkwaiblinger requested review from a team as code owners December 24, 2024 22:03
@kirkwaiblinger kirkwaiblinger requested review from Josh-Cena and hamishwillee and removed request for a team December 24, 2024 22:03
```

It is a design pattern which is also known as a {{glossary("Self-Executing Anonymous Function")}} and contains two major parts:

1. The first is the anonymous function with lexical scope enclosed within the [grouping operator](/en-US/docs/Web/JavaScript/Reference/Operators/Grouping) `()`. This prevents accessing variables within the IIFE idiom as well as polluting the global scope.
2. The second part creates the immediately invoked function expression `()` through which the JavaScript engine will directly interpret the function.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this was particularly incomprehensible to me

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed since it doesn't have to be anonymous or even enclosed within (). And the scope the function expression creates does not belong to the enclosing ():

const [uncleDavidStr, uncleDavidFunc] = function uncleDavidFunc() {
    return ['Uncle David', uncleDavidFunc];
}();
(uncleDavidFunc, function uncleDavidFunc() {
})(); // ReferenceError: uncleDavidFunc is not defined

@@ -6,45 +6,74 @@ page-type: glossary-definition

{{GlossarySidebar}}

An **IIFE** (Immediately Invoked Function Expression) is a {{glossary("JavaScript")}} {{glossary("function")}} that runs as soon as it is defined.
Copy link
Contributor Author

@kirkwaiblinger kirkwaiblinger Dec 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At first read, this sounds to me as a reader like

function implicitlyRunsImmediatelyForSomeReason() {}

rather than an explicit pattern.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks accurate.

important to limit the number of global variables. If we have some initiation code that we don't need to use
again, we could use the IIFE pattern. As we will not reuse the code again, using IIFE in this case is better than
important to limit the number of variables at the top level of a script
(this advice [does not apply to module code](/en-US/docs/Web/JavaScript/Guide/Modules#other_differences_between_modules_and_classic_scripts)).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think leaving out modules is a good idea, since it implies that it's okay to pollute the module scope (and pollute implies that the scope will keep variables that are no longer needed).

const year2000 = new Date('2000');
const currentDate = new Date();
export const isAfterYear2000 = currentDate > year2000;
export const isAfterYear2000 = (() => {
  const year2000 = new Date('2000');
  const currentDate = new Date();
  return currentDate > year2000;
})();

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a critical conceptual difference between "I want to avoid an intermediate variable for all the reasons you might ordinarily want to avoid an intermediate variable" and "if I create an intermediate variable here it will be a global variable" (which applies to top level of scripts only). My goal is to convey that difference.

Do you have a suggestion how I might communicate that better? I.e. to communicate that if it's not the top level of a script, this is still a useful pattern, but it doesn't solve nearly as catastrophic a problem as the script global variable problem.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't look necessary to mention modules when the focus is already on the global namespace. Though it's true the advice is more lenient with modules.

Copy link
Contributor

@60x20 60x20 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good without the exclusion of modules.

// IIFE being used to initialize a variable
const value = (() => {
const randomValue = Math.random();
if (randomValue > 0.5) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (randomValue > 0.5) {
if (randomValue >= 0.5) {

Nitpicking but for an even distribution, the true branch should include the 0.5 value.
Range for the false branch: 0 <= x < 0.5
Range for the true branch: 0.5 <= x < 1

@@ -6,45 +6,74 @@ page-type: glossary-definition

{{GlossarySidebar}}

An **IIFE** (Immediately Invoked Function Expression) is a {{glossary("JavaScript")}} {{glossary("function")}} that runs as soon as it is defined.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks accurate.

```

It is a design pattern which is also known as a {{glossary("Self-Executing Anonymous Function")}} and contains two major parts:

1. The first is the anonymous function with lexical scope enclosed within the [grouping operator](/en-US/docs/Web/JavaScript/Reference/Operators/Grouping) `()`. This prevents accessing variables within the IIFE idiom as well as polluting the global scope.
2. The second part creates the immediately invoked function expression `()` through which the JavaScript engine will directly interpret the function.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed since it doesn't have to be anonymous or even enclosed within (). And the scope the function expression creates does not belong to the enclosing ():

const [uncleDavidStr, uncleDavidFunc] = function uncleDavidFunc() {
    return ['Uncle David', uncleDavidFunc];
}();
(uncleDavidFunc, function uncleDavidFunc() {
})(); // ReferenceError: uncleDavidFunc is not defined

@Josh-Cena
Copy link
Member

This page is getting too long. In general glossary entries should try to be a few paragraphs. I will try to move this to the JS reference instead.

@Josh-Cena
Copy link
Member

Moved the examples around. @kirkwaiblinger @60x20 WDYT?

};
})(balance);

const firstAccount = makeWithdraw(100); // "I will do bad things with your money"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

neither here nor there really, but I really dislike this example

  • The specific code example is hard to follow and just.... weird 😆
  • I'm not sure this use pattern in general is that useful especially with #private class members these days. But I could be wrong about this

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a bit weird, but this is exactly how modules work, so I think it's still useful, at least not any less than the for loop scoping example below. We already said that "Many traditional use cases of IIFEs have been obsoleted by new syntax features such as modules and block-scoped declarations", so I'd like to keep this for now.

@kirkwaiblinger
Copy link
Contributor Author

@Josh-Cena I'm happy!

Copy link
Member

@Josh-Cena Josh-Cena left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Thanks a lot!

@Josh-Cena Josh-Cena merged commit 9a7e014 into mdn:main Jan 4, 2025
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Content:Glossary Glossary entries Content:JS JavaScript docs size/m [PR only] 51-500 LoC changed
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants