Javascript Number Prototype Set Value Directly [duplicate]

TL;DR – You can’t do that, your initial version of bitSet is how you need to define it. You’ll need to save its return value when you use it, e.g., x = x.bitSet(2). You can create your own mutable number object, though, if you like. (More on that below.)

Just for clarity (you probably know this): JavaScript has both number primitives and Number objects. Normally, you’re dealing with primitives. The reason Number.prototype works is that a temporary object is created using the primitive’s value when a method is called on it. Unless something explicitly saves the object, though, it’s as though we were just dealing with primitives.

Numbers are not mutable in JavaScript.1 So your bitSet method cannot change the numeric value of what it’s called on; instead, it has to return a new number with the changes made (e.g., your original version).

Note that even if you could change a Number object’s value, you’re almost never dealing with a number object in code outside functions you’ve assigned to Number.prototype. For instance:

Number.prototype.bitSet = function(bit) {
    return this | (1<<bit);
};
var x = 32;
x = x.bitSet(2);
console.log(x); // 36
console.log(typeof x); // "number", not "object"
var o = new Number(36);
console.log(typeof o); // "object"

In the above, when x = x.bitSet(2); is executed, the number primitive is converted to a temporary Number object, your bitSet method is called, and then the result is whatever your bitSet method returns; unless bitSet does something to store this somewhere, the temporary object is then thrown away. (That’s the theory; in fact, your JavaScript engine may well optimize away the object entirely, if it can determine that the code in your function only uses the number as though it were a primitive number.)

So suppose in my code above, we did something to change the state of the Number object in that x.bitSet(2) line. Since that object is temporary and not stored anywhere (unless we store it; it’s not in x, x contains a primitive number), whatever we stored on the object would be lost. We can even prove that:

Number.prototype.test = function() {
  this.foo = Math.random();
  console.log("this.foo", this.foo); // some number
};
var x = 42;
x.test();
console.log(typeof x);       // "number", not "object"
console.log("x.foo", x.foo); // undefined

this was definitely an object, we added a property to it and used that property. But x still had the primitive.

You could have your own mutable number type, though:

function MyNumber(value) {
    this.value = typeof value === "number" ? value : 0;
}
MyNumber.prototype.bitSet = function(bit) {
    this.value = this.value | (1 << bit);
};
MyNumber.prototype.valueOf = function() {
    return this.value;
};
MyNumber.prototype.toString = function() {
    return this.value.toString();
};

// Usage:
var m = new MyNumber(42);
m.bitSet(2);
console.log(String(m)); // "46"
var n = m + 5;
console.log(n);         // 51

The valueOf function is called any time the JavaScript engine needs to convert your number object to a number. toString is called when the JavaScript engine needs to convert your number object to a string.

Or in ES2015:

class MyNumber {
    constructor(value) {
      this.value = typeof value === "number" ? value : 0;
    }
    bitSet(bit) {
      this.value = this.value | (1 << bit);
    }
    valueOf() {
      return this.value;
    }
    toString() {
      return this.value.toString();
    }
}

// Usage:
var m = new MyNumber(42);
m.bitSet(2);
console.log(String(m)); // "46"
var n = m + 5;
console.log(n); // 51

1 “Numbers are not mutable in JavaScript” Technically, that’s not true. Primitive numbers are not mutable, but Number objects are — but their underlying numeric value (what the spec calls its [[NumberData]]) cannot be changed. (Number objects can have other properties with state that can be changed, just not their numeric value.) So “Numbers are not mutable in JavaScript” is a reasonable shorthand statement, if not perfectly correct.

Leave a Comment