JavaScript Prototype - The Secret Guide

Pro Members Only

This lesson is available if you have an active subscription.

Alternatively, some member might be able to gift it to you.

If you already have a subscription, you can sign in.

Professional Modern JavaScript Lessons

1.Course Intro
free
⏱️ 1:13
2.Setup & Tooling
free
⏱️ 3:32
3.Debugger Statements and Breakpoints
free
⏱️ 2:17
4.Primitive Data Types and Values
free
⏱️ 3:06
5.JavaScript Variables - let and const
free
⏱️ 4:50
6.Comments in JavaScript
free
⏱️ 2:55
7.JavaScript Identifer Naming
free
⏱️ 2:52
8.Using TypeScript
free
⏱️ 4:26
9.JavaScript String Masterclass
free
⏱️ 9:29
10.JavaScript Boolean Type
⏱️ 6:45
11.Missing Guide to JavaScript Numbers
⏱️ 15:28
12.JavaScript Objects Demystified
⏱️ 13:33
13.Functions in JavaScript
⏱️ 20:25
14.JavaScript Arrays Masterclass
⏱️ 22:31
15.JavaScript If Else Statements and Best Practices
⏱️ 6:13
16.JavaScript Conditional Expressions
⏱️ 8:38
17.JavaScript Loose vs Strict Equality
⏱️ 4:02
18.Truthy vs Falsy in JavaScript
⏱️ 3:44
19.Concept of JavaScript Nullish and Unification
⏱️ 5:51
20.JavaScript Classes - Object Oriented Programming
⏱️ 10:30
21.JavaScript Error Handling and Exceptions
⏱️ 13:21
22.JavaScript Nullish Operators
⏱️ 5:48
23.JavaScript Switch Statement Masterclass
⏱️ 8:07
24.JavaScript For Loop Iteration Simplified
⏱️ 10:59
25.JSON Masterclass
⏱️ 7:59
26.JavaScript While and Do While Loops
⏱️ 2:52
27.JavaScript Date and Time Simplified
⏱️ 13:16
28.this in JavaScript
⏱️ 12:04
29.JavaScript Tagged Templates Masterclass
⏱️ 5:48
30.Promises in JavaScript
⏱️ 10:01
31.JavaScript Async Await Masterclass
⏱️ 9:00
32.JavaScript Symbols Demystified
⏱️ 7:25
33.JavaScript Iterators and Iterables
⏱️ 8:50
34.JavaScript Generators Simplified
⏱️ 9:17
35.JavaScript Prototype - The Secret Guide
⏱️ 11:21
36.JavaScript Set Builtin Data Structure
⏱️ 9:52
37.JavaScript Map Builtin - HashMap Magic
⏱️ 10:38
38.JavaScript Deferred Promise Pattern - withResolvers
⏱️ 3:35
39.Cloning and Deep Copying in JavaScript
⏱️ 3:14
40.JavaScript Async Await Sequencing and Execution Masterclass
⏱️ 10:31
41.JavaScript Memory Management Masterclass
⏱️ 5:26
42.JavaScript WeakMap Demystified
⏱️ 8:58
43.JavaScript bigint Masterclass
⏱️ 5:35
44.JavaScript WeakSet Explained with Examples
⏱️ 7:47
45.JavaScript Regular Expressions Masterclass
⏱️ 17:54
46.JavaScript Weak References Demystified
⏱️ 5:29
47.JavaScript Memory Leaks Demonstrations and Fixes
⏱️ 6:01
48.Semicolon Free Coding in JavaScript
⏱️ 3:46
49.JavaScript Modules Masterclass
⏱️ 11:36

JavaScript Prototype - The Secret Guide

Subscription Required

You must have an active subscription to access this content.
If you already have a subscription, you can sign in.

Secret __proto__

const alpha = { name: 'John' };
console.log(typeof alpha.name); // 'string'
console.log(typeof alpha.toString); // 'function'
console.log(typeof alpha.__proto__); // 'object'
console.log(typeof alpha.__proto__.toString); // 'function'

const beta = {
age: 42,
__proto__: alpha,
};

