How to Duplicate Object Properties in Another Object

How to duplicate object properties in another object?

for(var k in firstObject) secondObject[k]=firstObject[k];

Copying properties from one object to another with a condition

One lazy option is:

_.extend(a, _.pick(b, _.keys(a)));

_.pick filters the source object by using the .keys of the destination object and the result is used for extending the destination object.

If you don't want to modify the original objects just pass an empty object to the _.extend function.

_.extend({}, a, _.pick(b, _.keys(a)));

How do I correctly clone a JavaScript object?

2022 update

There's a new JS standard called structured cloning. It works in many browsers (see Can I Use).

const clone = structuredClone(object);

Old answer

To do this for any object in JavaScript will not be simple or straightforward. You will run into the problem of erroneously picking up attributes from the object's prototype that should be left in the prototype and not copied to the new instance. If, for instance, you are adding a clone method to Object.prototype, as some answers depict, you will need to explicitly skip that attribute. But what if there are other additional methods added to Object.prototype, or other intermediate prototypes, that you don't know about? In that case, you will copy attributes you shouldn't, so you need to detect unforeseen, non-local attributes with the hasOwnProperty method.

In addition to non-enumerable attributes, you'll encounter a tougher problem when you try to copy objects that have hidden properties. For example, prototype is a hidden property of a function. Also, an object's prototype is referenced with the attribute __proto__, which is also hidden, and will not be copied by a for/in loop iterating over the source object's attributes. I think __proto__ might be specific to Firefox's JavaScript interpreter and it may be something different in other browsers, but you get the picture. Not everything is enumerable. You can copy a hidden attribute if you know its name, but I don't know of any way to discover it automatically.

Yet another snag in the quest for an elegant solution is the problem of setting up the prototype inheritance correctly. If your source object's prototype is Object, then simply creating a new general object with {} will work, but if the source's prototype is some descendant of Object, then you are going to be missing the additional members from that prototype which you skipped using the hasOwnProperty filter, or which were in the prototype, but weren't enumerable in the first place. One solution might be to call the source object's constructor property to get the initial copy object and then copy over the attributes, but then you still will not get non-enumerable attributes. For example, a Date object stores its data as a hidden member:

function clone(obj) {
if (null == obj || "object" != typeof obj) return obj;
var copy = obj.constructor();
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr];
}
return copy;
}

var d1 = new Date();

/* Executes function after 5 seconds. */
setTimeout(function(){
var d2 = clone(d1);
alert("d1 = " + d1.toString() + "\nd2 = " + d2.toString());
}, 5000);

The date string for d1 will be 5 seconds behind that of d2. A way to make one Date the same as another is by calling the setTime method, but that is specific to the Date class. I don't think there is a bullet-proof general solution to this problem, though I would be happy to be wrong!

When I had to implement general deep copying I ended up compromising by assuming that I would only need to copy a plain Object, Array, Date, String, Number, or Boolean. The last 3 types are immutable, so I could perform a shallow copy and not worry about it changing. I further assumed that any elements contained in Object or Array would also be one of the 6 simple types in that list. This can be accomplished with code like the following:

function clone(obj) {
var copy;

// Handle the 3 simple types, and null or undefined
if (null == obj || "object" != typeof obj) return obj;

// Handle Date
if (obj instanceof Date) {
copy = new Date();
copy.setTime(obj.getTime());
return copy;
}

// Handle Array
if (obj instanceof Array) {
copy = [];
for (var i = 0, len = obj.length; i < len; i++) {
copy[i] = clone(obj[i]);
}
return copy;
}

// Handle Object
if (obj instanceof Object) {
copy = {};
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]);
}
return copy;
}

throw new Error("Unable to copy obj! Its type isn't supported.");
}

The above function will work adequately for the 6 simple types I mentioned, as long as the data in the objects and arrays form a tree structure. That is, there isn't more than one reference to the same data in the object. For example:

// This would be cloneable:
var tree = {
"left" : { "left" : null, "right" : null, "data" : 3 },
"right" : null,
"data" : 8
};

// This would kind-of work, but you would get 2 copies of the
// inner node instead of 2 references to the same copy
var directedAcylicGraph = {
"left" : { "left" : null, "right" : null, "data" : 3 },
"data" : 8
};
directedAcyclicGraph["right"] = directedAcyclicGraph["left"];

// Cloning this would cause a stack overflow due to infinite recursion:
var cyclicGraph = {
"left" : { "left" : null, "right" : null, "data" : 3 },
"data" : 8
};
cyclicGraph["right"] = cyclicGraph;

It will not be able to handle any JavaScript object, but it may be sufficient for many purposes as long as you don't assume that it will just work for anything you throw at it.

What is the most efficient way to copy some properties from an object in JavaScript?

You can achieve it with a form of destructuring:

const user = { _id: 1234, firstName: 'John', lastName: 'Smith' };
const { _id, ...newUser } = user;
console.debug(newUser);

