Altering the built-in prototypes of fundamental objects, or the built-in prototype chains, is generally discouraged as it can lead to unforeseen issues. It is strongly advised not to proceed with such modifications.
Number.__proto__
represents the prototype of the Number
function, and not the prototype for instances of Number
(which is Number.prototype
).
In JavaScript, there are both number primitives and Number objects. Typically, you interact with a number primitive. Even when using properties (including methods) on a number primitive (n = 42
) like toString
, the underlying mechanism references these from Number.prototype
despite n
being a primitive.
It is possible to modify the prototype of Number.prototype
. For example, setting it to null
ensures that Number
objects only inherit from Number.prototype
(thus breaking the connection with
Object.prototype</code)), effectively preventing property lookup on a number primitive to access properties and methods from <code>Object.prototype
:
const n = 8;
console.log(typeof n.hasOwnProperty); // function
console.log(Object(n) instanceof Number); // true
console.log(Object(n) instanceof Object); // true
Object.setPrototypeOf(Number.prototype, null);
console.log(typeof n.hasOwnProperty); // undefined
console.log(Object(n) instanceof Number); // true
console.log(Object(n) instanceof Object); // false
(Object(n)
returns a Number
object created from the number primitive n
. This approach was used since instanceof
always evaluates to false
for primitives [n instanceof Number
returns false
], necessitating an object conversion for inheritance checks.)
The association between Number
objects and Object
has been severed in this scenario.
Once again, this act is discouraged due to its potential to cause disruptions. Just because something is feasible doesn't imply it should be done.
Nevertheless, I realize it's feasible to incorporate specific items within the chain (like in Number-Object) using the following code:
Number.prototype.alpha = "def";
let num5 = 99;
console.log(num5.__proto__);
This action merely adds a property to Number.prototype
, without actually inserting anything into the prototype chain. However, altering the prototype chain directly is achievable by changing the prototype of Number.prototype
:
function Custom() {
}
// Transform `Custom.prototype` to an object whose prototype
// is equivalent to the prototype of `Number.prototype` (which by default is
// `Object.prototype`).
// (`Object.create` instantiates an object while setting its prototype
// to the specified object.)
Object.defineProperty(Custom, "prototype", {
value: Object.create(Object.getPrototypeOf(Number.prototype)),
writable: true,
});
Object.defineProperty(Custom.prototype, "constructor", {
value: Custom,
writable: true,
configurable: true,
});
Object.defineProperty(Custom.prototype, "example", {
value() {
return "hi there";
},
writable: true,
configurable: true,
});
Object.setPrototypeOf(Number.prototype, Custom.prototype);
const n = 8;
console.log(n.example()); // "hi there"
console.log(Object(n) instanceof Custom); // true
A constructor function was utilized here solely to facilitate the usage of instanceof
for checking inheritance; however, introducing a prototype without a constructor function is also viable. Below is the same code sans a constructor function:
const custom = Object.create(Object.getPrototypeOf(Number.prototype));
Object.defineProperty(custom, "example", {
value() {
return "hi there";
},
writable: true,
configurable: true,
});
Object.setPrototypeOf(Number.prototype, custom);
const n = 8;
console.log(n.example()); // "hi there"
Note 1: It is best to abstain from altering the prototype of existing objects (e.g., using Object.setPrototypeOf
). JavaScript engines optimize operations based on the assumption (typically valid) that an object's prototype remains constant once created. Changing the prototype disrupts these optimizations for the associated object.
Note 2: The usage of the deprecated __proto__
accessor property was intentionally avoided throughout. Instead, use Object.getPrototypeOf
along with (if necessary) Object.setPrototypeOf
for any new implementations. Furthermore, the usage of __proto__
would be unsuccessful for any object lacking inheritance from Object.prototype
, where the feature is typically defined.