Prototype in JavaScript

Always wondered about that prototype thing in JavaScript? It's not as hard as you'd think...

Hey everyone. It’s been a few weeks since I last blogged. I’ve been on a vacation in Poland which was awesome! If you ever want to visit Poland I recommend visiting Gdańsk, a beautiful city, and Malbork Castle, the largest castle in the world!
Anyway, this blog isn’t about travel, it’s about programming.

So last time I finished my series on the MEAN stack, MongoDB, Express, AngularJS and Node.js. That meant a lot of JavaScript. Not just front-end, but also back-end. Next to my blog I’ve been writing a lot of JavaScript in my daily life too. And while writing all that JavaScript there was one thing I just didn’t quite understand, prototype. I’m not talking about the Prototype library, which kind of lost the battle for most popular all round JavaScript library to jQuery, I’m talking about prototypal object inheritance. I started asking around. I know some full-stack developers with years of experience in front- and back-end, but guess what? They didn’t fully understand prototype either. And then I went to look on the interwebs, but guess what? There just aren’t that many good prototype tutorials around. And that’s what this post is all about.

Prototype, you don’t really need it…

So when asking my friends why, after all these years, they still didn’t know prototype their answer was something along the lines of “I never needed it.” Sure, that was the reason I never looked into it before too. Truth is that you can write JavaScript apps and libraries without ever needing prototype. But if you want to write fast JavaScript code you better start using prototype.

So first of all, what is prototype and why is it better than no prototype? In JavaScript each function has a prototype property. Prototype has all the, I guess you could call it default, methods and properties that an object, created through that function using the ‘new’ keyword, should have. As we know any object in JavaScript can have any method or property, we can just define them at runtime as we go. And that’s probably the big difference between using prototype and not using it. With prototype you define methods design time, or up front.

Let’s look at an example. Let’s say I have a Person object, the constructor and usage could look as follows.

So what happens when we call new Person(‘Sander’, ‘Rossel’)? First, two new instances of String are created, ‘Sander’ and ‘Rossel’. Second, a new object is created. After that the object, representing a Person, gets three new properties, firstName and lastName, which are assigned the two strings, and the function fullName, for which a new function is instantiated. That last part is crucial, a new function instance is created every time you create a new person object. Now performance and memory wise this isn’t optimal. Let’s see how we can optimize this.

That’s a bit of code, but what happens is that we create 10.000.000 (that’s ten million) instances of Person with the fullName function defined on the Person object and we create ten million instances of a Person without the fullName function and use the pre-defined getFullName function instead. Then we log the time both methods took.

It may surprise you, but the result I get differs greatly per browser. Here they are (times in milliseconds):

IE FF Chrome
Full name: 3705 361 2805
No full name: 3121 21 222

What this shows is that Firefox is fastest by far and IE is, of course, really very slow, especially when it comes to the method without full name. All browsers are considerably faster (especially Chrome) using the getFullName method though.

Enter prototype

Now that we’ve seen that functions in your constructors aren’t really optimal, especially when they don’t use any internal state of an object, and that we’ve seen how to optimize that let’s look at a better way, prototype.

The use of an external function doesn’t feel right. Full name should be part of your Person object, but now we have to call some external function to get it. That’s where prototype comes in. Functions in JavaScript have a prototype property. Prototype defines static methods, like getFullName, and ‘pastes’ them on your objects through prototypal inheritance.

And that’s really all there is to it! We have now defined the fullName function on PersonProto’s prototype, which means every instance of PersonProto now gets the fullName function.

var p = new PersonProto('Sander', 'Rossel');
var n = p.fullName();

If we’d benchmark this we’d get about the same speed as we got earlier when using the getFullName function (really, try it).

You might be tempted to think it doesn’t matter whether you use a static method like getFullName or prototype, other than the manner in which you invoke the function (object.function() vs. function(object)). That isn’t true though, prototype has a few pros and cons compared to other methods. First of all, using prototype, we’ve lost control over ‘this’. Earlier, when defining fullName in the constructor we could use ‘self’, which always points to the correct instance of Person. We’ve lost that benefit with prototype and ‘this’ is now dependent on the context in which the function was invoked. Below code will break.

It’s the same code on the outside, but fullName of Person points to ‘self’ while fullName of PersonProto points to this (which, in the second call, is ‘window’).

Another pro, maybe, of prototype is that prototypal functions cannot be deleted from an object (although they can be overwritten). The first bit will run fine and prints ‘Sander Rossel’, the second part will break.

So we have an Employee with a salary and, of course, a name. An Employee is actually just a Person with a salary. So we ‘inherit’ the prototype of PersonProto. We also define a new function on the prototype, getSalary. Unfortunately, while Employee now has the fullName function, this has some undesired side effects…

