Javascript соединить два объекта

How to Merge Objects in JavaScript

Developers often need to merge or copy objects for tasks like combining data or creating new instances. Techniques like the spread ( . ) operator (used for merging properties of multiple objects) and the Object.assign() method (for copying properties from one object to another) are essential tools for these tasks. However, understanding when and how to use them is crucial for effective object manipulation. In this article, I’ll cover some practical applications of these methods, their strengths and weaknesses, and the concept of deep copying before merging nested objects.

Table of contents

Approaches for Merging Objects

1. The Spread Operator ( . )

The spread operator ( . ) is a common approach to merge objects in JavaScript. It has the form <. object1, . object2>. When properties with the same keys exist in the source objects, the spread operator overwrites the values in the target object with the latest source object’s values.

const defaults = < color: 'red', size: 'medium' >; const userSettings = < color: 'blue' >; const combinedSettings = < . defaults, . userSettings >; console.log(combinedSettings); // Output:

2. The Object.assign() Method

Object.assign() is a JavaScript method for merging objects. Its syntax is Object.assign(target, source1, source2, . ) , where you merge source objects into the target object. When properties with the same keys exist in the source objects, Object.assign() overwrites the values in the target object with the latest source object’s values.

const defaults = < color: 'red', size: 'medium' >; const userSettings = < color: 'blue' >; const combinedSettings = Object.assign(<>, defaults, userSettings); console.log(combinedSettings); // Output:

Pitfalls and Considerations

Here are the potential pitfalls and issues with both the spread operator and Object.assign() method for merging objects in JavaScript:

1. Shallow copying

Both the spread operator and Object.assign() perform shallow copying when merging objects. This means that nested objects are still references to the original objects. Modifying the nested objects in the merged object can affect the original objects, which may lead to unintended side effects.

2. Overwriting properties

When merging objects with properties that have the same keys, both the spread operator and Object.assign() overwrite the values in the resulting object with values from the latest source object. This behavior may cause the loss of data if not handled carefully.

3. Compatibility issues

The spread operator is part of ECMAScript 2015 (ES6) and is not supported in older JavaScript environments or browsers, such as Internet Explorer. This may cause compatibility issues if your code needs to run in older environments. In such cases, it’s better to use Object.assign() , which has wider support.

Читайте также:  Python convert string to bool

4. Non-enumerable properties

Both the spread operator and Object.assign() only copy enumerable properties from source objects to the target object. Non-enumerable properties are not copied during the merging process, which may lead to missing data or unexpected behavior.

5. Performance concerns

In cases where you need to merge large objects or perform merging operations frequently, using Object.assign() or the spread operator may cause performance issues due to the creation of new objects during the merging process.

6. Prototype properties

Object.assign() copies properties from the source object’s prototype to the target object, which may lead to unexpected behavior if the source object’s prototype has properties that conflict with the target object’s properties. The spread operator, on the other hand, does not copy prototype properties.

It’s essential to be aware of these pitfalls and issues when using the spread operator or Object.assign() to merge objects in JavaScript. In specific scenarios, you may need to employ alternative approaches, such as deep cloning or deep merging functions, to overcome these limitations.

Which One to Use

Both Object.assign() and the spread operator effectively merge objects. The spread operator is more concise and modern, while Object.assign() offers better compatibility with older JavaScript environments.

To decide which method to use, consider:

  1. If your environment supports the spread operator (such as the latest ECMAScript version), use it for its concise syntax.
  2. If compatibility with older JavaScript environments is essential, choose Object.assign() .
  3. If you need to copy a nested object (one with objects nested inside it) read on to Deep Copying Objects.

Deep Merging: Deep Copy & Merge Objects

Both the spread operator and Object.assign() create a shallow copy of the object(s) being copied. Essentially this means the new object will have references to the same nested objects (e.g. arrays and functions) as the original object, rather than having copies of them.

Knowing and avoiding this is essential before merging objects together.

The example below shows how editing nested objects on a copied object can affect the original:

const planet = < name: 'Earth', emoji: '🌍', info: < type: 'terrestrial', moons: 1 >>; // Shallow copy using the spread operator const shallowCopyPlanet = < . planet >; // Modifying the nested object in the shallow copy shallowCopyPlanet.info.moons = 2; console.log('Original planet:', planet.info.moons); // Original planet: 2 console.log('Shallow copy of the planet:', shallowCopyPlanet.info.moons); // Shallow copy of the planet: 2

The output of this code shows that the info.moons property on the original object planet has been changed by editing it in shallowCopyPlanet (You probably don’t want this).

A custom Deep Merging function

Here’s a function that deep copies multiple objects before merging them and returns a single object. In the code, the deepMergeObjects function takes any number of input objects, creates deep copies of them using the JSON.parse(JSON.stringify()) technique, and then merges them using the spread operator inside the reduce() method. The merged object will contain deep copies of the properties from the input objects.

const deepMergeObjects = (. objects) => < const deepCopyObjects = objects.map(object =>JSON.parse(JSON.stringify(object))); return deepCopyObjects.reduce((merged, current) => (< . merged, . current >), <>); > // Example usage: const countries = < USA: < capital: 'Washington D.C.', emoji: '🇺🇸', population: 331000000 >>; const countriesDetails = < USA: < language: 'English', currency: 'USD' >, Germany: < capital: 'Berlin', emoji: '🇩🇪', language: 'German', currency: 'EUR', population: 83000000 >>; const mergedData = deepMergeObjects(countries, countriesDetails);

Conclusion

Thanks for reading! I hope this article has given you a deep understanding of merging objects in JavaScript and not just a shallow introduction. Being able to combine objects in this should merge nicely with your JavaScript skills and spread your coding prowess. For any questions or comments, join us over at the SitePoint Community Forum.

