JavaScript Tutorial for Programmers - Prototype(1)

I still remember the days of debugging CORS problem when I put together some projects using JavaScript (& ajax), “a very particular programming language” in my first impression. Recently I got a great opportunity. The new role uses JS, the browser-side script that is now winning in all sides, as the major language. So I tooke it as a good chance to learn JS more systematically, and this series will be part of the outcome of my study. As the name implies, I will not cover primary level such as “if, else” (condition), “for” (or any kinds of loops), or basic OOP concepts. Instead, I will focus only on differences so you can learn this versatile language like reviewing a pull request, and use it the next day in your next awesome project.

prototype, a semi-OOP semantic

A prototype is a singleton that is created for each class (by JS runtime), so that instances of the class can be constructed based on the in memory template. I call prototype semi-OOP because it is not normal. For instance, this is how a prototype based inheritance is programmed:

I will cover prototype based inheritance in the next post. For now, we just grasp the idea of how things are different here.

Practical implication

As per discussed in the last post, ES6 has already defined a more standard OOP paradigm in JavaScript. And ES6 code can be “transpiled” (compile into another language or syntax) into ES5 so the two standards are equally compatible with various browsers in practice. Does that mean prototype is not useful anymore? My answer is No, because it still largely exists in a large amount of existing code. For concrete numbers, if grep -R prototype *|wc -l, at the point of time when I am writing, in Angular, the output shows there are 286 lines; in React, there are 405; and Vue, 756). As for me, I need to know prototype to understand these 1447 lines of backbones. Last but not least, the frameworks are ordered alphabetically 😅.

Playaround with prototype

In the following example, we first define a constructor (If you do not know what is a constructor in JS context, please ⬅ to my last post). Then we use it to create an object and examine the prototype(s).

Example:

Result:

An initial observation:

1. prototype only exists in a class (a.k.a., a constructor). If you need to access prototype from a class instance (a.k.a., an object), __proto__ is the way to go.
2. prototype and __proto__ are just two sides of one coin. In technical words, they refer to the same instance, i.e., the singleton mentioned in the beginning of this text.
3. the prototype of a class can be changed at runtime, and all the instances of this class are affected accordingly.

Moreover, a modification of __proto__ of an instance can change the prototype (definition) of a class, and all the sibling instances are affected in a cascade manner.

Example:

Result:

This operation is dangerous. It will cause side-effect and confusion in a project with reasonable complexity as the definition of a class can not be easily traceable. Hence I highly recommend considering __proto__ final (in Java) or constant (in C++) and should be never touched.

If you really want to modify the behavior of an object, say, add a property, at least modify the object itself rather than __proto__.

Result:

On the other hand, adding a property to a class effectively creates a static member (in other language term).

Result:

I would recommend this usage.

So the bright side of this feature is flexibility, empowered by that

Everything is object

Everything in JavaScript is object. That includes, functions, constructors (class)es, instances, prototypes and __proto__s, etc. Let’s prove it in code.

Example:

Result:

Furthermore, Object is subdivided into two categories, first class objects and all other normal objects. Normal objects are just variables, which can be created, modified, assigned to other variables, and passed as arguments (or return value), all in runtime. Whilst first class object is the “platinum version” of object that unlocks extra privileges. Besides the operations listed above, first class object can be invoked (as a normal function); and it can be invoked to create normal objects (as a constructor). I think those extra privileges can explain from another perspective why first class object is attached one extra member property prototype alongside __proto__.

More examples:

Result:

Except for…

Exception 1, primitive types

Did I just said everything is object?

Result:

Even though a string literal is not an object, it contains __proto__ that is an object?! So either string literal is an object, which is obviously not, or what I said in the last section is just bullshit.

It is not. What happens here is that a mechanism called automatic wrapping kicks in, which wraps the no-object (primitive) variables to its object counterpart , in this case, a String(), as required. Automatic wrapping can enable calling methods directly from primitives as well:

Result:

Same phenomenon happens: the runtime wrap the literal to String() automatically and calls the indexOf() method. And the rule applies to other primitive types (int, float) as well.

Exception 2, ???

All sounds perfect until I tried this

Example:

Result:

Apparently var obj and obj.__proto__ are objects according to the first two outputs. However, when I want to confirm if obj.__proto__ is really an object, runtime gives me a false. I hope I am not the first bloger who writes about things he is not sure himself, but if you have an answer, please let me know in the comments. It does not matter if you don’t, as __proto__ is no-standard usage anyway.

In the next post, I will discuss one of the hardest parts of JavaScript, inheritance based on prototype chain.

That's it. If you have any suggestions, or you just like the read, , and send me your comments. Thank you for your time and attention. I'll catch you later.