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 */ }

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.