How can I duplicate an object to another object, without changing the base object in Kotlin?

You are just assigning the same object (same chunk of memory) to another variable. You need to somehow create a new instance and set all fields.

header2 = Record()
header2.name = header1.name

However in Kotlin, if the Record class was Data class, Kotlin would create a copy method for you.

data class Record(val name: String, ...)
...
header2 = header1.copy()

And copy method allows you to override the fields you need to override.

header2 = header1.copy(name = "new_name")

how to copy properties from one object to another with different values C#

Deep cloning can be achieved easily through serialization, however to only copy across non-null fields needs more conditional logic, In this case I call this a Coalesce so I've named my Method CoalesceTo. You could refactor this into an extension method if you wanted to, but I wouldn't recommend it, instead put this inside a static helper class. As useful as this might be, I don't encourage it as your "goto" for a production business runtime.

Using Reflection for these types of solutions is usually the most inefficient mechanism, but it gives us a lot of flexibility and is great for mocking, prototyping and quick unit test expressions.

  • Although not in this example, it would be easy to add in checks to exclude [Obsolete] properties for advanced scenarios

The following example uses Property Name comparison, so you don't have to pass in objects of the same type. Notice that IsNull and IsValueType methods have been created to encapsulate those concepts, simplifying tweaks you might want to make to this method.

  • This method also checks that properties can be read/written before proceeding, which allows us to support readonly properties on the source object, and of course we don't try to write to readonly properties.
  • The final value parse and write is wrapped in a try catch statement that is suppressing any errors, It takes a bit of tweaking to get code like this to work universally, but it should work fine for simple type definitions.
/// <summary>
/// Deep Copy the top level properties from this object only if the corresponding property on the target object IS NULL.
/// </summary>
/// <param name="source">the source object to copy from</param>
/// <param name="target">the target object to update</param>
/// <returns>A reference to the Target instance for chaining, no changes to this instance.</returns>
public static void CoalesceTo(object source, object target, StringComparison propertyComparison = StringComparison.OrdinalIgnoreCase)
{
var sourceType = source.GetType();
var targetType = target.GetType();
var targetProperties = targetType.GetProperties();
foreach(var sourceProp in sourceType.GetProperties())
{
if(sourceProp.CanRead)
{
var sourceValue = sourceProp.GetValue(source);

// Don't copy across nulls or defaults
if (!IsNull(sourceValue, sourceProp.PropertyType))
{
var targetProp = targetProperties.FirstOrDefault(x => x.Name.Equals(sourceProp.Name, propertyComparison));
if (targetProp != null && targetProp.CanWrite)
{
if (!targetProp.CanRead)
continue; // special case, if we cannot verify the destination, assume it has a value.
else if (targetProp.PropertyType.IsArray || targetProp.PropertyType.IsGenericType // It is ICollection<T> or IEnumerable<T>
&& targetProp.PropertyType.GenericTypeArguments.Any()
&& targetProp.PropertyType.GetGenericTypeDefinition() != typeof(Nullable<>) // because that will also resolve GetElementType!
)
continue; // special case, skip arrays and collections...
else
{
// You can do better than this, for now if conversion fails, just skip it
try
{
var existingValue = targetProp.GetValue(target);
if (IsValueType(targetProp.PropertyType))
{
// check that the destination is NOT already set.
if (IsNull(existingValue, targetProp.PropertyType))
{
// we do not overwrite a non-null destination value
object targetValue = sourceValue;
if (!targetProp.PropertyType.IsAssignableFrom(sourceProp.PropertyType))
{
// TODO: handle specific types that don't go across.... or try some brute force type conversions if neccessary
if (targetProp.PropertyType == typeof(string))
targetValue = targetValue.ToString();
else
targetValue = Convert.ChangeType(targetValue, targetProp.PropertyType);
}

targetProp.SetValue(target, targetValue);
}
}
else if (!IsValueType(sourceProp.PropertyType))
{
// deep clone
if (existingValue == null)
existingValue = Activator.CreateInstance(targetProp.PropertyType);

CoalesceTo(sourceValue, existingValue);
}
}
catch (Exception)
{
// suppress exceptions, don't set a field that we can't set
}

}
}
}
}
}
}