That’s right, PersonProto now also has a getSalary function! That’s because Employee.prototype == PersonProto.prototype. So once we add getSalary to Employee.prototype PersonProto now has it too.

We can fix this by creating a temporary constructor, assigning the prototype to the temporary constructor, instantiating an object using the temporary constructor and assigning that to the prototype of the inheriting object. Last, because a prototype is assigned to the constructor function, we must set the prototype’s constructor to the inheriting constructor.

So here o has the PersonProto prototype and o is of the type PersonProto. Now let’s use Object.create for inheritance like we’ve seen above (for this example I’ve created an Employee2 which is similar to Employee).

Prototype vs. __proto__

As I said before prototype kind of ‘glues’ the static functions to the object instances you create. This happens through the __proto__ property each object instance has. Each instance of an object has a __proto__ property defined, which is constructed using the constructor.prototype. So while object literals don’t have a prototype property they do have a __proto__ property which you can use to dynamically extend the prototype of an object.

So by adding fullName to o.__proto__ we’ve actually added fullName to Object.prototype! That means ALL your objects now have a fullName function.

var i = 10;
console.log(i.fullName());

See why doing that is highly discouraged? It’s slow to boot. I just thought you should know about it.

So that’s it about prototype. I have some final remarks for you before you go and use this knowledge out in the wild.
Don’t change the prototype of built-in types such as Object and Array. You could do this to support new functionality in older browsers, but there are probably a few libraries that already do that for you.
Prototype can have a negative impact on performance. What happened when we called fullName on Employee? The JavaScript engine looks for fullName on the object, but could not find it. It then looked for fullName on the Employee prototype, but again couldn’t find it. It works its way down the prototype chain and looked in the PersonProto prototype next, where it found fullName and called it. You can imagine that having huge prototype chains can be bad for performance (but why would you have huge prototype chains anyway?).
Last, as I said before, you can use JavaScript without ever needing prototype. Likewise, you can inherit objects without the need for prototype. For example, you can create a function Employee that creates a Person, adds the salary property and the getSalary function, and returns that.

License

Share

About the Author

Sander Rossel is a Microsoft certified professional developer with experience and expertise in .NET and .NET Core (C#, ASP.NET, and Entity Framework), SQL Server, Azure, Azure DevOps, JavaScript, and other technologies.
He has an interest in various technologies including, but not limited to, Cloud, NoSQL, Continuous Integration and Deployment, Functional Programming, and software quality in general.
In his spare time he writes articles for MSDN, CodeProject, and his own blog, as well as books about Object Oriented Programming, Databases, and Azure.

Comments and Discussions

Very clearly organized…
I’m a long time JavaScript developer (close to 15 years – yes you can survive that) and used prototype intensively, not only because it makes your code less resource hungry, but it also makes a cleaner code…
And that’s exactly what surprised me here – “I never needed it.”!?!? That’s impossible – the moment your cross a certain line of complexity (and size) with your application, you can not create valuable code without prototype…Anybody, who plain on long-time-large-scale JS application must use prototype…and this blog is a perfect starting point…

(I was in Marienburg, but didn't noticed because of the Polish name, some 30 years ago...Even in the dark days of the communist Poland it was a wonderful place!)

Notice that it's not correct to say "Prototype defines static methods", since the methods defined on a constructor's prototype do not correspond to static (or class-level) methods. A static (or class-level) method cannot be invoked on a context object, like in p.fullName(), rather it has to be defined, and invoked, on the constructor, like Person.fullName(p).

Also, your code pattern for inheritance, with Temp(), is pretty weird. As explained in my JavaScript Summary article, there is a well-defined best practice code pattern for inheritance with constructor-based classes, proposed by Mozilla in their JavaScript Guide (ths is a must read for JS programmers).

Notice that it's not correct to say "Prototype defines static methods", since the methods defined on a constructor's prototype do not correspond to static (or class-level) methods. A static (or class-level) method cannot be invoked on a context object, like in p.fullName(), rather it has to be defined, and invoked, on the constructor, like Person.fullName(p).

That may be true, but the function is still declared only once. Perhaps it's best compared to C# extension methods, and those are static (although invoked on an instance)
I agree with you that it doesn't sound correct, but I wouldn't know how to say it differently. Suggestions are welcome.

You say "but the function is still declared only once". That's however not the defining characteristic of static methods, which do not use the indexical "this" variable.

I take it the best practice you refer to is by using Object.create?

That's also an option (as explained in my JavaScript Summary article), but the classical inheritance code pattern recommended by Mozilla is a 3-part pattern. I copy it here for your convenience, but you should read my article.