JavaScript 20 🧬 Arrays
Arrays in JavaScript are used to store multiple values in a single variable. They’re fundamental in organizing and managing data in a list-like structure.
Arrays are versatile — used to store ordered lists of elements. You can add, remove, and update elements using various methods, iterate with for, for...of, and .forEach(), and use array methods like .map(), .filter(), and .reduce() for functional transformations.
A Quick Look at the Examples
// Creating arrays
const fruits = ['apple', 'banana', 'cherry'];
const numbers = new Array(10); // 10 empty slots
const names = new Array('Alice', 'Bob', 'Charlie'); // 3 elements
// Accessing elements
console.log(fruits[0]); // 'apple'
console.log(fruits[2]); // 'cherry'
console.log(fruits[fruits.length - 1]); // 'cherry' (last)
// Modifying
fruits[1] = 'mango'; // Update
delete fruits[1]; // Remove (not recommended)
fruits.pop(); // Remove last
fruits.shift(); // Remove first
fruits.push('orange'); // Add to end
fruits.unshift('grape'); // Add to beginning
// Iterating
for (let i = 0; i < fruits.length; i++) {
console.log(fruits[i]);
}
for (const fruit of fruits) {
console.log(fruit);
}
fruits.forEach((fruit, index) => {
console.log(`Index ${index}: ${fruit}`);
});
// Mixed types
const mixed = [1, 'hello', true, { name: 'Alice' }];
a. Arrays Introduction
Arrays in JavaScript are used to store multiple values in a single variable. They are fundamental in organizing and managing data in a list-like structure.
Key Characteristics
| Feature | Description |
|---|---|
| Ordered | Elements have a specific order (index-based) |
| Zero-indexed | First element is at index 0 |
| Dynamic size | Can grow or shrink as needed |
| Mixed types | Can hold different data types |
| Iterable | Supports for, for...of, .forEach() |
| Functional methods | .map(), .filter(), .reduce() |
Common Pitfalls
- Undefined elements (from
deleteor sparse arrays) - Improper iteration (using
for...ininstead offor...of) - Off-by-one errors (accessing
arr[arr.length])
b. Create an Array and Access Its Elements
Creating Arrays
| Method | Syntax | Notes |
|---|---|---|
| Array Literal ⭐ | const arr = ['a', 'b', 'c'] | Preferred — clean and fast |
| Array Constructor | const arr = new Array('a', 'b') | Rarely used |
| Array Constructor (length) | const arr = new Array(10) | Creates 10 empty slots ⚠️ |
// ✅ Preferred — array literal
const fruits = ['apple', 'banana', 'cherry'];
// ⚠️ Creates an array with 10 EMPTY slots (not filled with 10!)
const numbers = new Array(10);
console.log(numbers.length); // 10
console.log(numbers[0]); // undefined
// Array constructor with elements
const names = new Array('Alice', 'Bob', 'Charlie');
console.log(names); // ['Alice', 'Bob', 'Charlie']
⚠️ Warning: new Array(10) creates an array with 10 empty slots, NOT an array containing the number 10! Use [10] for that.
const singleNumber = [10]; // [10] — one element
const emptySlots = new Array(10); // [empty × 10]
Accessing Array Elements
Arrays are zero-indexed — the first element is at index 0.
const fruits = ['apple', 'banana', 'cherry'];
console.log(fruits[0]); // 'apple' (first)
console.log(fruits[1]); // 'banana' (second)
console.log(fruits[2]); // 'cherry' (third)
console.log(fruits[3]); // undefined (out of bounds)
// Access last element
console.log(fruits[fruits.length - 1]); // 'cherry'
Index diagram:
Index: 0 1 2
┌─────────┬─────────┬─────────┐
fruits: │ 'apple' │'banana' │'cherry' │
└─────────┴─────────┴─────────┘
Length: 3
c. Modify Array Elements
You can update or remove elements from an array using various methods.
Update an Element
const fruits = ['apple', 'banana', 'cherry'];
fruits[1] = 'mango';
console.log(fruits); // ['apple', 'mango', 'cherry']
Remove Elements
| Method | Effect | Example |
|---|---|---|
delete arr[i] | Sets to undefined (leaves a hole) ⚠️ | delete fruits[1] |
pop() | Removes last element | fruits.pop() |
shift() | Removes first element | fruits.shift() |
splice(i, n) | Removes n elements starting at i | fruits.splice(1, 1) |
const fruits = ['apple', 'banana', 'cherry'];
// ⚠️ Not recommended — leaves a hole
delete fruits[1];
console.log(fruits); // ['apple', undefined, 'cherry']
console.log(fruits.length); // 3 (length unchanged!)
// ✅ Recommended — pop() removes last
fruits.pop();
console.log(fruits); // ['apple', 'banana']
// ✅ Recommended — shift() removes first
fruits.shift();
console.log(fruits); // ['banana', 'cherry']
Add Elements
| Method | Effect | Example |
|---|---|---|
push() | Adds to end | fruits.push('orange') |
unshift() | Adds to beginning | fruits.unshift('grape') |
splice(i, 0, item) | Inserts at position | fruits.splice(1, 0, 'kiwi') |
const fruits = ['apple', 'banana'];
fruits.push('orange');
console.log(fruits); // ['apple', 'banana', 'orange']
fruits.unshift('grape');
console.log(fruits); // ['grape', 'apple', 'banana', 'orange']
d. Iterating Over an Array, length, and Features
Three Ways to Iterate
1. Classic for Loop
const fruits = ['apple', 'banana', 'cherry'];
for (let i = 0; i < fruits.length; i++) {
console.log(fruits[i]);
}
// apple
// banana
// cherry
2. for...of Loop (Recommended for values)
for (const fruit of fruits) {
console.log(fruit);
}
// apple
// banana
// cherry
3. .forEach() Method
fruits.forEach((fruit, index) => {
console.log(`Index ${index}: ${fruit}`);
});
// Index 0: apple
// Index 1: banana
// Index 2: cherry
Comparison
| Loop | Gives you | Can break? | Best for |
|---|---|---|---|
for | Index + value | ✅ Yes (break) | Complex logic |
for...of | Value only | ✅ Yes (break) | Simple iteration |
.forEach() | Index + value | ❌ No | Functional style |
The length Property
Returns the number of elements in the array.
const fruits = ['apple', 'banana', 'cherry'];
console.log(fruits.length); // 3
// Empty array
console.log([].length); // 0
⚠️ Gotcha: Setting length truncates or extends the array:
const arr = [1, 2, 3, 4, 5];
arr.length = 3;
console.log(arr); // [1, 2, 3] — truncated!
arr.length = 5;
console.log(arr); // [1, 2, 3, empty × 2] — extended with holes!
Dynamic Size and Mixed Types
// Dynamic size
const arr = [1, 2, 3];
arr.push(4); // [1, 2, 3, 4]
arr.pop(); // [1, 2, 3]
arr.push(4, 5, 6); // [1, 2, 3, 4, 5, 6]
// Mixed data types
const mixed = [1, 'hello', true, { name: 'Alice' }, [1, 2, 3], null];
console.log(mixed[0]); // 1
console.log(mixed[1]); // 'hello'
console.log(mixed[3].name); // 'Alice'
Sparse Arrays (Pitfall)
const fruits = ['apple', 'banana', 'cherry'];
fruits[10] = 'new fruit';
console.log(fruits.length); // 11
console.log(fruits); // ['apple', 'banana', 'cherry', empty × 7, 'new fruit']
// Indexes 3-9 are empty (undefined)
// forEach skips empty slots
fruits.forEach((fruit, i) => console.log(i, fruit));
// 0 apple
// 1 banana
// 2 cherry
// 10 new fruit (skips 3-9)
e. Built-in Methods
Mutating Methods (Modify Original)
| Method | Description | Example | Result |
|---|---|---|---|
push(item) | Adds to end | arr.push('new') | [1, 2, 'new'] |
pop() | Removes last | arr.pop() | [1, 2] |
shift() | Removes first | arr.shift() | [2, 3] |
unshift(item) | Adds to beginning | arr.unshift('first') | ['first', 1, 2, 3] |
splice(i, n, ...items) | Adds/removes at position | arr.splice(1, 1, 'new') | Removes 1 at index 1, inserts ‘new’ |
Non-Mutating Methods (Return New)
| Method | Description | Example | Result |
|---|---|---|---|
slice(start, end) | Shallow copy of portion | arr.slice(1, 3) | [2, 3] |
indexOf(item) | First index of item | arr.indexOf('apple') | 0 (or -1) |
includes(item) | Checks existence | arr.includes('apple') | true / false |
join(sep) | Joins into string | arr.join(', ') | "1, 2, 3" |
map(fn) | New array with transformed values | arr.map(x => x * 2) | [2, 4, 6] |
filter(fn) | New array with filtered elements | arr.filter(x => x > 1) | [2, 3] |
reduce(fn, init) | Single value | arr.reduce((a, b) => a + b, 0) | 6 |
Examples
const arr = [1, 2, 3];
// Mutating
arr.push(4); // [1, 2, 3, 4]
arr.pop(); // [1, 2, 3]
arr.unshift(0); // [0, 1, 2, 3]
arr.shift(); // [1, 2, 3]
arr.splice(1, 1); // [1, 3] (removes 2)
arr.splice(1, 0, 2); // [1, 2, 3] (inserts 2 at index 1)
// Non-mutating
const arr2 = [1, 2, 3, 4, 5];
console.log(arr2.slice(1, 3)); // [2, 3]
console.log(arr2.indexOf(3)); // 2
console.log(arr2.includes(3)); // true
console.log(arr2.join(', ')); // "1, 2, 3, 4, 5"
console.log(arr2.map(x => x * 2)); // [2, 4, 6, 8, 10]
console.log(arr2.filter(x => x > 2)); // [3, 4, 5]
console.log(arr2.reduce((a, b) => a + b, 0)); // 15
Complete Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Arrays</title>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
background: #f8f9fa;
color: #333;
line-height: 1.6;
}
h1 { color: #007bff; border-bottom: 3px solid #007bff; padding-bottom: 10px; }
h2 { color: #28a745; border-left: 4px solid #28a745; padding-left: 15px; margin-top: 30px; }
.demo-box {
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
margin: 15px 0;
}
pre {
background: #1e1e1e;
color: #d4d4d4;
padding: 15px;
border-radius: 8px;
overflow-x: auto;
font-family: 'Courier New', monospace;
font-size: 0.9rem;
line-height: 1.8;
}
.keyword { color: #569cd6; }
.string { color: #ce9178; }
.number { color: #b5cea8; }
.function { color: #dcdcaa; }
.comment { color: #6a9955; }
.boolean { color: #569cd6; }
#output {
background: #e9ecef;
padding: 15px;
border-radius: 8px;
margin-top: 15px;
min-height: 40px;
font-family: 'Courier New', monospace;
font-size: 0.85rem;
border-left: 4px solid #007bff;
white-space: pre-wrap;
}
table {
width: 100%;
border-collapse: collapse;
margin: 15px 0;
}
th, td {
padding: 10px;
border: 1px solid #ddd;
text-align: left;
}
th { background: #007bff; color: white; }
tr:nth-child(even) { background: #f8f9fa; }
.btn {
padding: 10px 20px;
background: #007bff;
color: white;
border: none;
border-radius: 6px;
font-size: 1em;
font-weight: bold;
cursor: pointer;
margin: 5px;
transition: all 0.3s;
}
.btn:hover {
background: #0056b3;
transform: translateY(-2px);
}
.btn-success { background: #28a745; }
.btn-success:hover { background: #1e7e34; }
.btn-danger { background: #dc3545; }
.btn-danger:hover { background: #a71d2a; }
.array-display {
font-family: 'Courier New', monospace;
font-size: 1.1em;
color: #007bff;
background: #f8f9fa;
padding: 15px;
border-radius: 8px;
margin: 10px 0;
border-left: 4px solid #007bff;
word-break: break-all;
}
</style>
</head>
<body>
<h1>Arrays</h1>
<div class="demo-box">
<h2>1. Creating Arrays</h2>
<pre>
<span class="comment">// ✅ Array literal (preferred)</span>
<span class="keyword">const</span> fruits = [<span class="string">'apple'</span>, <span class="string">'banana'</span>, <span class="string">'cherry'</span>];
<span class="comment">// ⚠️ Array constructor with length</span>
<span class="keyword">const</span> numbers = <span class="keyword">new</span> <span class="function">Array</span>(<span class="number">10</span>); <span class="comment">// 10 empty slots</span>
<span class="comment">// Array constructor with elements</span>
<span class="keyword">const</span> names = <span class="keyword">new</span> <span class="function">Array</span>(<span class="string">'Alice'</span>, <span class="string">'Bob'</span>, <span class="string">'Charlie'</span>);
</pre>
</div>
<div class="demo-box">
<h2>2. Accessing Elements</h2>
<pre>
<span class="keyword">const</span> fruits = [<span class="string">'apple'</span>, <span class="string">'banana'</span>, <span class="string">'cherry'</span>];
console.log(fruits[<span class="number">0</span>]); <span class="comment">// 'apple'</span>
console.log(fruits[<span class="number">2</span>]); <span class="comment">// 'cherry'</span>
console.log(fruits[fruits.length - <span class="number">1</span>]); <span class="comment">// 'cherry' (last)</span>
</pre>
</div>
<div class="demo-box">
<h2>3. Interactive: Array Operations</h2>
<div class="array-display" id="arrayDisplay">['apple', 'banana', 'cherry']</div>
<div style="margin: 10px 0;">
<button class="btn btn-success" onclick="arrayOp('push')">push('date')</button>
<button class="btn btn-danger" onclick="arrayOp('pop')">pop()</button>
<button class="btn btn-danger" onclick="arrayOp('shift')">shift()</button>
<button class="btn btn-success" onclick="arrayOp('unshift')">unshift('grape')</button>
<button class="btn" onclick="arrayOp('update')">Update [1]</button>
<button class="btn" onclick="arrayOp('reset')">Reset</button>
</div>
<div id="arrayStatus"></div>
</div>
<div class="demo-box">
<h2>4. Array Methods Cheat Sheet</h2>
<table>
<tr>
<th>Method</th>
<th>Description</th>
<th>Mutates?</th>
</tr>
<tr><td><code>push()</code></td><td>Add to end</td><td>✅ Yes</td></tr>
<tr><td><code>pop()</code></td><td>Remove last</td><td>✅ Yes</td></tr>
<tr><td><code>shift()</code></td><td>Remove first</td><td>✅ Yes</td></tr>
<tr><td><code>unshift()</code></td><td>Add to beginning</td><td>✅ Yes</td></tr>
<tr><td><code>splice()</code></td><td>Add/remove at position</td><td>✅ Yes</td></tr>
<tr><td><code>slice()</code></td><td>Copy portion</td><td>❌ No</td></tr>
<tr><td><code>indexOf()</code></td><td>Find index</td><td>❌ No</td></tr>
<tr><td><code>includes()</code></td><td>Check existence</td><td>❌ No</td></tr>
<tr><td><code>join()</code></td><td>Join to string</td><td>❌ No</td></tr>
<tr><td><code>map()</code></td><td>Transform</td><td>❌ No</td></tr>
<tr><td><code>filter()</code></td><td>Filter</td><td>❌ No</td></tr>
<tr><td><code>reduce()</code></td><td>Reduce to single value</td><td>❌ No</td></tr>
</table>
</div>
<div class="demo-box">
<h2>5. Live Output — All Examples</h2>
<div id="output">Loading...</div>
</div>
<script>
// ============================================
// Arrays — Live Demo
// ============================================
let results = [];
// 1. Creating arrays
results.push('📌 Creating Arrays:\n');
const fruits = ['apple', 'banana', 'cherry'];
results.push(' Array literal: [' + fruits.join(', ') + ']');
const emptySlots = new Array(3);
results.push(' new Array(3) → length: ' + emptySlots.length + ', values: ' + JSON.stringify(emptySlots));
const names = new Array('Alice', 'Bob', 'Charlie');
results.push(' new Array("Alice", "Bob", "Charlie") → [' + names.join(', ') + ']');
results.push('');
// 2. Accessing elements
results.push('📌 Accessing Elements:\n');
results.push(' fruits[0] → ' + fruits[0]);
results.push(' fruits[2] → ' + fruits[2]);
results.push(' fruits[fruits.length - 1] → ' + fruits[fruits.length - 1]);
results.push(' fruits[99] → ' + fruits[99] + ' (out of bounds)');
results.push('');
// 3. Modifying elements
results.push('📌 Modifying Elements:\n');
const modFruits = ['apple', 'banana', 'cherry'];
modFruits[1] = 'mango';
results.push(' After fruits[1] = "mango": [' + modFruits.join(', ') + ']');
modFruits.pop();
results.push(' After pop(): [' + modFruits.join(', ') + ']');
modFruits.push('orange');
results.push(' After push("orange"): [' + modFruits.join(', ') + ']');
modFruits.unshift('grape');
results.push(' After unshift("grape"): [' + modFruits.join(', ') + ']');
modFruits.shift();
results.push(' After shift(): [' + modFruits.join(', ') + ']');
results.push('');
// 4. Iterating
results.push('📌 Iterating:\n');
const iterateFruits = ['apple', 'banana', 'cherry'];
let forLoop = [];
for (let i = 0; i < iterateFruits.length; i++) {
forLoop.push(iterateFruits[i]);
}
results.push(' for loop: [' + forLoop.join(', ') + ']');
let forOfLoop = [];
for (const fruit of iterateFruits) {
forOfLoop.push(fruit);
}
results.push(' for...of: [' + forOfLoop.join(', ') + ']');
let forEachResult = [];
iterateFruits.forEach((fruit, index) => {
forEachResult.push(index + ':' + fruit);
});
results.push(' forEach: [' + forEachResult.join(', ') + ']');
results.push('');
// 5. Array methods
results.push('📌 Array Methods:\n');
const arr = [1, 2, 3, 4, 5];
results.push(' Original: [' + arr.join(', ') + ']');
results.push(' slice(1, 3): [' + arr.slice(1, 3).join(', ') + ']');
results.push(' indexOf(3): ' + arr.indexOf(3));
results.push(' includes(4): ' + arr.includes(4));
results.push(' join(" - "): "' + arr.join(' - ') + '"');
results.push(' map(x => x * 2): [' + arr.map(x => x * 2).join(', ') + ']');
results.push(' filter(x => x > 2): [' + arr.filter(x => x > 2).join(', ') + ']');
results.push(' reduce((a,b) => a+b): ' + arr.reduce((a, b) => a + b, 0));
results.push(' Original (unchanged): [' + arr.join(', ') + ']');
results.push('');
// 6. Mixed types
results.push('📌 Mixed Types:\n');
const mixed = [1, 'hello', true, { name: 'Alice' }, [1, 2, 3], null];
results.push(' [' + mixed.map(v => typeof v).join(', ') + ']');
results.push(' mixed[3].name → ' + mixed[3].name);
results.push('');
// 7. Sparse arrays
results.push('📌 Sparse Arrays (⚠️ Pitfall):\n');
const sparse = ['apple', 'banana', 'cherry'];
sparse[10] = 'new fruit';
results.push(' After sparse[10] = "new fruit":');
results.push(' length: ' + sparse.length);
results.push(' sparse[5] → ' + sparse[5] + ' (empty slot)');
results.push(' ⚠️ Sparse arrays can cause bugs — avoid them!');
document.getElementById('output').textContent = results.join('\n');
// ============================================
// Interactive Array Operations
// ============================================
let interactiveArray = ['apple', 'banana', 'cherry'];
function updateDisplay() {
document.getElementById('arrayDisplay').textContent = '[' +
interactiveArray.map(v => v === undefined ? 'undefined' : `'${v}'`).join(', ') + ']';
}
function arrayOp(op) {
const status = document.getElementById('arrayStatus');
let before = '[' + interactiveArray.join(', ') + ']';
let message = '';
switch (op) {
case 'push':
interactiveArray.push('date');
message = 'push("date") → added to end';
break;
case 'pop':
const popped = interactiveArray.pop();
message = `pop() → removed "${popped}"`;
break;
case 'shift':
const shifted = interactiveArray.shift();
message = `shift() → removed "${shifted}"`;
break;
case 'unshift':
interactiveArray.unshift('grape');
message = 'unshift("grape") → added to beginning';
break;
case 'update':
if (interactiveArray.length > 1) {
interactiveArray[1] = 'mango';
message = 'fruits[1] = "mango" → updated index 1';
} else {
message = 'Array too short to update index 1';
}
break;
case 'reset':
interactiveArray = ['apple', 'banana', 'cherry'];
message = 'Reset to original';
break;
}
updateDisplay();
status.innerHTML = `<p><strong>${message}</strong></p>
<p>Before: <code>${before}</code></p>
<p>After: <code>${'[' + interactiveArray.join(', ') + ']'}</code></p>
<p>Length: ${interactiveArray.length}</p>`;
}
updateDisplay();
</script>
</body>
</html>
Quick Reference
Creating Arrays
| Method | Example | Notes |
|---|---|---|
| Literal ⭐ | const arr = ['a', 'b', 'c'] | Preferred |
| Constructor | const arr = new Array('a', 'b') | With elements |
| Constructor (length) | const arr = new Array(10) | 10 empty slots ⚠️ |
Mutating Methods (Modify Original)
| Method | Description | Example |
|---|---|---|
push() | Add to end | arr.push('x') |
pop() | Remove last | arr.pop() |
shift() | Remove first | arr.shift() |
unshift() | Add to beginning | arr.unshift('x') |
splice() | Add/remove at position | arr.splice(1, 1, 'new') |
Non-Mutating Methods (Return New)
| Method | Description | Example |
|---|---|---|
slice() | Copy portion | arr.slice(1, 3) |
indexOf() | Find index | arr.indexOf('x') |
includes() | Check existence | arr.includes('x') |
join() | Join to string | arr.join(', ') |
map() | Transform values | arr.map(x => x * 2) |
filter() | Filter elements | arr.filter(x => x > 2) |
reduce() | Reduce to single value | arr.reduce((a, b) => a + b, 0) |
Iteration Methods
| Method | Gives you | Can break? |
|---|---|---|
for | Index + value | ✅ Yes |
for...of | Value only | ✅ Yes |
.forEach() | Index + value | ❌ No |
Best Practices
✅ Do This:
// Use array literals
const arr = [1, 2, 3];
// Use for...of for simple iteration
for (const item of arr) {
console.log(item);
}
// Use map/filter/reduce for transformations
const doubled = arr.map(x => x * 2);
const evens = arr.filter(x => x % 2 === 0);
const sum = arr.reduce((a, b) => a + b, 0);
// Use spread for copying
const copy = [...arr];
// Use includes for existence check
if (arr.includes('apple')) { }
// Use slice to copy a portion
const portion = arr.slice(1, 3);
❌ Don’t Do This:
// Don't use delete (leaves holes)
delete arr[1]; // ❌ Leaves undefined at index 1
// Don't use new Array(n) expecting n elements
const arr = new Array(5); // ❌ 5 EMPTY slots, not [5]
// Don't use for...in for arrays
for (const i in arr) { } // ❌ Iterates indices as strings
// Don't forget that sort() mutates!
arr.sort(); // ❌ Modifies original!
// Don't access out of bounds
console.log(arr[arr.length]); // ❌ undefined!
Common Pitfalls
| Pitfall | Problem | Solution |
|---|---|---|
new Array(5) | Creates 5 empty slots | Use [5] for single element |
delete arr[i] | Leaves holes | Use splice() or filter() |
for...in on arrays | Iterates indices as strings | Use for...of |
sort() mutates | Original array changed | Use [...arr].sort() |
| Sparse arrays | Empty slots cause bugs | Avoid or fill with fill() |
arr[arr.length] | Out of bounds | Use arr[arr.length - 1] |
== vs === | Type coercion | Use === |
Pro Tip: Use array literals ([]) — they’re cleaner and faster than new Array(). Use for...of for simple iteration and .forEach() for functional style. The map, filter, and reduce methods are pure — they return new arrays without modifying the original. But push, pop, shift, unshift, splice, and sort mutate the original array — use them carefully! And remember: arrays are zero-indexed — the first element is at index 0, and the last is at arr.length - 1.
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!