The Object Prototype

&

Prototypal Inheritance
in JavaScript

A Presentation by Kostas Minaidis

Chapter 1

The Object

An Object is a collection of key/value pairs,
referred to as the Object's properties:

let obj = {
  key: "value",
  first_name: "kostas",
  last_name: "minaidis"
}

Creating an Object
in JavaScript:

1) Object Literal:

let obj = { first: "kostas", last: "minaidis" }

2) Object Constructor:

let obj = new Object({ first: "kostas", last: "minaidis" });

Both create the following structure:

Object obj {
  first: "kostas",
  last: "minaidis",
  __proto__: Object
}

Meet the __proto__ property

Whenever we create a new Object, a __proto__ property is implicitly attached to it.


 Object obj {
  first: "kostas",
  last: "minaidis",
  __proto__: Object
 }

The __proto__ property is a link that points to: Object.prototype


obj.__proto__ === Object.prototype

The Object.prototype is also an object itself and contains a set of helper methods. The role of __proto__ is to implicitly make these methods available to the newly created object.


 Object.prototype {
   constructor: [Function],
   hasOwnProperty: [Function],
   toString: [Function],
   valueOf: [Function],
   ...
 }

Accessing the Object.prototype methods
Our obj Object
let obj = { 
  key: "value",
  __proto__: Object.prototype
}

Accessing the obj object's own properties:

obj.key;
// "value"

Accessing the prototype's methods:

obj.valueOf();
// { key: "value" }
obj.hasOwnProperty( "key" );
// true
obj.hasOwnProperty( "valueOf" );
// false
Object.prototype

 {
   constructor: [Function],
   hasOwnProperty: [Function],
   toString: [Function],
   valueOf: [Function],
   ... more methods ...
 }

Accessing an object's own properties:

Accessing an object's inherited properties:

Chapter 2

The Constructor

What is a Constructor?

A function called with the new keyword.

A function constructor always returns a new object
whose type depends on the constructor.

Calling builtin functions using the new keyword

  let obj = new Object( { key: "value" } );

  let arr = new Array( 1, 2, 3 );

  let err = new Error( "Whoops!" );


Produces:

  { key: "value" }
  
  [ 1, 2, 3 ]
  
  Error: Whoops!


*Remember: typeof Object === typeof Array === typeof Error === "function"

All of our newly created objects contain a __proto__ property
which links them to their constructor's prototype object...


  obj { key: "value" }
  arr [ 1, 2, 3 ]
  err Error: Whoops!



  obj.__proto__ === Object.prototype
  arr.__proto__ === Array.prototype
  err.__proto__ === Error.prototype


...and subsequently to the object prototype's inherited methods:


  obj.valueOf(); // { key: "value" }
  arr.reverse(); // [ 3, 2, 1 ]
  err.message;   // ""



  Object.prototype.valueOf
  Array.prototype.reverse()
  Error.prototype.message


By linking object instances to their Constructor prototype object we are conserving memory and gaining speed.

Multiple instances of a Constructor, can share a single set of methods through the prototype object, while maintaining their own unique set of property values:


  Array.prototype.sort [Function]
  Array.prototype.reverse [Function]
  Array.prototype.map [Function]
  ...

// Unique properties:    // Shared methods:

  let arr1 = [1,2,3];     arr1.sort();
  let arr2 = [4,5,6];     arr2.sort();
  let arr3 = [7,8,9];     arr3.sort();


We can also create our own Constructors using custom functions and construct custom objects using the new keyword.

Our Pizza Constructor...

function Pizza( sauce, cheese ){
  this.sauce = sauce;
  this.cheese = cheese;
}

let yummy = new Pizza("tomato","mozzarella");


...produces:

 yummy {
  sauce: "tomato",
  cheese: "mozzarella"
 }


*Note: The this keyword inside a function constructor, refers to the object being constructed.

Chapter 3

Prototypal Inheritance

By utilizing JavaScript's prototype object and its underlying linkage mechanism we can implement some powerful object oriented patterns.


Let's dive into some examples...

Create a Constructor that will create new instances with unique properties:

	
function User( options ) {

  this.name = options.name;
  this.surname = options.surname;
  this.plan = options.plan;

}		
	

Add methods to our Constructor's prototype object.
These methods will be created once but will be shared by all new instances.

	
User.prototype.getFullName = function(){
  return this.name + " " + this.surname;
}

User.prototype.upgradePlan = function(){
  this.plan = "Premium";
}
	

Our newly created instances will be sharing the same set of methods
inherited from their constructor's prototype object:

	

  let user001 = new User(
	  { name: "Jane", surname: "Doe", plan: "Basic" }
  );
  
  let user002 = new User(
	  { name: "John", surname: "Dalton", plan: "Basic" }
  );
 
  let user003 = new User(
	  { name: "Rebecca", surname: "Brown", plan: "Basic" }
  );

  user001.getFullName();  // "Jane Doe";
  user002.upgradePlan();  // { plan: "Premium", name: "John", ... }
  user003.getFullName();  // "Rebecca Brown"


Extending Objects

We can extend Constructors and their prototype object
by using the Object.create() builtin method.

	
let Child = Object.create( Parent );

From MDN: The Object.create() method creates a new object, using an existing object as the prototype of the newly created object.

We can use the power and flexibility of Object.create() to extend an object's prototype like this:

		
Child.prototype = Object.create( Parent.prototype );
	
	

Let's extend our User Object to create a new type of Premium User object

	
function PremiumUser( options ){
  User.call(this, { name: options.name, surname: options.surname });
  this.plan = "Premium";
}

PremiumUser.prototype = Object.create( User.prototype );
PremiumUser.prototype.constructor = PremiumUser;

PremiumUser.prototype.special = function(){
  return "Premium Specials!";
}
// Shadowing / Overriding our Parent's method:
PremiumUser.prototype.upgradePlan = function(){
  this.plan = "Golden";
}


Let's create our first Premium User instace:

	
let prem001 = new Premium({ name: "Clark", surname: "Kent" })

prem001.getFullName();  // "Clark Kent"

prem001.upgradePlan();  // { plan: "Golden", name: ... }


A stroll down Prototype lane...

Thank you!