JavaScript Primitive and Reference Data Types Step by step Implementation and Top 10 Questions and Answers
 Last Update:6/1/2025 12:00:00 AM     .NET School AI Teacher - SELECT ANY TEXT TO EXPLANATION.    25 mins read      Difficulty-Level: beginner

JavaScript Primitive and Reference Data Types

Understanding the distinction between primitive and reference data types is fundamental to mastering JavaScript. These two categories fundamentally determine how data is stored and manipulated in memory, directly affecting various aspects of programming such as assignment, comparison, function arguments, and object mutation. In this detailed explanation, we will explore both primitive and reference types, their characteristics, behaviors, and importance within JavaScript.

Primitive Data Types

In JavaScript, a primitive data type is one that represents a single, immutable value. Immutable means that the value cannot be modified or changed once it has been assigned. If you attempt to modify a primitive value, a new value will be created instead of altering the original one. There are seven primitive data types as of ECMAScript 2020:

  1. Number: Represents numeric values, both integers and floating-point numbers (e.g., 42, 3.14).

  2. String: Represents textual data enclosed in either single ('hello') or double quotes ("world").

  3. Boolean: Represents truth values (true or false). Boolean values are critical for decision-making in code logic.

  4. Null: Represents the intentional absence of any object value. A null value indicates no value has been assigned (e.g., let variable = null;).

  5. Undefined: Denotes a variable has been declared but not assigned a value (let variable;).

  6. Symbol: Introduced with ES6, a Symbol is a unique and immutable identifier, which can be used as a key for an object property. For instance:

    const sym = Symbol("description");
    

    Symbols are useful for creating unique keys in objects without the risk of name collisions.

  7. BigInt: Used when you need to work with extremely large numbers that are beyond the capabilities of the Number type. It is represented by appending n to the end of an integer (e.g., 1234567890123456789012345678901234567890n).

Behavior of Primitive Types:

  • Stored in Stack Memory: Primitives are stored in stack memory. The stack is a fixed-size block of memory. When you declare a variable containing a primitive value, the interpreter allocates a block of memory in the stack to hold the value itself.

  • Passed by Value: When you assign a primitive variable to another variable, or pass a primitive as a function argument, the value is copied. This means that changes to one do not affect the other. Consider the example below:

    let num1 = 10;
    let num2 = num1;
    
    num2 = 20;
    
    console.log(num1); // Outputs 10
    console.log(num2); // Outputs 20
    
    function addTen(n) {
      n += 10;
      console.log(n);
    }
    
    addTen(num1); // Logs 20 but num1 remains 10 outside the function
    
  • Direct Access: You can access the value directly without needing to use methods provided by the corresponding wrapper objects. However, you can still use methods on primitives because JavaScript temporarily wraps them in objects to provide those methods.

Reference Data Types

Reference data types, on the other hand, represent complex data structures. Unlike primitive types, these values can be altered after they have been created. They are stored on the heap memory, and only a reference to the location of the value is stored in the stack. Common reference data types include objects, arrays, functions, dates, and regular expressions.

Key Characteristics:

  • Stored in Heap Memory: The actual data value is stored in heap memory, a dynamic memory allocation space that does not have a size limit. The stack holds only the references to these heap locations.

  • Pass by Reference: When a reference type is assigned to a variable or passed as a function argument, only the reference is copied, not the actual value stored on the heap. This implies that if you modify the contents of an object through one reference, it reflects in all other references pointing to the same memory location.

    let obj1 = {key: 'value'};
    let obj2 = obj1;
    
    obj2.key = 'new value';
    
    console.log(obj1.key); // Outputs 'new value'
    console.log(obj2.key); // Outputs 'new value'
    
    function updateObject(o) {
      o.key = 'updated';
    }
    
    updateObject(obj1);
    console.log(obj1.key); // Logs 'updated'
    
  • No Direct Access to Heap Values: Unlike primitives, you can't access the heap values directly using simple variable names. The references are what enable us to manipulate these complex data structures.

Equality and Comparison