Читайте также:  Относительный путь python pathlib

Share This Article

Mark is the General Manager of SitePoint.com. He loves to read and write about technology, startups, programming languages, and no code tools.

Источник

Object.assign()

The Object.assign() static method copies all enumerable own properties from one or more source objects to a target object. It returns the modified target object.

Try it

Syntax

Parameters

The target object — what to apply the sources’ properties to, which is returned after it is modified.

The source object(s) — objects containing the properties you want to apply.

Return value

Description

Properties in the target object are overwritten by properties in the sources if they have the same key. Later sources’ properties overwrite earlier ones.

The Object.assign() method only copies enumerable and own properties from a source object to a target object. It uses [[Get]] on the source and [[Set]] on the target, so it will invoke getters and setters. Therefore it assigns properties, versus copying or defining new properties. This may make it unsuitable for merging new properties into a prototype if the merge sources contain getters.

For copying property definitions (including their enumerability) into prototypes, use Object.getOwnPropertyDescriptor() and Object.defineProperty() instead.

Both String and Symbol properties are copied.

In case of an error, for example if a property is non-writable, a TypeError is raised, and the target object is changed if any properties are added before the error is raised.

Note: Object.assign() does not throw on null or undefined sources.

Examples

Cloning an object

const obj =  a: 1 >; const copy = Object.assign(>, obj); console.log(copy); // 

Warning for Deep Clone

For deep cloning, we need to use alternatives like structuredClone() , because Object.assign() copies property values.

If the source value is a reference to an object, it only copies the reference value.

const obj1 =  a: 0, b:  c: 0 > >; const obj2 = Object.assign(>, obj1); console.log(obj2); // < a: 0, b: < c: 0 >> obj1.a = 1; console.log(obj1); // < a: 1, b: < c: 0 >> console.log(obj2); // < a: 0, b: < c: 0 >> obj2.a = 2; console.log(obj1); // < a: 1, b: < c: 0 >> console.log(obj2); // < a: 2, b: < c: 0 >> obj2.b.c = 3; console.log(obj1); // < a: 1, b: < c: 3 >> console.log(obj2); // < a: 2, b: < c: 3 >> // Deep Clone const obj3 =  a: 0, b:  c: 0 > >; const obj4 = structuredClone(obj3); obj3.a = 4; obj3.b.c = 4; console.log(obj4); // < a: 0, b: < c: 0 >> 

Merging objects

const o1 =  a: 1 >; const o2 =  b: 2 >; const o3 =  c: 3 >; const obj = Object.assign(o1, o2, o3); console.log(obj); // console.log(o1); // < a: 1, b: 2, c: 3 >, target object itself is changed. 

Merging objects with same properties

const o1 =  a: 1, b: 1, c: 1 >; const o2 =  b: 2, c: 2 >; const o3 =  c: 3 >; const obj = Object.assign(>, o1, o2, o3); console.log(obj); // 

The properties are overwritten by other objects that have the same properties later in the parameters order.

Copying symbol-typed properties

const o1 =  a: 1 >; const o2 =  [Symbol("foo")]: 2 >; const obj = Object.assign(>, o1, o2); console.log(obj); // < a : 1, [Symbol("foo")]: 2 >(cf. bug 1207182 on Firefox) Object.getOwnPropertySymbols(obj); // [Symbol(foo)] 

Properties on the prototype chain and non-enumerable properties cannot be copied

const obj = Object.create( // foo is on obj's prototype chain.  foo: 1 >,  bar:  value: 2, // bar is a non-enumerable property. >, baz:  value: 3, enumerable: true, // baz is an own enumerable property. >, >, ); const copy = Object.assign(>, obj); console.log(copy); // 

Primitives will be wrapped to objects

const v1 = "abc"; const v2 = true; const v3 = 10; const v4 = Symbol("foo"); const obj = Object.assign(>, v1, null, v2, undefined, v3, v4); // Primitives will be wrapped, null and undefined will be ignored. // Note, only string wrappers can have own enumerable properties. console.log(obj); // 

Exceptions will interrupt the ongoing copying task

const target = Object.defineProperty(>, "foo",  value: 1, writable: false, >); // target.foo is a read-only property Object.assign(target,  bar: 2 >,  foo2: 3, foo: 3, foo3: 3 >,  baz: 4 >); // TypeError: "foo" is read-only // The Exception is thrown when assigning target.foo console.log(target.bar); // 2, the first source was copied successfully. console.log(target.foo2); // 3, the first property of the second source was copied successfully. console.log(target.foo); // 1, exception is thrown here. console.log(target.foo3); // undefined, assign method has finished, foo3 will not be copied. console.log(target.baz); // undefined, the third source will not be copied either. 

Copying accessors

const obj =  foo: 1, get bar()  return 2; >, >; let copy = Object.assign(>, obj); console.log(copy); // // The value of copy.bar is obj.bar's getter's return value. // This is an assign function that copies full descriptors function completeAssign(target, . sources)  sources.forEach((source) =>  const descriptors = Object.keys(source).reduce((descriptors, key) =>  descriptors[key] = Object.getOwnPropertyDescriptor(source, key); return descriptors; >, >); // By default, Object.assign copies enumerable Symbols, too Object.getOwnPropertySymbols(source).forEach((sym) =>  const descriptor = Object.getOwnPropertyDescriptor(source, sym); if (descriptor.enumerable)  descriptors[sym] = descriptor; > >); Object.defineProperties(target, descriptors); >); return target; > copy = completeAssign(>, obj); console.log(copy); // < foo:1, get bar() < return 2 >> 

Specifications

Browser compatibility

BCD tables only load in the browser

See also

Источник

Оцените статью