skip to Main Content

I was given a task to understand the .toString and .valueOf methods, who calls them, where they are used, how they work, how they are called and how to change calling sequence.

I am getting an error when I trying to override this:

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 returns an error RangeError: Maximum call stack size exceeded, how can I override value of to return, for example, string – ‘The number is ${this}’

I’ve found out that everything is working if I remove console.log(new Number(33).toString());

I have tried to console.log this and got such output:
Code output

2

Answers


  1. I really do not want to give this advice, and do not know why you wouldn’t declare a sub Class that has its prototype set to Object.create(Number.prototype) but if you want to do it on all Numbers, than you can go with a monkey patch:

    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)
    

    change the valueOf and toString to whatever you need.

    Warning: this is not good.

    Login or Signup to reply.
  2. When creating a Number using new, you create a Number object, which is not a primitive – see MDN. That may be the origin of the error.

    I think there are better ways to override Number methods, without polluting its prototype.

    One of those is for example creating a custom Number object, using a closure to hold its value and extending that with some functions. That way you don’t need protoype (or this for that matter). Something like:

    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);
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search