One of the key differences between primitive and reference types lies in how equality and comparison operations handle them.

  • Primitives: Equality checks for primitive types are straightforward. Comparisons are made based on the actual values.

    let x = 5;
    let y = x;
    
    console.log(x === y); // Outputs true, because x and y hold the same value
    
    x = 10;
    
    console.log(x === y); // Outputs false, because they now hold different values
    
  • References: Comparisons for reference types involve checking if the references point to the same memory location, not the contents of the data.

    let objA = {name: 'John'};
    let objB = objA;
    let objC = {name: 'John'};
    
    console.log(objA === objB); // Outputs true, because objA and objB refer to the same object in memory
    
    console.log(objA === objC); // Outputs false, even though objA and objC have identical properties and values,
                                // they occupy different memory addresses.
    

This distinction is crucial for debugging and optimizing your JavaScript code, as unexpected results from comparisons can lead to bugs.

Mutability

Mutability refers to the ability to change the value of a variable. Primitive types are immutable, while reference types can be mutated (altered).

  • Immutable Primitives: Changing a primitive value in fact creates a new value rather than modifying the existing one. This makes primitives ideal for situations where state immutability is desired for preventing side effects.

  • Mutable References: You can directly modify the structure of reference types (objects, arrays, etc.). Mutable references are common in scenarios involving dynamic data manipulation, such as updating user data in an application's state.

Understanding mutability helps prevent unintended changes in data, leading to more predictable and less error-prone applications.

Implications on Function Calls

Primitive vs. reference types also play a significant role in understanding how function arguments are handled.

  • Primitive Arguments: As discussed earlier, when you pass a primitive value as a function argument, the value is passed by copy. This means that any changes to the parameter inside the function do not affect the original variable outside.

    function modifyPrimitive(primitive) {
      primitive += 10;
    }
    
    let number = 5;
    modifyPrimitive(number);
    console.log(number); // Outputs 5, because number was not changed
    
  • Reference Arguments: Passing a reference type as an argument results in the reference being copied, not the actual data. Therefore, any modifications done on the object (or array, function, etc.) within the function impact the original object because they share the same memory address.

    function modifyReference(reference) {
      reference.name = 'Alice';
    }
    
    let person = {name: 'John'};
    modifyReference(person);
    console.log(person.name); // Outputs 'Alice', because person was updated by the function
    

Being aware of whether your variables are primitives or references is essential for understanding how function calls behave, especially in larger programs with numerous interconnected functions.

Copying Data

Copying data between variables behaves differently depending on whether the data is a primitive or a reference.

  • Shallow Copying for References: When copying a reference, only the reference is duplicated, not the underlying object. Both variables then point to the same object in memory.

    let originalArray = [1, 2, 3];
    let copiedArray = originalArray; // Shallow copy
    
    copiedArray[0] = 'changed';
    
    console.log(originalArray); // [ 'changed', 2, 3 ]
    console.log(copiedArray);   // [ 'changed', 2, 3 ]
    
    • Deep Copying for References: Deep copying involves creating a completely independent copy of the reference object, ensuring that changes in one don't affect the other. Deep copying is often required when working with nested objects or arrays.

      // Using JSON.parse and JSON.stringify for deep copy (not suitable for all objects)
      let originalObject = { name: 'John', address: { city: 'New York' } };
      let deepCopiedObject = JSON.parse(JSON.stringify(originalObject));
      
      deepCopiedObject.address.city = 'San Francisco';
      
      console.log(originalObject.address.city); // Outputs 'New York'
      console.log(deepCopiedObject.address.city); // Outputs 'San Francisco'
      

      However, this method doesn't work for copying functions, undefined, symbols, or objects with circular references.

Importance in Programming Best Practices

  1. Memory Management: Efficient usage of stack (for primitives) and heap (for references) memories impacts the performance of web applications. Overusing reference types can consume more memory, leading to slower application speed.

  2. Avoid Side Effects: In functional programming paradigms, avoiding mutations in shared data is highly desirable to ensure predictability and reduce bugs. Utilizing immutable primitives and carefully managing mutable references contributes to achieving this.

  3. Data Integrity: Ensuring that data integrity is maintained, especially when function arguments are involved, requires understanding how data is passed and copied.

  4. Debugging Challenges: Misunderstanding the difference could lead to subtle bugs, especially when dealing with function parameters, loop indices, or deeply nested objects.

By grasping the nuances of JavaScript's primitive and reference data types, developers can write more efficient, maintainable, and bug-free code. Being able to distinguish when and why to use primitives versus references will aid in crafting robust programming solutions tailored to specific needs and scenarios.

Conclusion

