Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript spread operator with class instances

How can I modify a class instance using the spread operator, while keeping its constructor the same?

The question may be clearer with an example.

class User {
    constructor({ name = "", age = 0 }) {
        this.name = name
        this.age = age
    }

    getName() {
        return this.name
    }

    getAge() {
        return this.age
    }
}

Creating a regular instance works fine:

const u1 = new User({ name: 'John Doe', age: 33 })
console.log(u1.getAge()) // 33

What does not work is using the spread operator with the instance:

const u2 = { ...u1, age: 34 }
console.log(u2.getAge()) // 

I read that the spread operator only copies own enumerable properties, so I also tried this:

const u3 = { ...u1, ...User.prototype, age: 34 }
console.log(u3.getAge())

This works better (it allows me to call the methods in User), but still breaks when using instanceof or Object.isPrototypeOf():

console.log(u1 instanceof User) // true
console.log(u2 instanceof User) // false
console.log(u3 instanceof User) // false

console.log(User.isPrototypeOf(u1)) // true
console.log(User.isPrototypeOf(u2)) // false
console.log(User.isPrototypeOf(u3)) // false

I also tried these, but they didn't work either:

const u4 = Object.assign({ age: 34 }, u1)
const u5 = Object.assign({ age: 34 }, u1, User.prototype)

So, TL:DR, is it possible to create a copy of a class instance which changes some properties of the parent, but keeps a reference to its constructor?

Hope I made myself clear. Thanks in advance for the help!

like image 934
spaceface Avatar asked Jan 24 '23 23:01

spaceface


1 Answers

With the { } object literal notation you always create a plain object, never an instance of your custom class. You should use the new operator to get a new instance (or Object.create):

class User {
    constructor({ name = "", age = 0 }) {
        this.name = name
        this.age = age
    }

    getName() {
        return this.name
    }

    getAge() {
        return this.age
    }
}

const u1 = new User({ name: 'John Doe', age: 33 })
console.log(u1.getName(), u1.getAge()) // John Doe, 33

const u2 = new User({ ...u1, age: 34 });
console.log(u2.getName(), u2.getAge()) // John Doe, 34
like image 101
trincot Avatar answered Feb 06 '23 18:02

trincot