Advanced JavaScript: Object Prototypes

kyle-simpson-v1

Welcome to Part 7 of this review of the Pluralsight and Front End Masters course Advanced JavaScript by Kyle Simpson.

Kyle Simpson is Head of Curriculum for MakerSquare and an evangelist of the open web. He lives in Austin, Texas, and is passionate about all things JavaScript.

He’s written 8 books published by O’Reilly, including six books in the You Don’t Know JS series.

Kyle teaches JavaScript and has eight courses recorded by Front End Masters.

He’s a public speaker, and contributes to the world of OSS.

In this series:

Part 1 – Introduction
Part 2 – Scope
Part 3 – Lexical Scope
Part 4 – Block scoping
Part 5 – Dynamic Scope, Hoisting and this
Part 6 – Closure
Part 7 – Object Prototypes

Object-Orienting

Object-Orienting is the other major area of JavaScript with a lot of surrounding confusion.

He warns that the following teachings significantly diverge from what the majority of the JavaScript community believes about the language.

Kyle will make the case that there are no such things as classes in JavaScript, and that we need a very different design pattern for our software.

Prototype

Every single “object” is built by a constructor function

Or to be most accurate, it’s built by a constructor call. We saw that in Part 5 when we looked at the new keyword.

For describing languages such as C++ and Java, Kyle says a more accurate term than “object-oriented” would be “class-oriented”.

Perhaps only JavaScript and Lua deserve the term object-oriented? In these languages we can create objects without a class.

Each time a constructor is called, a new object is created

Kyle objects to the words “based on” in the following sentence:

A constructor makes an object based on its own prototype

This implies that we take the prototype and copy it, like class-oriented languages do.

wrong-way

A more accurate statement would be:

A constructor makes an object linked to its own prototype

But what do we mean that a constructor is making objects linked to some other prototype object?

Prototype

(Also see this & Object Prototypes Chapter 5)

This is another piece of code that we’re going to spend a lot of time on:

function Foo(who) {
this.me = who;
}
Foo.prototype.identify = function() {
return “I am ” + this.me;
};

var a1 = new Foo(“a1”);
var a2 = new Foo(“a2”);

a2.speak = function() {
alert(“Hello, ” + this.identify() + “.”);
};

a1.constructor === Foo;
a1.constructor === a2.constructor;
a1.__proto__ === Foo.prototype;
a1.__proto__ === a2.__proto__;

Kyle begins to draw a diagram of what occurs when this code is interpreted by the JavaScript engine.

Objects are represented as squares and functions as circles. In this section I’ll use the word entity to mean either an object or a function.

Before the first line of code is executed

It’s definitely helpful to visualize these because the names are a bit confusing: the first entity drawn is a function named Object.

There’s also an object (square) linked to it, and this is called object.prototype.

(Also see section 19.1.3 Properties of the Object Prototype Object in the specification)

These two entities exist at the beginning of every JavaScript program and is part of the environment that is created.

Line 1