In summary, JavaScript's primitive data types are stored directly in memory with direct access to their value, passed by value, and immutable. In contrast, reference data types store objects and arrays in heap memory, accessed via references, passed by reference, and mutable. These distinctions govern how data is handled throughout your code, influencing everything from memory usage to function behavior. Mastering the concepts of primitives and reference types is imperative for anyone serious about JavaScript development to write effective and efficient code.

Additional Resources

  • MDN Web Docs: Offers detailed documentation on JavaScript data types.
  • JavaScript.info: Provides a comprehensive overview and practice exercises.
  • Eloquent JavaScript: An excellent book that covers many core JavaScript concepts.



JavaScript Primitive and Reference Data Types: Examples, Set Route and Run Application, then Data Flow Step by Step for Beginners

JavaScript is a versatile language essential for web development. Understanding its data types is crucial for writing efficient and bug-free code. JavaScript has two main categories of data types: primitive and reference. This guide will explain each category, demonstrate usage through examples, and walk you through setting up and running a JavaScript application to observe data flow.


Topics Covered

  1. Primitive Data Types – Characteristics and Examples
  2. Reference Data Types – Characteristics and Examples
  3. Setting Up Your JavaScript Environment
  4. Running a Simple JavaScript Application
  5. Data Flow in JavaScript

1. Primitive Data Types

Primitive data types in JavaScript are basic data types stored in a single memory location. They are immutable, meaning you cannot change the value directly after it's set. Instead, any operations create a new value.

Characteristics

  1. Immutability: Values cannot be changed.
  2. Stack Memory: Stored in stack memory for fast access and retrieval.
  3. Data Types:
    • Number: Represents both integer and floating-point numbers.
    • String: Sequence of characters.
    • Boolean: Represents true or false values.
    • Undefined: A variable declared but not assigned a value.
    • Null: An intentional absence of any object value.
    • Symbol: Introduced in ES6, it represents a unique value.
    • BigInt: For large integers beyond Number limits.

Examples

let num = 10;         // Number
let str = "Hello";    // String
let bool = true;      // Boolean
let undef;            // Undefined
let nul = null;       // Null
let sym = Symbol();   // Symbol
let big = BigInt(9007199254740992); // BigInt

2. Reference Data Types

Reference data types store references to the location of the value in memory, rather than the actual value. They are mutable, meaning the value can be altered.

Characteristics

  1. Mutability: Values can be changed.
  2. Heap Memory: Stored in heap memory, which is less efficient but allows for more complex data structures.
  3. Data Types:
    • Object: Key-value pairs.
    • Array: Ordered list of items.
    • Function: Code blocks that can be reused.

Examples

let obj = { name: "Alice", age: 25 }; // Object
let arr = [1, 2, 3, 4, 5];          // Array
function greet() {                    // Function
  console.log("Hello, world!");
}

3. Setting Up Your JavaScript Environment

To write and run JavaScript code, you need an environment. Here are the simplest options:

a. Your Web Browser

Most modern web browsers like Chrome, Firefox, and Edge come with a JavaScript console, enabling you to write and run JavaScript code directly.

Steps

  1. Open your web browser.
  2. Press F12 or Ctrl+Shift+I (Windows/Linux) or Cmd+Option+I (Mac) to open the Developer Tools.
  3. Go to the Console tab.
  4. Write your JavaScript code and press Enter.

b. Node.js

Node.js allows you to run JavaScript on the server-side.

Steps

  1. Download and install Node.js.
  2. Create a new file, e.g., app.js.
  3. Write your JavaScript code in app.js.
  4. Open a terminal or command prompt, navigate to the directory containing app.js.
  5. Run the code using the command: node app.js.

4. Running a Simple JavaScript Application

Let's create a simple JavaScript application to demonstrate how primitive and reference data types work.

