14

I have a typescript class

export class Restaurant {

  constructor ( private id: string, private name: string ) {

  }

  public getId() : string {
    return this.id;
  }

  public setId(_id : string) {
    this.id = _id;
  }

  public getName () {
    return this.name;
  }

  public setName ( _name:string ) {
    this.name = _name;
  }

}

I then have an instance of this class ( this is an example ):

restaurant:Restaurant = new Restaurant(1,"TestRest");

I then store this restaurant object in some sort of cache

cache.store( restaurant );

then later in my application I get the restaurant back

var restToEdit = cache.get( "1" );
restToEdit.setName( "NewName" );

But because of javascripts pass by reference on objects, the changes I make to restToEdit also get saved in the restaurant that is in the cache.

I basically want the restaurant in the cache to be a totally different instance to the restToEdit.

I have tried using jQuery.clone and extend, but it doesn't seem to work and I think this is because of it being a typescript object. Or will that not matter?

Any answers on how to clone this object would be appreciated

Thanks

4 Answers 4

20
  • Using standard ES6 features

    const clone = Object.assign({}, myObject)
    

    Warning: this performs a shallow clone.

    This excellent page from MDN contains tons of details on cloning, including a polyfill for ES5

  • A "quick" way of deep cloning is to use JSON utilities

    const clone = JSON.parse(JSON.stringify(myObject))
    
  • A "proper" way of cloning is to implement a clone method or a copy constructor...

I know, I know, not enough JQuery

Sign up to request clarification or add additional context in comments.

8 Comments

Object.assign copies with reference.
Using Json.parse and then Json.stringify loses the functions assigned to the object
@JaganathanBantheswaran ... which is perfectly fine if your shallow cloning or cloning immutable properties !
Using Object.assign doesn't feel right in Typescript. Obviously I know once it compiles down to js it would be fine but it just doesnt feel like thats the solution for me & even so I want a deep clone, as I explained the properties are not immutable
@JaganathanBantheswaran angular.copy is not available in angular 2
|
5

This seems to work for me:

var newObject = Object.assign(Object.create(oldObj), oldObj)

Object.create creates a new instance with empty properties Object.assign then takes that new instance and assigns the properties

A more robust version of a clone function

    clone(obj) {
        if(Array.isArray(obj)) {
            return Array.from(obj);
        } else {
            return Object.assign(Object.create(obj), obj);
        }
    }

2 Comments

Only does a shallow clone. Any references still point to the same from the original object.
I would suggest to use Object.create(Object.getPrototypeOf(obj)) instead of Object.create(obj). Current code has the next issue: if obj had a property that was undefined during the copy, then after changing this property to some value in original obj, clone will see the change.
3

If you're using TS 2.1, you can use object spread operator to create a shallow copy:

const obj = { a: 1 };
const clonedObj = { ...obj };

Comments

1

.clone() only clones DOM elements. In order to clone JavaScript objects try jQuery.extend. Something like this

// Shallow copy
var newObject = jQuery.extend({}, oldObject);

// Deep copy
var newObject = jQuery.extend(true, {}, oldObject);

Typescript transpiles to JavaScript. So, JavaScript way will work fine.

Demo:

// Transpiled version of TypeScript
"use strict";
    var Restaurant = (function () {
        function Restaurant(id, name) {
            this.id = id;
            this.name = name;
        }
        Restaurant.prototype.getId = function () {
            return this.id;
        };
        Restaurant.prototype.setId = function (_id) {
            this.id = _id;
        };
        Restaurant.prototype.getName = function () {
            return this.name;
        };
        Restaurant.prototype.setName = function (_name) {
            this.name = _name;
        };
        return Restaurant;
    }());

// Test Snippet
var r1 = new Restaurant(1, "A");
var r2 = jQuery.extend(true, {}, r1);

r2.setName("B");

console.log(r1.name);
console.log(r2.name);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

2 Comments

Thanks, this works. Just didnt feel right in regards to typescript. I dont like using Javascript code within the typescript just because I know it will work. But for now this seems like the only solution. Thanks
You can wrap it up on the class/prototype: public clone(): Restaurant { /* same jquery code, just return r2 */ }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.