/// <summary>
/// Check if a boxed value is null or not
/// </summary>
/// <remarks>
/// Evaluate your own logic or definition of null in here.
/// </remarks>
/// <param name="value">Value to inspect</param>
/// <param name="valueType">Type of the value, pass it in if you have it, otherwise it will be resolved through reflection</param>
/// <returns>True if the value is null or primitive default, otherwise False</returns>
public static bool IsNull(object value, Type valueType = null)
{
if (value is null)
return true;

if (valueType == null) valueType = value.GetType();

if (valueType.IsPrimitive || valueType.IsEnum || valueType.IsValueType)
{
// Handle nullable types like float? or Nullable<Int>
if (valueType.IsGenericType)
return value is null;
else
return Activator.CreateInstance(valueType).Equals(value);
}

// treat empty string as null!
if (value is string s)
return String.IsNullOrWhiteSpace(s);

return false;
}
/// <summary>
/// Check if a type should be copied by value or if it is a complexe type that should be deep cloned
/// </summary>
/// <remarks>
/// Evaluate your own logic or definition of Object vs Value/Primitive here.
/// </remarks>
/// <param name="valueType">Type of the value to check</param>
/// <returns>True if values of this type can be straight copied, false if they should be deep cloned</returns>
public static bool IsValueType(Type valueType)
{
// TODO: any specific business types that you want to treat as value types?

// Standard .Net Types that can be treated as value types
if (valueType.IsPrimitive || valueType.IsEnum || valueType.IsValueType || valueType == typeof(string))
return true;

// Support Nullable Types as Value types (Type.IsValueType) should deal with this, but just in case
if (valueType.HasElementType // It is array/enumerable/nullable
&& valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(Nullable<>))
return true;

return false;
}

Because we are using reflection here, we cant take advantage of optimisations that Generics could offer us. If you wanted to adapt this to a production environment, consider using T4 templates to script out a Generic typed version of this logic as extension methods to your business types.

Deep Cloning -

You'll notice I specifically skip arrays and other IEnumerable structures... There's a whole can of worms in supporting them, it might be better to not let the one method attempt a Deep copy, so take the nested call to CoalesceTo out, then call the clone method on each object in the tree.

The problem with arrays/collections/lists is that before you could clone, you would need to identify a way to synchronise the collection in the source with the collection in the target, you could make a convention based on an Id field or some kind of attribute like [KeyAttribute] but that sort of implementation needs to be highly specific to your business logic and is outside of the scope of this already monstrous post ;)

Types like Decimal and DateTime are problematic in these types of scenarios, they should not be compared to null, instead we have to compare them to their default type states, again we can't use the generic default operator or value in this case because the type can only be resolved at runtime.

So I've changed your classes to include an example of how DateTimeOffset is handled by this logic:

public class Employee
{
public int EmployeeID { get; set; }
public string EmployeeName { get; set; }
public DateTimeOffset Date { get; set; }
public float? Capacity { get; set; }
Nullable<int> MaxShift { get; set; }
public Address ContactAddress { get; set; }
}

public class Address
{
public string Address1 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
}

public static void TestMethod1()
{
Employee employee = new Employee();
employee.EmployeeID = 100;
employee.EmployeeName = "John";
employee.Capacity = 26.2f;
employee.MaxShift = 8;
employee.Date = new DateTime(2020,1,22);
employee.ContactAddress = new Address();
employee.ContactAddress.Address1 = "Park Ave";
employee.ContactAddress.City = "New York";
employee.ContactAddress.State = "NewYork";
employee.ContactAddress.ZipCode = "10002";

Employee employeeCopy = new Employee();
employeeCopy.EmployeeID = 101;
employeeCopy.EmployeeName = "Tom";
employeeCopy.ContactAddress = new Address();

CoalesceTo(employee, employeeCopy);
}

This results in the following object graph:

{
"EmployeeID": 101,
"EmployeeName": "Tom",
"Date": "2020-01-22T00:00:00+11:00",
"Capacity":26.2,
"MaxShift":8,
"ContactAddress": {
"Address1": "Park Ave",
"City": "New York",
"State": "NewYork",
"ZipCode": "10002"
}
}

How can I clone a JavaScript object except for one key?

There is a Destructuring assignment syntax in JavaScript that can be used

let obj = {a: 1, b: 2, c: 3, z:26};
let {b, ...rest} = obj;

// skips the "Unused variable" warning
let {b: _, ...rest} = obj;

// removes property based on the dynamic key
const dynamicKey = "b";
let {[dynamicKey]: _, ...rest} = obj;

Modern browsers already support it out of the box.
See: JavaScript operator: Destructuring assignment: Rest in objects

For old browser versions there is an option to use Babel to support destructuring assignment. It will be transpiled into:

"use strict";

function _objectWithoutProperties(obj, keys) {
var target = {};
for (var i in obj) {
if (keys.indexOf(i) >= 0) continue;
if (!Object.prototype.hasOwnProperty.call(obj, i)) continue;
target[i] = obj[i];
}
return target;
}

var x = { a: 1, b: 2, c: 3, z: 26 };
var b = x.b;

var y = _objectWithoutProperties(x, ["b"]);

Elegant way to copy only a part of an object

One way to do it is through object destructuring and an arrow function:

let source = {    x: 120,    y: 200,    z: 150,    radius: 10,    color: 'red',};
let result = (({ x, y, z }) => ({ x, y, z }))(source);
console.log(result);


Related Topics



Leave a reply



Submit