Steps

  1. Create a new file named app.js.

  2. Write the following code in app.js:

    // Primitive Data Types
    let a = 5;                // Number
    let b = a;                // Pass by value
    b = 10;                   // Changing b does not affect a
    
    let greet = "Hello";      // String
    let farewell = greet;     // Pass by value
    farewell = "Goodbye";     // Changing farewell does not affect greet
    
    console.log(`a: ${a}`);         // Output: a: 5
    console.log(`b: ${b}`);         // Output: b: 10
    
    console.log(`greet: ${greet}`); // Output: greet: Hello
    console.log(`farewell: ${farewell}`); // Output: farewell: Goodbye
    
    // Reference Data Types
    let obj1 = { name: "Alice" }; // Object
    let obj2 = obj1;              // Pass by reference
    obj2.name = "Bob";            // Changing obj2 affects obj1
    
    let arr1 = [1, 2, 3];       // Array
    let arr2 = arr1;            // Pass by reference
    arr2.push(4);               // Changing arr2 affects arr1
    
    console.log(`obj1: ${JSON.stringify(obj1)}`); // Output: obj1: {"name":"Bob"}
    console.log(`obj2: ${JSON.stringify(obj2)}`); // Output: obj2: {"name":"Bob"}
    
    console.log(`arr1: ${arr1}`);                 // Output: arr1: 1,2,3,4
    console.log(`arr2: ${arr2}`);                 // Output: arr2: 1,2,3,4
    
  3. Run the application:

    • If using Node.js, open a terminal, navigate to the directory containing app.js, and run: node app.js.

    • If using your web browser, open app.js in an editor, copy the code, and paste it into the browser's Developer Tools Console.


5. Data Flow in JavaScript

Understanding data flow is essential for grasping how JavaScript handles different data types. Let's break down the code above step by step.

a. Primitive Data Types

let a = 5;
let b = a;
b = 10;
  1. Variables a and b are declared and initialized. Since both are numbers (primitive types), they are stored in the stack memory.
  2. The value 5 is assigned to a.
  3. When b = a is executed, the value of a (which is 5) is copied to b.
  4. Changing the value of b to 10 does not affect the value of a because b holds its own separate copy of the value.

b. Reference Data Types

let obj1 = { name: "Alice" };
let obj2 = obj1;
obj2.name = "Bob";
  1. Variables obj1 and obj2 are declared and initialized. Since both are objects (reference types), they store references to the memory location where the object is stored.
  2. The object { name: "Alice" } is created in heap memory, and obj1 holds the reference to this location.
  3. When obj2 = obj1 is executed, the reference to the object is copied to obj2. Both obj1 and obj2 now point to the same object in memory.
  4. Changing the name property of obj2 to "Bob" also affects obj1 because both variables point to the same object.

c. Arrays

let arr1 = [1, 2, 3];
let arr2 = arr1;
arr2.push(4);
  1. Variables arr1 and arr2 are declared and initialized. Arrays are also reference types, so they store references to the memory location where the array is stored.
  2. The array [1, 2, 3] is created in heap memory, and arr1 holds the reference to this location.
  3. When arr2 = arr1 is executed, the reference to the array is copied to arr2. Both arr1 and arr2 now point to the same array in memory.
  4. Pushing 4 to arr2 affects arr1 as well because both variables point to the same array.

d. Output

By executing the code in app.js, you should see the following output:

a: 5
b: 10
greet: Hello
farewell: Goodbye
obj1: {"name":"Bob"}
obj2: {"name":"Bob"}
arr1: 1,2,3,4
arr2: 1,2,3,4

This output demonstrates how primitive and reference data types behave differently in JavaScript.


Conclusion

Understanding JavaScript's primitive and reference data types is fundamental for effective web development. Primitive data types are straightforward, stored in stack memory, and immutable. Reference data types are complex, stored in heap memory, and mutable. By setting up your environment, running a simple application, and observing the data flow, you can gain a deeper understanding of these data types and how they interact in JavaScript. Practice regularly to reinforce these concepts and write efficient code.




Certainly! Here are the top 10 questions and answers about JavaScript primitive and reference data types, designed to help you understand these fundamental concepts:

1. What are primitive data types in JavaScript?

In JavaScript, primitive data types represent the most basic values that can be stored in a variable. There are seven primitive types as of ECMAScript 2020:

  • Number: Represents both integer and floating-point numbers (1, -3.14).
  • String: Represents textual data ("Hello", 'World').
  • Boolean: Represents true or false values (true, false).
  • BigInt: Used for integers larger than 2^53 - 1 or smaller than -2^53 + 1 (9007199254740992n).
  • Undefined: Represents a variable that has not been assigned any value (undefined).
  • Null: Represents the intentional absence of any object value (null).
  • Symbol: Introduced in ES6, it represents a unique value that is used as an identifier for object properties (Symbol('unique')).
