patternjavascriptCritical
How does JavaScript .prototype work?
Viewed 0 times
howprototypedoesjavascriptwork
Problem
I'm not that into dynamic programming languages but I've written my fair share of JavaScript code. I never really got my head around this prototype-based programming, does any one know how this works?
I remember a lot discussion I had with people a while back (I'm not exactly sure what I'm doing) but as I understand it, there's no concept of a class. It's just an object, and instances of those objects are clones of the original, right?
But what is the exact purpose of this ".prototype" property in JavaScript? How does it relate to instantiating objects?
Update: correct way
Also these slides really helped a lot.
var obj = new Object();
obj.prototype.test = function() { alert('Hello?'); };
var obj2 = new obj();
obj2.test();I remember a lot discussion I had with people a while back (I'm not exactly sure what I'm doing) but as I understand it, there's no concept of a class. It's just an object, and instances of those objects are clones of the original, right?
But what is the exact purpose of this ".prototype" property in JavaScript? How does it relate to instantiating objects?
Update: correct way
var obj = new Object(); // not a functional object
obj.prototype.test = function() { alert('Hello?'); }; // this is wrong!
function MyObject() {} // a first class functional object
MyObject.prototype.test = function() { alert('OK'); } // OKAlso these slides really helped a lot.
Solution
Every JavaScript object has an internal "slot"(i.e. hidden property) called
These prototypes connect objects into prototype chains for looking up properties. When you try to access a property from an object by either
An object's
Note that the
Before JavaScript introduced the class syntax, people used the syntax
For example, here's one way:
...and here's another way:
But if you're careful, you might have found that
...the resulting object's
Finally, if you create a new object via
[[Prototype]](square brackets are deliberate) whose value is either null or an object. The value is colloquially known as "the prototype of that object."These prototypes connect objects into prototype chains for looking up properties. When you try to access a property from an object by either
obj.propName or obj['propName'], and the object does not own(obj.hasOwnProperty('propName')) the property, the runtime will try to find the property from the prototype chain of that object by recursively referencing the [[Prototype]] slots until a null is reached.An object's
[[Prototype]] is initially set during object creation, and modern JavaScript allows read and write access to the [[Prototype]] in the following ways:- The
new Ctor()syntax, which sets[[Prototype]]toFunc.prototypefor the newly created object.
- The
extendskeyword, which configures the prototype chain for the class syntax.
Object.create, which will set the supplied argument as the[[Prototype]]of the resulting object.
Object.getPrototypeOfandObject.setPrototypeOf(get/set the[[Prototype]]after object creation)
- The standardized accessor property named
__proto__. (but it has unusual behaviours when an object has a prototype ofnull.)
Note that the
.prototype is a genuine property, not an internal slot. Therefore, all classes, and all functions that can be used with the new operator, have a property named .prototype in addition to their own [[Prototype]] internal slot. This dual use of the word "prototype" is the source of endless confusion amongst newcomers to the language.Before JavaScript introduced the class syntax, people used the syntax
new Ctor() to simulate classical inheritance by prototypical inheritance:- Shared members, e.g. methods, were added to the constructor's
.prototypeproperty.
- Instance fields, however, were added to the object itself during construction.
For example, here's one way:
function Child() {}
function Parent() {}
Parent.prototype.inheritedMethod = function () { return 'this is inherited' }
function inherit(child, parent) {
child.prototype = Object.create(parent.prototype)
child.prototype.constructor = child
return child;
}
Child = inherit(Child, Parent)
const o = new Child
console.log(o.inheritedMethod()) // 'this is inherited'
...and here's another way:
function Child() {}
function Parent() {}
Parent.prototype.inheritedMethod = function () { return 'this is inherited' }
function inherit(child, parent) {
function tmp() {}
tmp.prototype = parent.prototype
const proto = new tmp()
proto.constructor = child
child.prototype = proto
return child
}
Child = inherit(Child, Parent)
const o = new Child
console.log(o.inheritedMethod()) // 'this is inherited'
But if you're careful, you might have found that
Parent's instance fields are not considered in these two cases. Fortunately, in ES2015 these details are hidden and we can just write a one-liner version thanks to the extends syntax:class Parent { inheritedMethod() { return 'this is inherited' } }
class Child extends Parent {}
const o = new Child
console.log(o.inheritedMethod()) // 'this is inherited'
...the resulting object's
[[Prototype]] will be set to an instance of Parent, whose [[Prototype]], in turn, is Parent.prototype.Finally, if you create a new object via
Object.create(foo), the resulting object's [[Prototype]] will be set to foo.Context
Stack Overflow Q#572897, score: 1068
Revisions (0)
No revisions yet.