David542
David542

Reputation: 110257

Copying values to an object clone/prototype

Let's say I have the following object where I want to initialize it with values (outside a class):

let person = {
    firstName: undefined,
    lastName: undefined,
    get fullName() {
        return `${this.firstName} ${this.lastName}`;
    }
}
let p = Object.create(person);
p.firstName = 'Ralph';
p.lastName = 'Smedley';
console.log(p.fullName);

Why doesn't the above work when doing the following?

let person = {
    firstName: undefined,
    lastName: undefined,
    get fullName() {
        return `${this.firstName} ${this.lastName}`;
    }
}
                         // use default Object so don't override inherited object
let ralph = Object.assign({}, person, {firstName: 'Ralph', lastName: 'Smedley'});
console.log(ralph.fullName);

What would be the proper way to do this second approach?

Upvotes: 1

Views: 24

Answers (1)

CertainPerformance
CertainPerformance

Reputation: 370809

When you use Object.assign, the getters are invoked at that time (and the result is put as a data property onto the new object). Your getter isn't running after ralph is created - it's running before that.

let person = {
    firstName: undefined,
    lastName: undefined,
    get fullName() {
        console.log('getting fullName');
        return `${this.firstName} ${this.lastName}`;
    }
}
let ralph = Object.assign({}, person, {firstName: 'Ralph', lastName: 'Smedley'});

After that occurs, you're left with an object of:

{
  firstName: "Ralph"
  fullName: "undefined undefined"
  lastName: "Smedley"
}

So logging ralph.fullName will give you what exists in that property, which is "undefined undefined"

Using Object.create, on the other hand, does not invoke getters that may exist on the object - all it does is set the internal prototype.

If you wanted to copy over the method too, you could do:

const person = {
    firstName: undefined,
    lastName: undefined,
    get fullName() {
        return `${this.firstName} ${this.lastName}`;
    }
};

const objectAssignWithGettersSetters = (target, ...args) => {
  for (const arg of args) {
    Object.defineProperties(target, Object.getOwnPropertyDescriptors(arg));
  }
  return target;
}
const ralph = objectAssignWithGettersSetters({}, person, {firstName: 'Ralph', lastName: 'Smedley'});
console.log(ralph.fullName);

Upvotes: 3

Related Questions