Является ли JavaScript языком с передачей по ссылке (pass-by-reference) или с передачей по значению (pass-by-value)?
Примитивные типы в JavaScript (такие как числа, строки и т.д.) передаются по значению. Однако объекты представляют особый случай, поскольку их можно интерпретировать и как передаваемые по значению (когда учитывается, что переменная, содержащая объект, является ссылкой на этот объект), и как передаваемые по ссылке (когда учитывается, что переменная объекта содержит сам объект).
Как правильно представить соглашения о передаче аргументов в JavaScript? Существует ли выдержка из официальной спецификации JavaScript, которая определяет семантику этого поведения?
JavaScript fundamentally is a pass-by-value language
JavaScript is fundamentally a pass-by-value language, where all function arguments are passed as values rather than references. While primitive types (numbers, strings, booleans, etc.) are passed by straightforward value, objects and arrays are passed by value where the value happens to be a reference to the original object. This distinction means that JavaScript never supports traditional pass-by-reference semantics where a function could directly modify the variable reference in the calling scope.
Contents
- Understanding Pass-by-Value in JavaScript
- The Object Reference Illusion
- ECMAScript Specification Clarification
- Practical Examples and Common Misconceptions
- Key Takeaways for Developers
Understanding Pass-by-Value in JavaScript
JavaScript’s argument passing mechanism is consistently implemented as pass-by-value across all data types. This means that when you pass an argument to a function, JavaScript creates a copy of that value and passes the copy to the function, leaving the original variable unchanged.
For primitive types like number, string, boolean, null, undefined, symbol, and bigint, this behavior is straightforward and intuitive:
let x = 10;
function changeValue(value) {
value = 20;
}
changeValue(x);
console.log(x); // Output: 10 (unchanged)
In this example, the function receives a copy of the value 10, not a reference to the original variable x. When the function changes the local parameter value, it has no effect on the original variable x.
According to the JavaScript in Plain English article, “JavaScript does not support pass-by-reference, it is a pass-by-value language.” This fundamental characteristic is essential for understanding how JavaScript handles function parameters.
The Object Reference Illusion
The confusion about JavaScript’s argument passing arises when dealing with objects, arrays, and functions. While JavaScript is still pass-by-value, the value being passed for these reference types is the address or reference to the actual object in memory.
This is where the distinction between pass-by-reference and pass-by-reference-value becomes crucial:
- True pass-by-reference (as in C++): The function receives a reference to the variable itself, allowing it to modify the variable reference in the calling scope
- Pass-by-reference-value (JavaScript’s approach): The function receives a copy of the reference value, allowing it to modify the object’s properties but not the variable reference itself
As Snook.ca explains, “There is a big difference between ‘passing-by-reference’ and ‘passing-a-reference-by-value’. Javascript does not support the passing of parameters by reference.”
Consider this example:
let obj = { value: 10 };
function changeObjectReference(obj) {
obj = { value: 20 }; // This creates a new object and assigns it to the local parameter
}
changeObjectReference(obj);
console.log(obj.value); // Output: 10 (unchanged)
The function cannot modify the original variable obj to point to a different object. However, if we modify properties of the object:
let obj = { value: 10 };
function changeObjectProperty(obj) {
obj.value = 20; // This modifies the property of the original object
}
changeObjectProperty(obj);
console.log(obj.value); // Output: 20 (changed)
This works because both the original variable obj and the parameter obj refer to the same object in memory. The function can modify the object’s contents but cannot change which object the variable references.
ECMAScript Specification Clarification
The official ECMAScript specification provides definitive guidance on this behavior. As stated in the Software Engineering Stack Exchange answer:
“ECMAScript is purely pass-by-value, always with no exceptions.”
More precisely, the specification describes this as a special case of pass-by-value where the value being passed is an unforgeable reference to a potentially shared, potentially mutable value.
The MDN documentation also confirms this, quoting from the specification:
“Arguments are always passed by value and never passed by reference.”
This means that regardless of whether you’re passing a primitive type or an object, the underlying mechanism is consistent - a value is always passed. The difference lies in what that value represents:
- For primitives: the actual data value
- For objects: a reference (memory address) to the object
As noted in the Stack Overflow discussion, “JavaScript always evaluates each expression in a function call parameter list before calling the function, so the parameters are always values.”
The specification also clarifies that “the semantics of a parameter being passed to a function is completely independent of how that parameter was declared” (whether using var, let, or const), further emphasizing that the declaration mechanism doesn’t change the fundamental pass-by-value semantics.
Practical Examples and Common Misconceptions
Let’s explore several practical examples that demonstrate JavaScript’s argument passing behavior and address common misconceptions.
Example 1: Primitive Types in Action
function modifyPrimitive(num, str, bool) {
num = 100;
str = "modified";
bool = false;
}
let originalNum = 50;
let originalStr = "original";
let originalBool = true;
modifyPrimitive(originalNum, originalStr, originalBool);
console.log(originalNum); // 50
console.log(originalStr); // "original"
console.log(originalBool); // true
Result: All original values remain unchanged, demonstrating that primitives are passed by value.
Example 2: Object Property Modification
function modifyObjectProperty(obj) {
obj.property = "modified";
}
let myObject = { property: "original" };
modifyObjectProperty(myObject);
console.log(myObject.property); // "modified"
Result: The object property is modified, but this doesn’t mean pass-by-reference - it means the function received a copy of the reference value, allowing access to the same object.
Example 3: Object Reassignment
function reassignObject(obj) {
obj = { property: "new object" };
}
let myObject = { property: "original" };
reassignObject(myObject);
console.log(myObject.property); // "original"
Result: The original object remains unchanged, proving that JavaScript doesn’t support true pass-by-reference.
Example 4: Array Behavior
function modifyArray(arr) {
arr[0] = "modified";
arr.push("new element");
arr = ["completely new array"];
}
let myArray = ["original", "elements"];
modifyArray(myArray);
console.log(myArray); // ["modified", "elements", "new element"]
Result: The array contents can be modified (because the reference points to the same array), but reassigning the parameter doesn’t affect the original variable.
Common Misconceptions Addressed:
- “Objects are passed by reference” - This is incorrect. Objects are passed by value where the value is a reference to the object.
- “Using
letvsvaraffects parameter passing” - The specification confirms that parameter passing semantics are independent of declaration type. - “Functions can modify variable references in the calling scope” - JavaScript cannot do this; it can only modify object properties through shared references.
Key Takeaways for Developers
Understanding JavaScript’s argument passing semantics is crucial for writing predictable code. Here are the key points developers should remember:
-
JavaScript is fundamentally pass-by-value: All function arguments are passed as values, never as true references.
-
Primitives vs. Objects behave differently:
- Primitives: The actual value is copied
- Objects: A copy of the reference (memory address) is passed
-
The “reference” terminology can be misleading: What people often call “pass-by-reference” in JavaScript is more accurately described as “pass-by-reference-value” or “passing a reference by value”.
-
Function limitations:
- Functions can modify object properties (when given access to the same object)
- Functions cannot reassign variables in the calling scope
- Functions cannot change which object a variable references
-
Practical implications:
- To modify objects, pass the object and modify its properties
- To return multiple values, use objects/arrays or destructuring
- For true pass-by-reference behavior, use object properties or arrays as containers
As GeeksforGeeks summarizes, “JavaScript passes reference values for objects but not ‘by reference’ as in languages like C++.” This distinction is essential for avoiding common bugs and writing robust JavaScript code.
Sources
- Is JavaScript a pass-by-reference or pass-by-value language? - Stack Overflow
- Pass-By Value and Pass-By Reference in JavaScript with Examples - Scaler Topics
- Javascript pass by reference or value - Flexiple
- JavaScript: Passing by Value or by Reference - Snook.ca
- Understanding Pass by Value and Pass by Reference in JavaScript - Frontend Weekly
- Is JavaScript pass-by-value or pass-by-reference? - 30 seconds of code
- Pass by Value and Pass by Reference in Javascript - GeeksforGeeks
- The Difference Between Values and References in JavaScript - Dmitri Pavlutin
- Pass By Value vs. Pass By Reference in JavaScript - JavaScript in Plain English
- Does JavaScript pass by reference? - Stack Overflow
- Pass by value vs pass by reference in JavaScript - DEV Community
- ECMAScript specification of primitives and objects - Software Engineering Stack Exchange
- How To Use ES6 Arguments And Parameters — Smashing Magazine
- Passing ECMAScript 6 const as Function Argument - Stack Overflow
- ECMAScript Language Specification - ECMA-262 Edition 5.1
- ECMAScript 2015 Language Specification – ECMA-262 6th Edition
- ECMAScript® 2026 Language Specification
- ECMAScript® 2024 Language Specification
- Understanding the ECMAScript spec, part 3 · V8
- Function.prototype.arguments - JavaScript | MDN
Conclusion
JavaScript is unequivocally a pass-by-value language according to both its implementation and the official ECMAScript specification. While this behavior is straightforward for primitive types, objects create an illusion of pass-by-reference because the values passed are references to the actual objects in memory.
The key distinction is that JavaScript implements “pass-by-reference-value” rather than true pass-by-reference. This means:
- Function arguments are always copies of values
- For objects, those values are references to the objects
- Functions can modify object properties but cannot change variable references in the calling scope
This understanding is critical for writing predictable JavaScript code and avoiding common bugs related to variable scope and object mutation. The official specification consistently confirms this behavior, leaving no room for ambiguity about JavaScript’s argument passing semantics.