function Foo(who) {

The diagram drawn for this is similar to the above, with two entities, a Foo function and an object connected by .prototype.

However there’s also a connection in the opposite direction called .constructor

Foo.constructor does not mean “was constructed by Foo”

Kyle says constructor is merely an arbitrary word. It could have been abracadabra.

There’s a dual linkage between the function Foo and the object.

We skip over line 2 and 3 and onto

Line 4

Foo.prototype.identify = function() {

Kyle writes the word identify inside the square. Although identify is actually a function, we can think of it as an object property for our purposes here.

Line 8

var a1 = new Foo(“a1”);

We skipped over line 2 earlier, but the function Foo includes this line:

Line 2

this.me = who;

Now, earlier in the course (end of Part 5 or read the new binding section in YDKJS) we learned that four things happen when we use the new keyword.

Kyle draws these things out for us

  1. We create a brand new object
  2. The brand new object is [[Prototype]] linked to the other object
  3. Set as the this binding. combined with line 2 we have me added as a property of the brand new object
  4. It returns this, which then one line 1 we assign to “a1”

Line 9

var a2 = new Foo(“a2”);

We go through the same process as we did for line 8 and create a new object with the label “a2”.

Line 11

a2.speak = function() {

speak is added as a property of a2.

Kyle points out that there is no a1.speak at this point.

Line 15

a1.constructor === Foo;

There is no constructor property for a1.

What happens is it goes up the prototype chain.

Kyle points out that this mechanism looks a lot like the scope model we learned earlier.

There are [[Prototype]] linkages from both a1 and a2 to the original entity object

We also see a linkage drawn from the Foo object to the object was created before we even got to line 1.

Prototypes Explained Part 2

Line 17

a1.__proto__ === Foo.prototype;

Kyle says we can and should pronounce __proto__ as “dunder proto” instead of “underscore underscore proto underscore underscore”.

a1.__proto__ calls __proto__ from what was created before we reached line 1. It’s a getter function.

Kyle says __proto__ wasn’t standardized but everyone adopted it except Internet Explorer.

__proto__ is not present in the ES5.1 spec however I found it in the ES2016  and ES2015 specifications so that is one of the lesser known improvements in “ES6”.

It’s also supported in Microsoft Edge according to Kangax. If fact basic support was added to IE 11 and Kyle says this.

We move onto the next slide, which is a modified version of the previous one. The last four lines are:

a1.constructor === Object.getPrototypeOf(a1);
a2.constructor === Foo;
a1.__proto__ === a2.__proto__;
a2.__proto__ === a2.constructor.prototype;

Object.getPrototypeOf is a mechanism introduced in ES5 which extracts the internal prototype characteristic.

There’s a “crappy and hacky” way to get the linkage if you need to support IE8 and below:

a2.__proto__ === a2.constructor.prototype;

This is an indirect approach where we go to the function part of Foo first (using .constructor) and then back to the object (using .prototype).

Kyle warns that both .constructor and the .prototype are writable properties, so this will only work if neither of these are overwritten.

So in summary we have three ways to get the linkage:

  1. __proto__ (“dunder proto”) – available in IE11+
  2.  Object.getPrototypeOf – available in IE9+
  3. .constructor.prototype – available in ES3 browsers

Prototype Linkages

(Also see Inheritance and the prototype chain from MDN and this & object prototypes chapter 4)

The first benefit of the prototype linkage is the ability to delegate to a different object to handle a method call or property reference.

The this mechanism is an effective mechanism for this delegation when we behave by the rules.

New code example:

function Foo(who) {
this.me = who;
}
Foo.prototype.identify = function() {
return “I am ” + this.me;
};

var a1 = new Foo(“a1”);
a1.identify(); // “I am a1”

a1.identify = function() { // <–Shadowing
alert(“Hello, ” +
Foo.prototype.identify.call(this) +
“.”);
};

a1.identify(); // alerts: “Hello, I am a1.”

Kyle asks the audience what happens on this line?

a1.identify(); // “I am a1”

There’s no delegation here. The identify property is added directly to a1 and this is called shadowing.

Properties on the prototype chain can shadow each other.

Class-oriented coding mandates parent classes and child classes which method names that are the same. Child classes are able to override an abstract parent class.

But here we see this is not how JavaScript works. Kyle calls the following line explicit polymorphism:

Foo.prototype.identify.call(this)

It’s a long-winded way to achieve relative polymorphism (Kyle calls it “crazy crappy syntax”) but if adherence to the class design pattern was our priority, this is what we would need to do.

Conversely, if we use different method names, our JavaScript code can be a lot more elegant.

Kyle calls the next code sample “super unicorn magic”

SuperUnicorn

function Foo(who) {
this.me = who;
}

Foo.prototype.identify = function() {
return “I am ” + this.me;
};

Foo.prototype.speak = function() {
alert(“Hello, ” +
this.identify() + // super unicorn magic
“.”);
};

var a1 = new Foo(“a1”);
a1.speak(); // alerts: “Hello, I am a1.”

Why is this magic? When we call a1.speak, the speak method gets called through the delegation on Foo.prototype, and in this function we have this.identify.

The this keyword is bound to a1, so this.identify means a1.identify.

a1 doesn’t have an identify method, but it still works.

It moves up the prototype chain to find the identify method.

That was a lot of technical information. What can we learn from it?

We don’t need to do the ugly shadowing method that we saw earlier. JavaScript works better if we don’t try to use it like a class-oriented language. And this is because JavaScript doesn’t use copy mechanisms, it uses prototype linkage behavior delegation.

Metaphors for Lexical Scope and Dynamic Scope

We see the buildings metaphor diagram again. The building on the right hand side representing “dynamic scope” means the this keyword plus prototype.

If the this keyword tells us to use the “dynamic scope” building, then prototype is our navigation tool once we are inside that building. For example: a1.identify

  1. identify isn’t found on a1
  2. traverses up a level using the prototype “elevator”
  3. if it fails to find identify, it keeps going up until it reaches…
  4. object prototype

Whereas global scope is the top of our lexical scope building metaphor, object prototype is the top of the dynamic scope building metaphor.

Although using our metaphor, these buildings seem to work the same way, these are like buildings from parallel universes because we can never travel from one to the other.

parallel-universe

This magic portal into the alternate scoping world does not exist

Prototype: Objects Linked

Another example of us trying to model objects as classes:

function Foo(who) {
this.me = who;
}
Foo.prototype.identify = function() {
return “I am ” + this.me;
};

function Bar(who) {
Foo.call(this, who);
}

// Bar.prototype = new Foo(); //Or…
Bar.prototype = Object.create(Foo.prototype);
// NOTE: .constructor is borked here, need to fix

Bar.prototype.speak = function() {
alert(“Hello, ” + this.identify() + “.”);
};

var b1 = new Bar(“b1”);
var b2 = new Bar(“b2”);

b1.speak(); // alerts: “Hello, I am b1.”
b2.speak(); // alerts: “Hello, I am b2.”

There are some subtle problems when thinking in terms of parent and child classes.

I will skip the workshop exposition here because we’ve already seen problems with using classes as a design pattern. Just don’t do this.

Most developers use libraries to solve these problems for us. Kyle asks “what if there was a way to get rid of having to use all the libraries?”

For the following slides, remember the linkage in the above code is b1 to Bar.prototype to Foo.prototype

Linked Prototype diagram

We see a complete diagram illustrating our code, and after a minute we see an even more complex diagram to illustrate it in full detail. The takeaways are:

  1. (Pessimistic) This is really complex
  2. (Optimistic) There’s ubiquitous internal consistency in JavaScript because everything is explained by the exact same core set of rules

There’s a way to remove a lot of the complexity.

Quiz: Prototype Behavior

  1. What is a constructor?
  2. What is a [[Prototype]] and where does it come from?
  3. How does a [[Prototype]] affect an object?
  4. How do we find out where an object’s [[Prototype]] points to (3 ways)?

See the course for the answers.

Exercise 3

The exercise 2 solution is the starting point for this exercise. Participants use their new knowledge about the prototype to replace the module pattern.

This clip is followed by the solution.

Kyle says overall the module pattern is more useful in his code than the prototype pattern, but we haven’t seen his favorite pattern yet.

Continue to Part 8 – Inheritance and OLOO

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s