Welcome to my JavaScript notebook! Here, I've compiled a variety of tips, tricks, and simple snippets that I've gathered over time. These notes come from various sources, including my professional work, problem-solving on LeetCode, and personal projects. My aim is to document these insights for my own reference and to share them with anyone who might find them useful or interesting. Whether you're a fellow developer or just curious about JavaScript, I hope you'll find something valuable in these pages.
Array
Creating an array filled with empty arrays: 1
let filledWithEmptyArrays = Array(3).fill().map(() => []);
Creating a 2D array (e.g., for a visitation matrix):
1
let visited = Array.from({ length: l }, () => Array.from({ length: l }, () => 0));
Creating an array filled with zeros: 1
Array(26).fill(0);
Creating an array filled with false: 1
Array(n).fill(false);
dp
1 | let dp = new Array(N).fill(0); |
2D array
1 | const N = 5; |
output: 1
2
3
4
5
6
7
8dp [
[ 0, 0, 0, 0, 0, 0 ],
[ 0, 0, 0, 0, 0, 0 ],
[ 0, 0, 0, 0, 0, 0 ],
[ 0, 0, 0, 0, 0, 0 ],
[ 0, 0, 0, 0, 0, 0 ],
[ 0, 0, 0, 0, 0, 0 ]
]
visited
0 = Unvisited, 1 = Visiting, 2 = Visited; Or simply use boolean,
depends on the use case. 1
let visited = new Array(numCourses).fill(0);
adjacency
This approach is explicit about initialising the array with null
values before mapping. 1
2
3
4
5let N = 10
let adj = new Array(N).fill(null).map(() => []);
let prerequisites = [[1,0],[0,1]];
prerequisites.forEach(([a, b]) => adj[a].push(b));
Sorting Arrays
Sort an array of numbers in ascending order: 1
[11, 2, 22, 1].sort((a, b) => a - b);
Priority Queue (pq)
Min-Heap based on sum of pairs: 1
2
3const pq = new PriorityQueue({
compare: (a, b) => a.sum - b.sum
});
Max-Heap based on sum of pairs: 1
2
3const pq = new PriorityQueue({
compare: (a, b) => b.sum - a.sum
});
Can enqueue with data set like so: 1
pq.enqueue({ sum: 100, i: 0, j: 0 });
MinPriorityQueue
- This class allows you to manage elements in a min-heap fashion, where the smallest element is always at the top.
- It's particularly useful for problems where you need to efficiently access and remove the smallest element repeatedly.
MaxPriorityQueue
- This class manages elements in a max-heap fashion, where the largest element is always at the top.
- Use it when you need to access and remove the largest element efficiently.
Example Usage:
Here's a quick example of using a MinPriorityQueue
in a
LeetCode problem:
1 | let heap = new MinPriorityQueue(); |
Note: These classes are specific to the LeetCode
environment and are not available in standard JavaScript. You will need
to implement your own or use a third-party library if you are working
outside LeetCode. 1
npm install --save @datastructures-js/priority-queue
1 | const { |
PriorityQueue in this repo is implemented as 3 types:
- PriorityQueue that accepts a custom comparator between elements.
- MinPriorityQueue which considers an element with smaller priority number as higher in priority.
- MaxPriorityQueue which cosiders an element with bigger priority number as higher in priority.
Build From Scratch
Min-Heap Implementation
A min-heap is a binary tree where the parent nodes are smaller than their children. Here's a basic implementation:
1 | class MinHeap { |
Max-Heap Implementation
A max-heap is similar to a min-heap, but the parent nodes are larger than their children.
1 | class MaxHeap { |
Key Points to Remember:
- Min-Heap: Always keeps the smallest element at the top.
- Max-Heap: Always keeps the largest element at the top.
- Time Complexity: Insertion and deletion operations both take \(O(\log n)\) time, where \(n\) is the number of elements in the heap.
- Use Cases: Min-heaps are useful for problems requiring efficient access to the minimum element (e.g., Dijkstra's algorithm), while max-heaps are used when you need quick access to the maximum element (e.g., priority scheduling).
LeetCode Imported Tips
When working on LeetCode problems, you might come across built-in
utility classes like MinPriorityQueue
and
MaxPriorityQueue
. These classes are provided by the
LeetCode environment to simplify the process of implementing priority
queues, which are essentially min-heaps and max-heaps.
1 | JavaScript node.js 20.10.0 |
- LeetCode - What are the environments for the programming languages?
- GitHub - @datastructures-js/priority-queue
Working with JSON
Convert an object or array to a JSON string: 1
JSON.stringify(obj);
map - set()
Initialise a map with key-value pairs: 1
2
3
4
5const myMap = new Map([
['key1', 'value1'],
['key2', 'value2'],
['key3', 'value3']
]);
Convert map values to an array: 1
const valuesArray = Array.from(myMap.values());
set - add()
...
Math
Find the maximum value in a list of numbers: 1
Math.max(...list);
Round a number to at most 2 decimal places: 1
Math.round(num * 100) / 100;
To ensure numbers like 1.005 round correctly: 1
Math.round((num + Number.EPSILON) * 100) / 100;
CSS: Adding Styles to :before and :after
Dynamically add CSS styles to :before
and
:after
selectors: 1
2var styleElem = document.head.appendChild(document.createElement("style"));
styleElem.innerHTML = ".add-fading-" + nth + ":before { z-index: 1 !important; }";
NPM Packages
md-file-tree by @michalbe
Generate a markdown tree of all files in a directory, recursively:
1 | ## Display in console |
JavaScript Obfuscator
Obfuscate JavaScript code to make it harder to understand:
1
2
3
4
5
6
7
8
9
10
11var fs = require("fs");
var jsObfuscator = require("js-obfuscator");
fs.readFile("./000_unencrypted-js/main.js", "UTF-8", function (error, code) {
if (error) throw error;
var obfuscatedResult = jsObfuscator.obfuscate(code);
fs.writeFile("./js/main.js", obfuscatedResult.getObfuscatedCode(), function (fsError) {
if (fsError) console.log(fsError);
console.log("Obfuscated.");
});
});
TypeScript: Child Manager Configuration
Example configuration for managing multiple processes:
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43{
"processes": [
{
"name": "Frontend",
"command": {
"executor": "yarn",
"args": [
"start"
],
"path": "../fe-project",
"isWindows": false
},
"maxLogs": 200
},
{
"name": "WebSocket",
"command": {
"executor": "yarn",
"args": [
"start"
],
"path": "../server-project",
"isWindows": false
},
"maxLogs": 300
},
{
"name": "Docker",
"command": {
"executor": "docker-compose",
"args": [
"up"
],
"path": "../be-project",
"isWindows": false
},
"maxLogs": 300
}
],
"captureExit": true,
"longLive": false,
"debug": false
}
HTML: onkeydown
To put on <form>
to prevent user clicks on
enter.
1 | onkeydown="return event.key != 'Enter';" |
Spread operator
1 | const obj = { name: "Jing Hui", age: 24 } |
Destructuring assignments
You can use them in different contexts, such as swapping values, extracting properties from objects or arrays, and working with functions:
Swapping Two Variables
This is the most common use case: swapping two variables without using a temporary variable.
1 | let a = 5; |
got this from Rotate Array (todo add link)
Extracting Values from Arrays
You can use destructuring to assign array elements to variables.
1 | const numbers = [1, 2, 3, 4]; |
Default Values in Array Destructuring
If the array is shorter than expected, you can provide default values.
1 | const colors = ['red']; |
Object Destructuring
You can destructure objects to extract specific properties into variables.
1 | const person = { |
Object Destructuring with Aliases
You can also rename the extracted properties by assigning them to new variable names.
1 | const employee = { |
Nested Object Destructuring
Destructuring can also be used for nested objects.
1 | const student = { |
Function Parameter Destructuring
You can destructure objects or arrays passed as function parameters.
1 | // Destructure object in function parameters |
Rest Operator in Destructuring (Spread Operator)
You can use the rest (...
) operator to capture the
remaining elements after destructuring.
1 | const fruits = ['apple', 'banana', 'cherry', 'date']; |
Ignoring Values in Destructuring
You can ignore certain elements when destructuring arrays.
1 | const scores = [100, 90, 85, 80]; |
Combining Arrays and Destructuring
Destructuring works seamlessly when combining multiple arrays.
1 | const arr1 = [1, 2, 3]; |
TODO: Rest Operator
(...
)
The rest operator is used to gather multiple elements into a single array or object. You usually see it in function parameters or destructuring.
Example 1: Rest in Function Parameters
In functions, the rest operator gathers all the extra arguments passed to the function into an array.
1 | function showNumbers(...numbers) { |
Breakdown:
- The
...numbers
gathers all the arguments (1, 2, 3, 4, 5) into a single array namednumbers
.
Example 2: Rest in Array Destructuring
In destructuring, the rest operator gathers remaining elements of an array into a new array.
1 | const [first, second, ...rest] = [10, 20, 30, 40, 50]; |
Breakdown:
first
gets the value10
,second
gets20
, and the rest of the values (30, 40, 50
) are collected into therest
array.
Example 3: Rest in Object Destructuring
You can also use the rest operator to gather remaining properties of an object.
1 | const person = { name: 'Alice', age: 25, country: 'USA' }; |
Breakdown:
name
getsAlice
, and the remaining properties (age
,country
) are collected into thedetails
object.
Spread Operator (...
)
The spread operator is used to spread out the elements of an array, object, or iterable into individual elements.
Example 1: Spread in Arrays
Spread operator expands the elements of an array. This is often used to combine arrays.
1 | const arr1 = [1, 2]; |
Breakdown:
...arr1
spreads out[1, 2]
, and...arr2
spreads out[3, 4]
, combining them into one array.
Example 2: Spread in Function Calls
You can pass the elements of an array as individual arguments to a function using the spread operator.
1 | const numbers = [5, 6, 7]; |
Breakdown:
...numbers
spreads the array[5, 6, 7]
intoMath.max
as individual arguments (5, 6, 7
).
Example 3: Spread in Objects
The spread operator can copy properties from one object to another.
1 | const obj1 = { a: 1, b: 2 }; |
Breakdown:
...obj1
spreads the properties ofobj1
into a new object, followed by...obj2
spreading the properties ofobj2
.
Summary of Differences
Feature | Rest Operator (... ) |
Spread Operator (... ) |
---|---|---|
Purpose | Gathers elements into an array/object | Spreads elements into individual items |
Usage | Function parameters, destructuring | Function calls, array/object merging |
Example | function(...args) {} |
Math.max(...[1, 2, 3]) |
Final Thoughts
- Rest collects multiple elements into an array or
object.
- Example: Collect remaining arguments in a function.
- Spread takes an array or object and breaks it into
individual elements.
- Example: Pass an array as arguments to a function or merge arrays/objects.
🐛 Common Errors
Array Referencing Issue
The method that causes all elements to reference the same array:
1
let adj = new Array(N).fill([]);
- When using fill with objects (including arrays), it copies the reference to the object.
- For primitive types (like numbers or strings), it copies the value.
- Avoiding Common Pitfalls: Don't use fill with mutable objects if you need distinct instances.
✅ The Correct Way!
This approach is more concise and directly initialises the array
elements: 1
2
3let adj = new Array(N).fill(null).map(() => []);
// OR
let adj = Array.from({ length: N }, () => []);
TODO
- https://threejs.org/