Ace Your Next JavaScript Interview: Values, References, Coercion & Equality (Part 2) ✨
Learn the deeper concepts in JavaScript, such as values, references, coercion & equality (5 minutes)
A few months ago, I shared an article about how to Ace Your Next JavaScript Interview (part 1), where I dug deeper into fundamental concepts like Scope, Hoisting, and Closures.
In today’s article, I’ll continue to demystify and simplify other JavaScript concepts, such as values, references, coercion & equality.
Every time I have a JavaScript interview, I review these notes to refresh my knowledge and prepare.
If you missed the previous article (part 1), check it out here:
Outlier (powered by Scale AI) - Sponsor
Outlier provides premium freelance coding opportunities for frontend developers.
up to $50 per hour (USD) based on expertise and location
some other countries it is up to $30 per hour (USD) due to location
weekly payouts via PayPal & AirTM—no waiting weeks to get paid
performance bonuses available on select projects
Explore how frontend developers are shaping AI's future (and getting paid for it).
Primitive Types & Pass-by-Value
JavaScript has seven basic data types: string, number, boolean, undefined, null, symbol, and object (everything else).
The first six are called primitives or primitive types.
When you assign or pass a primitive value, JavaScript makes a fresh new copy each time.
This means that it never links back to the original.
const price = 16;
let newPrice = price; // JS copies 16 into `newPrice`
newPrice += 1;
console.log(price === newPrice); // false
console.log(price); // 16
console.log(newPrice); // 17
The same rule applies when passed inside a function where primitives stay isolated:
function increasePrice(x) {
x += 1;
}
increasePrice(price);
console.log(price); // it's still 16
Primitives are passed by value, so you work only on copies, never on the original value.
Objects & Pass-by-Reference
Objects and arrays are stored as references.
Two objects with the same shape are not equal unless they point to the same piece of memory.
You can think of these references as “links” to some piece of data on the computer.
const a = { val: 16 };
const b = { val: 16 };
console.log(a === b); // false
When we compare the objects, we refer to their references (“links”), checking whether the underlying data (memory) is the same or not.
This also means that if we change something in `a` it won’t reflected also in `b`.
const a = { val: 16 };
const b = { val: 16 };
a.val = 160;
console.log(a.val); // 160
console.log(b.val); // 16
On the other side, if we assign one object to another, it will copy only the reference.
const a = { val: 16 };
const b = a; // JS copies the reference, not the actual data
console.log(a === b); // true
In this case, both `a` and `b` point to the same data (memory), so the variables are equal.
This also means that if we change something in `a` it will be reflected also in `b`.
const a = { val: 16 };
const b = a;
a.val = 160;
console.log(a.val); // 160
console.log(b.val); // 160
If we want to create a new object based on existing one, we can use the spread operator:
const original = { val: 16 };
const copy = { ...original };
copy.val = 12;
console.log(original.str, copy.str); // 16, 12
⚠️ Keep in mind that spreading only duplicates the top level properties of the object.
Nested objects will still share the same references.
This is called `shallow copy`.
const original = { stats: { val: 16 } };
const copy = { ...original };
copy.stats.val = 12;
console.log(original.stats.val); // 12 (not 16)
If we want to a deep copy, we can use the structuredClone method or similar:
const original = { stats: { val: 16 } };
const copy = structuredClone(original);
copy.stats.val = 12;
console.log(original.stats.val); // 16
Coercion
JavaScript often “helps” you with converting types on the fly.
Sometimes this behavior can be handy but also confusing.
Converting a value from one type to another is often called “type casting,” when done explicitly, and “coercion” when done implicitly (forced by the rules of how a value is used).
For example, addition with a string turns the numbers intro strings:
42 + '' // '42'
42 + '0' // '420'
However, subtraction forcer strings into numbers:
'42' - 7 // 35
There’re some other quirks like `null + 1 → 1`, `undefined + 1 → NaN`, etc.
❗Pro Tip: Try to always use the same data types in logical operations, if you’re not sure what you’re doing or don’t want unexpected behaviors.
To make this happen, we can use explicit casts or “Boxing Wrappers”:
Number('42'); // 42
String(42); // '42'
Boolean(undefined); // false;
Logical Operators Return Values
The `| |` and `&&` operators don’t always give you `true` or `false`.
The value produced will always be the value of one of the two original values.
const a = 42, b = 'Hi', c = null;
a || b // 42 (first truthy)
a && b // 'Hi' (both truthy, returns second)
a || c // 42
a && c // null
b || c // 'Hi'
b && c // null (first truthy, second falsy)
When you use the `| | ` operator, if the first value casts to `true`, you will get that value returned.
Otherwise, you’ll always get the second value returned.
In the case of `&&` operator, you’ll always get the second value if they’re both casted to `true`.
If the first one is coerced to `false` then you’ll get it’s value returned.
As this behavior might look a bit confusing, it powers quick defaults and use cases:
function greet(name) {
console.log(`Hello, ${name || 'friend'}!`);
}
greet(); // Hello, friend!
// or in modern JavaScript projects, you might see default parameters assigned in the function signature
function greet(name = 'friend') {
console.log(`Hello, ${name}!`);
}
greet(); // Hello, friend!
or even in React:
{Boolean(name) && <p>{name}</p>}
Equality (`==` vs. `===`)
`==` checks for value equality after coercion
`===` checks for value equality without coercion
42 == '42' // true (
42 === '42' // false
❗Pro Tip: Use `===` by default to avoid unexpected behaviors.
📌 TL;DR
Primitives are copied by value; Objects share references.
Be careful with shallow vs. deep copies.
Coercion happens silently. Prefer explicit casting.
`| |` and `&&` return one of their operands. It’s handy for defaults.
Prefer `===` over `==` to keep comparison predictable.
That's all for today. I hope this was helpful. ✌️
How I can help you further?
Become the Senior React Engineer at your company! 🚀
👋 Let’s connect
You can find me on LinkedIn, Twitter(X), Bluesky, or Threads.
I share daily practical tips to level up your skills and become a better engineer.
Thank you for being a great supporter, reader, and for your help in growing to 24.4K+ subscribers this week 🙏
You can also hit the like ❤️ button at the bottom to help support me or share this with a friend. It helps me a lot! 🙏