✨🧱 JavaScript Data Types: 27 Quick Questions You Need To Master
Tags: javascript, webdev, beginners, programming
Published: 2024-06-03 07:00:00

# 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**.

<figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ykizq6i9i6wmfvxz8oo8.png">
  <figcaption>JavaScript data types with examples</figcaption>
</figure>

---

# 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.

```javascript
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.

![Primitive Types in memory](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zd6ak2f75ao06vd91733.gif)

---
# 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:

```javascript
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:

```javascript
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)
```

![Non-primitive types in memory](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tf8vnzbjwm0p08pkwvm6.gif)

---
# 5. How do you get the type of a value?
You can use `typeof` to get the type of a value.

```javascript
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` because `typeof null` returns `object` 😅. To safely check if `value` is an object, you need to do `value != null && typeof value === "object"`

---
# 6. What does `typeof (() => {})` return?
This is the other exception with `typeof`.

`typeof fn` returns `function` instead of `object` 🤦‍♀️.

```javascript
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)`.

```javascript
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` and `Number.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` or `undefined` 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.

```javascript
const me = {
  name: "Fatou",
  age: 30,
  job: "Software Engineer"
}
```

### Three things to know about keys

1. Only `string` or `symbol` values are allowed as keys. Any other value will be converted to `string` through coercion (see Question #12)
2. They are case-sensitive
3. You need `[]` to access keys with space separation

```javascript
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:

```javascript
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 the `sayHi` function. If the function was called like this, `const fn = me.sayHi; fn();`, `this != me`. You can learn more about `this` rule [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this).

---

# 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:

```javascript
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](https://www.scaler.com/topics/javascript/type-coercion-javascript/), 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:**
```javascript
// 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`

```javascript
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 `[] == ![]` returns `true` 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](https://en.wikipedia.org/wiki/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.

![Object representation in memory](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kbosllo7mzl8kd9i5rei.gif)

---
# 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:

```javascript
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 use `me["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
```javascript
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
```javascript
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 is `Array.prototype`
- the prototype of objects like `{ name: "Fatou"}` is `Object.prototype`
- etc.

**Option #2: Explicitly set the prototype**
```javascript
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**

```javascript
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**
```javascript
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:
1. The property/method exists on the _prototype_ object => JavaScript will return it
2. The prototype method is _undefined_ => JavaScript will return _undefined_
3. 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.

```javascript
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](https://dev.to/lydiahallie/javascript-visualized-prototypal-inheritance-47co) 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:

```javascript
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:

1. Convert `name` to `new String(name)`, which is an object.
2. Access the `trim` method on the String object, returning "Ndeye Fatou Diop"
3. Return the result

---
# 24. Can you give 3 ways to create an `undefined` value?

- Option #1: Explicitly set the value to undefined

```javascript
let age = undefined;
```

- Option #2: Declare a variable without an initial value

```javascript
let age;
var name;
```

- Option #3: Access a property/method that doesn't exist
```javascript
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:

```javascript
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 than `shallow copy`. Make sure you actually need it before reaching for it.

![Deep vs shallow copy](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kwpr4wk0go44wm89v587.gif)

---
# 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".

```javascript
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.

```javascript
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](https://frontendjoy.substack.com/)**.

If you want daily tips, find me on [X/Twitter](https://twitter.com/_ndeyefatoudiop).