console.log(beta.age); // 42
console.log(beta.name); // 'John'

alpha.name = 'Jane';
console.log(beta.name); // 'Jane'

proto Member Lookup

const person = {
__proto__: {
__proto__: {
__proto__: {
name: 'Jack',
age: 18,
},
},
},
};

console.log(person.name); // Jack
console.log(person.age); // 18
console.log(person.weight); // undefined

console.log(person.__proto__.__proto__.__proto__.__proto__.__proto__); // null

prototype

// .__proto__ === [[Prototype]]
// VS
// .prototype

class Alpha { log() { console.log('Bonjour'); } }
console.log(typeof Alpha); // 'function'
console.log(typeof Alpha.prototype); // 'object'
console.log(typeof Alpha.prototype.log); // 'function'

function Beta() { }
console.log(typeof Beta); // 'function'
console.log(typeof Beta.prototype); // 'object'
Beta.prototype.log = function() { console.log('Bonjour'); }

new Operator and prototype

let created;
class NewEffects {
constructor(message) {
this.message = message;
created = this;
}
log() { console.log(this.message); }
}

const instance = new NewEffects('Bonjour');
console.log(instance === created); // true
console.log(Object.keys(instance)); // [ 'message' ]
console.log(typeof instance.log); // 'function'
console.log(typeof NewEffects.prototype.log); // 'function'
console.log(instance.__proto__ === NewEffects.prototype); // true
console.log(typeof instance.__proto__.log); // 'function'
instance.log(); // 'Bonjour'

Builtin Prototypes

function Func() { }
const func = new Func();
console.log(func.__proto__ === Func.prototype); // true

class Cls { }
const cls = new Cls();
console.log(cls.__proto__ === Cls.prototype); // true

const str = 'abc';
console.log(str.__proto__ === String.prototype); // true

const num = 123.4;
console.log(num.__proto__ === Number.prototype); // true

console.log(typeof Number.prototype.toPrecision); // function
console.log(typeof num.__proto__.toPrecision); // function
console.log(num.toPrecision(3)); // 123

Polyfills

String.prototype.upperCaseTrim = function () {
return this.toUpperCase().trim();
};

console.log(''.__proto__ === String.prototype); // true

console.log(''.__proto__.upperCaseTrim === String.prototype.upperCaseTrim); // true

console.log(' hello world '.upperCaseTrim()); // 'HELLO WORLD'

function upperCaseTrim(value) {
return value.toUpperCase().trim();
}

console.log(upperCaseTrim(' hello world ')); // 'HELLO WORLD'

Classes and proto-chaining

class Animal {
eat() { return 'yum yum'; }
}
class Bird extends Animal {
fly() { return 'flap flap'; }
}

const bird = new Bird();

console.log(bird.__proto__ === Bird.prototype); // true
console.log(bird.__proto__.fly === Bird.prototype.fly); // true
console.log(bird.fly()); // flap flap

console.log(Bird.prototype.__proto__ === Animal.prototype); // true
console.log(bird.__proto__.__proto__ === Animal.prototype); // true
console.log(bird.__proto__.__proto__.eat === Animal.prototype.eat); // true
console.log(bird.eat()); // yum yum

Object.create

let animal = {
eat: function () { return 'yum yum'; }
};

let bird = {
__proto__: animal,
fly: function () { return 'flap flap'; },
};
console.log(bird.eat()); // yum yum
console.log(bird.fly()); // flap flap

bird = Object.create(animal);
bird.fly = function () { return 'flap flap'; };
console.log(bird.eat()); // yum yum
console.log(bird.fly()); // flap flap

null Proto

let dictionary = {};
dictionary['john'] = true;
dictionary['jane'] = false;
console.log(dictionary.__proto__ === Object.prototype); // true
console.log(Object.prototype.toString); // function
console.log('toString' in dictionary); // true
if (dictionary['toString']) { console.log('toString went to the party'); }

dictionary = Object.create(null);
console.log('__proto__' in dictionary); // false
dictionary['john'] = true;
dictionary['jane'] = false;
console.log('john' in dictionary); // true
console.log('jane' in dictionary); // true
console.log('toString' in dictionary); // false
javascript
typescript
react
playwright

