Deep Analysis of Pass-by-Value and Reference Mechanisms in JavaScript

Nov 21, 2025 · Programming · 9 views · 7.8

Keywords: JavaScript | pass-by-value | pass-by-reference | object copying | memory model

Abstract: This article provides an in-depth exploration of variable passing mechanisms in JavaScript, systematically analyzing the differences between pass-by-value and pass-by-reference. Through detailed code examples and memory model explanations, it clarifies the distinct behaviors of primitive types and object types during assignment and function parameter passing. The article also introduces best practices for creating independent object copies, helping developers avoid common reference pitfalls.

Fundamental Principles of JavaScript Variable Passing

Understanding variable passing mechanisms is crucial for writing reliable JavaScript code. The core rule can be summarized as: JavaScript always uses pass-by-value, but when a variable references an object, this "value" is actually a reference to the object.

Differences Between Primitive and Object Types

Data types in JavaScript can be categorized into primitive types and object types. Primitive types include numbers, strings, booleans, null, undefined, Symbol, and BigInt. These types use true pass-by-value mechanism during transmission.

let a = 5;
let b = a; // b receives a copy of a's value
b = 10;
console.log(a); // Outputs 5, a's value remains unaffected

The passing mechanism for object types (including arrays, functions, and plain objects) differs significantly. When assigning or passing objects, what gets transmitted is a reference to the object, not a copy of the object itself.

Detailed Analysis of Function Parameter Passing

Consider the following example code, which helps understand the specific behavior of function parameter passing:

function modifyValues(a, b, c) {
    a = 3; // Reassignment, doesn't affect original variable
    b.push("new item"); // Modifies array content, affects original array
    c.property = false; // Modifies object property, affects original object
}

let num = 4;
let arr = ["item1", "item2"];
let obj = {property: true};

modifyValues(num, arr, obj);
console.log(num, arr, obj.property); // 4, ["item1", "item2", "new item"], false

In this example, the variable num is a primitive type, and reassignment within the function doesn't affect the external variable. However, arr and obj are object types passed by reference, so modifications to them affect the original objects.

Variable Assignment and Reference Sharing

When assigning an object to another variable, both variables reference the same object:

let original = {color: "red"};
let reference = original; // reference now points to the same object

reference.color = "blue";
console.log(original.color); // Outputs "blue"

This behavior also applies to arrays:

let array1 = [1, 2, 3];
let array2 = array1;
array2.push(4);
console.log(array1); // [1, 2, 3, 4]

Methods for Creating Independent Object Copies

To avoid unintended reference sharing, it's necessary to create independent copies of objects. Here are several commonly used methods:

Using the spread operator (ES6):

let originalObj = {a: 1, b: 2};
let copyObj = {...originalObj};
copyObj.a = 3;
console.log(originalObj.a); // Still 1

Using Object.assign:

let shallowCopy = Object.assign({}, originalObj);

For deeply nested objects, recursion or specialized library functions are required:

function deepClone(obj) {
    if (obj === null || typeof obj !== "object") return obj;
    if (obj instanceof Date) return new Date(obj);
    if (obj instanceof Array) return obj.map(item => deepClone(item));
    
    let cloned = {};
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
            cloned[key] = deepClone(obj[key]);
        }
    }
    return cloned;
}

Memory Model Analogy for Better Understanding

To better grasp these concepts, imagine computer memory as a warehouse. Primitive types are like individual boxes, where each variable has its own independent copy. Object types resemble large shelves, where multiple variables may point to the same shelf, sharing access through references.

This memory model explains why modifying object properties affects all variables referencing that object, while reassigning primitive type variables only affects the current variable.

Practical Considerations in Development

In practical programming, understanding these mechanisms helps with:

By mastering JavaScript's passing mechanisms, developers can better control data flow and write more robust, maintainable applications.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.