Search code examples
javascriptgetter-setterassignment-operatores6-class

Is there a way of having arithmetic operators use getters and setters in Javascript ES6?


I have a rudimentary ID system where a number is translated into a string and padded with zeros to be at least 3 digits. It works fine as long as I'm only using a regular assignment. Is there any way of having arithmetic operators work with the setter as well?

class Test {
  constructor() {
    this.id = 0;
  }

  /**
   * @param {Number} num
   */
  set id(num) {
    if (num < 10) {
      this._id = '00' + num;
    } else if (num < 100) {
      this._id = '0' + num;
    } else {
      this._id = '' + num;
    }
  }

  get id() {
    return this._id;
  }

  incrementID(increment=1) {
    const id = parseInt(this.id);
    this.id = id + increment;
  }
}

const test = new Test();
test.id = 5;
console.log(`ID is: ${test.id}`); // ID is: 005

test.id += 5;
console.log(`ID is: ${test.id}`); // ID is: 00055 (How?!?)

I know I could have an incrementID method like the one I wrote, but that feels like it's against the philosophy that ES6 setters and getters have.

As a side note, what is even happening with the addition assignment? I would've expected the result to be 0055 if anything weird, since it's a number being added to a string.


Solution

  • Well, theoretically you could make 'id' an object and provide a hook to convert it to a number by default:

    class ID {
        constructor(value) {
            this.value = value;
        }
    
        [Symbol.toPrimitive](hint) {
            if (hint === 'number' || hint === 'default')
                return Number(this.value)
            return String(this.value);
        }
    }
    
    class Test {
        constructor() {
            this.id = new ID('000');
        }
    
        set id(num) {
            let s;
            if (num < 10) {
                s = '00' + num;
            } else if (num < 100) {
                s = '0' + num;
            } else {
                s = '' + num;
            }
            this._id = new ID(s);
    
        }
    
        get id() {
            return this._id;
        }
    }
    
    
    const test = new Test();
    test.id = 5;
    console.log(`ID is: ${test.id}`); // ID is: 005
    
    test.id += 5;
    console.log(`ID is: ${test.id}`); // ID is: 010

    Docs

    That said, a practical way would be to have two properties (number and a formatted string), as suggested above.