From 709613a950d489e6b26b05708dab7e64e7b07094 Mon Sep 17 00:00:00 2001 From: Kirk Waiblinger Date: Tue, 24 Dec 2024 13:34:27 -0800 Subject: [PATCH] lots of iife writeup --- files/en-us/glossary/iife/index.md | 100 +++++++++++++++--- .../operators/comma_operator/index.md | 3 +- 2 files changed, 86 insertions(+), 17 deletions(-) diff --git a/files/en-us/glossary/iife/index.md b/files/en-us/glossary/iife/index.md index 51ec1142139f450..f1e04cb48746a7d 100644 --- a/files/en-us/glossary/iife/index.md +++ b/files/en-us/glossary/iife/index.md @@ -6,45 +6,71 @@ 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. +An **IIFE** (Immediately Invoked Function Expression) is an idiom in which a {{glossary("JavaScript")}} {{glossary("function")}} runs as soon as it is defined. The name IIFE is promoted by Ben Alman in [his blog](https://web.archive.org/web/20171201033208/http://benalman.com/news/2010/11/immediately-invoked-function-expression/#iife). ```js +// standard IIFE (function () { - // … + // statements… })(); +// IIFE with arguments +(function (a, b) { + console.log(a + b); + return a * b; +})(1, 2); // logs 3. evaluates to 2. + +// arrow function variant (() => { - // … + // statements… })(); +// async IIFE (async () => { - // … + // statements… })(); + +// IIFE being used to initialize a variable +const value = (() => { + const randomValue = Math.random(); + if (randomValue > 0.5) { + return "heads"; + } else { + return "tails"; + } +}()); ``` 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. +1. A function _expression_. This usually needs to be [enclosed in parentheses](/en-US/docs/Web/JavaScript/Reference/Operators/Grouping) in order to be parsed correctly. + +2. Immediately _calling_ the function expression. Arguments may be provided, + though IIFEs without arguments are more common. + +IIFEs are a common pattern used to execute arbitrarily many statements in their own scope, in the place of an expression. +They are similar to, but much more powerful than, the [comma operator](/en-US/docs/Web/JavaScript/Reference/Operators/Comma_operator), which can only execute multiple expressions and, therefore, does not provide a way to use local variables or control flow statements. ## Use cases -### Avoid polluting the global namespace +### Avoid polluting the global namespace in script code -Because our application could include many functions and global variables from different source files, it's -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 -using a function declaration or a function expression. +Because our application could include many functions and global variables from different source files, it's 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)). +If we have some initialization code that we don't need to use again, we could use the IIFE pattern. +As we will not reuse the code again, using an IIFE in this case is better than using a function declaration or a function expression. ```js -(() => { - // some initiation code - let firstVariable; - let secondVariable; +// top-level of a script (not a module) + +var globalVariable = (() => { + // some initialization code + let firstVariable = something(); + let secondVariable = somethingElse(); + return firstVariable + secondVariable; })(); -// firstVariable and secondVariable will be discarded after the function is executed. +// firstVariable and secondVariable cannot be accessed outside of the function body. ``` ### Execute an async function @@ -152,9 +178,51 @@ console.log(i); // Uncaught ReferenceError: i is not defined. When clicked, these buttons alert 0 and 1. +### Control flow statements in expression positions + +IIFEs enable us to use language constructs such as `switch` in an expression. + +```js +someObject.property = (() => { + switch (someVariable) { + case 0: + return "zero"; + case 1: + return "one"; + default: + return "unknown"; + } +})(); +``` + +This approach can be especially useful in scenarios where you want to make a variable `const`, but +are forced to use `let` or `var` during initialization: + +```js +let onlyAssignedOnce; +try { + onlyAssignedOnce = someFunctionThatMightThrow(); +} catch (e) { + onlyAssignedOnce = null; +} +``` + +Using IIFEs, we can make the variable `const`: + +```js +const onlyAssignedOnce = (() => { + try { + return someFunctionThatMightThrow(); + } catch (e) { + return null; + } +})(); +``` + ## See also - [IIFE](https://en.wikipedia.org/wiki/Immediately-invoked_function_expression) (Wikipedia) +- [Comma Operator](/en-US/docs/Web/JavaScript/Reference/Operators/Comma_operator) - Related glossary terms: - {{Glossary("Function")}} - {{Glossary("Self-Executing Anonymous Function")}} diff --git a/files/en-us/web/javascript/reference/operators/comma_operator/index.md b/files/en-us/web/javascript/reference/operators/comma_operator/index.md index d97fb909670d1ca..079345d3606050d 100644 --- a/files/en-us/web/javascript/reference/operators/comma_operator/index.md +++ b/files/en-us/web/javascript/reference/operators/comma_operator/index.md @@ -24,7 +24,7 @@ expr1, expr2, expr3/* , … */ ## Description -You can use the comma operator when you want to include multiple expressions in a location that requires a single expression. The most common usage of this operator is to supply multiple updaters in a `for` loop. +You can use the comma operator when you want to include multiple expressions in a location that requires a single expression. The most common usage of this operator is to supply multiple updaters in a `for` loop. For an idiom allowing multiple _statements_ in a location that requires a single expression, you may use an [IIFE](/en-US/docs/Glossary/IIFE). Because all expressions except the last are evaluated and then discarded, these expressions must have side effects to be useful. Common expressions that have side effects are assignments, function calls, and [`++`](/en-US/docs/Web/JavaScript/Reference/Operators/Increment) and [`--`](/en-US/docs/Web/JavaScript/Reference/Operators/Decrement) operators. Others may also have side effects if they invoke [getters](/en-US/docs/Web/JavaScript/Reference/Functions/get) or trigger [type coercions](/en-US/docs/Web/JavaScript/Data_structures#type_coercion). @@ -148,3 +148,4 @@ globalThis.isDirectEval = false; ## See also - [`for`](/en-US/docs/Web/JavaScript/Reference/Statements/for) +- [IIFE](/en-US/docs/Glossary/IIFE)