Dom Mastery
What is the DOM?
The Document Object Model (DOM) is a programming interface for HTML and XML documents. It represents the structure of a document as a tree-like model, where each element in the document is a node in the tree.
The DOM provides a way to interact with and manipulate the content, structure, and style of a web page.
Understanding the Tree Structure of the DOM
The DOM tree structure represents the hierarchical relationship of elements in an HTML document. It consists of various types of nodes.
Node Types
The most common types of nodes encounters when working with HTML documents are :
- ➡️ DOCUMENT_NODE
- 🔖 (window.document)
- ➡️ ELEMENT_NODE
- 🔖 (body, a, p, script, style, html, h1 etc…)
- ➡️ ATTRIBUTE_NODE
- 🔖 (class=“funEdges”)
- ➡️ TEXT_NODE
- 🔖 (text characters in an html document including carriage returns and white space)
- ➡️ DOCUMENT_FRAGMENT_NODE
- 🔖 (document.createDocumentFragment())
- ➡️ DOCUMENT_TYPE_NODE
- 🔖 ()
- [!] … The tree starts with the document node as the root and branches out to its child nodes, forming a parent-child relationship.
The Node and their numerical representation
All node are represented by a given numerical value in the DOM. Some examples
Interface/Constructor: nodeType (returned from .nodeType): HTMLElement, (e.g. HTMLBodyElement) = 1 (i.e. LEMENT_NODE)| Text = 3 (i.e. TEXT_NODE)| Attr = 2 (i.e. ATTRIBUTE_NODE)| HTMLDocument = 9 (i.e. DOCUMENT_NODE)| DocumentFragment = 11 (i.e. DOCUMENT_FRAGMENT_NODE)| DocumentType = 10 (i.e. DOCUMENT_TYPE_NODE)|
Overview Of key aspects of the dom
- 🔥 DOM Structure:
- 🔖 The DOM represents the structure of an HTML or XML document as a tree of nodes. Each element, attribute, and text in the document is represented by a node object. The DOM tree starts with the root node, usually the
document
object, and branches out to form parent-child relationships.
- 🔖 The DOM represents the structure of an HTML or XML document as a tree of nodes. Each element, attribute, and text in the document is represented by a node object. The DOM tree starts with the root node, usually the
- 🔥 Accessing Elements:
- 🔖 You can access elements in the DOM using methods like
getElementById()
,querySelector()
, orgetElementsByTagName()
and more… These methods allow you to select specific elements based on their ID, CSS selectors, or tag names.
- 🔖 You can access elements in the DOM using methods like
- 🔥 Modifying Elements:
- 🔖 Once yu have a reference to an element, you can modify its properties, such as
textContent
,innerHTML
, orsetAttribute()
, to change its content, structure, or attributes. You can also add or remove CSS classes using theclassList
property.
- 🔖 Once yu have a reference to an element, you can modify its properties, such as
- 🔥 Creating and Removing Elements:
- 🔖 The DOM provides methods like
createElement()
,createTextNode()
, andappendChild()
to create new elements, text nodes, and append them to existing elements. You can also remove elements using methods likeremoveChild()
or the newerremove()
method.
- 🔖 The DOM provides methods like
- 🔥 Handling Events:
- 🔖 Events allow you to respond to user interactions or other actions in the browser. You can attach event listeners to elements using methods like
addEventListener()
, and specify functions to be executed when the event occurs. Common events include click, submit, mouseover, etc.
- 🔖 Events allow you to respond to user interactions or other actions in the browser. You can attach event listeners to elements using methods like
- 🔥 DOM Traversal:
- 🔖 You can traverse the DOM tree using properties like
parentNode
,childNodes
,firstChild
,nextSibling
, etc., to navigate between elements and access their siblings, parents, or children.
- 🔖 You can traverse the DOM tree using properties like
- 🔥 CSS and Styles:
- 🔖 You can manipulate CSS styles of elements using properties like
style
to access or modify inline styles. Alternatively, you can add or remove CSS classes using theclassList
property.
- 🔖 You can manipulate CSS styles of elements using properties like
- 🔥 Dynamic Updates:
- 🔖 The DOM allows you to update elements dynamically based on user interactions, data changes, or other events. By modifying the DOM, you can create dynamic web applications and provide a rich user experience.
- 🔥 Performance Considerations:
- 🔖 Manipulating the DOM can be an expensive operation in terms of performance. It’s important to optimize your code by minimizing DOM access, batch operations, and using techniques like event Event Delegation to improve performance.
DOM Nodes and Elements
Consider the following HTML snippet:
- [/] DOM Nodes:
- 🔖 Nodes are the fundamental building blocks of the DOM. Each node represents an element, attribute, or text within the document. Nodes have properties and methods that allow manipulation and traversal of the DOM tree.
- [/] Element Nodes:
- 🔖 Element nodes represent HTML elements in the DOM tree. They have properties and methods specific to elements, allowing access and modification of attributes, content, and style.
- 💡 Element nodes represent HTML elements in the DOM tree.
- 💡 They are the building blocks of the DOM structure.
- 💡 Each opening and closing tag in the HTML creates an element node.
- 💡 Element nodes can have attributes, child nodes, and text content.
- 💡 In the example above, the
<div>
and<span>
elements are element nodes.
- 🔖 Element nodes represent HTML elements in the DOM tree. They have properties and methods specific to elements, allowing access and modification of attributes, content, and style.
- [/] Text Nodes:
- 🔖 Text nodes represent the textual content within an element. They store the actual text content and can be accessed and modified accordingly.
- 💡 Text nodes represent the textual content within an element.
- 💡 They contain the actual text within an HTML element.
- 💡 Text nodes are children of element nodes.
- 💡 In the example above, the text ”Hello, ” and ”world!” are text nodes.
- 💡 Note that white spaces, line breaks, and even HTML comments are also represented as text nodes.
- 🔖 Text nodes represent the textual content within an element. They store the actual text content and can be accessed and modified accordingly.
- [/] Attribute Nodes:
- 🔖 Attribute nodes represent the attributes of an element. They contain information about the element’s properties, such as ID, class, or custom attributes.
- 💡 Attribute nodes represent the attributes of an HTML element.
- 💡 They contain key-value pairs that provide additional information about an element.
- 💡 Attribute nodes are part of an element node and are not separate nodes in the DOM tree.
- 💡 In the example above, the id and class attributes of the
<div>
element are attribute nodes.
- 🔖 Attribute nodes represent the attributes of an element. They contain information about the element’s properties, such as ID, class, or custom attributes.
Let's see an example JavaScript code that demonstrates accessing these different node types:
Properties and methods for working nodes
All node objects (e.g Element, Attr, Text etc…) inherit properties and methods from a primary Node object. These properties and methods are the baseline values and functions for manipulating, inspecting, and traversing the DOM
Node Properties:
- ➡️ childNodes
- ➡️ firstChild
- ➡️ lastChild
- ➡️ nextSibling
- ➡️ nodeName
- ➡️ nodeType
- ➡️ nodeValue
- ➡️ parentNode
- ➡️ previousSibling
Node Methods:
- ➡️ appendChild()
- ➡️ cloneNode()
- ➡️ compareDocumentPosition()
- ➡️ contains()
- ➡️ hasChildNodes()
- ➡️ insertBefore()
- ➡️ isEqualNode()
- ➡️ removeChild()
- ➡️ replaceChild()
Document Methods
- document.createElement()
- document.createTextNode()
HTML * Element Properties:
- ➡️ innerHTML
- ➡️ outerHTML
- ➡️ textContent
- ➡️ innerText
- ➡️ outerText
- ➡️ firstElementChild
- ➡️ lastElementChild
- ➡️ nextElementChild
- ➡️ previousElementChild
- ➡️ children
HTML element Methods:
- ➡️ insertAdjacentHTML()
Loading JS in our browser
There are multiple ways to load JavaScript code in a web browser. Here are some common methods:
1. Inline Script
JavaScript code can be included directly within an HTML file using the <script>
tag. This approach is simple and suitable for small code snippets.
Here’s an example:
2. External Script
JavaScript code can be placed in an external JavaScript file with a .js
extension and then included in an HTML file using the <script>
tag. This method allows for better code organization and reuse.
Here’s an example:
3. Asynchronous Script Loading
Adding the async
attribute to the <script>
tag allows the JavaScript file to load asynchronously while the rest of the HTML content continues to load. This can help improve page loading speed.
Here’s an example:
4. Deferred Script Loading
Adding the defer
attribute to the <script>
tag also loads the script asynchronously, but it maintains the order of execution in relation to other scripts and the DOM Content Loaded event. This can be useful when script dependencies need to be maintained.
Here’s an example:“
5. Dynamic Script Loading
JavaScript code can be loaded dynamically using JavaScript itself. This is done by creating a new <script>
element and appending it to the DOM. This method is useful when scripts need to be loaded based on certain conditions.
Here’s an example:
6. Module Scripts
JavaScript modules can be loaded using the <script type="module">
tag. This approach allows for modular code organization and supports features like import
and export
.
Here’s an example:
These are some of the commonly used methods for loading JavaScript in web browsers. The choice of method depends on factors such as script size, dependencies, execution order, and loading behavior.
The windows object in JS
In JavaScript, the window
object represents the global window or browser context. It is an important object that provides access to various properties, methods, and events related to the browser window or tab.
Here’s some information about the window
object:
- [/] Global Scope:
- 🔖 The
window
object serves as the global scope for JavaScript in a browser environment. Variables and functions declared outside of any function or block scope are attached to thewindow
object and can be accessed globally.
- 🔖 The
- [/] Browser Information:
- The
window
object provides properties to access information about the browser and the current window, such aswindow.location
for the URL of the current page,window.navigator
for information about the browser and user agent, andwindow.document
for the document object representing the current HTML document.
- The
- [/] Methods for Interacting with the Window: The
window
object provides methods to interact with the browser window, such aswindow.alert()
for displaying an alert dialog,window.prompt()
for displaying a prompt dialog, andwindow.confirm()
for displaying a confirmation dialog. These methods allow you to interact with the user and gather input. - [/] Timers: The
window
object includes methods for creating timers and executing code at specified intervals, such aswindow.setTimeout()
andwindow.setInterval()
. These methods are used for scheduling code execution after a certain delay or repeatedly at a specified interval. - [/] Handling Events: The
window
object supports event handling through methods likewindow.addEventListener()
andwindow.removeEventListener()
. These methods allow you to register event listeners for various events likeclick
,load
,scroll
, and more. - [/] Frames and Windows: The
window
object provides properties and methods to work with frames and windows, such aswindow.frames
to access the collection of frames within a window,window.open()
to open a new browser window or tab, andwindow.close()
to close the current window or tab. - [/] Global Object: In JavaScript, the
window
object serves as the global object in the browser environment. This means that properties and methods defined on thewindow
object are accessible globally. For example, you can access theconsole
object aswindow.console
, theMath
object aswindow.Math
, and so on.You don't really have to use window.function because by default js asume that you are using the window and knows what you mean, instead of window.alert() or window.console.log() you can just omit the window object
Essential objects and properties available on the window
object:
window.document
: Represents the DOM document object, allowing access to the HTML structure and content of the current page.window.navigator
: Provides information about the user’s browser and operating system, including properties likenavigator.userAgent
andnavigator.platform
.window.location
: Allows manipulation of the URL and provides information about the current page’s URL, such aslocation.href
,location.hostname
, andlocation.reload()
.window.localStorage
andwindow.sessionStorage
: Allow storage of key-value pairs locally in the browser. They provide methods likesetItem()
,getItem()
, andremoveItem()
for data storage and retrieval.window.setTimeout()
andwindow.setInterval()
: Enable the scheduling of timers to execute functions after a specified delay or at regular intervals.window.alert()
,window.prompt()
, andwindow.confirm()
: Display dialog boxes to interact with the user, showing messages, requesting input, or asking for confirmation.window.open()
: Opens a new browser window or tab with a specified URL and optional settings.window.close()
: Closes the current browser window or tab programmatically.window.history
: Provides control over the browser’s session history, allowing navigation back and forth using methods likehistory.back()
,history.forward()
, andhistory.go()
.window.scrollTo()
andwindow.scroll()
: Allow scrolling the window to a specific position or to an element on the page.
Document object
#DOM
In JavaScript, the document
object represents the HTML document loaded in the browser. It provides an interface to interact with the elements, styles, and structure of the web page.
- [/] Accessing Elements:
- 🔖 The
document
object provides methods to access and manipulate elements in the HTML document. Common methods includedocument.getElementById()
to retrieve an element by its uniqueid
,document.getElementsByClassName()
to retrieve elements by their class names, anddocument.querySelector()
document.querySelectorAll()
to select elements using CSS selectors.
- 🔖 The
- [/] Modifying Elements:
- 🔖 The
document
object allows you to modify elements’ content, attributes, and styles. You can use properties likeelement.textContent
orelement.innerHTML
to change the content of an element,element.setAttribute()
to set or modify attributes, andelement.style
to manipulate CSS styles.
- 🔖 The
- [/] Creating and Deleting Elements:
- 🔖 The
document
object provides methods to create new elements and insert them into the document. You can usedocument.createElement()
to create a new element,element.appendChild()
to append an element to another element, andelement.remove()
to remove an element from the document.
- 🔖 The
- [/] Events and Event Handling:
- 🔖 The
document
object allows you to attach event handlers to elements and respond to user actions. You can use methods likeelement.addEventListener()
andelement.removeEventListener()
to register and unregister event listeners for various events such asclick
,keydown
,submit
, and more.
- 🔖 The
- [/] DOM Traversal:
- 🔖 The
document
object provides methods to traverse and navigate the document’s DOM (Document Object Model) tree. You can access an element’s parent, children, siblings, and other related elements using methods likeelement.parentNode
,element.children
,element.nextElementSibling
, and more.
- 🔖 The
- [/] Document Properties:
- 🔖 The
document
object exposes properties that provide information about the document itself. Some commonly used properties includedocument.title
for the document’s title,document.URL
for the URL of the document,document.documentElement
for the root<html>
element, anddocument.head
anddocument.body
for the<head>
and<body>
elements, respectively.
- 🔖 The
- [/] Loading and Manipulating Stylesheets:
- 🔖 The
document
object allows you to manipulate stylesheets dynamically. You can access and modify existing stylesheets using properties likedocument.styleSheets
, and you can add new stylesheets to the document using methods likedocument.createElement('link')
anddocument.head.appendChild()
.
- 🔖 The
document vs document.element
- document: The
document
object represents the entire HTML document. It provides an interface to interact with the elements, styles, and structure of the web page. You can use thedocument
object to access and manipulate elements, modify styles, create new elements, handle events, and perform various operations on the document.- 🔖 For example, you can use
document.getElementById()
to retrieve an element by its uniqueid
,document.createElement()
to create a new element, ordocument.querySelector()
to select elements using CSS selectors. - 🔖 The
document
object is the entry point to the DOM (Document Object Model) and serves as the global interface for working with the HTML document in JavaScript.
- 🔖 For example, you can use
- document.documentElement: The
document.documentElement
property refers to the root element of the document, which is typically the<html>
element. It represents the top-level element in the DOM hierarchy. You can access the root element usingdocument.documentElement
,
Interacting with the Dom, Messing with the DOM
When messing with the dom you can be sure to use the methods bellow:
Tip createElement():
The
document.createElement(tagName)
method creates a new element with the specified HTML tag name. This method returns the newly created element object.
Tip appendChild():
The
appendChild()
method is used to add an element as the last child of another element. It appends the specified element as a child to the end of the list of children of the target element.
Tip insertBefore():
The
insertBefore(newElement, referenceElement)
method allows you to insert a new element before a specified reference element. It inserts the new element as a child element just before the reference element.
Tip replaceChild():
The
replaceChild(newElement, oldElement)
method is used to replace an existing child element with a new element. It replaces theoldElement
with thenewElement
in the parent element.
Tip innerHTML():
The
element.innerHTML
property allows you to set or retrieve the HTML content of an element. You can use it to set the HTML content of an element, including child elements, by assigning a string of HTML code to it.
Tip [cloneNode]:
The
cloneNode()
method creates a copy of an element, including all its attributes and child elements. It allows you to clone an element and then manipulate or append the cloned element to the DOM.
The
DocumentFragment
interface represents a minimal document object that can be used as a container for other nodes. It allows you to create an in-memory container to hold multiple elements or nodes before appending them to the actual DOM. This can improve performance when adding multiple elements at once.
Elements in the DOM
Selecting elements in our DOM
To select elements in the DOM (Document Object Model) using JavaScript, there are several methods and techniques available.
getElementById():
The document.getElementById(id)
method selects an element based on its unique id
attribute. It returns a single element or null
if no element with the specified ID is found.
This method selects an element by its unique ID. It is the fastest and most efficient way to select an element since IDs are required to be unique within a document. However, it can only select a single element.
getElementsByClassName():
The document.getElementsByClassName(className)
method selects elements based on their class name. It returns a live HTML Colleciton of elements that have the specified class.
Like the previous methods, you can loop over the collection or access elements using indexing.
getElementsByTagName():
The document.getElementsByTagName(tagName)
method selects elements based on their HTML tag name. It returns a live HTMLCollection of elements that have the specified tag.
It returns a live
HTMLCollection
containing all elements with the specified tag name. LikeNodeList
,HTMLCollection
is not an array, but you can loop over it or access elements using indexing.
querySelector():
The document.querySelector(selector)
method selects the first element that matches a CSS selector. It returns the first matching element or null
if no element is found.
It provides great flexibility and can select elements based on various criteria such as tag name, class name, attribute values, and more. It supports complex selectors but may be slower compared to more specific methods.
querySelectorAll():
The document.querySelectorAll(selector)
method selects all elements that match a CSS selector. It returns a static NodeList containing all matching elements.
It can select multiple elements and allows you to iterate over them using methods like
forEach
or indexing. Keep in mind thatNodeList
is not a true array, so some array methods may not be directly applicable.
Warning
querySelector()
andquerySelectorAll()
are considered the best for element selection in the DOM due to the following reasons:
- [/] They support CSS selectors, making it flexible to write the selection logic.
- [/] You Can select elements based on complex criteria and relationships!.
- [/]
querySelector()
selects the first matching element, whilequerySelectorAll()
returns a collection of all matching elements.- [/] They have good browser compatibility and work across major modern browsers.
- [/] They enable dynamic selection by constructing selectors at runtime.
- [/] They support non-standard selectors for selecting elements based on their states.
some browser implementations or libraries extend the CSS selector syntax by introducing non-standard selectors that enable you to select elements based on additional criteria, such as states or behaviors. These non-standard selectors are not part of the official CSS specification but are supported by specific browsers or libraries.
For instance, some examples of non-standard selectors include:
- [!]
:checked
: Selects input elements that are checked (e.g.,input[type="checkbox"]:checked
).- [!]
:hover
: Selects elements that are currently being hovered over by the mouse.- [!]
:focus
: Selects elements that currently have focus. These non-standard selectors allow you to target elements based on their dynamic states or interactions, providing more flexibility in styling or manipulating elements based on their current state.
Traversing the DOM
In addition to the above methods, you can traverse the DOM hierarchy using properties and methods available on DOM elements. For example, you can access parent elements using parentNode, select siblings using previousSibling and nextSibling, or navigate child elements using childNodes or children.
Closest Method in JS
The closest
method in JavaScript allows you to find the closest ancestor element that matches a specified CSS selector. It starts from the current element and traverses up the DOM tree until it finds a matching element or reaches the document root.
closest(selector)
:
Returns the closest ancestor element that matches the provided CSS selector.
parentNode and parentElement:
parentNode
The parentNode
property returns the parent node of the current element. It allows you to access the immediate parent element of an element.
parentElement:
The parentElement
property is similar to parentNode
and returns the parent element of the current element. It provides direct access to the parent element without considering other types of nodes.
ParentNode vs ParentElement
ParentNode ParentElement Returns the parent node of the current node, including non-element nodes. Returns the parent element of the current node, skipping non-element nodes. If the parent node is an element, it is returned as is. If the parent node is an element, it is returned as the parent element. If the parent node is not an element, such as a text node or comment node, it is still returned. If the parent node is not an element, the search continues up the DOM tree until an element node is found. Can be used to traverse up the DOM tree and access any type of node. Only works with element nodes and provides direct access to the parent element.
Accessing Child Elements:
The children
property returns a live HTMLCollection
containing all child elements of the current element. It excludes non-element nodes and provides direct access to the child elements.
childNodes
The childNodes
property returns a live NodeList
containing all child nodes of the current element, including both element and non-element nodes.
previousSibling
The previousSibling
property returns the previous sibling node of the current element, including text nodes or other non-element nodes.
nextSibling
The nextSibling
property returns the next sibling node of the current element, including text nodes or other non-element nodes.
previousElementSibling
The previousElementSibling
property returns the previous sibling element of the current element. It skips non-element nodes and only considers element nodes.
nextElementSibling
The nextElementSibling
property returns the next sibling element of the current element. It skips non-element nodes and only considers element nodes.
Difference between next Sibling and nextSibling Element
Next Sibling Next Sibling Element Refers to the next element node that shares the same parent as the current element node. Refers to the next element node that shares the same parent as the current element node. Element nodes are specific types of nodes that represent HTML elements. Element nodes are specific types of nodes that represent HTML elements. The nextElementSibling
property is used to access the next element sibling.The nextElementSibling
property is used to access the next element sibling.Example: If you have a <ul>
element with multiple<li>
elements as its children, the next element sibling of an<li>
element would be another<li>
element if one exists. Text nodes or comment nodes that may exist between the<li>
elements would be skipped.Example: If you have a <ul>
element with multiple<li>
elements as its children, the next element sibling of an<li>
element would be another<li>
element if one exists. Text nodes or comment nodes that may exist between the<li>
elements would be skipped.
Modifying element property
When working with the Document Object Model (DOM), there are several ways to modify the properties of an element in JavaScript.
Direct Property Assignment
You can directly assign values to element properties using dot notation:
Once you’ve created an element, you can modify its properties, such as id
, class
, textContent
, or style
. Use various element properties and methods to set attributes and content.
element.property = value;
SetAttribute()
The setAttribute()
method allows you to set attributes on an element:
element.setAttribute('attributeName', 'value');
Style Property
The style
property allows you to modify inline CSS styles of an element:
element.style.property = value;
classList Property
The classList
property provides methods to add, remove, toggle, or check the presence of CSS classes on an element:
element.classList.add() ...remove() ...toggle() ...contains()
Dataset Property
The dataset
property allows you to access and modify custom data attributes (data-* attributes) on an element:
element.dataset.attributeName = value;
The Js Part
InnerText vs textContent vs InnerHTML
Inner HTML Property
The innerHTML
property allows you to modify the HTML content within an element, including nested elements:
element.innerHTML = 'new content';
Always be careful using this one , cause it might lead to xss
Inner Text Property
The innerText
property is used to set or retrieve the visible text content of an element, including the text of its descendants.
It represents only the visible text, excluding any hidden or non-rendered elements.
textContent Property
The textContent
property allows you to set or get the text content of an element, excluding any HTML tags:
The textContent
property is similar to innerText
in that it represents the textual content of an element, including its descendants.
However, unlike
innerText
,textContent
returns all text content, including hidden or non-rendered elements, and preserves the original spacing and line breaks.
element.textContent = 'new text';
Adding elements to the dom
Adding an Element to the DOM: After creating and modifying the element, you need to add it to the DOM tree.
insertAdjacentHTML()
The insertAdjacentHTML()
method allows you to insert HTML content at a specific position relative to an element. You provide a position and the HTML content as parameters.
insertAdjacentHTML(position,element) where position in( beforebegin
,
afterbegin,
beforeend, and
afterend` )
appendChild()
The appendChild()
method appends a new child element to an existing element:
The
appendChild()
method is used to append a single child element to a parent element. It takes an element node as its parameter and adds it as the last child of the parent element.
parentElement.appendChild(newElement);
append():
The append()
method is a newer method introduced in modern browsers. It allows appending multiple nodes and/or strings as children to a parent element. It accepts a variable number of arguments, including element nodes, text strings, or other DOM objects.
In the above example, the
append()
method appendschildElement1
, the text string'Some Text'
, andchildElement2
as children of theparentElement
.
appendChild() vs append()
- 🔥
appendChild()
can only append a single element node as a child, whileappend()
can append multiple elements, strings, or DOM objects.- 🔥
appendChild()
returns the appended child element, whereasappend()
does not return anything.
prepend()
The prepend()
method inserts one or more elements at the beginning of an element’s children:
parentElement.prepend(element1, element2, ...);
insertBefore()
The insertBefore()
method inserts a new element before an existing element as a sibling:
parentElement.insertBefore(newElement, referenceElement);
replaceChild()
The replaceChild()
method replaces an existing child element with a new element:
parentElement.replaceChild(newElement, oldElement);
You can do this by selecting an existing element in the document where you want to append the new element and using the appendChild()
method.
Creating elements in JS
When working with the Document Object Model (DOM), there are several ways to create elements dynamically using JavaScript. Each method has its advantages and use cases. In this guide, we will explore various techniques for creating elements in JavaScript.
document.createElement()
In JavaScript, you can create and add elements to the DOM (Document Object Model) dynamically using the document.createElement()
method and various other DOM manipulation techniques. Here’s how you can create elements and add them to the DOM:
- Creating an Element: To create a new element, use the
document.createElement(tagName)
method. Pass the desired HTML tag name as the argument. For example, to create a<div>
element, you would usedocument.createElement('div')
. This method returns a new element object.
Success
- Use this method to create any HTML element dynamically.
- Set the element’s properties, such as
className
,id
,textContent
, orinnerHTML
, as needed.- Append the element to the desired location in the DOM using methods like
appendChild()
orinsertBefore()
.
Don't forget to add the created element to the DOM using appropriate methods. Failing to do so will result in the element not being rendered on the page.
innerHTML property
The innerHTML
property allows you to create and insert multiple elements, including their HTML structure, into an existing element.
Success
- Use this method when you have a complex HTML structure to create and insert
- Take advantage of template literals or other string manipulation techniques to build the desired HTML structure dynamically.
Don't use
innerHTML
when dealing with untrusted or user-generated content to avoid potential security risks (e.g., cross-site scripting).
insertAdjacentHTML()
The insertAdjacentHTML()
method allows you to insert HTML content at a specific position relative to an element. You provide a position and the HTML content as parameters.
Success
- Use this method when you want to insert HTML content at a specific position relative to an element.
- Utilize the available positions:
beforebegin
,afterbegin
,beforeend
, andafterend
to control the insertion location.- Flexibility:
insertAdjacentHTML()
allows you to insert HTML content at a specific position relative to an element. You have control over where the content should be inserted, such as before the element, after the element, as the first child, or as the last child.- Convenience: It provides a convenient way to insert complex HTML structures or snippets without the need for manually creating and manipulating multiple elements.
- Performance: Compared to manipulating the DOM directly,
insertAdjacentHTML()
can be more efficient when inserting large amounts of HTML content. It avoids repeatedly modifying the DOM and triggers fewer reflows and repaints.
Don't use this method to create a single element. It's more suitable for inserting HTML content.
Security risks: When using
insertAdjacentHTML()
, you must be cautious about potential security risks, especially when inserting user-generated or untrusted content. Inserting HTML content directly from untrusted sources can lead to cross-site scripting (XSS) vulnerabilities if proper sanitization and validation are not applied. Limited manipulation:insertAdjacentHTML()
focuses on inserting HTML content but doesn’t provide fine-grained control for modifying existing elements or handling events. If you need to perform complex operations on elements, such as attaching event listeners or manipulating attributes, you may need to combineinsertAdjacentHTML()
with other DOM manipulation methods. Code readability: Inserting HTML directly through strings can make your code less readable and harder to maintain, especially when dealing with complex HTML structures. It may be more challenging to debug or make changes in the future. Accessibility concerns: When usinginsertAdjacentHTML()
, you need to ensure that the dynamically inserted content adheres to accessibility standards. This includes providing appropriate ARIA attributes, keyboard accessibility, and semantic structure.
Overall,
insertAdjacentHTML()
is a powerful method for inserting HTML content at specific positions, offering flexibility and performance benefits. However, it's essential to be mindful of security risks, maintain code readability, and consider other DOM manipulation requirements when using this method.
CreateDocumentFragment()
In JavaScript, a Document Fragment is a lightweight container used to hold a group of DOM nodes temporarily. It allows you to create and manipulate a collection of DOM nodes without directly modifying the main DOM tree. Fragments provide a way to efficiently perform multiple DOM operations and then insert the entire group of nodes into the document all at once, minimizing the number of DOM manipulations and improving performance.
The
createDocumentFragment()
method creates a lightweight "virtual" document fragment that allows you to create and manipulate elements before appending them to the main DOM. Here's an example:
Advantages of using fragment
- Container for DOM Nodes: A fragment is essentially an empty container that can hold DOM nodes. It is not part of the main document tree itself.
- Improved Performance: When you manipulate the DOM, each insertion or removal of a node can trigger a document reflow and repaint, which can be computationally expensive. By using a fragment, you can perform multiple DOM manipulations on the fragment, and then insert the entire fragment into the document, minimizing the number of reflows and repaints.
- Document Structure: Unlike the main document, fragments don’t have a
doctype
,html
, orbody
element. They are independent containers that can hold any type of DOM nodes.- Manipulation Flexibility: You can freely manipulate the nodes within a fragment using various DOM manipulation methods like
appendChild
,removeChild
,insertBefore
, and more. You can also modify attributes, add event listeners, or perform any other operation just like you would on regular DOM nodes.- Efficient Insertion: Once you have finished manipulating the nodes in the fragment, you can insert the fragment into the document using methods like
appendChild
orinsertBefore
. This action moves all the nodes from the fragment into the document, preserving their structure and order.- No Visible Impact: Fragments do not have a visual representation or impact on the rendered output of the document. They are purely used as a tool for efficient DOM manipulation.
Creating nested elements
you can also create nested elements by following the same process. Create the child elements, modify their properties, and append them to their parent element using appendChild()
.
Cloning A Node cloneNode()
#cloning
cloneNode(): The cloneNode()
method creates a shallow copy of an element, including its attributes and child nodes. It allows you to specify whether to clone only the element (cloneNode(false)
) or deep clone the entire subtree (cloneNode(true)
).
Pros: Simple and widely supported method for cloning elements.
Con: Creates a shallow copy, meaning event listeners and certain properties may not be copied.
importNode():
The importNode()
method is used to import a node from another document or document fragment. It creates a deep copy of the element and its descendants, including attributes and child nodes.
Success Pros: Allows importing elements from other documents or document fragments.
Warning Cons: Requires a reference to another document or document fragment.
Classes and style in js
Controlling Styles in JavaScript In JavaScript, you can dynamically control styles of HTML elements to create interactive and visually appealing web applications. This allows you to modify various style properties, such as colors, dimensions, positions, and more. Let’s explore the possibilities and best practices for controlling styles in JavaScript.
Inline Styles
One way to control styles is by directly modifying the inline styles of an element.
The style
property of an element allows you to access and manipulate individual style properties.
Here’s an example:
CSS Classes and ClassList
Using CSS classes provides a more flexible and maintainable approach for controlling styles. You can add, remove, or toggle CSS classes on elements using the classList
property. Here are some examples:
Adding a class
Removing a class
Toggling a class from an element
element.classList.toggle(class, force);
- [/]
class
: The name of the class to toggle. - [/]
force
(optional):- ➡️ A Boolean value that specifies whether to force the class to be added (
true
) or removed (false
). Ifforce
istrue
, the class will be added regardless of its current presence. Ifforce
isfalse
, the class will be removed regardless of its current presence. Ifforce
is not provided, the class will be toggled based on its current presence (added if not present, removed if present).
- ➡️ A Boolean value that specifies whether to force the class to be added (
Manipulating Class Name
Another way to control styles is by manipulating the className
property of an element.
This property allows you to set or modify the entire list of CSS classes assigned to an element.
This approach is less recommended compared to using
classList
.
Modifying the Style Attribute
You can directly modify the style
attribute of an element using the setAttribute()
method. However, this approach can become cumbersome when dealing with multiple style properties.
Best Practices
- ➡️ Prefer using CSS classes and manipulating the
classList
property for controlling styles. This separates style definitions from JavaScript code and promotes code maintainability. - ➡️ Avoid inline styles and directly modifying the
style
property orsetAttribute()
method, except for specific cases where dynamic styling is necessary. - ➡️ Utilize CSS stylesheets to define most of your styles. JavaScript should be used for dynamic style changes or interactions.
Event listeners
Event listeners are a fundamental concept in JavaScript for handling and responding to various events that occur in a web page.
- What are Event Listeners?: Event listeners are functions that are executed in response to specific events happening in the DOM, such as a button click, mouse movement, or keyboard input. They allow you to define custom code that runs when a particular event occurs.
Event Types:
Events can be categorized into different types, such as
- 🔥 click:
- The
click
event occurs when a mouse button is clicked on an- nf.
- The
- 🔥 mouseover and mouseout:
- The
mouseover
event occurs when the mouse pointer enters an element, while themouseout
event occurs when the mouse pointer leaves an element.
- The
- 🔥 keydown and keyup:
- The
keydown
event occurs when a keyboard key is pressed, while thekeyup
event occurs when the key is released.
- The
- 🔥 submit:
- The
submit
event occurs when a form is submitted.
- The
- 🔥 focus and blur:
- The
focus
event occurs when an element receives focus, such as when it is clicked or tabbed into, while theblur
event occurs when the element loses focus.
- The
- 🔥 load:
- The
load
event occurs when a web page or an image has finished loading.
- The
- 🔥 scroll:
- The
scroll
event occurs when an element’s scroll position changes.
- The
- 🔥 input and change: - [ ] The
input
event occurs when the value of an input field or textarea changes, while thechange
event occurs when the value is committed (for example, when the user clicks outside the input field). Each event type represents a specific action or interaction that can trigger an event listener.
Adding event listeners
In JavaScript, you can add event listeners to elements using the addEventListener()
method. The general syntax for adding an event listener is as follows:
- 🔖
element
is the HTML element to which you want to attach the event listener. - 🔖 eventType is a string that represents the type of event you want to listen for, such as ”click”, ”mouseover”, ”keydown”, etc.
- 🔖 eventListenerFunction is the function that will be executed when the specified event occurs.
Running an event once
To run an event listener only once, you can use the addEventListener()
method with the once
option set to true
. Here’s how you can do it:
This approach is convenient when you want to perform a specific action or execute a function only on the first occurrence of the event. Once the event is triggered, the listener is automatically removed, and subsequent events of the same type on the element will not trigger the listener again.
Removing Event listeners
To remove an event listener that was previously added using addEventListener()
, you can use the removeEventListener()
method. The removeEventListener()
method allows you to specify the same event type and listener function that were used when attaching the event listener. Here’s the general syntax:
Obviously this does not work with arrow functions , cause arrow functions are not same
Event Propagation
Event propagation refers to the process of an event being dispatched and traversing through the DOM tree. There are two phases of event propagation:
- [/] The capturing phase
- [/] The bubbling phase
By default, events triggered on an element propagate up the DOM tree to the element's parent, its ancestors, and on up until the root element (
html
).
Capturing Phase
- 🔖 The capturing phase is the initial phase of event propagation.
- 🔖 During this phase, the event is triggered at the top of the DOM tree (outermost element) and propagates down towards the target element.
- 🔖 Events in the capturing phase are handled by ancestors of the target element.
- 🔖 The capturing phase allows events to be captured or intercepted before reaching the target element.
The capturing phase happens before the bubbling phase and allows you to handle events as they propagate from the root of the DOM tree to the target element.
During the capturing phase, the event starts at the root of the DOM tree (usually the
window
object) and travels down to the target element.This phase is less commonly used in event delegation because it requires explicitly setting the
capture
option totrue
when adding an event listener.Output Outer clicked Inner clicked Button clicked
In this example, we have three elements nested inside each other. By attaching event listeners with the
true
parameter (indicating the capturing phase), we can observe the capturing phase in action. The events are triggered in the order of outer to inner elements.
Bubbling Phase
When an event is triggered on an element, it “bubbles” up through its parent elements. This means that if you click on a child element, the click event will also trigger on all its parent elements. Event delegation takes advantage of this bubbling behavior.
This is the default behavior of events on elements unless you stop the propagation ^0bcf79
- [/] The bubbling phase is the second phase of event propagation.
- [/] During this phase, the event is triggered at the target element and propagates up the DOM tree towards the top (outermost element).
- [/] Events in the bubbling phase are handled by ancestors of the target element.
- [/] The bubbling phase allows events to be handled by multiple ancestors of the target element.
Stop Event Propagation
To stop event propagation in JavaScript, you can use the event.stopPropagation()
method
Stop Event Propagation through the capture or bubbling phase
Warning
event.stopPropagation()
only stops the event from propagating further up or down the DOM tree. It does not prevent other event listeners on the same element from being called.
Stop Other listeners from executing
If you want to prevent other listeners from executing, you can use event.stopImmediatePropagation()
instead.
In this case,
event.stopImmediatePropagation()
not only stops the event from propagating to ancestor elements but also prevents other listeners attached to the same element from being called.
Stop Propagation vs Stop Immediate Propagetion
#stopPropagation#StopImmediatePropagation
- 🔥
stopPropagation()
stops the event from reaching ancestor or descendant elements but allows other event listeners on the same element to execute. - 🔥
stopImmediatePropagation()
not only stops event propagation but also prevents any remaining event listeners on the same element from being called, regardless of their order of attachment. - [?]
stopPropagation()
:- [/] Stops the event from propagating further up or down the DOM tree.
- [/] Prevents the event from triggering event listeners on ancestor or descendant elements.
- [/] Other event listeners on the same element will still be executed.
- [/] Subsequent event listeners on ancestor elements will not be triggered.
- [/] Event propagation in the current phase (capturing or bubbling) is halted.
- [?]
stopImmediatePropagation()
:- [/] Stops the event from propagating further up or down the DOM tree.
- [/] Prevents the event from triggering any remaining event listeners on the same element.
- [/] Other event listeners on the same element will not be executed.
- [/] Subsequent event listeners on ancestor elements will not be triggered.
- [/] Event propagation in the current phase (capturing or bubbling) is halted.
- [/] No additional event listeners for the current element will be called.
Event Delegation
Event Delegation is a pattern based upon the concept of Event Bubbling. It is an event-handling pattern that allows you to handle events at a higher level in the DOM tree other than the level where the event was first received.
Event delegation is a technique in JavaScript where instead of attaching event listeners to individual elements, you attach a single event listener to a parent element. This allows you to handle events that occur on child elements without needing to attach separate listeners to each child.
Why event delegation ?
-
💡 Event delegation is a technique that allows you to handle events on parent elements instead of attaching listeners to individual child elements.
-
💡 To implement event delegation, attach a single event listener to a parent element and use the
event.target
property to determine the specific child element that triggered the event. -
💡 Event delegation is particularly useful for handling events on dynamically created or large sets of elements, improving performance and memory efficiency.
-
🔥 Attaching event listener to parent: - 💡 With event delegation, you attach an event listener to a parent element that encompasses the child elements you’re interested in. This parent element should be an ancestor of the target elements you want to handle events for. - 🔥 Handling events dynamically: - 💡 Since the event listener is attached to a parent element, it can handle events for current and future child elements. This is especially useful when working with dynamically added or removed elements from the DOM.
Taking advantage of the event propagation
You add and even listener to all your button Then you create a new button , this button won’t have the event listener You are gonna have to create an even listener for the button or simply Take advantage of the delegation to create an event listener to the parent
Tips and Tricks
- 🔥 Event target:
- 💡 When an event occurs, you can access the target element on which the event was originally triggered. By examining the target element, you can determine which child element was actually clicked or interacted with.
- 💡 Use
event.preventDefault()
to prevent the default behavior of an event, such as form submissions or link navigation. - 💡 Use
event.stopPropagation()
to stop the event from further propagation, preventing it from reaching ancestors. - 💡 Use
event.stopImmediatePropagation()
to stop the event from further propagation and prevent other listeners attached to the same element from being called. - 💡 Take advantage of the
dataset
attribute to store information on HTML elements and use event delegation based on that data. - 💡 Utilize the
matches()
method to check if the target element matches a specific CSS selector in event delegation scenarios.
Data Attributes in JavaScript
HTML data attributes provide a way to store custom data on HTML elements. These attributes are prefixed with data-
and can be accessed and manipulated using JavaScript.
Creating data attributes in html
What are Data Attributes?
Data attributes are attributes in HTML tha t allow you to store custom data on elements. They follow the format data-*
, where *
represents the name of the attribute. For example, data-name="John"
creates a data attribute called “name” with the value “John”.
Accessing Data Attributes using JavaScript:
You can access data attributes using the dataset
property of an HTML element in JavaScript. The dataset
property returns an object with properties corresponding to the data attribute names.
Manipulating Data Attributes:
You can read and modify data attributes using the dataset
property. For example, to change the value of a data attribute, you can simply assign a new value to the corresponding property.
Simple program to get all buttons add events to them and when they are clicked over 4 times, they disappear
Simple Program that simulates a todo list
Dom tips and tricks
Creating templates Clone
#templates#clone#components Templates in JavaScript and HTML provide a convenient way to define reusable content that can be dynamically populated and inserted into the DOM. They allow you to create a template structure with placeholders for data, which can then be cloned and customized as needed.
Creating our templates
1. Define the Template:
Start by creating a template in your HTML file using the <template>
element. Inside the template, you can structure your desired content using HTML, and use placeholders or data attributes to indicate dynamic parts.
```html
```
#### 2. Accessing the template
To access the template, you can use JavaScript to retrieve it using its ID and the `content` property.
Info Template Content Access
The
content
property of a template element provides access to the content within the template.You can access the content using the
content
property and manipulate its elements and structure.
3. Cloning and customizing the template
You can create copies of the template using the cloneNode()
method and modify the content by accessing the elements within the template. Replace the placeholder values with the desired data.
4. Insert the Cloned Template into the DOM:
Once you’ve customized the cloned template, you can insert it into the desired location in the DOM using methods like appendChild()
or insertBefore()
.
By following these steps, you can create reusable templates and dynamically populate them with data. This approach helps separate the structure of your content from the data, making your code more maintainable and scalable
HTML Collection vs Nodelist
HTMLCollection:
- 🔥 An
HTMLCollection
is a live collection of elements that is automatically updated when the underlying DOM changes. - 🔥 It is typically returned by methods like
getElementsByTagName()
andgetElementsByClassName()
. - 🔥
HTMLCollection
objects have a named index based on the element’s position in the DOM tree. - 🔥 They do not have built-in array methods like
forEach()
ormap()
. - 🔥 However, you can iterate over them using a
for
loop or convert them to an array usingArray.from()
or the spread operator.
NodeList:
- 🔥 A
NodeList
is also a collection of nodes but can contain different types of nodes like elements, text nodes, comments, etc. - 🔥 It is typically returned by methods like
querySelectorAll()
and certain DOM properties likechildNodes
. - 🔥
NodeList
objects are usually static, meaning they do not automatically update when the DOM changes. - 🔥 They can be accessed using both numeric indices and methods like
item()
orforEach()
. - 🔥
NodeList
objects inherit the methods ofArray.prototype
, so you can directly use array methods on them.
Race Conditions
In simple terms, a race condition occurs when two or more parts of a program or system try to access and modify a shared resource simultaneously, resulting in unpredictable or undesired behavior. It's like a race between different parts of the program to access and modify the resource, and the outcome depends on which part "wins" the race.
Imagine a scenario where two or more threads or processes in a program are trying to update the same variable or access the same data at the same time. If proper synchronization mechanisms are not in place, the order in which these threads or processes execute their operations may become unpredictable. This can lead to situations where one operation may overwrite or interfere with the result of another operation, causing data inconsistencies, incorrect calculations, or even program crashes.
To prevent race conditions, developers use various synchronization techniques such as locks, mutexes, semaphores, or atomic operations. These mechanisms help ensure that only one thread or process can access the shared resource at a time, eliminating the possibility of conflicting modifications.
Module and bundlers
Modules and bundlers are both related to organizing and managing JavaScript code, but they serve different purposes:
Modules:
In JavaScript, modules provide a way to organize and encapsulate code into separate files or modules. Each module can have its own private variables, functions, classes, or objects. Modules allow you to
- ➡️ Modularize your codebase,
- ➡️ improve code maintainability,
- ➡️ reusability, and readability.
With the introduction of ES6 (ECMAScript 2015), JavaScript has native support for modules using the import
and export
keywords. ES6 modules allow you to import functions, variables, or objects from other modules and use them in your code. ES6 modules are supported in modern browsers and can also be used in Node.js with the appropriate configuration.
## <script type="module" src="index.js">
The attribute
type="module"
in the<script>
tag is used to indicate that the script file should be treated as an ECMAScript module. It enables the use of modern JavaScript module features such asimport
andexport
.
When you include the type="module"
attribute in a <script>
tag, the JavaScript file specified in the src
attribute will be loaded and executed as a module. This allows you to organize your JavaScript code into separate modules and use features like module-level scope, named exports, and imports.
The nice thing about using the type module is that it automatically gives us the defer attribute.
It automatically makes our import a defer.
Exporting and Importing Modules
In JavaScript modules, there are two ways to export functionality: export
and export default
.
export:
- ➡️ The
export
keyword is used to export named exports from a module. - ➡️ With
export
, you can export multiple values or functions from a module. - ➡️ When importing from the module, you need to use the same names for the imported values.
- ➡️ You can have multiple named exports in a single module.
utils.js
main.js
In this example, we have a
square
function and aPI
constant exported from theutils.js
module. We import and use them in themain.js
module using theimport
statement.
export default
- ➡️ The
export default
syntax is used to export a single value or object as the default export of a module. - ➡️ You can only have one default export per module.
- ➡️ When importing, you can choose any name for the imported value. math.js
main.js
We can rename the default export to anything that pleases us. and it will still work.
In this example,
math.js
exports an object withadd
andsubtract
functions as the default export. We import it using the namemathOperations
in themain.js
module.
Combining Import and name import
Node and packages managers
Initialize Node
Initialize the node packages, this simply create package.json files that keeps track of our dependencies.
Installing a package
Using a package.
Research about
- windows Parent object.
Reflow vs Repaint
Reflow (or Layout):
Reflow refers to the process of calculating the layout and positioning of elements on a web page. It occurs when there are changes to the structure or style of elements that affect their dimensions or position. For example, adding or removing elements, modifying their size, changing the font, or adjusting the margins and paddings can trigger a reflow.
During a reflow, the browser recalculates the layout of the affected elements and their relationships, determines their position on the page, and resolves any conflicts or dependencies. This process can be resource-intensive and may cause performance bottlenecks, especially on complex pages with many elements.
Reflow triggers:
- [/] Adding, removing, or modifying the DOM structure of the page.
- [/] Changing the dimensions of elements (e.g., width, height, padding, margin).
- [/] Modifying the position or display properties of elements.
- [/] Altering the font size or text content of elements.
- [/] Updating CSS styles that affect the layout, such as floats or positioning.
- [/] Modifying the document flow by hiding/showing elements or manipulating visibility.
Repaint (or Rendering):
Repaint, also known as rendering, is the process of updating the visual appearance of elements on the screen without changing their layout or position. It occurs when there are changes to the visual properties of elements, such as color, background, border, or visibility.
During a repaint, the browser updates the affected pixels on the screen to reflect the modified visual properties. This process is generally faster than reflow since it doesn’t involve recalculating the layout. However, frequent repaints can still impact performance, particularly if applied to a large number of elements or complex visual effects.
Repaint triggers:
- [/] Changing the color, background, border, or opacity of elements.
- [/] Modifying the visibility or display properties of elements.
- [/] Applying CSS transitions or animations.
- [/] Adjusting the outline or box-shadow properties of elements.
- [/] Updating the content of an input field or textarea.
- [/] Scrolling the page (although this may trigger both reflow and repaint).
Threads of Execution
#Execution JS is not that fancy, it goes though our code line by line, and does run/execute each line known as thread of execution. It threads it’s way down the code as it goes.
- ➡️ It also save data like strings and arrays so we can use the data later on. (it stores the data in the memory.)
Threads simply takes the code, run it over and over again line by line. (it's simply the ability of going over line by line and do execute the lines.)
Call Stack
JavaScript keeps track of what function is currently running (where is the thread of execution)
In the bottom we always have our global execution context
Every time we entered in a function , a new call execution context is created, meaning we have something new on top of our call stack when it’s done executing it goes outside and a new the lower thing gets to continue running. while our global execution context is at the bottom.
Why do we even need functions?
Because we don’t want to break the dry principles, Not repeating ourselves is the first why to use functions.
Generalizing functions
- 💡 Parameters’ (placeholders) mean we don’t need to decide what data to run our functionality on until we run the function
- ➡️ Then provide an actual value (‘argument’) when we run the function
- 💡 Higher order functions follow this same principle.
- ➡️ We may not want to decide exactly what some of our functionality is until we run our function G
Dealing with functionalities in functions
Now suppose we have a function copyArrayAndMultiplyBy2*/
What if want to copy array and divide by 2?
now what about a function that adds 3 to each element?
You could have a function that doubles elements of an array, add 2 to every element of an array divide each element to the array by two and so on... we can have all this functions but technically, we would be breaking the dry principle !.
Or simply create a function that not only take parameters but also functionalities as arguments.
How is the above even possible?
The above is possible because in js functions are considered as First Class Objects They can co-exist with and can be treated like any other javascript object
- ➡️ Assigned to variables and properties of other objects
- ➡️ Passed as arguments into functions
- ➡️ Returned as values from functions
Higher-order functions
They are functions that Takes in a function or passes out a function Just a term to describe these functions any function that does it we call that - but there’s nothing different about them inherently
Why call back functions and higher order functions ?
- ➡️ Callbacks and Higher Order Functions simplify our code and keep it DRY
- Declarative readable code: Map, filter, reduce - the most readable way to write code to work with data
- Asynchronous JavaScript: Callbacks are a core aspect of async JavaScript, and are under-the-hood of promises, async/await
Anonymous and Arrow functions
- Improve immediate legibility of the code
- But at least for our purposes here they are ‘syntactic sugar’
- Understanding how they’re working under-the-hood is vital to avoid confusion
Closure
If you really understand closure, then there is no doubt that you do get javaScript.
- Closure is the most esoteric of javaScript Concepts
- Enables Powerful pro-level function one ‘once’ and memoize
- Create functions that runs only once
- Not repeat tasks that perform some heavy operations if we have done them before.
- Many javaScript design patterns include the module pattern uses closure
- Iterator
- partial application
- carrying
- maintaining states in an asynchronous wold
- Build iterators, handle partial application and maintain state in an asynchronous world.
If you really understand closure, you can be able to do some really cool industry styff.
Functions with memories
- 🔖 When our functions get called, we create a live store of data(local memory/variable environment/state) for that function’s execution context.
- 🔖 When the function finishes executing, its local memory is deleted(except the return value)
- 💡 But what if our functions could hold onto live data between execution?
- This would let our function definitions have an associated cache/persistent memory
- But it all starts with us returning a function from another function
- [ ]
In the code above what is really happening is that :
- ➡️ Step1:
- 💡 Creating or Defining our function createFunction()
- ➡️ Step2:
- 💡 Defining our constant called generatedFunc
- [/] Call our create function which will create a new Execution context.
- [/] Define our multiply by two function And returns it.
- [/] Now Generated Func is equal to the function multiply by two
- [/] The execution context gets deleted.
- [/] Call our create function which will create a new Execution context.
- 💡 Define the result variable that holds generatedFunc which is itself a function.
- [!] GeneratedFunc Has no relationship with createFunction rather it is multiply by 2.
- 💡 Create a new execution context to run the generated func
- [/] The codes in the generatedFunc is indeed the multiplyby2 which gets executed.
- 💡 Defining our constant called generatedFunc
The Bond
When a function is defined, it gets a bond to the surrounding Local Memory ("Variable Environment") in which it has been defined.
The backpack
The BackPack / P.L.S.R.D
- ➡️ We return incrementCounter’s code (function definition) out of outer into global and give it a new name - myNewFunction
- ➡️ We maintain the bond to outer’s live local memory - it gets ‘returned out’ attached on the back of incrementCounter’s function definition.
- ➡️ So outer’s local memory is now stored attached to myNewFunction - even though outer’s execution context is long gone
- ➡️ When we run myNewFunction in global, it will first look in its own local memory first (as we’d expect), but then in myNewFunction’s ‘backpack’
What can we call this ‘backpack’?
- 🔥 Closed over ‘Variable Environment’ (C.O.V.E.)
- 🔥 Persistent Lexical Scope Referenced Data (P.L.S.R.D.)
- 🔥 ‘Backpack’
- 🔥 ‘Closure’
- ➡️ The ‘backpack’ (or ‘closure’) of live data is attached incrementCounter (then to myNewFunction) through a hidden property known as scope which persists when the inner function is returned out
The Individual Backpack
If we run 'outer' again and store the returned 'incrementCounter' function definition in 'anotherFunction', this new incrementCounter function was created in a new execution context and therefore has a brand new independent backpack I
Why closure then ?
Closure gives our functions persistent memories and entirely new toolkit for writing professional code
- 🔥 Helper functions:
- [/] Everyday professional helper functions like ‘once’ and ‘memoize’
- 🔥 Iterators and generators:
- [/] Which use lexical scoping and closure to achieve the most contemporary patterns for handling data in JavaScript
- 🔥 Module pattern:
- [/] Preserve state for the life of an application without polluting the global namespace
- 🔥 Asynchronous JavaScript:
- [/] Callbacks and Promises rely on closure to persist state in an asynchronous environment