"JavaScript" is the colloquial name for ECMAScript.
The ECMA in ECMAScript refers to ECMA, an organization in Europe and the standards body that determines what goes into the ECMAScript language (JavaScript).
ES3 / ECMAScript 3
- ~2006
- First attempt to get all the browser vendors on the same page and use consistent DOM APIs.
- Old browsers, some other unique environments.
ES6 / ECMAScript 6
- ~2015
- Modern "JavaScript" that we're teaching today.
- Modern browsers only (includes Edge but not Internet Explorer, for instance.)
Recall the basics of JavaScript that we have already covered. They are mostly very general and abstract. They do not specifically reference the HTML elements on a web page.
-
Data types
- String
- Number / Float
- Boolean
- Array
- Object
- Function
- Class
- Map - Array-like (but always unique!)
- Set - Object-like
- "Weird ones" / "Offballs"
- undefined
- null
- NaN
- Infinity
-
Built-in Global objects
- Math
- .random()
- .round(num)
- .ceil(num)
- .floor(num)
- .max(num1, num2)
- .min(num1, num2)
- .abs(num)
- .sqrt(num)
- .pow(num, exponent)
- Date
- .now()
- JSON
- .parse()
- Promise
- new Promise(callbackFunction)
- (resolve, reject)
- promise.then()
- promise.catch()
- Promise.all()
- new Promise(callbackFunction)
- Math
-
Control flow
- If/Else
- Loops
So far, our JS environment is the browser.
The browser is the windowed application that runs on an operating system that happens to have a orchestrated system for rendering HTML, CSS, and JS.
The browser's scripting engine handles ES6 + the DOM API.
- Stands for:
- Document Object Model
- Application Programming Interface
- Not part of ECMAScript 6, but gets added to our environment automatically as additional functionality by the web browser
- Provides access to the current state of the rendered tree of HTML elements as well as other properties about the user's browser
- The global object
- Every JavaScript environment has a global object, sometimes referred to as
globalThis
.
- Every JavaScript environment has a global object, sometimes referred to as
- Provides access to various browser-specific functionalities including the DOM API.
- Represents the browser at a high level, including the browser application's resizable/scrollable container.
- Because it is the global object, the
window.
is implied, and does not need to typed out in code, but sometimes helps for clarity.console.log("Hello world")
vswindow.console.log("Hello world")
- Don't use
window.
- Here
console
works like a built-in global object.
- Don't use
const totalHeight = innerHeight + 300
vsconst totalHeight = window.innerHeight + 300
- Use
window.
for clarity. innerHeight
by itself is ambiguous, and it's easy to accidentally create a local variable calledinnerHeight
!
- Use
- I prefer to use the longer
window.document.querySelector()
over simplydocument.querySelector()
, since it's easy to accidentally create a local variable calleddocument
!
- .innerWidth <-- viewport width
- .innerHeight <-- viewport height
- .console
- .log()
- .scrollY <-- window scroll position (up/down)
- .scrollX <-- window scroll position (left/right)
- .location <-- page's current URL
- .history
- .back() <-- Equivalent to user hitting "back" button
- .navigator
- .document <-- See below
- .addEventListener("scroll")
- .addEventListener("resize")
- .removeEventListener("eventType", callbackFunction)
- .scrollTo(x, y)
- Scroll the web page to a specific point
- .alert("message")
- Show the default pop-up dialog with OK button
- .setTimeout(callbackFunction, interval)
- Do something in the future
- .requestAnimationFrame(callbackFunction)
- Do something on next frame render
- .fetch(url, options) => Promise
- Retrieve an external resource
- .matchMedia("css media query")
- .addEventListener("change", callbackFunction)
- Callback fires when CSS media query changes to true or false
- Represents a web page loaded in the browser
- Web pages used to be called "documents" because the early web was primarily designed to display research papers
- Holds the element tree
- .documentElement => Element
- .activeElement => Element that is currently focused
- .cookie
- window.document.cookie =
mycookie="helloworld"
;
- window.document.cookie =
- .querySelector("css selector")
- .querySelectorAll("css selector")
- .createElement("element-name")
- All elements in the DOM use the
Element
interface - Elements inherit the
Node
interface- Not all Nodes are Elements
- The other kind of Node is
TextNode
- HTML elements (div, a, span, etc) get the
HTMLElement
interface.- Other types of Elements might include SVG elements, etc.
- More specific types of HTML elements have specialized interfaces:
- HTMLButtonElement
- HTMLBodyElement
- etc.
.querySelector()
only retrieves Elements, not text nodes, but may retrieve SVG Elements or other Elements that don't use the HTMLElement interface.
- .textContent => The text nodes that are direct descenants of an element
- .innerText => All the text nodes of this element and all its descendants.
- .children => HTMLCollection
- .parentElement => Element
- .nextElementSibling => Element
- .classList <-- API for manipulating element's class attribute
- .add("className")
- .remove("className")
- .toggle("className")
- .contains("className") => Boolean
- .style <-- only mapping to the element's style attribute
- .setProperty("color", "red")
- .getPropertyValue("color") // red
Compare element.style to window.getComputedStyle(element) which gives you what was typed in the CSS stylesheet, and "won":
window.getComputedStyle(element);
- window.getComputedStyle()
- .setProperty()
- .getPropertyValue()
- Array-like representations of the DOM
- Update as the DOM changes
const allMyBeautifulParagraphs = window.document.querySelectorAll("p");
- Wrap in
Array.from()
to get a real array that won't change
const allMyBeautifulParagraphs = Array.from(window.document.querySelectorAll("p"));
- .querySelector("css selector")
- .querySelectorAll("css selector")
- .closest("css selector")
- .matches("css selector")
- .contains(element)
- .append(element)
- .prepend(element)
- .remove()
- .getAttribute("attribute-name")
- .setAttribute("attribute-name", "value")
- .scrollIntoView()
- .focus()
- .getBoundingClientRect()
- .height
- .width
- .top
- .left
- .addEventListener("eventType", callbackFunction)
- "click"
- "change"/"input"
- "submit"
- .removeEventListener("eventType", callbackFunction)
myButtonElement.addEventListener("click", (event) => {
console.log(event.eventType);
});
vs.
function buttonClickHandler(event) {
console.log(event);
}
myButtonElement.addEventListener("click", buttonClickHandler);
// Can only remove via reference to same function used to add
myButtonElement.removeEventListener("click", buttonClickHandler);
- Provides properties and methods for the event that is being fired inside the callback function of .addEventListener()
- .preventDefault()
- .stopPropagation()
- Other properties depend on the type of the Event
- .currentTarget
- The element that the event listener was added to.
myButtonElement.addEventListener("click", (event) => {
console.log(event.currentTarget); // myButtonElement
});
- .target
- The element that is currently responding to the event listener callback
- May be firing on the element that the event listener was added to, or may be firing on one of its ancestors or descendants.
-
Some events will only fire on one element (the .currentTarget)
-
Others "bubble" meaning the callback is fired on all ancestors and descendants of the .currentTarget element
-
There are two paradigms for propagating events:
-
Bubble mode (Bottom -> Top)
- The default mode
- Fires on the innermost child element first
- Then fires on every ancestor element
-
Capture mode (Top -> Bottom)
- Specified as an extra argument in .addEventListener()
- Fires on the top-most ancestor element first
- Then fires on every descendant element
-
myButtonElement.addEventListener(
"click",
(event) => {
console.log(event.currentTarget); // myButtonElement
},
{
capture: true, // Set capture mode instead of bubble mode
}
);
- To only fire on a specific element, guard by comparing target to currentTarget:
if (event.target !== event.currentTarget)) {
return;
}
// Logic continues if they are the same.
// ...
- To prevent further bubbling/capturing at any point, call:
- event.stopPropagation()
- You could add an event listener to many elements that all exist inside the same ancestor element...
<ul class="my-list">
<li></li>
<li></li>
<li></li>
</ul>
const listItemElements = Array.from(
window.document.querySelectorAll(".my-list > li")
);
listItemElements.forEach((listItemElement) => {
listItemElement.addEventListener("click", doTheThing);
});
- ...Or you could add one event listener to the common ancestor element, knowing the event will bubble and its callback function will fire on all the children:
const listElement = window.document.querySelector(".my-list");
listElement.addEventListener("click", (event) => {
if (event.target.matches(".my-list > li")) {
doThething();
}
});
- This is called event delegation, and can be used for performance purposes, since setting
addEventListener
so many times can cause browser sluggishness, vs just setting one time.