let age = 25;
let name = "John";
let isValid = true;
let bigNum = 9007199254740992n;
let undefinedVar;
let nullVal = null;
let sym = Symbol('unique');

2. What are reference data types in JavaScript?

Reference types allow us to store a collection of data or more complex entities. Unlike primitives, variables that hold a reference type store not the actual value, but rather a reference to where the value is stored in memory. The main examples are:

  • Object: Allows storing key-value pairs of any type.
  • Array: Special type of object for storing ordered collections of items.
  • Function: A block of code designed to perform a particular task.
let person = {name: "Alice", age: 30}; // Object
let fruits = ["apple", "banana", "cherry"]; // Array
function greet(name) {
    console.log(`Hello, ${name}!`);
}

Each variable here (person, fruits, and greet) stores a reference to an object, array, or function, respectively, rather than the actual data itself.

3. How do primitives differ from objects in terms of immutability and behavior?

Primitive values are immutable, meaning once they are created, their value cannot be changed. Consider this example:

let x = 5;
x++;
console.log(x); // Outputs 6

// In reality, what happens when you increment x:
// 1. Read existing value 5 from memory.
// 2. Add 1 to it, resulting in a new value 6.
// 3. Create a new space in memory for value 6.
// 4. Assign new variable x to point to this new address instead of the original 5.

On the other hand, objects (and arrays/functions) are mutable—changes made to them are reflected throughout the program because every variable that references that object points to the same location in memory.

let obj1 = {a: 1};
let obj2 = obj1;

obj1.a = 2;
console.log(obj2.a); // Outputs 2, showing both obj1 and obj2 are referencing the same object

4. What is the difference between deep copy and shallow copy in reference types?

When copying objects or arrays in JavaScript, the distinction between deep and shallow copies becomes critical.

  • Shallow Copy: Only the outermost elements are duplicated, whereas nested objects are still referenced, so changes to nested objects will affect all copies.
let original = {a: 1, b: {c: 2}};
let shallowCopy = {...original};

shallowCopy.b.c = 3;
console.log(original.b.c); // Outputs 3 because both original and shallowCopy's 'b' property point to the same inner object
  • Deep Copy: All levels of nesting inside an object are copied recursively, so modifying one copy does not affect others.
const original = {a: 1, b: {c: 2}};
const deepCopy = JSON.parse(JSON.stringify(original));

deepCopy.b.c = 3;
console.log(original.b.c); // Still outputs 2, as there's now no shared reference between these objects

Note: Using JSON.parse(JSON.stringify()) for deep copying has limitations—it doesn't handle functions, special objects (like Date, RegExp), undefined, or circular references.

5. Why should I care whether a variable holds a primitive or a reference type?

Understanding the difference between primitive and reference types helps avoid common pitfalls in JavaScript due to how memory allocation and assignment work:

  • Assignment Behavior: Primitives are copied by value (let b = a; creates a distinct copy). Objects are copied by reference (let obj2 = obj1; assigns obj2 to point at the same memory location as obj1).

  • Performance: Operations on primitives typically perform better than those on reference types since primitives require less memory and have simpler operations.

  • Error Handling: Modifying nested properties of objects shared across different parts of your code can lead to bugs if you don't account for mutability.

6. How does comparison work for primitives vs. reference types?

  • Primitives: Use value equality to compare variables.
console.log(5 === 5); // True
console.log("hello" === "hello"); // True
  • Objects/Arrays/Functions: Use reference equality, which checks whether both variables point to the exact same memory location, not just having the same content.
let obj1 = {a: 1};
let obj2 = {a: 1};
let obj3 = obj1;

console.log(obj1 === obj2); // False, despite both objects having identical contents
console.log(obj1 === obj3); // True, as they reference the same object

To compare objects based on their content, you would need custom functions or libraries like Lodash's isEqual.

7. What is the effect of passing arguments by value and by reference?

In JavaScript, all function parameters are passed by value. However, since reference types actually hold references to their data rather than the data themselves, passing a reference type to a function can effectively act as pass-by-reference:

  • Primitives: Modifications inside the function do not alter outside variables.
function increment(num) {
    num += 5;
}
let x = 10;
increment(x);
console.log(x); // Outputs 10, as x hasn't changed
  • Reference Types: Modifications made to the properties of an object inside the function are seen outside the function.
