Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript / TypeScript: Difference between `Object.assign({}, myClass)`/`Object.create(myClass)` and constructor `new MyClass()`

I wish I could post my project verbatim for this question, but I cannot.

Essentially, I have the following classes:

class Lowest {
    someValue: string
    
    constructor(someValue: string) {
        this.someValue = someValue
    }
}
class Middle {
    lowest: Lowest

    constructor(someValue: string) {
        this.lowest = new Lowest(someValue)
    }
}
class Highest {
    private _middle: Middle
    otherValue: SomeOtherClass

    // normal getter
    public get middle(): Middle {
       return this._middle
    }

    public set middle(next: Middle) {
       this._middle = next
       // notice: when `_middle` is set, I update another property!
       otherValue.doSomething(this._middle)
    }

    constructor(config: { someValue: string }) {
        this.middle = new Middle(config.somevalue)
    }
}

In some places in my program, I have a reference to a Highest instance and need to alter its middle.lowest.someValue sub-property. Now, for architectural reasons that I cannot really describe here, I need to update the Highest.otherValue property whenever Highest.middle. As I am using TypeScript, I simply perform this operation in the setter for Highest.middle. As such, I cannot just straight up set Highest.middle.lowest to some value.

My first approach was:

const nextMiddle = Object.assign({}, highestInstance.middle)
nextMiddle.lowest.someValue = "some other thing"
highestInstance.middle = nextMiddle

However, this ended up causing some very strange issues. Now, I had no real technical need for performing a deep clone of nextMiddle, so I overcame it with the following code:

const nextMiddle = highestInstance.middle
nextMiddle.lowest.someValue = "some other thing"
highestInstance.middle = nextMiddle

While I was experimenting with the best fix, I implemented a Middle.copy() method that basically just calls new Middle() and new Lowest() with the values from the previous instance. This also solved my technical issues, but left me even more confused.

I understand that there's a big difference between simply re-assigning highestInstance.middle and using Object.assign() to clone it, but I don't understand why there does not seem to be a difference between Object.assign() and new Middle()

What are the real differences with these three methods of cloning/re-assignment?

like image 922
foxtrotuniform6969 Avatar asked Feb 03 '26 18:02

foxtrotuniform6969


1 Answers

had no real technical need for performing a deep clone of nextMiddle, so I overcame it with the following code:

Object.assign({}, highestInstance.middle) is creating a shallow copy and not a deep copy.

The issue here is using Middle Setter is forcing yourself to perform otherValue: SomeOtherClass only when middle is updated.

it will update it even if you just do just :

high.middle.lowest.someValue = 'new value'
high.middle = high.middle; // setter triggered

A possible solution is to create a call-back chain rather than using a setter:

    type voidFun = () => void;

class Lowest {
    private _someValue: string
    
     public get someValue(): string {
       return this._someValue
    }

    private  update?: voidFun; // create an optional callback

    public set someValue(next: string) {
       this._someValue = next
       this.update?.call(undefined);
    
    }

    constructor(someValue: string, fun?: voidFun) {
        this._someValue = someValue
        this.update = fun;// pass down
    }
}

class Middle {
    lowest: Lowest;

    constructor(someValue: string, fun?: voidFun) {
        this.lowest = new Lowest(someValue, fun)
    }
}

class Highest {
    private _middle: Middle
    otherValue: any = {};

    
    // normal getter
    public get middle(): Middle {
       return this._middle
    }

    // now you dont need middle setting so it cant be updated by anyone directly 
    // if you still want to have you can have it too
    private callBack = () => {
        console.log('lower was update');
        this.otherValue.myMiddle  = this._middle.lowest.someValue;
    }

    constructor(config: { someValue: string } = { someValue : 'constr' }) {
        this._middle = new Middle(config.someValue, this.callBack) 
    }
}



 let high = new Highest()
 high.middle.lowest.someValue = 'new value'
// high.middle = high.middle; // now not possible unless you create setter
console.log('updated middle high',high)
like image 190
vaira Avatar answered Feb 05 '26 07:02

vaira



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!