When, we make a new variable of type number (say num1), its __proto__
points to Number Object
. The __proto__
of it, will again point to Object Core
, its __proto__
points to null
, thereby ending the Prototype-chain.
What I am trying to do, is override this chain in middle, by trying to change the __proto__
link from Number Object
to some string. I cannot do the break in chain, as after my assignment its still pointing to Object Core
structure.
Am I doing something wrong to break this prototype chain OR is it impossible to break the pre-defined prototype chain in browser!
Number.__proto__ = "abc";
let num4 = 8;
console.log(num4.__proto__);//returns Number Object
console.log(num4.__proto__.__proto__)//should return string "abc"
Output:
However, I know I can add certain item in the middle of chain (like in Number-Object) by following code:
Number.prototype.alpha = "def";
let num5 = 99;
console.log(num5.__proto__);
Output:
Number.__proto__
is the prototype of the Number
function, not the prototype for Number
objects (which is Number.prototype
).
Also, JavaScript has both number primitives and Number objects. Most of the time, you're dealing with a number primitive. When you use properties (including methods) on a number primitive (n = 42
) such as like toString
, the JavaScript engine gets those from Number.prototype
even though n
is a primitive.
You can change the prototype of Number.prototype
. For instance, you can set it to null
so that Number
objects no longer inherit from anything but Number.prototype
(breaking the link with Object.prototype
), meaning property lookup on a number primitive doesn't find properties and methods from Object.prototype
anymore:
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 for the number primitive n
. I used it there because instanceof
is always false
for primitives [n instanceof Number
is false
, for instance]. To check inheritance, we need an object temporarily.)
As you can see, the link between Number
objects and Object
has been broken.
Again, this is a very bad idea in the general case, as it will tend to break things. Just because we can do it doesn't mean we should.
However, I know I can add certain item in the middle of chain (like in Number-Object) by following code:
Number.prototype.alpha = "def"; let num5 = 99; console.log(num5.__proto__);
That's just adding a property to Number.prototype
, not inserting something into the prototype chain. But it's possible to insert into the prototype chain, too, since we can change the prototype of Number.prototype
:
function Custom() {
}
// Change `Custom.prototype` to an object whose prototype
// is the prototype of `Number.prototype` (which will be
// `Object.prototype` in an unsullied environment).
// (`Object.create` creates an object setting its prototype
// to the given 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
I used a constructor function there just so we could readily use instanceof
to check inheritance, but you can insert a prototype without a constructor function. Here's that same code without one:
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: Changing the prototype of an existing objects (e.g., with Object.setPrototypeOf
) is best avoided. JavaScript engines optimize on the assumption (which is normally true) that the prototype of an object won't change once it's been created. Changing it breaks that assumption, which removes those optimizations from the object.
Note 2: You'll notice I didn't use the __proto__
accessor property anywhere above. It's deprecated and should not be used in new code, use Object.getPrototypeOf
and (if absolutely necessary) Object.setPrototypeOf
instead. It would also fail for any object that doesn't inherit from Object.prototype
, since that's where the __proto__
accessor property is defined.