1. What is a data type?
Every value in JavaScript has a specific type.
This type determines what operations can be performed on the value and how it's stored π³οΈ.
This is known as the data type.
2. How many data types?
There are 8 data types in JavaScript: number, string, boolean, null, undefined, bigint, symbol and object.
3. What is a primitive data type?
Every type except the object type π .
So, there are 7 primitive data types: string, number, boolean, undefined, null, symbol, bigint.
Primitive values have the following characteristics:
- They don't have methods or properties.
- They are immutable: you cannot modify the value once it is created.
- They are directly stored in the memory stack.
let sample = 'immutable'
console.log(sample) // "immutable"
sample[0] = 'V' // changing the first letter to V
console.log(sample) //"immutable" (since the string cannot change)
What the heck is the memory stack?
A JavaScript program has a memory where it stores variables/values for later access.
That memory consists of the stack and the heap.
- Stack: Stores static data (data with a fixed size). Since primitive values are immutable and won't change, they will be stored here.
- Heap: Stores object values. The heap's size can change during the code execution to accommodate object value changes.
4. What is a non-primitive data type?
The object
type is the only non-primitive data type.
This includes: object literals ({ name: "Fatou" }
), functions (function sayHi(){}
), arrays ([1, 2, 3]
), etc.
There is a crucial difference between primitive and non-primitive data types.
π When a variable contains a non-primitive data type, it doesn't hold the actual object value.
Instead, it contains a reference to that object in memory (i.e., in the heap).
Think of a reference like an address.
House != Address
However, if I do things like:
- Send a gift to
{fillInYourAdress}
. - Paint the house at address
{fillInYourAdress}
.
It will affect your house.
In the JavaScript world, this is equivalent to the following code:
const house = {
floors: 2,
gifts: [],
color: "blue"
}
house.gifts.push("Red dress")
house.color = "red"
Keep this distinction in mind when passing objects to functions.
In the following example, the code modifies the original array since it is passed to the function as an address:
function addUser(arr){
const randomId = "123"
arr.push({ id: randomId } );
return arr;
}
const users = [];
console.log(users); // []
const newUsers = addUser(users);
console.log(newUsers); // [{ id: ... }]
console.log(users); // [{ id: ... }] (since users was modified)
5. How do you get the type of a value?
You can use typeof
to get the type of a value.
const name = "Ndeye Fatou Diop";
console.log(typeof "Hello") // "string"
console.log(typeof("Hi")) // "string"
console.log(typeof name) // "string"
π‘ Note: This method doesn't work for
null
becausetypeof null
returnsobject
π . To safely check ifvalue
is an object, you need to dovalue != null && typeof value === "object"
6. What does typeof (() => {})
return?
This is the other exception with typeof
.
typeof fn
returns function
instead of object
π€¦ββοΈ.
const sayHi = (name) => console.log(`Hi, ${name}`)
console.log(typeof sayHi); // "function"
7. How do you check if a value
is an array in JavaScript?
typeof arr
returns object
since arrays are objects.
Instead, you can use Array.isArray(value)
.
const nums = [1, 2, 3];
console.log(Array.isArray(nums)); // true
console.log(Array.isArray({})); // false
8. What is the difference between number and bigint?
Only integers within the range [-9007199254740991, 9007199254740991]
are safe to manipulate in JavaScript.
Integers outside this range can give incorrect mathematical results.
For example, 9007199254740993 - 9007199254740992
will return 0
instead of 1
.
BigInt was introduced for integers outside this range. Any integer can be converted to a bigint by appending n
to it or using BigInt(...)
9007199254740993n - 9007199254740992n
will correctly return 1n
.
π‘ Tip: You can get the min/max safe integers with
Number.MIN_SAFE_INTEGER
andNumber.MAX_SAFE_INTEGER
.
9. What is the difference between null
and undefined
?
There is a slight difference.
undefined
conveys a value that hasn't been defined yet. It's like you just bought a new house, and someone asks about the swimming pool πββοΈ. You haven't even thought about it yet β it's undefined!null
conveys a value that has been set to "empty". It's like you bought the house and decided there wouldn't be a swimming pool (since you're too broke for it π ).
π‘ Note: Don't rely on that distinction in your code. Just consider any value
null
orundefined
as empty.
10. What is a property?
Objects have properties.
Each property associates a key with a value.
For example, the object me
has the properties name
, age
, etc.
const me = {
name: "Fatou",
age: 30,
job: "Software Engineer"
}
Three things to know about keys
- Only
string
orsymbol
values are allowed as keys. Any other value will be converted tostring
through coercion (see Question #12) - They are case-sensitive
- You need
[]
to access keys with space separation
const obj = {
"first name": "Fatou"
};
console.log(obj.first name); // Doesn't work
console.log(obj["first name"]); // "Fatou"
11. What is a method?
Methods are special properties that associate a key with a function.
That function can only be accessed through the object like this:
const me = {
name: "Ndeye Fatou Diop",
sayHi(){
console.log(`Hi, my name is ${this.name}`)
},
sayHelloWorld(){
console.log("Hello World")
}
}
me.sayHi(); // Hi, my name is Ndeye Fatou Diop
const sayHelloFn = me.sayHelloWorld;
sayHelloFn();
π‘ Note: Be careful with the
this
object in thesayHi
function. If the function was called like this,const fn = me.sayHi; fn();
,this != me
. You can learn more aboutthis
rule here.
12. What is coercion?
Remember question #1?
A data type only supports certain operations.
For example, we can add numbers like this 1 + 2
.
What happens when we try "invalid" operations like "8" + 9
?
π Coercion happens.
It is when JavaScript implicitly converts values from one data type to another.
In the example above, JavaScript will convert 9
to the string "9"
and return "8" + "9" => "89"
.
More examples of coercion:
const result = "9" - 5; // returns 4 since "9" is coerced into the number `9`
const sum = true + false; // returns 1 since true is coerced into 1 and false into 0
π‘ Notes: There are coercion rules, but you don't need to remember them all. Instead, avoid comparing apples and oranges and invalid operations π .
13. What is a falsy value? What is the opposite of it? Can you name all falsy values?
The simplest answer: If Boolean(value)
returns false, value
is falsy.
So, every falsy value will be coerced to false
when JavaScript expects a boolean value (see Question #12).
Examples:
// value is falsy
if(value) {
// Not reachable since `value` will be coerced into `false`
}
const name = value && "myValueHere"; // `name` will be equal to `value` since `value` will be coerced to false
There are only 10 falsy values:
false
-
0
,+0
,-0
,0n
,NaN
- empty string:
""
,''
, etc. null
undefined
-
document.all
: the only falsy object
If a value is not falsy (i.e., not present in this list), it is truthy.
14. How do you convert a value to its boolean representation?
You have two options:
Option #1:
Boolean(value)
Option #2 (better):
!!value
console.log(Boolean(1)); // true
console.log(Boolean(0)); // false
console.log(!!1); // true
console.log(!!0); // false
15. What is the difference between ==
and ===
?
===
is like ==
except no coercion happens, and the types need to be the same.
In fact, ==
will return true if the two values are equal after JavaScript coercion kicks in.
For example, 1 == true
returns true because JavaScript will coerce 1
into a boolean. Since 1
is truthy (see Question #13), it will be equivalent to true.
Conversely, 1 === true
will return false since the types differ.
π‘ Tip: Never use
==
unless for checking if a value is null/undefined. Otherwise, coercion may kick in, resulting in unexpected results. For example[] == ![]
returnstrue
since both sides are coerced into numbers ([] => 0
,![] => false => 0
since[]
is truthy)
16. Why does 0.1 + 0.2 === 0.3
return false?
0.1 and 0.2 are floating point numbers.
In JavaScript (and many other languages), floating-point numbers are represented using the IEEE 754 standard.
Unfortunately, numbers like 0.1 and 0.2 cannot be represented precisely in this standard, leading to a loss of precision.
As a result, 0.1 + 0.2
is equivalent to approximate(0.1) + approximate(0.2)
, which results in something slightly different from 0.3.
17. Why is {} === {}
returning false?
This question is easy if you understand Question #4.
{}
are objects. As a result, each one stores a different reference pointing to a different value in memory (heap).
Since those references (i.e., addresses) are different, the comparison returns false.
18. What are the different ways to access an object property?
There are two options (using dot notation or bracket notation).
Let's say we have the following object, and we want to access the name
property:
const me = {
name: "Ndeye Fatou Diop",
job: "Software Engineer",
"way of life": "Coding"
}
We can do:
me.name
me["name"]
π‘ Note: For properties with spaces like
"way of life"
, we can only useme["way of life"]
.
19. How do you safely do obj.value
when obj
can be undefined or null?
We have two options:
Option #1:
obj != null ? obj.value : undefined
Option #2 (better): Use the optional chaining operator like this
obj?.value
20. How do you loop through the values of an array or object?
For an array
const arr = [1, 2, 3]
// Option 1: Use for...of
for(let x of arr) {
console.log(x)
}
// Option 2: Use for with indices
for(let i = 0; i < arr.length; i++) {
console.log(arr[i])
}
// Option 3: Use forEach
arr.forEach(x => {
console.log(x)
})
For an object
const obj = {
name: "Fatou",
age: 30
}
// Option 1: Use `Object.keys`
Object.keys(obj).forEach(k => {
console.log(obj[k])
})
// Option 2: Use `Object.values`
Object.values(obj).forEach(x => {
console.log(x)
})
// Option 3: Use `Object.entries`
Object.entries(obj).forEach(([k, x]) => {
console.log(x)
})
π‘ Important: Avoid
for...in
since it may produce unexpected results.
21. What is prototypal inheritance?
Every object in JavaScript has a hidden property [[Prototype]]
called the prototype that is either an object or undefined.
This property can be accessed via obj.__proto__
.
Where does the prototype come from?
There are multiple ways to set an object prototype:
Option #1: Just create the object
Every object will have a default prototype when set.
For example,
- The prototype of
array
objects isArray.prototype
- the prototype of objects like
{ name: "Fatou"}
isObject.prototype
- etc.
Option #2: Explicitly set the prototype
const car = {
wheels: 4
};
const bmw = {
brand: "BMW"
};
bmw.__proto__ = car; // bmw.[[Prototype]] is equal to car
Option #3: Create the object with a given function
function Car(brand){
this.brand = brand
}
const bmw = new Car("BMW"); // bmw.[[Prototype]] has the following shape: { constructor: Car, β¦ }
Option #4: Create the object with Object.create
const car = {
wheels: 4
};
const bmw = Object.create(car); // bmw.[[Prototype]] is equal to car
bmw.brand = "BMW";
What is the prototype used for?
So, every object has a prototype. Now what? π
When you try to access a method or property on an object, JavaScript will first examine the object.
When no property/method can be found, JavaScript will look into the prototype object.
Three things can happen:
- The property/method exists on the prototype object => JavaScript will return it
- The prototype method is undefined => JavaScript will return undefined
- The prototype method is not undefined => Inheritance kicks in. Since the prototype is an object, it has its own prototype. So JavaScript will look into the prototype of the prototype. It will continue doing so until it finds the property/method or the prototype becomes undefined.
This is prototypal inheritance π. We inherit the properties/methods of the prototype. The ultimate prototype is Object.prototype
and Object.prototype.__proto__ === undefined
.
In the example below, bmw
object does not have the wheels
property, so the one on car
will be returned.
const car = {
wheels: 4
};
const bmw = {
brand: "BMW",
print(){
console.log(`My brand is ${this.brand} and I have ${this.wheels} wheels`);
}
};
bmw.__proto__ = car; // Sets bmw.[[Prototype]] to car
bmw.print(); //"My brand is BMW and I have 4 wheels"
π‘ Note: If you want to learn more about prototypal inheritance? Check this great post from @lydiahallie.
22. How do you check whether a property exists in an object?
Your first instinct may be to use obj.value !== undefined
, but this can go wrong in these cases:
-
obj
is undefined -
obj.value
is present by undefined -
value
is present in the prototype chain (see Question #21)
We can try value in obj
, but this breaks when obj
is undefined or null.
The safest way to achieve this? π obj?.hasOwnProperty(value)
23. Why can we call methods like .trim()
on string values?
Primitive values like strings have no methods.
So, how the heck does this work? π
Well, it is through a neat feature called auto-boxing β¨
What is auto-boxing in JavaScript?
Every primitive type except null
and undefined
has an associated object wrapper class (see table below).
Data Type | Object wrapper |
---|---|
null | N/A |
undefined | N/A |
number | Number |
string | String |
boolean | Boolean |
bigint | BigInt |
symbol | Symbol |
Auto-boxing is when JavaScript temporarily converts a primitive type to its corresponding object wrapper when certain methods or properties are accessed.
Let's look at an example:
const name = "Ndeye Fatou Diop ";
const cleanName = name.trim(); // cleanName = "Ndeye Fatou Diop"
When we do name.trim()
, name
is a primitive value and doesn't have methods. JavaScript will then:
- Convert
name
tonew String(name)
, which is an object. - Access the
trim
method on the String object, returning "Ndeye Fatou Diop" - Return the result
24. Can you give 3 ways to create an undefined
value?
- Option #1: Explicitly set the value to undefined
let age = undefined;
- Option #2: Declare a variable without an initial value
let age;
var name;
- Option #3: Access a property/method that doesn't exist
const me = {
name: "Ndeye Fatou Diop"
}
let age = me.age; // `age` is undefined because it doesn't exist in the object
25. What is the difference between shallow copy and deep copy?
First, what is a copy?
Let's say I have an array arr1
, and I want to create a copy of that array arr2
.
I can't do const arr2 = arr1
since the arrays will point to the same object, and any modification to arr2
will affect arr1
(see Question #3).
So what is the solution?
π const arr2 = [...arr1];
This will make sure the two arrays point to different objects in memory.
But there is a catch π .
This works fine when the arrays contain primitive values like const arr1 = [1, 2, 3]
, but what if the arrays contain objects like const arr1 = [ { name: "Fatou"}]
?
What happens when I do arr2[0].name = "Thomas"
?
Will arr1[0]
be affected? π Yes.
Because arr2
still contains a list of references that are the same as in arr1
. So, any modification will affect the objects these references point to.
The copy we did was a shallow copy.
A deep copy is when we create new references for every object, so any modification does not affect the original objects.
In the example above, we can do a deep copy this way:
const arr1 = [ { name: "Fatou"}]
// Option #1: This will only work when every value can be serialized
const arr2 = JSON.parse(JSON.stringify(arr1))
// Option #2: Use `structuredClone`
const arr2 = structuredClone(arr1)
π‘ Important:
Deep copy
is more expensive thanshallow copy
. Make sure you actually need it before reaching for it.
26. What is the result of Symbol("name") === Symbol("name")
π False.
Every call to Symbol
returns a different value, even if the descriptions are the same.
27. Can you change the data type of a variable?
Variables don't have a type; values have π .
In fact, when we have the following code, typeof name
is equivalent to typeof "Ndeye Fatou Diop"
which returns "string".
const name = "Ndeye Fatou Diop"
const type = typeof name; // returns "string"
As a result, since variables declared with var
and let
can have their values changed, their types can also change.
let x = "Ndeye Fatou Diop"
console.log(typeof x); // logs "string"
x = 45;
console.log(typeof x); // logs "number"
Thank you for reading this post π.
If you liked this article, join my FREE newsletter, FrontendJoy.
If you want daily tips, find me on X/Twitter.