如何在 JavaScript 中覆盖 valueOf() 作为 Number 原型的行为?

How can I override the behavior of valueOf() as a prototype of the Number in JavaScript?

提问人:yarslvd 提问时间:11/16/2023 最后编辑:yarslvd 更新时间:11/17/2023 访问量:97

问:

我的任务是了解 .toString 和 .valueOf 方法、谁调用它们、在哪里使用它们、它们如何工作、如何调用以及如何更改调用顺序。

当我尝试覆盖它时,我收到一个错误:

Number.prototype.toString = function () {
  return "This is the number: " + this
};

Number.prototype.valueOf = function () {
  //console.log(this)
  return this;
}

console.log(new Number(33).toString());
console.log(new Number(34).valueOf())

Js返回错误,如何覆盖值返回,例如字符串 - 'The number is ${this}'RangeError: Maximum call stack size exceeded

我发现如果我删除,一切正常console.log(new Number(33).toString());

我试图控制台.log这个并得到这样的输出:代码输出

javascript 数字 原型 原型js

评论

0赞 yarslvd 11/16/2023
@David我已经更新了问题并发现它仅在我控制台之前.log新的Number(33).toString()时才起作用
3赞 Danny 11/16/2023
由于 的字符串连接,具有隐式递归。toStringthis
0赞 yarslvd 11/16/2023
@Danny,那么我怎样才能以正确的方式覆盖这两种方法呢?
0赞 Pointy 11/17/2023
如果你愿意花时间描述你为什么要这样做,它将帮助人们为你提供想法。你的目标是什么?这在您正在从事的项目的背景下意味着什么?

答:

1赞 ibrahim tanyalcin 11/16/2023 #1

我真的不想给出这个建议,也不知道为什么你不声明一个将其原型设置为的潜艇,但如果你想在所有数字上这样做,那么你可以使用猴子补丁:ClassObject.create(Number.prototype)

Number.prototype.toString = (function(f){return function(){return `whatever ${f.call(this)}`}})(Number.prototype.toString)

Number.prototype.valueOf = (function(f){return function(){return f.call(this)}})(Number.prototype.valueOf)

将 AND 更改为您需要的任何内容。valueOftoString

警告:这不好。

评论

0赞 yarslvd 11/17/2023
非常感谢!我知道最好不要覆盖这些方法,但这是我的任务。另外,我还有一个问题。我们覆盖了这些方法,它们仅适用于使用构造函数(new Number(10))创建的数字,对吗?我们是否有机会改变在隐式转换过程中以文字形式表示的数字的行为?
1赞 Pointy 11/17/2023
@yarslvd当你编写类似的东西时,(数字原语)会自动转换为数字实例。(17).valueOf()17
0赞 yarslvd 11/17/2023
@Pointy,是的,我理解这一点,但是,例如,如果 console.log(“3” + myNum),在这种情况下数字是“const myNum = 10”,那么数字如何转换为字符串?
0赞 Pointy 11/17/2023
@yarslvd,每当将数字转换为字符串时,都会调用该方法。.toString()
0赞 yarslvd 11/17/2023
@Pointy 但是,当我们使用数字的文字表达式时,为什么不使用我们的重写方法呢?.toString()
0赞 KooiInc 11/16/2023 #2

创建 using 时,您将创建一个 Number 对象,该对象不是原语 - 请参阅 MDN。这可能是错误的根源。Numbernew

我认为有更好的方法可以覆盖方法,而不会污染其.Numberprototype

例如,创建一个自定义对象,使用闭包来保存其值,并使用某些函数扩展它。这样你就不需要(或就此而言)。像这样:Numberprotoypethis

function XNumber(nr = 0) {

  // the number function encloses [nr]
  const number = nrGiven => {
    nr = nrGiven;
  }
  
  const myNumberExtensions = {
    toString() { return `This is the number ${nr}`},
    set value(val) { nr = val; },
    clone(value) { return XNumber(value ?? nr); },
    increment(withValue = 1) { nr += withValue; return number; },
    valueOf() { return nr; },
  };
  
  // because Function is just another object,
  // you can extend it with custom methods
  Object.entries(Object.getOwnPropertyDescriptors(myNumberExtensions))
    .forEach( ([key, descriptor]) => { 
      Object.defineProperty(number, key, descriptor); 
    }
  );
  
  return number;
}

const myNr1 = XNumber(41);
const myNr2 = myNr1.clone().increment();

console.log(myNr1.toString());
// toString automatically when within a (template) string:
console.log(`${myNr1}`);

console.log(myNr2.valueOf());
// valueOf automatically when appended to a string
console.log(""+myNr2);

评论

0赞 Pointy 11/16/2023
并不是说我同意修改 Number 原型,但有一个功能是表达式会自动选择修改后的方法。(x * 2).toString()
0赞 KooiInc 11/16/2023
@Pointy当然,一切都有代价; 不过会起作用。XNumber(x*2).toString()
0赞 yarslvd 11/17/2023
谢谢,但我有一个确切的任务来覆盖这些方法以了解 JS 的工作原理)