Class & Prototypal Inheritance

Presenter: Yauheni Pozdnyakov

 t.me/youhy

We'll talk about...

  • Object and types 

  • Prototypes

  • OOP in JS

Something important before...

TYPES!

Primitives

and...

Boxing

Unboxing

Boxing & Unboxing

Boolean ()

 

Number ()

 

String ()

Primitives

Object constructors

var a = 5;
let b = 'I love JS'
const iReallyDo = true; 

//nothing but primitives

a.toString(); //"5"
b.toUpperCase(); //"I LOVE JS"

METHOD CALL OVER  A PRIMITIVE???? WHAT???

Boxing & Unboxing

let a = 'I love js ';
a.toUpperCase();

IT'S OKAY!

a - primitive

let's pack it...
var tempA = new String(a)
typeof tempA // object

let's call toUpperCase() method from String object over tempA

tempA// I LOVE JS

unbox tempA to a

a// I LOVE JS

STILL PRIMITIVE!!!

Conclusion

  • Primitives are not Objects and do not have propeties
  • JS creates object over the primitive(Boxes it)
  • Perfoms an action over it
  • Returns modefied value back to the primitive (Unboxes it)
  • Destroys object

Some code

let length = 'this is string'.length; //what you see

 

let length = (new String('this is string')).length; // what is done

Prototypes

  • Is Object
  • Could be used as a constructor
function A() {}

Inner properties  [[Construct]] and Prototype

  • [[Construct]] allocates memory for new instance
  • is called by "new" 
function A(){}
A(); // call A as a function
var a = new  A(); // call for [[Constructor]] to create an instance of A

Constructor property

JavaScript’s object system is based on prototypes, not classes.

const Coder= function(name, lang) {
  this.name = name;
  this.lang = lang;
  this.code = () => `${this.name} codes ${this.lang}`;
};

const john = new Coder('John', 'JavaScript');
const mary = new Coder('Mary', 'GoLang');

john.code() // John codes JavaScript
mary.code() // Mary codes GoLang
console.log(john.constructor); // function Coder(name, lang) { ... };
console.log(john.constructor.name); // Coder
console.log(john instanceof Coder); // true

Constructor property is assigned to each function created with "new" and points to the Constructor function, which has created this instance

Each time creates function and with code function inside of it.

let a=25;
a.constructor === Number//????

A little bit more about "New"

  • Create a new instance
  • Bind `this` to the new instance
  • Reference the new object’s delegate [[Prototype]] to the object referenced by the constructor function’s `prototype` property.
  • Names the object type after the constructor, which you’ll notice mostly in the debugging console. You’ll see `[Object Foo]`, for example, instead of `[Object object]`.
  • Allows `instanceof` to check whether or not an object’s prototype reference is the same object referenced by the .prototype property of the constructor.

Prototype and _proto_

const Coder= function(name, lang) {
  this.name = name;
  this.lang = lang;
};

Coder.prototype.code = function(){
  return `${this.name} codes ${this.lang}`
};

const john = new Coder('John', 'JavaScript');
john.code() // John codes Javascript

Creates prototype object

Places code function inside of it

No need to copy  code function to each instance of Coder

code method is accessed by _proto_ link from Coder instance to Coder.prototype object

Array.prototype.shift()
[].shift()

Any difference?

Prototype chaining

console.dir([].__proto__); // same as
console.dir(Array.prototype);

WHY???

// For Numbers
console.dir((10).__proto__); // Number
console.dir((10).__proto__.__proto__); // Object

// For Strings
console.dir('str'.__proto__); // String
console.dir('str'.__proto__.__proto__); // Object

// For objects
console.dir([].__proto__); // Array
console.dir([].__proto__.__proto__); // Object

// For Coder 
console.dir(john.__proto__); // Coder
console.dir(john.__proto__.__proto__); // Object

 If a property is not found on the object, the lookup is delegated to the delegate prototype, which may have a link to its own delegate prototype, and so on up the chain until you arrive at`Object.prototype`, which is the root delegate.

Prototype delegation

Prototype and _proto_

  • _proto_ chaining (looking for methods in chain of prototypes)

  • Prevents from useless copies
  • All instanses share same linked methods stored once (Bad or Good geather afterwards)
  • Prototype stores methods that should be applied to each instance
  • All instances reffer to the same prototype, if method in prototype has been changed - all instances will use modified method. 

Conclusion

Class & Prototypal Inheritance

Class Inheritance: A class is a description of the object to be created. Classes inherit from classes and create subclass relationships:class hierarchy

May or may not use "class" keyword from ES6

Prototypal Inheritance: A prototype is a working object instance. Objects inherit directly from other objects.

Single-ancestor parent/child hierarchies and create the tightest coupling available in OO design.

Instances are typically instantiated via factory functions, object literals, or `Object.create()`.

Base Class Problem

  1. `A` is the base class
  2. `B` inherits from `A`
  3. `C` inherits from `B`
  4. `D` inherits from `B`

`C` calls `super`, which runs code in `B`. `B` calls `super` which runs code in `A`.

A` and `B` contain unrelated features needed by both `C` & `D`. `D` is a new use case, and needs slightly different behavior in `A`’s init code than `C` needs. So the newbie dev goes and tweaks `A`’s init code. `C` breaks because it depends on the existing behavior, and `D` starts working.

Concatenative inheritance

`Object.assign()` ES6

Underscore/Lodash’s `.extend()`

We have features:

Features list
feat1
feat2
feat3
feat4

`C` needs `feat1` and `feat3`

`D` needs `feat1`, `feat2`, `feat4`

const C = compose(feat1, feat3);
const D = compose(feat1, feat2, feat4);

D needs something different from feat1??

No problem! Let's customise feat1 for D not affecting for others

const D = compose(custom1, feat2, feat4);

And `C` remains unaffected!

ES6 classes

ES6 classes desugar to constructor functions, so everything that follows about constructor functions also applies to ES6

Benefits of Constructors & `class`:

  • `this` refers to the new object.
  • Some people like the way `myFoo = new Foo()` reads.
  • There may be a micro-optimization performance benefit
  • A single, canonical way to emulate classes in JavaScript. Prior to ES6, there were several competing implementations in popular libraries

Drawbacks of Constructors & `class`:

  •  Required `new`

  • Temptation for users to create problematic class hierarchies using the extends keyword.

Conclusion

  • JavaScript Prototypal model is very dynamic
  • Object.create creates the same prototype chain
  • Think weather classic inheritance is the best for you, or maybe today is time for extending and concatinating objects?
  • ES6 classes doesn't change anything in the JavaScript world! They are still translated into prototypes and constructor function.
  • constructor(){...} from ES6 Classes turns into constructor function like in ES5
  • Methods from ES6 classes are assigned to prototype like in ES5

Any questions?

THANK YOU FOR ATTENTION!!!

Class and Prototypal Inheritance

By Yauheni Pozdnyakov

Class and Prototypal Inheritance

  • 158