I’ve been revisiting JavaScript recently.
Not because I’ve never used it before, but because I realised there were a lot of things I could recognise when I saw them in code without feeling fully confident that I understood them properly.
That distinction started bothering me.
I could read JavaScript.
I could follow what was happening.
But being able to look at code and understand it is not always the same as being able to sit down with a blank file and write it confidently yourself.
So I decided to go back to the basics.
And weirdly enough, I’ve been enjoying it a lot more than I expected.
There’s something satisfying about revisiting something familiar and realising you understand it differently the second time around.
Starting from the beginning again
I started with things like:
const userName = "Sabi";
const role = "admin";
let postCount = 0;
Very basic stuff.
At first, part of me wanted to rush through it because I already knew what const and let were.
But slowing down actually helped.
Instead of just remembering that let can be reassigned and const cannot, I started thinking more deliberately about why I would choose one over the other.
That set the tone for the rest of the refresher.
I wasn’t just trying to remember syntax.
I wanted the concepts to actually make sense.
Functions exposed a few gaps
Functions were another area where I thought I was already comfortable.
Then I started paying more attention to the smaller details.
For example:
function checkAccess(role) {
return role === "admin";
}
checkAccess("admin");
role is the parameter.
"admin" is the argument.
Simple distinction, but it reminded me how easy it is to skip over small concepts because you’ve seen them so many times.
Those gaps add up.
Arrays were where things started getting more interesting
I revisited arrays and loops, then moved into:
map()
filter()
find()
some()
every()
reduce()
These are methods I’ve seen and used before, but going through them one by one made the differences much clearer.
For example:
const users = [
{ name: "Sabi", role: "admin" },
{ name: "Kong", role: "member" },
{ name: "Vandal", role: "member" }
];
To get all admins:
const admins = users.filter(
(user) => user.role === "admin"
);
To get one particular user:
const user = users.find(
(user) => user.name === "Vandal"
);
Same array.
Different intention.
That sounds obvious, but writing these things myself made them stick much better than just reading examples.
I had been using callbacks without really thinking about them
This was one of the more useful moments.
Something like:
users.filter((user) => user.role === "admin");
looks completely normal.
But that function inside filter() is a callback.
When I recreated the idea manually:
function welcomeUser(name) {
console.log(`Welcome, ${name}`);
}
function welcomeUsers(users, callback) {
for (let i = 0; i < users.length; i++) {
callback(users[i]);
}
}
it clicked more clearly.
A callback stopped sounding like some special JavaScript concept.
It was just a function being passed into another function so it could be called later.
Sometimes understanding something is really just removing the fancy name from it.
Destructuring finally stopped feeling like magic
I’ve used destructuring plenty of times before:
const { name, role } = user;
and:
const [firstUser, secondUser] = users;
But during the refresher, I actually made a mistake and tried to destructure an array using {}.
That was useful.
It forced me to think about what JavaScript was actually doing.
Objects:
const { name, role } = user;
Arrays:
const [firstUser, secondUser] = users;
Objects are matched by property name.
Arrays are matched by position.
That mistake probably taught me more than just reading the correct syntax would have.
Spread and rest made more sense this time
Then came spread:
const updatedUsers = [...users, "Efo"];
and:
const updatedUser = {
...user,
role: "admin"
};
I’d seen this syntax countless times before.
But revisiting it properly made the logic much clearer.
Spread takes existing values and spreads them into a new structure.
Rest uses the same ... but collects values:
function addUsers(...users) {
return users;
}
The way I remember it now is:
Spread = spread things out
Rest = gather things together
Simple, but it works.
Async JavaScript was probably the most important part
Promises and async/await were where the refresher became much more valuable.
I created a Promise like this:
const getUsers = new Promise((resolve, reject) => {
setTimeout(() => {
resolve([
{ name: "Sabi", role: "admin" },
{ name: "Kong", role: "member" }
]);
}, 5000);
});
Then worked with .then():
getUsers
.then((users) => {
return users.filter(
(user) => user.role === "member"
);
})
.then((members) => {
return members.map(
(member) => member.name
);
})
.then((names) => {
console.log(names);
});
One thing that stood out here was the difference between logging and returning.
This:
console.log(users);
shows me something.
This:
return users;
passes the value forward so another part of the program can use it.
I knew that already in isolation, but Promise chaining made the difference feel much more important.
async/await made everything easier to reason about
Once I moved from .then() to:
async function showUsers() {
try {
const users = await getUsers;
const members = users.filter(
(user) => user.role === "member"
);
const names = members.map(
(member) => member.name
);
console.log(names);
} catch (error) {
console.log(error.message);
}
}
the flow became much easier to read.
I also finally got a stronger understanding of what await actually does.
It pauses the current async function.
It does not pause the entire JavaScript program.
That distinction made async code feel a lot less mysterious.
Fetch tied everything together
Then I moved into fetch().
const response = await fetch(
"https://jsonplaceholder.typicode.com/users"
);
if (!response.ok) {
throw new Error("Failed to fetch users");
}
const users = await response.json();
This was probably the point where the refresher stopped feeling like a list of separate JavaScript topics.
Suddenly everything connected:
functions
↓
Promises
↓
async/await
↓
HTTP
↓
fetch
↓
JSON
↓
arrays
↓
map / filter / find
That was one of the biggest things I took away from the whole process.
The concepts make much more sense when they stop being separate chapters and start working together.
Modules were a good place to finish
The final part of the refresher was modules.
I practised exporting functions:
export function findUser(users, name) {
return users.find(
(user) => user.name === name
);
}
export function getAdmins(users) {
return users.filter(
(user) => user.role === "admin"
);
}
and importing them somewhere else:
import {
findUser,
getAdmins
} from "./users.js";
I also revisited the difference between named exports and default exports.
Named:
export function findUser() {}
import { findUser } from "./users.js";
Default:
export default function UserProfile() {}
import UserProfile from "./UserProfile.js";
This is something I’ve seen constantly in modern JavaScript code, but going back to the fundamentals made it feel much less like framework magic.
The main thing I realised
The biggest takeaway from this refresher wasn’t any one JavaScript feature.
It was realising how easy it is to confuse familiarity with understanding.
You can see something a hundred times and still have gaps.
You can recognise code without being able to write it confidently.
You can use a pattern without fully understanding why it works.
That was the whole reason I went back.
Not to become a JavaScript expert before moving on.
Just to make the foundation stronger.
And somewhere along the way, I started enjoying the process more than I expected.
There’s a different kind of confidence that comes from understanding the basics properly.
Not the confidence of knowing everything.
Just the confidence of knowing what you’re standing on.
So far I’ve revisited:
- variables and data types
- operators and conditionals
- functions and scope
- arrays and loops
-
map,filter,find,some,everyandreduce - objects
- destructuring
- spread and rest
- callbacks
- error handling
- Promises
async/await- HTTP and
fetch - modules
And I actually feel better for slowing down.
Next for me is TypeScript.
But this time, I’m moving forward with a much clearer understanding of the JavaScript underneath it.
Sometimes going back isn’t really going backwards.
Sometimes it’s just the fastest way to stop building on shaky ground.
Top comments (0)