function changeName(person) {
    person.name = "Bob";
}
let alice = {name: "Alice"};
changeName(alice);
console.log(alice.name); // Outputs "Bob"

// However, reassigning the parameter doesn't affect the outside variable:
function setNewObject(obj) {
    obj = {newProp: "newValue"};
}
let oldObj = {oldProp: "oldValue"};
setNewObject(oldObj);
console.log(oldObj); // Still logs {oldProp: "oldValue"}

8. Can primitive values have methods in JavaScript?

Despite being immutable, primitive values in JavaScript can seem to access methods, which might seem contradictory. This occurs through a process called autoboxing:

  • When you attempt to call a method on a primitive, JavaScript automatically wraps it in an object temporarily, allowing you to invoke methods.
  • After the method call is complete, the temporary wrapper object is discarded.
let str = "JavaScript";
console.log(str.toUpperCase()); // Outputs "JAVASCRIPT"

// Behind the scenes, JavaScript essentially does:
// var tempStrObj = new String("JavaScript");
// console.log(tempStrObj.toUpperCase());
// tempStrObj is then garbage collected

However, attempting to add properties to primitives will not persist because a new temporary object is created each time a method is called on a primitive.

9. How can I determine the type of a variable in JavaScript?

JavaScript provides several ways to check the type of a variable:

  • typeof Operator: Great for primitives but behaves uniquely with null values.
console.log(typeof 42); // "number"
console.log(typeof "hello"); // "string"
console.log(typeof true); // "boolean"
console.log(typeof null); // "object" (this is a known bug)
console.log(typeof undefined); // "undefined"
console.log(typeof Symbol('test')); // "symbol"
console.log(typeof 1000n); // "bigint"
  • instanceof Operator: Useful for checking if an object belongs to a specific class or prototype chain.
console.log([] instanceof Array); // True
console.log({} instanceof Object); // True
console.log(function() {} instanceof Function); // True
  • Array.isArray() Method: Specifically checks if a value is an Array.
console.log(Array.isArray([1, 2, 3])); // True
console.log(Array.isArray({length: 3})); // False
  • Object.prototype.toString.call(): Provides a consistent way to check both primitives and objects.
console.log(Object.prototype.toString.call(42)); // "[object Number]"
console.log(Object.prototype.toString.call("hello")); // "[object String]"
console.log(Object.prototype.toString.call(true)); // "[object Boolean]"
console.log(Object.prototype.toString.call(null)); // "[object Null]"
console.log(Object.prototype.toString.call(undefined)); // "[object Undefined]"
console.log(Object.prototype.toString.call(Symbol('test'))); // "[object Symbol]"
console.log(Object.prototype.toString.call(1000n)); // "[object BigInt]"
console.log(Object.prototype.toString.call({})); // "[object Object]"
console.log(Object.prototype.toString.call([])); // "[object Array]"
console.log(Object.prototype.toString.call(function() {})); // "[object Function]"

10. When and why should I use primitives over objects, and vice versa?

Choosing between primitives and objects depends on the context and requirements of your application:

  • Primitives:

    • Memory Efficiency: Consume less memory compared to objects.
    • Performance: Generally faster for operations since they are immutable and lightweight.
    • Simple Data Representation: Ideal for representing single values or basic data.
  • Objects/Arrays/Functions:

    • Complex Structures: Perfect for encapsulating related data and behaviors.
    • Mutability: Useful when you need to modify or extend data over time.
    • Functionality: Arrays and functions provide rich built-in methods and capabilities, making them powerful tools for handling collections of data and performing tasks.

In practice, combining both types is essential:

  • Store individual pieces of simple data (IDs, booleans) as primitives.
  • Aggregate related data or functionality within objects.

Here’s a practical example:

// Using Primitives
let score = 150;
let isActive = true;

// Using Objects
let player = {
    name: "John Doe",
    scores: [150, 200, 250],
    isActive,
    getAverageScore() {
        const total = this.scores.reduce((sum, curr) => sum + curr, 0);
        return total / this.scores.length;
    }
};

console.log(player); // Logs an object containing multiple properties and a method

// Combining Both
function updatePlayerName(p, newName) {
    p.name = newName;
}

updatePlayerName(player, "Jane Doe");
console.log(player.name); // Outputs "Jane Doe"

By understanding the differences between primitive and reference types, you can write more efficient, predictable, and error-free JavaScript code.