Useful links:
Table of contents
- Beginning
- getPrototypeOf / setPrototypeOf
- __proto__
- Object.create
- Prototype chains
- Function prototypes
- Prototype inheritance
- Global Objects
- ES6 Classes
- Extensions
- Quiz
Beginning
const a = {};
What properties does this object have?
None? Let’s try to log it in browser.
Object a
has [[Prototype]]
. What is it? It’s just a hidden property. Value of this property is link to an object.
In our case value of [[Prototype]]
is link to Object.prototype
. What is Object.prototype
?
Just an object that’s have methods like toString()
and etc (check photo).
What does this connection between object a
and Object.prototype
mean?
const a = {};
console.log(a.toString());
Will there be a mistake? No. Why? JS engine like
Okay I should execute toString
in a
. Let’s check a
. a
doesn’t have field toString
, so let’s go to prototype of a
object.
It’s link to Object.prototype
. Okay, I found toString
in Object.prototype
, let’s execute it. Engine checks all prototype chain.
If object doesn’t have some field, engine go to prototype. If prototype doesn’t have filed - engine will check prototype of prototype until it finds
this field or the prototype will be null
. Prototype of Object.prototype is null. Don’t believe me? How to see prototype of something via JS but not dev tools?
getPrototypeOf / setPrototypeOf
These methods appeared in ES5. getPrototypeOf(obj)
returns prototype of obj
. setPrototypeOf(obj, anotherObj)
, now prototype of obj
is anotherObj
const a = {
print: () => console.log("Hello")
}
const b = {};
console.log(Object.getPrototypeOf(a) === Object.getPrototypeOf(b));
Object.setPrototypeOf(b, a);
console.log(Object.getPrototypeOf(a) === Object.getPrototypeOf(b));
b.print();
Show output
truefalse
Hello
__proto__
This property appeared in ES6. Use it instead of getPrototypeOf/setPrototypeOf
.
const a = {
print: () => console.log("Hello")
}
const b = {};
console.log(a.__proto__ === b.__proto__);
b.__proto__ = a;
console.log(a.__proto__ === b.__proto__);
b.print();
Show output
truefalse
Hello
Object.create
Object.create(...);
creates a new object associated with the object we specified.
const B = Object.create(A);
- prototype of B is A.
Prototype chains
Thanks to prototype, we can delegate behaviour to someone with whom we are connected by a prototype
const Parent = {
name: "Parent",
doSomething: function() {
console.log("Method from Parent, but name is taken from " + this.name)
}
}
const ChildOfParent = Object.create(Parent);
ChildOfParent.name = "Child of Parent";
const ChildOfChild = Object.create(ChildOfParent);
ChildOfChild.name = "Child of Child";
ChildOfChild.doSomething();
Show output
Method from Parent, but name is taken from Child of ChildFunction prototypes
By default, all functions have a public, non-enumerable property called prototype
.
function Foo() {
// ...
}
Foo.prototype; // { }
Not a very good name. The prototype field (Foo.prototype
) that appears in the function
and the prototype of the function itself (Foo.__proto__
) are different things
function Foo() {
// ...
}
console.log(Foo.prototype === Foo.__proto__); // False!!!!!
Each object that is constructed via new FunctionName()
syntax is given a link to the function
prototype (FunctionName.prototype
) by the its prototype (constructedObject.__proto__
)
function Person() {}
const person = new Person();
console.log(person.__proto__ === Person.prototype);
![](https://user-images.githubusercontent.com/57585370/137113380-fd21e527-3e78-4506-a5a6-46c54dd6a24e.png)
Person.prototype also has a constructor filed references the function itself
We want the person object to have a name
function Person(name) {
this.name = name;
}
const person = new Person("Ksenia");
console.log(person);
console.log(Person.prototype);
![](https://user-images.githubusercontent.com/57585370/137113557-1e415754-2ac9-490e-8f16-45b49310d6ac.png)
But we want each instance of Person to have a greeting method
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function() {
console.log("Hello, my name is " + this.name);
}
const person = new Person("Ksenia");
console.log(person);
console.log(person.sayHello());
console.log(Person.prototype);
![](https://user-images.githubusercontent.com/57585370/137113666-1fb68248-ea8b-4e79-a1a7-304114ef671d.png)
Prototype inheritance
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.mainInfo = function() {
console.log(`Main info: ${this.name}, ${this.age}`);
}
function Student(name, age, department) {
Person.call(this, name, age);
this.department = department;
}
Student.prototype = Object.create(Person.prototype);
// There is no constructor property in Student. you need
// to create it yourself
// Student.prototype.constructor = Student;
Student.prototype.educationInfo = function() {
console.log(`Education info: ${this. department}`);
}
const p = new Person("Ksenia", 19);
const s = new Student("Ksenia", 19, "Languages");
p.educationInfo() // error
s.educationInfo() // ok
Global objects
There are built-in objects in js (Object, Array, RegExp, Number, etc.)
const a = []; // Equal to const a = new Array();
When we create an instance of such “classes”, the __proto__
object refers to
Class.prototype
. And each Class.prototype
refers to Object.prototype
const a = [];
console.log(a.__proto__ === Array.prototype); // true
console.log(a.__proto__.__proto__ === Object.prototype); // true
const b = 43;
console.log(b.__proto__ === Number.prototype); // true
console.log(b.__proto__.__proto__ === Object.prototype); // true
If you can’t understand why primitive have __proto__
check this
ES6 Classes
Just syntactic sugar for prototypes. MDN
Extensions
- Loop
const a = {};
a.__proto__ = a; // TypeError: Cyclic __proto__ value
- Right constructor
function Foo() {
/* .. */
}
Foo.prototype = {
/* .. */
};
Object.defineProperty(Foo.prototype, "constructor", {
enumerable: false,
writable: true,
configurable: true,
value: Foo,
});
Quiz
- True or false
const a = {};
const b = {};
console.log(a.__proto__ === b.__proto__);
Show answer
True- True or false
const a = {};
const b = [];
console.log(a.__proto__ === b.__proto__);
Show answer
False- True or false
const a = {};
const b = [];
console.log(a.__proto__ === b.__proto__.__proto__);
Show answer
True- True or false
class A {};
function B() {};
console.log(A.__proto__ === B.__proto__);
Show answer
True- True or false
function Kek() {
this.hello = function() {
console.log("hello");
}
}
const a = new Kek();
const b = new Kek();
console.log(a.hello === b.hello);
Show answer
False- True or false
function Kek() {}
Kek.prototype.hello = function() {
console.log("Hello");
}
const a = new Kek();
const b = new Kek();
console.log(a.hello === b.hello);
Show answer
True- True or false
function Kek() {
this.hello = function() {
console.log("hello");
}
}
Kek.prototype.hello = function() {
console.log("Hello");
}
const a = new Kek();
const b = new Kek();
console.log(a.hello === b.hello);
Show answer
False- Console output
Object.prototype.toString = function() { console.log("KEK") }
const a = {};
a.toString();
Show answer
KEK- Console output
Object.prototype.toString = function() { console.log("KEK") }
const a = {
toString: () => console.log("LOL"),
};
a.toString();
Show answer
LOL- Console output
Object.prototype.toString = () => console.log("KEK");
const a = [1, 2, 3];
console.log(a.toString());
Show answer
1, 2, 3- Console output
Array.prototype.toString = () => console.log("KEK");
const a = [1, 2, 3];
a.toString();