Learnings.md Dump
Dump of learnings.md from the deleted notes repository
JavaScript Reference Guide
Click Event Listener
Adding a click event to an element is best achieved via .addEventListener
, you can then pass a function, or anonymous function that will be called when a click event occurs involving that element
element.addEventListener('click', func);
element.addEventListener('click', () => func());
1
2
3
element.addEventListener('click', function() {
console.log();
});
Can be async, use named or anonymous functions
Finding Elements
1
2
3
4
5
document.querySelector
document.querySelectorAll
document.getElementById
document.getElementsByClassName
document.getElementsByTagName
Semicolons
It’s advised to use semicolons but in testing you can rely on Automatic Semicolon Insertion (ASI), which is a feature from ECMAScript (ECMA) which allows semicolons to be optional in JavaScript. ASI is not perfect and can cause still lead to syntax errors and unexpected behaviour.
‘for’ Loop
There is a newer way to create for loops in JavaScript
that is more syntactically similar to Python
, the first method below
1
2
3
4
const array = [1, 2, 3, 4];
for (const item of array) {
console.log(item);
}
Another way is the forEach
loop which is similar to an enumeration in Python
using for index, item in enumerate(array)
1
2
3
array.forEach((item, index) => {
console.log(index, item);
});
The older method relies upon incrementing, and uses a start value let i = 0
, a conidition i < array.length
, and something that happens each loop i++
which increments i
by one
1
2
3
4
const array = [1, 2, 3, 4];
for (let i = 0; i < array.length; i++) {
console.log(array[i]);
}
JavaScript Arrow Function =>
/ Anonymous Function
Used with or without function body {}
document.addEventListener('click', () => console.log('test')
1
2
3
4
document.addEventListener('click', () => {
let value = x * 2
console.log(value);
});
Analogous with anonymous functions in Python
via lambda: print('hello')
or lambda x: print(x)
Script Defer
Using <script src="script.js" defer></script>
instead of <script src="script.js"></script>
saved from needing to wrap all functionality into main
function in script.js
and calling document.addEventListener('DOMContentLoaded', main)
. Which sounds like it wasn’t a big deal in theory, but global variables could not be defined outside of main
for fear that they might been assigned before the document elements load in, meaning lots of declaration without initialisation
statements / uninitialised variables
which were later initialised once main
was called.
Boilerplate
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Template</title>
<!-- ! Imports -->
<!-- ! CSS -->
<link rel="stylesheet" href="styles.css">
</head>
<body>
<!-- ! HTML -->
<div id="page">
</div>
<!-- ! JavaScript -->
<script src="script.js" defer></script>
</body>
</html>
1
Snippets
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Get ECMA date time string YYYY-MM-DDTHH:mm:ss.sssZ
function getDateString() {
const date = new Date();
const string = date.toISOString();
return string;
}
// Custom HTML element, with this.element attribute
class Custom {
constructor() {
this.element = document.createElement('div');
}
// Log text content of the element attribute
show() {
console.log(this.element.textContent);
}
}
1
2
3
static staticMethod() {
console.log(this) // Here 'this' refers to the class itself
}
Miscellaneous
You can add docstrings in JavaScript
as below
1
2
3
4
5
6
7
8
9
/**
* Add two numbers and return the result
* @param {number} a, the first number
* @param {number} b, second number
* @returns {number} the sum of a and b
*/
function add(a, b) {
return a + b;
}
- You can find ways to auto generate these docstrings
Requests return status codes and 200 and 201-299 are considered successful status codes
Things I Keep Forgetting / Mistakes I Keep Making
- CSS only has block commenting so you try and comment something out that has a comment inside and it does not work, or you try and uncomment one line of a block comment and it doesn’t work (use custom hotkey Ctrl + F1 to fix some issues)
- JavaScript has a less polluted namespace so you can use words you’d expect to be reserved eg.
let string = 'test'
- Declaring a variable or constant in the global scope, then assigning it a value in a function affects the global pointer eg.
var test = 5
in global withtest = 6
in a function call will alter the global value oftest
. Whereas usingvar test = 6
in the function will create a function scopedtest
variable. - Add
"use strict";
to a function or the script itself to disallow assigning value to an undeclared variable - Asynchronous functions do work how they should, but they make every function that calls them need to be async if they care about waiting for the result, rather than just the act of firing them
- You can use
margin: auto
in many cases to avoid usingdisplay: flex
on parent, and avoiding some quirks display: flex
can throw a real tantrum with scrolling / overflow if any of the elements are too big for its defined space- Remember to use
flex-grow: 0
,flex-shrink: 0
,flex-grow: 1
,flex-shrink: 1
more often on flex elements within adisplay: flex
parent position: absolute
requires the parent to have aposition
attribute such asrelative
orabsolute
, and the element will then be placed within the parent but out of the flow of its layout. An example would beposition: absolute; top: 0; left: 0;
which would place the element in the top left of the parent above all other elements, you may needz-index
in certain situations to ensure it is on top- Using
display: none !important
can ensure an element is hidden, useful in the class below1 2 3
.hidden { display: none !important; }
- You can toggle classes with
element.classList.toggle(name)
, remove classeselement.classList.remove(name)
, and add classeselement.classList.add(name)
, there will be no effect for a remove if it is not present, and no effect for an add if it is already present so they are safe methods - You can change a
CSS
style, rather than an element specificially by using something likedocument.querySelector('.hidden').style.display = 'block';
- You can clear all temporary
JavaScript
in-line styles from a given element usingelement.style = ''
, or reset a specific attribute to itsCSS
value using something likeelement.display.style = '';
- Asynchronous code returns a
Promise
object, you can eitherawait
promises so that a function is blocked until the promise is resolved, or use a callback viaPromise.then()
which will run the callback when the promise resolves1 2 3 4 5 6 7
asyncFunction() .then(result => { console.log('success'); }) .catch(error => { console.log('error'); });
- Text from different elements is usually attained via one of the ways below
1 2 3 4
element.textContent; element.value; element.innerHTML; element.innerText;
box-sizing: border-box;
fixes a great many problems in which padding, margin and border change the size and layout of an elementuser-select: none;
is useful to avoid text selection on double-click for an element
Niche Bugs
Had an issue where tapping between a non-empty textarea and a clickable div on mobile led to the phone trying to google search an empty string, hacked / fixed by clearing all window selection on clicking into the clickable div
1
2
3
4
5
6
7
function clearSelection() {
if (window.getSelection) { // Modern
window.getSelection().removeAllRanges();
} else if (document.selection) { // Legacy
document.selection.empty();
}
}
Had an issue where triple-clicking on dekstop in an empty contenteditable element tried to essentially tab to another text element even though they were not direct siblings, seemingly some sort of inate behaviour searching for nearest text nodes for a paragraph select / select all mechanic
Some older CDN modules / packages aren’t setup to be imported easily with modern import export / require define syntax
FFmpeg WASM is broken at the moment or underdocumented
Installing npm
for JavaScript
The main package manager for JavaScript
is npm
, and it works similar to pip
in Python
Install nvm for windows (as the actual nvm is for linux), then use that to install node
nvm -v nvm install latest nvm use 23.7.0 node -v npm -v
nvm allows you to switch the currently used version of node depending on the project with nvm use x.y.z
You can add your own custom .bat files to CMD path to call them globally
- Have decided to use folder
C:\bscripts