Objects built using prototype reference the common properties and methods that is stored in that prototype object rather than storing their own separate copies.
It is good to store functions and literals in prototype since they are not dynamically changing
function Time(hours, minutes) { this["hours"] = hours; this.minutes = minutes; Time.Now = "12:20" // static field this.printLog = function() { // better to define in prototype console.log("I am logging Time"); }}// defining fields using prototype// These fields are accessible to only objects of TimeTime.prototype.seconds = "45";Time.prototype.printTime = function() { console.log("12:20");}var time = new Time(12, 20);console.log(time);console.log(time.__proto__.seconds); // prints 45, __proto__ is accessible
[[Prototype]] vs prototype vs __proto__
Every object in JS has internal property called [[Prototype]] which can be accessed via different ways:
prototype is available to constructor function while it is not available to its corresponding instance.
__proto__ is available to object instances which can be accessed and points to the prototype
Access prototype chain
// we can chain prototypeobj.__proto__.__proto__
Modern JS way to get/set prototype:
Object.getPrototypeOf(obj)
returns the [[Prototype]] of obj.
Object.setPrototypeOf(obj, proto)
sets the [[Prototype]] of obj to proto.
Object.create(proto, [descriptors]
create an object with [[Prototype]] of obj to proto.
Default prototype
When we define an object literal or array using square brackets, the [[Prototype]] automatically points to Object.prototype or Array.prototype
We can add custom properties to Native wrapper prototype
But it is highly discouraged
It is used only in one situation: polyfills, where we want to support some latest methods in wrapper class
// if there's no such method, add it to the prototypeif (!String.prototype.repeatString) { String.prototype.repeatString = function(n) { // repeat the string n times // simple implementation return new Array(n + 1).join(this); };}console.log("La".repeatString(4)); // LaLaLaLa
Objects without __proto__
The [[Prototype]] can be either null or some object but cannot be some other primitive datatype like string:
let obj = {};let key = "__proto__"; // dynamically choosing key maybe via inputobj[key] = "some value"; // This fails since prototype must be null or objectconsole.log(obj[key]); // [object Object], not "some value"!
To avoid the above issue, we can use either Map or create objects without prototype:
// Object.create(null) creates object with prototype as nulllet obj = Object.create(null);let key = "__proto__"; // dynamically choosing key maybe via inputobj[key] = "some value"; // This passesconsole.log(obj[key]); // [object Object], not "some value"!