为了不污染或扩展原型(prototype) Number
对象,我尝试创建一个扩展 Number
的类。但是,当我执行此操作然后尝试向其中添加任何内容甚至将其添加到自身时,它会被转换回数字。
我知道发生这种情况是因为它采用数字 valueOf
属性值并将该值添加到另一个数字中返回,但我希望该值始终保留其子类,而无需创建额外的方法如下:
.add(x)
.sub(x)
.mul(x)
.div(x)
有没有一种方法可以实现这一点,类似于 Number
和 BigInt
类型允许这些类型的计算?我可以(但不想)扩展内置 Number 对象来支持我的自定义方法,但现在每当我尝试使用它们时,它们都会丢失所有方法。
例如:
let num = 5;
console.log(num.constructor); // Number
num += 2;
console.log(num); // 7
console.log(num.constructor); // still Number
但是,使用我的扩展类:
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)< 这样的计算时,我是否需要重新创建一个新的类实例
已完成,或者是否有另一种更原生的方式来添加现有对象的值。
如果以下是唯一的解决方法,我可能会坚持扩展内置的 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也就是说,所有值都将转换为基元(valueOf
、toString
),之后将基元连接在一起或相加 - 并且将导致基元的连接或添加以普通原语作为结果,可以是字符串、数字或 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) }
关于javascript - Number 的子类永久转换回内置 Number 对象/函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68277559/