Shallow Copy
Shallow copy refers to creating a new object that exactly copies the original object's properties. If the copied value is a primitive data type, the value itself is copied. If it's a reference data type, the memory address is copied. If the memory address of one object changes, the other object will also reflect that change.
(1) Object.assign()
Object.assign() is a method introduced in ES6 for copying objects. The first parameter is the target object, and the remaining parameters are source objects. The syntax is Object.assign(target, source_1, ...). This method can perform shallow copying and can also perform deep copying of one-dimensional objects.
Notes:
If the target object and source objects have properties with the same name, or if multiple source objects have properties with the same name, the properties of the latter objects will overwrite those of the former.
If the function has only one parameter, and that parameter is an object, it returns the object directly. If the parameter is not an object, it converts the parameter to an object and then returns it.
Since null and undefined cannot be converted to objects, the first parameter cannot be null or undefined, or it will throw an error.
let target = {a: 1};
let object2 = {b: 2};
let object3 = {c: 3};
Object.assign(target,object2,object3);
console.log(target); // {a: 1, b: 2, c: 3}
(2) Spread Operator
The spread operator can be used to copy properties when constructing literal objects. The syntax is: let cloneObj = { ...obj };.
let obj1 = {a: 1, b: {c: 1}};
let obj2 = {...obj1};
obj1.a = 2;
console.log(obj1); // {a: 2, b: {c: 1}}
console.log(obj2); // {a: 1, b: {c: 1}}
obj1.b.c = 2;
console.log(obj1); // {a: 2, b: {c: 2}}
console.log(obj2); // {a: 1, b: {c: 2}}
(3) Array Methods for Shallow Copying Arrays
Array.prototype.slice
The slice() method is a JavaScript array method that returns selected elements from an existing array. The syntax is array.slice(start, end), and the method does not modify the original array.
The method takes two optional parameters. If neither is provided, the method creates a shallow copy of the array.
let arr = [1, 2, 3, 4];
console.log(arr.slice()); // [1, 2, 3, 4]
console.log(arr.slice() === arr); // false
Array.prototype.concat
The concat() method is used to merge two or more arrays. This method does not modify the existing arrays but returns a new array.
The method takes two optional parameters. If neither is provided, the method creates a shallow copy of the array.
let arr = [1, 2, 3, 4];
console.log(arr.concat()); // [1, 2, 3, 4]
console.log(arr.concat() === arr); // false
(4) Implementing Shallow Copy
Here is a JavaScript code example to manually implement a shallow copy:
// Implementation of shallow copy
function shallowCopy(object) {
// Only copy objects
if (object === null || typeof object !== "object") return object;
// Determine whether to create a new array or object based on the type of the original object
let newObject = Array.isArray(object) ? [] : {};
// Iterate over the original object, and only copy its own properties
for (let key in object) {
if (object.hasOwnProperty(key)) {
newObject[key] = object[key];
}
}
return newObject;
}
Explanation:
Type Checking: The function first checks if the input is an object (not null or a primitive type). If not, it returns itself.
Type Determination: Based on whether the original object is an array or a plain object, the function creates a new array or a new object to hold the copied properties.
Property Copying: The function then iterates over the original object using a for...in loop. It checks if the property is directly on the object (i.e., not inherited) using hasOwnProperty(). If so, it copies the property to the new object.
Return: Finally, the new object (or array) with the copied properties is returned.
Test Case:
const original = {
name: 'Alice',
age: 25,
details: {
city: 'New York'
},
hobbies: ['reading', 'swimming']
};
const copy = shallowCopy(original);
console.log(copy);
// Output: { name: 'Alice', age: 25, details: { city: 'New York' }, hobbies: ['reading', 'swimming'] }
copy.name = 'Bob';
copy.details.city = 'Los Angeles';
copy.hobbies[0] = 'running';
console.log(original.name); // 'Alice', the basic property of the original object is not modified
console.log(original.details.city); // 'Los Angeles', the reference of the nested object is shared
console.log(original.hobbies[0]); // 'running', the reference of the array elements is shared
Deep Copy
Deep copy, in contrast to shallow copy, creates a new reference type and copies the corresponding values when encountering properties that are reference types. This means the object obtains a new reference type rather than a reference to the original type. Deep copy can be achieved for some objects using JSON's two functions, but since the JSON format is stricter than the JavaScript object format, it may fail when the property values include functions or Symbol types.
(1) JSON.stringify()
JSON.parse(JSON.stringify(obj)) is one of the more commonly used methods for deep copying. Its principle is to use JSON.stringify to serialize the JavaScript object into a JSON string, and then use JSON.parse to deserialize (restore) the JavaScript object.
This method can achieve deep copying in a simple and straightforward manner, but it has some limitations. If the object being copied contains functions, undefined, Date, RegExp, Map, Set, or Symbol values, these will be lost after processing with JSON.stringify().
function deepCopy(obj) {
return JSON.parse(JSON.stringify(obj));
}
const original = {
name: 'Alice',
age: 25,
details: {
city: 'New York',
hobbies: ['reading', 'swimming']
}
};
const copy = deepCopy(original);
copy.name = 'Bob';
copy.details.city = 'Los Angeles';
copy.details.hobbies[0] = 'running';
console.log(original.name); // 'Alice'
console.log(original.details.city); // 'New York'
console.log(original.details.hobbies[0]); // 'reading'
(2)_.cloneDeep provided by Lodash
The lodash library provides the _.cloneDeep method for performing deep copies.
const _ = require('lodash');
const original = {
name: 'Alice',
age: 25,
details: {
city: 'New York',
hobbies: ['reading', 'swimming'],
birthDate: new Date('1995-01-01')
}
};
const copy = _.cloneDeep(original);
copy.name = 'Bob';
copy.details.city = 'Los Angeles';
copy.details.hobbies[0] = 'running';
copy.details.birthDate.setFullYear(2000);
console.log(original.name); // 'Alice'
console.log(original.details.city); // 'New York'
console.log(original.details.hobbies[0]); // 'reading'
console.log(original.details.birthDate.getFullYear()); // 1995
(3) Implementing Deep Clone
function deepCopy(object, hash = new WeakMap()) {
// Non-object types or null, return directly
if (object === null || typeof object !== "object") return object;
// Check for circular references
if (hash.has(object)) return hash.get(object);
// Handle special object types
let newObject;
if (Array.isArray(object)) {
newObject = [];
} else if (object instanceof Date) {
newObject = new Date(object);
} else if (object instanceof RegExp) {
newObject = new RegExp(object);
} else {
newObject = {};
}
// Record the current object to avoid circular references
hash.set(object, newObject);
// Recursively copy all properties
for (let key in object) {
if (object.hasOwnProperty(key)) {
newObject[key] = deepCopy(object[key], hash);
}
}
return newObject;
}
// Test example
const original = {
name: "Alice",
age: 25,
details: {
city: "New York",
hobbies: ["reading", "swimming"],
birthDate: new Date("1995-01-01"),
pattern: /abc/g,
},
};
// Introduce a circular reference
original.self = original;
const copy = deepCopy(original);
console.log(copy);
Notice:
Return value for non-object types: If object is null or a non-object type (such as string, number, boolean), the function directly returns object. This ensures that the deep copy function returns the original value instead of undefined when encountering non-object types.
Handling circular references: A WeakMap is used to track objects that have already been copied. If the same object is encountered again, the function returns the previously created copy to prevent infinite recursion.
Handling special object types: The function includes special handling for Date and RegExp objects to correctly copy instances of these types. If additional types (e.g., Map, Set) need to be supported, the code can be further extended based on specific requirements.
SOCIAL SHARE CARD GENERATOR