Keywords: JavaScript | Deep Copy | Object Cloning | JSON | Reference Passing
Abstract: This article provides an in-depth exploration of JavaScript's object reference passing mechanism and its associated challenges. It thoroughly analyzes the principles and limitations of using JSON.parse(JSON.stringify()) for deep copying, compares shallow versus deep copy differences, and references Apex language cloning implementations to comprehensively explain best practices for creating independent object copies across various scenarios. The article includes complete code examples and performance analysis to help developers fully understand and master core JavaScript object cloning techniques.
Analysis of JavaScript Object Passing Mechanism
In JavaScript, objects are passed by reference, meaning that when we assign an object to another variable, we are actually sharing the same memory address. This mechanism can be clearly demonstrated through the following code example:
var json_original = {one:'one', two:'two'}
var json_new = json_original;
console.log(json_original); // Output: {one: 'one', two: 'two'}
console.log(json_new); // Output: {one: 'one', two: 'two'}
json_original.one = 'two';
json_original.two = 'one';
console.log(json_original); // Output: {one: 'two', two: 'one'}
console.log(json_new); // Output: {one: 'two', two: 'one'}From the output results, we can see that modifying properties of the original object json_original causes corresponding properties in the new variable json_new to change as well, confirming that both reference the same object instance.
Basic Concepts and Implementation Methods of Deep Copy
To create independent copies of objects and avoid side effects from reference sharing, we need to employ deep copy techniques. Deep copying recursively duplicates all levels of an object, ensuring the new object is completely independent from the original in memory.
For simple JSON objects, the most commonly used deep copy method utilizes JSON serialization and deserialization:
var json_original = {one:'one', two:'two'};
var json_new = JSON.parse(JSON.stringify(json_original));
json_original.one = 'modified';
console.log(json_original.one); // Output: 'modified'
console.log(json_new.one); // Output: 'one'This method converts the object to a JSON string using JSON.stringify(), then parses it back into a new object using JSON.parse(), thereby achieving complete deep copying.
Principles and Limitations of JSON Deep Copy Method
The effectiveness of the JSON.parse(JSON.stringify()) method is based on the characteristics of the JSON data format. JSON only supports basic data types (strings, numbers, booleans, null) and two structural types (objects and arrays), so during serialization, certain JavaScript-specific data types are ignored or converted:
- Functions are completely ignored
undefinedvalues are ignored in objects and converted tonullin arrays- Date objects are converted to ISO format strings
- Regular expressions are converted to empty objects
- Circular references cause serialization to fail
The following code demonstrates these limitations:
var obj = {
func: function() { return 'hello'; },
undef: undefined,
date: new Date(),
regex: /test/g
};
var cloned = JSON.parse(JSON.stringify(obj));
console.log(cloned.func); // Output: undefined
console.log(cloned.undef); // Output: undefined (missing in object)
console.log(cloned.date); // Output: date as string
console.log(cloned.regex); // Output: {}Comparative Analysis of Other Deep Copy Methods
Beyond the JSON method, other deep copy implementations exist, each with distinct characteristics:
jQuery's Deep Copy Implementation
If jQuery library is used in the project, deep copying can be achieved using the jQuery.extend() method:
// Shallow copy
var shallowCopy = $.extend({}, originalObject);
// Deep copy
var deepCopy = $.extend(true, {}, originalObject);jQuery's implementation can handle more JavaScript-specific data types but depends on external library inclusion.
Shallow Copy Characteristics of ES6 Spread Operator
ES6 introduced the spread operator, providing a concise way for shallow copying:
var shallowCopy = { ...oldObject };
var shallowCopyWithExtra = { ...oldObject, extraProp: 'value' };It's important to note that this remains shallow copying, and nested objects still share references.
Deep Copy Implementation Philosophy from Apex Language Perspective
Referencing object cloning implementations in Apex language provides insights into general deep copy design patterns. In Apex, deep copying is achieved through custom clone methods:
public class CustomObject {
public Integer primitiveValue = 0;
public List<String> stringList = new List<String>{'a', 'b'};
public CustomObject clone(Boolean deepClone) {
CustomObject cloned = this.clone();
if (deepClone) {
cloned.stringList = stringList.clone();
}
return cloned;
}
}The core idea of this implementation is: directly copy values for primitive type members, and recursively call clone methods for complex type members. This pattern can be adapted to JavaScript for implementing more universal deep copy functions.
Performance Considerations and Best Practice Recommendations
When selecting deep copy methods, comprehensive consideration of performance, compatibility, and functional requirements is essential:
- Simple JSON Objects: Prefer
JSON.parse(JSON.stringify())for better performance and simplicity - Complex Object Structures: Consider using specialized deep copy libraries or custom recursive functions
- Modern JavaScript Environments: Utilize
structuredClone()API (limited browser support) - Performance-Sensitive Scenarios: Avoid using deep copying in loops or high-frequency operations
Below is an example implementation of a universal deep copy function:
function deepClone(obj) {
if (obj === null || typeof obj !== 'object') {
return obj;
}
if (obj instanceof Date) {
return new Date(obj.getTime());
}
if (obj instanceof Array) {
return obj.map(item => deepClone(item));
}
if (obj instanceof Object) {
const cloned = {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
cloned[key] = deepClone(obj[key]);
}
}
return cloned;
}
}Practical Application Scenarios and Considerations
Deep copy technology is particularly important in the following scenarios:
- State Management: Maintaining state immutability in libraries like Redux
- Function Parameter Passing: Preventing internal function modifications from affecting external objects
- Caching Mechanisms: Creating independent snapshots of data
- Concurrent Operations: Avoiding data races in multi-threaded environments like Web Workers
When using deep copying, attention must be paid to memory usage and performance overhead, especially for large objects or deeply nested structures. In some cases, immutable data structure libraries can be considered for performance optimization.
By deeply understanding JavaScript's object reference mechanism and the characteristics of various deep copy methods, developers can select the most appropriate implementation based on specific requirements, ensuring code reliability and performance optimization.