Why are class getters/setters non-enumerable?

# /#!/JoePea (8 years ago)

I've ran into this bug due to non-enumerable accessors: tweenjs/tween.js#267

The problem is that Tween.js does not detect the getters/setters in a for..in loop.

The solution I came up with is ugly, re-defining the descriptors to be enumerable, as demonstrated below. Is there a better way? Why are accessors non-enumerable when (to end user who use the properties to access values) they are used in the exact same way that "properties" are? It seems that they should be enumerable because whether or not they are "accessors" is not the end user's concern, they merely access the "property"...

class XYZValues {
    constructor(x = 0, y = 0, z = 0) {
        this._x = x
        this._y = y
        this._z = z
    }

    onChanged() {}

    set x(value) {
        this._x = value
        this.onChanged()
    }
    get x() { return this._x }

    set y(value) {
        this._y = value
        this.onChanged()
    }
    get y() { return this._y }

    set z(value) {
        this._z = value
        this.onChanged()
    }
    get z() { return this._z }
}

const xDesc = Object.getOwnPropertyDescriptor(XYZValues.prototype, 'x')
xDesc.enumerable = true
Object.defineProperty(XYZValues.prototype, 'x', xDesc)

const yDesc = Object.getOwnPropertyDescriptor(XYZValues.prototype, 'y')
yDesc.enumerable = true
Object.defineProperty(XYZValues.prototype, 'y', yDesc)

const zDesc = Object.getOwnPropertyDescriptor(XYZValues.prototype, 'z')
zDesc.enumerable = true
Object.defineProperty(XYZValues.prototype, 'z', zDesc)

export {XYZValues as default}
# Logan Smyth (8 years ago)

FYI,

const xDesc = Object.getOwnPropertyDescriptor(XYZValues.prototype, 'x')
xDesc.enumerable = true
Object.defineProperty(XYZValues.prototype, 'x', xDesc)

const yDesc = Object.getOwnPropertyDescriptor(XYZValues.prototype, 'y')
yDesc.enumerable = true
Object.defineProperty(XYZValues.prototype, 'y', yDesc)

const zDesc = Object.getOwnPropertyDescriptor(XYZValues.prototype, 'z')
zDesc.enumerable = true
Object.defineProperty(XYZValues.prototype, 'z', zDesc)

can be done with

Object.defineProperty(XYZValues.prototype, 'x', {enumerable: true})
Object.defineProperty(XYZValues.prototype, 'y', {enumerable: true})
Object.defineProperty(XYZValues.prototype, 'z', {enumerable: true})

or even

['x', 'y', 'z'].forEach(prop => Object.defineProperty(XYZValues.prototype,

prop, {enumerable: true}))

Why are accessors non-enumerable when (to end user who use the properties

to access values) they are used in the exact same way that "properties" are? It seems that they should be enumerable because whether or not they are "accessors" is not the end user's concern, they merely access the "property"

Even if they were enumerable, there are still differences. The properties aren't own properties for instance, they exist on the class prototype, not on the instance itself. You'd run into similar problems with any library that doesn't traverse beyond own keys, like Object.assign, even with enumerability.

To me, your assertion that they are supposed to be interchangeable is the problem. If they need to be a perfect replacement for standard data properties in the constructor, your best bet would be to define them in the constructor as enumerable own getter/setter properties just like the data properties would have been.