Number 的 Sub-class 持续转换回内置 Number Object/Function

Sub-class of Number persistently gets converted back to built-in Number Object/Function

为了不污染或扩展原型 Number 对象,我试图创建一个扩展 Number 的 class。但是,当我这样做然后尝试向其添加任何内容甚至将其添加到自身时,它会转换回数字。

我知道发生这种情况是因为它采用数字 valueOf 属性 值并将该值与另一个数字相加返回,但我希望该值始终保留其子 class 而无需创建其他方法,例如:

有没有办法实现这一点,类似于 NumberBigInt 类型允许这些类型的计算?我可以——但不想——扩展内置的 Number 对象来支持我的自定义方法,但现在每当我尝试使用它们时,它们都会丢失所有的方法。

例如:

let num = 5;
console.log(num.constructor); // Number
num += 2;
console.log(num); // 7
console.log(num.constructor); // still Number

但是,使用我的扩展 class:

class MyNum extends Number {
    constructor (num = 0) {
        super(num);
    }
    get isEven() { return this.isInt && this % 2 === 0 }
    get isOdd() { return this.isInt && this % 2 !== 0 }
}
let num = new MyNum(5);
console.log(num.constructor); // MyNum
num += 2;
console.log(num); // 7
console.log(num.constructor); // back to Number

此外,如果这里唯一的解决方案是添加像 .add(x) 这样的方法,我是否需要在完成像 .add(x) 这样的计算时重新创建一个新的 class 实例,或者还有另一种更原生的方式来增加现有对象的价值。

如果下面是唯一的解决方法,我可能会坚持扩展内置 Number 对象:

class MyNum extends Number {
    constructor (num = 0) {
        super(num);
    }
    add(x) { return new MyNum(this.valueOf() + x) }
    sub(x) { return new MyNum(this.valueOf() - x) }
    mul(x) { return new MyNum(this.valueOf() * x) }
    div(x) { return new MyNum(this.valueOf() / x) }
    mod(x) { return new MyNum(this.valueOf() % x) }
    get isEven() { return this.isInt && this % 2 === 0 }
    get isOdd() { return this.isInt && this % 2 !== 0 }
}

如果你愿意

num += 2;

导致num之前是MyNum,之后是MyNum,恐怕是不可能的。正如 the specification 所说,所有值都将转换为原语(valueOftoString),之后将原语连接在一起或添加在一起 ​​- 原语的连接或添加将导致作为结果的普通基元,字符串、数字或 BigInt。

添加新的显式方法,如 .add 是唯一可行的选择。

数字对象的值是 in an internal slot,这是不可更改的(无论如何您都不想更改,因为更改可能会造成混淆)。我不认为有比 add(x) { return new MyNum(this.valueOf() + x) } 等更好的方法。但是您可以通过删除 valueOf 调用来稍微清理您的方法,不需要它们。

add(x) { return new MyNum(this + x) }
sub(x) { return new MyNum(this - x) }