JavaScript Basics and Data Types
What are JavaScript data types? How do you determine them?
- Two main categories: Primitive and Object
Primitive (immutable types) string, number, boolean, null, undefined, bigint, symbol
- Primitive values are immutable: modifying a variable means reassigning a new value rather than altering the original value.
Object (mutable types)
- General Object
- Array
- Array.isArray([1, 2, 3]) // true
- Function
- Object.prototype.toString.call(fn) // [object Function]
- Why is typeof misleading?
- typeof null === “object” → historical bug
- typeof [] === “object” → cannot distinguish arrays
Most reliable method: Object.prototype.toString.call(value) can differentiate almost all types.
Differences between ==, ===, and Object.is() in JavaScript
Summary:
- Use === by default.
- When you need to distinguish +0 / -0 and NaN, use Object.is().
- Avoid == because of implicit type coercion.
console.log(Object.is(+0, -0)); // false
console.log(Object.is(NaN, NaN)); // true
What is the difference between null, undefined, and undeclared?
- undefined: declared but not assigned → “not yet”
- null: declared and explicitly set to empty → “nothing”
- undeclared: never declared → “does not exist”
What’s the difference between Map and Object? Why do we need Map if we already have Object?
- Map is not a subtype of Object — they serve different purposes:
- Object represents structured data
- Map represents associations (key → value)
Use Map when you need:
- frequent lookups / deletions
- arbitrary key types
- mappings (ID → object, DOM → state, caches, graphs, counters)
Use Object when you need:
- structured data (user, order, config, form data)
Object keys are “names” (string/symbol), Map keys are real references (any type)
Plain objects are not iterable, Map is iterable
- Example: forEach applies side effects
const users = [
{ first: 'Tom', last: 'Smith' },
{ first: 'Jane', last: 'Doe' },
{ first: 'Lily', last: 'Deng' }
];
users.forEach((user) => {
user.fullName = `${user.first} ${user.last}`;
});
console.log(users);
Output:
[
{ first: 'Tom', last: 'Smith', fullName: 'Tom Smith' },
{ first: 'Jane', last: 'Doe', fullName: 'Jane Doe' },
{ first: 'Lily', last: 'Deng', fullName: 'Lily Deng' }
]
- for…of supports sequential async execution and early break
const urls = [
'/api/user',
'/api/orders',
'/api/notifications'
];
async function fetchSequential() {
for (const url of urls) {
try {
const res = await fetch(url); // for...of supports await
if (!res.ok) {
console.log('Failed at:', url);
break; // early break
}
const data = await res.json();
console.log('Success:', url, data);
} catch (error) {
console.log('Error:', url, error);
break; // early break
}
}
}
fetchSequential();
Object has no guaranteed order; Map preserves insertion order.
Map provides many key-value APIs that Object does not:
- set / get / has / delete / clear / size
- keys / values / entries
- for…of iteration directly on Map
Explain the differences among Set, Map, WeakSet, and WeakMap
- Memory = where data lives while your program runs (fastest storage)
- Bandwidth = speed of transferring data
- DOM = a tree of browser-generated objects representing the rendered page
- Set
- Similar to an array but values must be unique
- Accepts primitive and object types
- Methods: add, delete, has, size
- Iteration yields [value, value]
- WeakSet (weak reference version of Set)
- Only stores objects
- Weak references: when the object has no external references, it gets garbage-collected
- Ideal for: tracking DOM node states, preventing memory leaks
- Map
- Similar to Object, but:
- keys can be any type
- preserves order
- rich API: set/get/has/delete/size
- iterable via keys, values, entries
- WeakMap (weak reference version of Map)
- Keys must be object or symbol
- Keys are weak references → GC removes entries automatically
- Map uses strong references and will not auto-clean
- Ideal for: storing DOM-related state without polluting the DOM node
Why weak references matter?
When a DOM node is removed, a WeakMap automatically cleans up its associated state, avoiding memory leaks.
In JavaScript, what is the result of 0.1 + 0.2? Why? How to avoid related issues?
- Result:0.30000000000000004
- Reason:JavaScript uses IEEE-754 double-precision floating-point numbers, which cannot precisely represent certain decimals.
- solution:nstr
//Step 1: Convert to fixed decimal
0.14499999582767487.toFixed(10) // "0.1449999958"
//Step 2: Detect consecutive patterns
"0.1449999958"
// ^^^^^
// 5 consecutive "9"s detected (≥ threshold of 4)
//Step 3: Truncate and clean up
"0.1449999958" → "0.145"
Purpose and benefits of strict mode (use strict)
- Enabling “use strict” at the beginning of a script or function:
- Disallows undeclared variables
"use strict";
x = 10; // Error: x is not declared
- Disallows duplicate parameter names
"use strict";
function sum(a, a) {} // Error
- Disallows deleting variables,(var / let / const )
"use strict";
var y = 20;
delete y; // Error
Should you use the ternary operator?
Yes for simple conditions
Avoid for complex logic — if it becomes unreadable, don’t use it
One-liners only
Short-circuit evaluation with
&&: if the left side is falsy → it returns the left side; if the left side is truthy → it returns the right side.