【发布时间】:2021-09-17 11:59:19
【问题描述】:
为了不污染或扩展原型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 }
}
【问题讨论】:
-
不像你的标题说的那样,它不会被转换回
Number。应用+=运算符会给出 primitive 值。num.constructor表达式临时将原始num包装成Number。 -
@trincot 我明白你的意思。
num instanceof Number返回错误。我可以添加一个math()方法,它接受当前值的参数,计算值,然后将新值作为新的MyNum实例返回。 -
“类似于
Number和BigInt类型允许这些”:它们不允许。(Number(1) + Number(2)) instanceof Number是假的。同样在那里,结果是一个“数字”原语(或分别为“bigint”原语)。 -
@trincot 对我来说这些数字实际上是数字“原语”是有道理的,但是这些数字原语为什么/如何从
Number.prototype继承方法?例如,如果我定义Number.prototype.round,它可用于数字原语。 -
这是因为当您尝试访问属性时,原语被包装到本机对象中。这是您无法覆盖的行为。
标签: javascript class javascript-objects prototype prototype-programming