Enjoy free content straight from your inbox 💌

No spam, unsubscribe at any time.

Transcript

00:00

Prototypes are not something that you need to know from modern Java script, but they definitely open a world of possibilities. If you want to do some low level programming or take a look behind the scenes of the magic of modern J Script at its score, we have the secret proto member. We create an object called Alpha that has a very simple name property pointing to the string, John. So of course type of alpha.name will be string, but in addition to name it has a few other properties as well. For example, it has a two string, which is of a type function. So the question is where are these things defined? And the answer is that when we created this object,

00:35

it's called a special property called proto, which itself is an object. And that object has a two stringing property that we are looking at. When we access a property off of a value, the JavaScript runtime first looks at the object, for example, that is what is happening with alpha.name, and if it doesn't find it over there, then it looks at the proto. And that is what is happening with alpha two stringing. So we can actually create an object called beta and provide a proto ourselves. And if you point the proto to Alpha, then in addition to the properties that we defined on beta, for example, age, it gets the properties that we define on Alpha as well, for example, name.

01:11

And we can actually prove that the name properties coming from Alpha, because when we modify Alpha name to be Jane and try to read the name property from beta, then we will get Jane. We can actually create a whole proto chain. And when we look up a member chow, skip sees if that object has that member, and if not, it transparently travels through the proto chain till it finds something that has that member or the proto becomes now. So let's do something crazy and create a person that is an object that has a proto of a proto of a proto that points to an object that has the member's name and age. And if you try to access person.name js,

01:46

skip travels up the chain till it finds something that has it. And the same for the age property. It travels up and finds the age 18, but if you try to access a property that does not exist anywhere in the proto chain, for example, weight, then JavaScript gives us that special value that we've talked about called Undefined. And what's really happening behind the scenes is that JavaScript has looked at person, proto, proto, proto te proto itself became null, and at that point gave up and gave us undefined. And the first time you see it, it can be a bit hard to believe. So let's just run this code to prove that this is how JavaScript functions.

02:20

Not to be confused with the instance proto, there is a special property called prototype that exists on classes and functions. And spoiler alert classes are just fancy functions. So we've been using this property proto under which we've been calling Proto, but the JavaScript language specification actually calls this proto concept as prototype squared bracketed, but we will call it proto because calling it prototype gets confusing because there is an actual property that exists on functions called prototype. Let's create a very simple class called Alpha that has a method log.

02:54

What might surprise you is that the type of alpha is actually going to be function and functions have a special property called prototype, which is an object, and any methods that we define on the class actually get defined as functions on the class prototype. So classes are actually just glorified functions and we can actually achieve the same effect with the function within transcript. And this is what people used to do before we actually got classes. We define a simple function called beta. Of course it is going to be of a type function just like the class, and it is going to have the prototype properties just like the class.

03:28

Additionally, any methods that we want on the class, we can actually just add to the prototype of the function. As far as the JavaScript runtime is concerned, the class alpha and the function beta are actually equivalent. We've talked about how the new operator impacts this during object creation. One more thing that the new operator does is that it assigns the function prototype to the created instances. Proto let's create a local variable that will help us see some of the effects of new. We create a simple class called new effects, and within the constructive we take a message property, which we add to this, and additionally, we save this value into the created variable.

04:05

We also add a simple log method that logs the message that we previously saved. Now when we create a new instance of the class by using the new operator, what happens is that JavaScript creates a new object and passes it to the constructor by using the disc keyboard. And this created object is what is eventually returned from the constructor, which we are storing in the instance variable. So whatever was this within the constructor, which we stored using created is exactly equal to the instance that is returned. So that is the main effect of the new operator, but it does something more. Note that the instance is only going to have one property,

04:39

which is going to be message which we set in the constructor, yet we can actually use instance log. We know that class methods are actually defined as properties on the function prototype. So new effects prototype dot log will be that method. So how does it end up on instance? And the answer to this mystery is another effect of the new operator, which is that it takes the function prototype and assigns it to the created instances proto. And since the log method is defined on the prototype is going to be available on instance proto. And as you know, when we access a property,

