DEV Community

Discussion on: The tale of three dots in Javascript

 
worsnupd profile image
Daniel Worsnup

I, too, was curious about this, so I decided to run some code in the console! It looks like both spread and assign will copy "normal" getters, but they will not copy getters that are explicitly marked as non-enumerable using Object.defineProperty or Reflect.defineProperty:

const obj1 = {
  get test() { return 'test' }
}

const obj2 = {}
Reflect.defineProperty(obj2, 'test', {
  enumerable: false,
  get() { return 'test' }
})

console.log(Object.keys(obj1)) // ['test']
console.log(Object.keys(obj2)) // []

const obj1Spread = { ...obj1 }
const obj1Assign = Object.assign({}, obj1)

const obj2Spread = { ...obj2 }
const obj2Assign = Object.assign({}, obj2)

console.log(Object.keys(obj1Spread)) // ['test']
console.log(Object.keys(obj1Assign)) // ['test']
console.log(Object.keys(obj2Spread)) // []
console.log(Object.keys(obj2Assign)) // []

However, when an object is an instance of a class that defines a getter, the getter is on the object's prototype and so it doesn't show up during enumeration and therefore doesn't get copied with object spread/assign:

class MyClass {
  get test() { return 'test' }
}

const obj = new MyClass()
const objSpread = { ...obj }

console.log(Object.keys(obj), Object.keys(objSpread)) // [], []

I would assume this behavior to be consistent with setters.