2

Given a class:

class Something {    
  constructor(something) {
   this._something = something; 
  }

  get something() {
    return this._something;
  }
}

I want to be able to spread the accessor values into a new object, for example:

const somethingObject = new Something(12);
const somethingSpread = { ...somethingObject };

However, it only outputs the class's _something attribute:

{ _something: 12 }

But what I'm looking for is something like this:

{ something: 12 }

I also tried with Object.assign, which gives the same output as above:

const somethingAssigned = Object.assign({}, somethingObject);
// Output: { _something: 12 }

Is it possible to accomplish this?

chazsolo
  • 7,873
  • 1
  • 20
  • 44
CodeIntern
  • 1,370
  • 2
  • 11
  • 15
  • Your code samples aren't valid JavaScript code: `Uncaught SyntaxError: Unexpected identifier` – Maxime Launois May 03 '19 at 15:04
  • @MaximeLaunois Pardon me, the question is about Javascript but has typings from TypeScript. Will remove the typings. – CodeIntern May 03 '19 at 15:09
  • Possible duplicate of [Cloning A JavaScript Object - Including Getters and Setters](https://stackoverflow.com/questions/34480936/cloning-a-javascript-object-including-getters-and-setters) – briosheje May 03 '19 at 15:23

2 Answers2

0

I came up with a bit of a hacky workaround that gets part of the way there. It works by calling a function in the object constructor, which copies the getters from the object's prototype onto the object itself, so they are available for the spread operator to see.

It's not perfect because you still get the private properties on the object, but it might serve as a starting point for someone to improve upon.

function enableGetterEnumeration(obj) {
  const pds = Object.getOwnPropertyDescriptors(Object.getPrototypeOf(obj));

  for (const [ pdname, pdprop ] of Object.entries(pds)) {
    if (pdprop.get) {
      Object.defineProperty(obj, pdname, {
        ...pdprop,
        enumerable: true,
      });
    }
  }
}

class MyObject {
  constructor() {
    this.count = 0;

    enableGetterEnumeration(this);
  }

  set info(n) {
    this.id = n;
    this.count++;
  }

  get info() {
    return `${this.id}'s class`;
  }
}

const c1 = new MyObject();
c1.info = 'John';

const literalC = {
  ...c1,
};

console.log(literalC); // { count: 1, info: "John's class", id: 'John' }

If you don't call enableGetterEnumeration() in the constructor, the info property won't appear in the final console.log().

Malvineous
  • 25,144
  • 16
  • 116
  • 151
-1

Just try:

class Something {
   private _something: Number;
   constructor(something: Number) {
     this._something = something;
   }

   public get something(): Number {
     return this._something;
   }

   public set something(value: Number) {
     this._something = value;
   }
}

function shallowClone(obj) {
   return Object.create(
   Object.getPrototypeOf(obj),
   Object.getOwnPropertyDescriptors(obj)
);

const var1 = new Something(12);
const var2 = shallowClone(var1);

console.log(var1, var1.something);
console.log(var2, var2.something);

output:

Something { _something: 12 } 12
Something { _something: 12 } 12