05:13

JavaScript magically looks up the P until it finds it. And that is how instance log just works. At the heart of a lot of magical features of JavaScript is a transparent assignment of a well-known prototype to the proto of the created value. We know that functions come with prototypes and the new operator assigns the prototype of the function to the created instances proto. And since classes are just glorified functions, that is exactly what happens for the class as well. But what might surprise you is that a proto assignment also happens for primitive types. As an example, when we create a string,

05:46

the created value has a proto member that points to the well-known string dot prototype, and similar prototypes exist for other primitives as well. For example, with a number, the created Values Proto is going to point to number prototype, and this is how these JavaScript priers actually get their built-in methods. The number prototype has a member called Two Precision, which is a function and we, because the prototype gets assigned to the proto, it magically shows up on the created numbers pro. And therefore, when we do number two, precision is really using the two precision method that is actually defined on the number prototype.

06:20

Because prototypes exist for the primitive types within JavaScript, it makes it super easy to add newer features of JavaScript to older JavaScript runtimes. And that is how Polyfils work. Let's say a new JavaScript spec has come out, which means that all JavaScript strings now get this magical method called uppercase stream. Even without updating our JavaScript on time, we can actually poly fill that method into our existing runtime by simply defining it on the string prototype. The only simple trick that we have to use over here is that instead of taking the string as a parameter, we use the disc key,

06:53

which we saw in its own dedicated lesson. By using this keyword, the string will automatically get passed in as this based on the string that is used to invoke the method. Now we know that every single time someone creates the string, it gets the magical P property which points to string prototype, which means that any created string has access to the uppercase stream because that is what we define on the string prototype. So if we call uppercase stream on a string with spaces at the edges, that is all and lowercase, the spaces at the edges get TriMed and the string turns to uppercase. Needless to say,

07:26

you shouldn't modify the built-in prototypes unless you are creating a polyfill because you will end up with conflicts instead just create a utility function. It's easier to create without making a mistake and much easier to understand at the point of usage for the next person. Here's a little non fact d j script class inheritance with the extent keyword actually also works by utilizing progenic. So we create a simple class animal with a method eat, and we create a simple class bird that extends animal and adds another method called fly. When we create an instance of the bird by using the new operator,

08:01

we already understand how the fly method will end up on the instance. The way it works is that the new operator assigns the prototype to the proto, and since the prototype has the fly method, it is going to be available on the bird proto, which means that bird fly just works. What we haven't explained yet is how does bird eat work? And the answer to this mystery is that the extent keyword actually creates a P chain between the two prototypes and assigns the prototype of the base class as the proto on the prototype of the child class. So if something is not found on the bird prototype,

08:36

it'll automatically be looked up from the animal prototype. And since the bird class prototype becomes a proto on the instance, methods defined on the animal prototype will magically become available on the bird instance. And that ladies and gentlemen is why we can just do bird eat all thanks to the progenic done by the extents keyword. We've been using the secret proto property, but there is actually a low level a P I that allows you to create simple prototype based inheritance. Let's create a simple animal that has a property eat, which is a function that returns yum, yum.

09:09

We can actually create a bird that inherits all of these properties by assigning the proto property to animal and then adding anything else that we want. For example, fly flap flap. And now we can do bird eat as well as bird fly. Using underscore proto underscore underscore is actually not something that is officially standardized and we've just been abusing it as it is a pretty known secret. The official recommendation is to actually assign the prototype by using object do create. So object or create actually creates a new object and sets the P to whatever is provided. So bird will be an object that has its pember pointing to animal.

09:46

So all that is left for us to do is to assign anything else that we want for the bird, which is just the fly method, flap flap. And this is equivalent to what we did before. We have the bird with the proto pointing to animal and the fly method added, and we can prove that by simply eating yum yum. And flying flap flap using nu value for a proto actually allows you to completely opt out of the default object prototype assignment. And this is great when you want complete control over what properties should show up on an object, let's create a simple object that we intend to use as the dictionary data structure used to track who came to our party and who didn't. As an example,

10:23

John came. So that is true and Jane didn't come, so that is false. But as we know, dictionary also has its proto assigned to the objector prototype. And since objector prototype has a number of things, for example, the two stringing function, it seems that two stringing is also present in dictionary. So it seems that two string also went to the party. What would be great is if you could create an object that didn't have anything other than what we wanted, not even proto. And that is exactly what objector create does with a null value. It creates an object that doesn't even have the proto property.

10:57

So when we say that John came to the party and Jane didn't come, John and Jane are the only things that are in the dictionary. That two string or anything else within the object prototype is not going to pollute a nice clean object. I hope you enjoyed this tutorial and some insights into how JavaScript actually works under the hood. As always, thank you for joining me and I will see you in the next one.

Professional Modern JavaScript

Professional Modern JavaScript

1.Course Intro
free
⏱️ 1:13
2.Setup & Tooling
free
⏱️ 3:32
3.Debugger Statements and Breakpoints
free
⏱️ 2:17
4.Primitive Data Types and Values
free
⏱️ 3:06
5.JavaScript Variables - let and const
free
⏱️ 4:50
6.Comments in JavaScript
free
⏱️ 2:55
7.JavaScript Identifer Naming
free
⏱️ 2:52
8.Using TypeScript
free
⏱️ 4:26
9.JavaScript String Masterclass
free
⏱️ 9:29
10.JavaScript Boolean Type
⏱️ 6:45
11.Missing Guide to JavaScript Numbers
⏱️ 15:28
12.JavaScript Objects Demystified
⏱️ 13:33
13.Functions in JavaScript
⏱️ 20:25
14.JavaScript Arrays Masterclass
⏱️ 22:31
15.JavaScript If Else Statements and Best Practices
⏱️ 6:13
16.JavaScript Conditional Expressions
⏱️ 8:38
17.JavaScript Loose vs Strict Equality
⏱️ 4:02
18.Truthy vs Falsy in JavaScript
⏱️ 3:44
19.Concept of JavaScript Nullish and Unification
⏱️ 5:51
20.JavaScript Classes - Object Oriented Programming
⏱️ 10:30
21.JavaScript Error Handling and Exceptions
⏱️ 13:21
22.JavaScript Nullish Operators
⏱️ 5:48
23.JavaScript Switch Statement Masterclass
⏱️ 8:07
24.JavaScript For Loop Iteration Simplified
⏱️ 10:59
25.JSON Masterclass
⏱️ 7:59
26.JavaScript While and Do While Loops
⏱️ 2:52
27.JavaScript Date and Time Simplified
⏱️ 13:16
28.this in JavaScript
⏱️ 12:04
29.JavaScript Tagged Templates Masterclass
⏱️ 5:48
30.Promises in JavaScript
⏱️ 10:01
31.JavaScript Async Await Masterclass
⏱️ 9:00
32.JavaScript Symbols Demystified
⏱️ 7:25
33.JavaScript Iterators and Iterables
⏱️ 8:50
34.JavaScript Generators Simplified
⏱️ 9:17
35.JavaScript Prototype - The Secret Guide
⏱️ 11:21
36.JavaScript Set Builtin Data Structure
⏱️ 9:52
37.JavaScript Map Builtin - HashMap Magic
⏱️ 10:38
38.JavaScript Deferred Promise Pattern - withResolvers
⏱️ 3:35
39.Cloning and Deep Copying in JavaScript
⏱️ 3:14
40.JavaScript Async Await Sequencing and Execution Masterclass
⏱️ 10:31
41.JavaScript Memory Management Masterclass
⏱️ 5:26
42.JavaScript WeakMap Demystified
⏱️ 8:58
43.JavaScript bigint Masterclass
⏱️ 5:35
44.JavaScript WeakSet Explained with Examples
⏱️ 7:47
45.JavaScript Regular Expressions Masterclass
⏱️ 17:54
46.JavaScript Weak References Demystified
⏱️ 5:29
47.JavaScript Memory Leaks Demonstrations and Fixes
⏱️ 6:01
48.Semicolon Free Coding in JavaScript
⏱️ 3:46
49.JavaScript Modules Masterclass
⏱️ 11:36