Coder Social home page Coder Social logo

prototypical-inheritance's Introduction

Welcome to Inheritance

Inheritance in programming languages is very similar to inheritance in the people world. If one object inherits from another, that means it behaves an aweful lot like it's 'ancestor' without being identical. JS's approach to inheritance is called 'Protoypical Inheritance'.

Even if you didn't know it you've been taking advantage of inheritance since day 1. Arrays are a great example:

let array = ["a", "b"];
let deleted_element = array.splice(0, 1);
console.log(array, deleted_element);

Where did '.splice' come from? You certainly didn't write it. What happens if you do this:

let array = ["a", "b"];
// array.splice === Array.prototype.splice;  -->  true
array.splice = function(arg) { console.log(arg) };
let deleted_element = array.splice(0, 1);
console.log(array, deleted_element);
// array.splice === Array.prototype.splice;  -->  false

And when you look up the documentation for '.splice' what's all this about 'Array.prototype.splice()'?

The short answer is that 'Array.prototype' is the ancestor of all arrays. All objects have a property called '__proto__' that sets that object's ancestor. Because the '__proto__' of all arrays is 'Array.prototype', any methods or properties attached to 'Array.prototype' can be called by any array. You can overwrite the properties/methods of an object's ancestor by attaching a property/method of the same name directly to the child object.

Pictures are helpful:

In JS objects are the players, not the game. The game is objects/prototypes, functions and asynchronicity. While there are language features that abstract away prototypical inheritance (constructor funcitons, es6 classes), but under the hood there are still just objects pointing at other objects. For this reason we will be covering pure prototype manipulation. Hopefully by the end of this long lesson you will not only be able to understand how JS language features are using inheritance but will be able to come up with your own solutions.

A series of videos from Mr. Funfunfunctional that complements this markdown lesson. Recommended.

TOP



Hands On Exploration

When you hear that everything in JS is an object, this is literally true. If you follow the prototype chain of any native JS type (number, object, funciton, array, ...) you will find that it's oldest ancestor is 'Object'. Object with a Capital "O". This isn't all theoretical, you can see it for yourself. Complete these mini-exercises in ChromDev for a preview of coming attractions:

  1. An Empty Object:
    1. Create an empty object called 'obj'.
    2. Type 'obj.' in the console, what options appear for autocomplete?
    3. Enter 'obj' in the console, see that arrow to the left of it? click that. What do you see?
    4. Click on the arrow to the left of '__proto__: Object'. What do you see?
    5. Enter 'obj.__proto__' in the console. How does it compare to what you saw in the stpes above?
    6. Enter 'obj.__proto__.__proto__' in the console.
  2. An Empty Array:
    1. Create an empty array called 'arr'.
    2. Type 'arr.' in the console, what options appear for autocomplete?
    3. Enter 'arr' in the console, see that arrow to the left of it? click that. What do you see?
    4. Click on the arrow to the left of '__proto__: Array'. What do you see?
    5. Click on the arrow to the left of '__proto__: Object'. What do you see?
    6. Enter 'arr.__proto__' in the console. How does it compare to what you saw in the stpes above?
    7. Enter 'arr.__proto__.__proto__' in the console. How does it compare to what you saw in the stpes above?
    8. Enter 'arr.__proto__.__proto__.__proto__' in the console.
  3. An Empty Function:
    1. Create an empty function called 'fun'.
    2. Type 'fun.' in the console, what options appear for autocomplete?
    3. Enter 'fun.__proto__' in the console. How does it compare to what you saw in the stpes above?
    4. Enter 'fun.__proto__.__proto__' in the console. How does it compare to what you saw in the stpes above?
    5. Enter 'fun.__proto__.__proto__.__proto__' in the console.
    6. Add a property to fun -> fun.prop = "prop". (Functions are also objects)
    7. Type 'fun.' in the console, find prop in the list of autocomplete options

Carry on to learn what all this means. The rest of this chapter will cover the basics of inheritance in Proto Lookup Chain, present some tools for studying inheritance in the wild with Useful Methods, and finally provide some Recommended Practices.

TOP


Proto Lookup Chain

What you saw in the exercises above is the prototype lookup chain for 3 primitive types in JS. When you try to access a method or property that doesn't exist on an object, JS will travel all the way up the lookup chain in search of that keyword before throwing an error.

Examples are better than words, read em or run em. These examples use a property, what happens if you use a method instead?:

  • Adding a property directly to an object:
    var ancestor_obj = {}; // lookup chain: ancestor_obj -> Object -> null
    ancestor_obj.prop; // undefined, nothing in this object's lookup chain has a '.prop'
    ancestor_obj.prop = 'prop';
    ancestor_obj.prop; // 'prop' 
    // you've seen this before, it's about time for some insight
  • Setting and using an object's lookup chain:
    var child_obj = {};// lookup chain: child_obj -> Object.prototype -> null
    child_obj.prop; // undefined, nothing in this object's lookup chain has a '.prop'
    child_obj.__proto__ = ancestor_obj; // This syntax is great for learning, but slow for production.  We will cover better ways of doing this later on in this markdwon.
    child_obj.prop; // 'prop'.  this value lives on ancestor_obj but is accessible to child_obj
    child_obj; // lookup chain: child_obj -> ancestor_obj -> Objec.prototypet -> null 
  • Overwriting an ancestor's property:
    child_obj.prop; // 'prop'
    child_obj.prop = 'child prop';
    child_obj.prop; // 'child prop'

Everything in JS has a '.__proto__' property, this property determines the next stop in it's lookup chain. The next stop also has a '.__proto__', and so on until you reach The Object whose '.__proto__' is 'null'. TOP


Useful Native Methods

In the examples above you saw how objects can have access to properties that aren't their own. JS has a couple native methods for exploring an object's prototype chain. They are great tools for studying and learning JS inheritance.

  • .getOwnPropertyNames():
    var ancestor_obj = {property: 'prop'};
    ancestor_obj.property; // 'prop'
    Object.getOwnPropertyNames(ancestor_obj); // ['property']
    var child_obj = {__proto__: ancestor_obj};
    child_obj.property; // 'prop'
    Object.getOwnPropertyNames(child_obj); // []
  • .hasOwnProperty():
    ancestor_obj.hasOwnProperty('property'); // true
    child_obj.hasOwnProperty('property'); // false
  • .isPrototypeOf():
    ancestor_obj.isPrototypeOf(child_obj); // true
    child_obj.isPrototypeOf(ancestor_obj); // false
    Object.prototype.isPrototypeOf(child_obj); // true
    Object.prototype.isPrototypeOf(ancestor_obj); // true
    Object.isPrototypeOf(ancestor_obj); // false
    // Notice that 'Object.prototype' is the ancestor not 'Object'
    // The 'prtototype' property is an object like any other
    // rather than pointing directly to 'Object', the proto chain points to a property of 'Object'.
    // This is very common in JS.  
    // Later in this lesson we will see why it is a practical design pattern
    • So far we've used the term 'ancestor' because it is more intuitive for learning how this works. This method introduces the correct term - 'prototype'. Moving forward we will be using the word 'prototype'.

There are more similar methods, but these three will be the most useful for analyzing code and learning inheritance. While it isn't a method, inspecting 'anything.__proto__' in ChromDev will also be invaluable.

TOP


Recommended Practices

In the previous examples we have set protoypes by directly manipulating the '.__proto__' property, this is not the best way to do things. There are three native methods designed to set inheritance chains. Each one serves a slightly different purpose. Below is our recommended practices for creating objects in your code:

  • Object Literals:
    • If you're making a simple object, don't worry about any of these other methods. Just use object literals. They're efficient, easy to read, maintainable, and convention. Even Object Factories (the next chapter) are just functions that build and return object literals. Most of the time literals are the right solution.
    • Check out ES6 enhanced object literals.
  • Object.create(): <- click for docs
    • Returns a new object with a prototype of your choice:
      var prototype_obj = {propterty: 'prop'};
      var child_obj = Object.create(prtototype_obj)
    • Cannot be used to change the prototype of an existing object, only to create new objects.
    • Mr Funfunfunctional explains.
  • Object.assign(): <- click for docs
    • Copies the properties from 1 or more objects into a target object. This is a simple example, read the docs for more details:
      var first_obj = {first_prop: 1};
      var second_obj = {second_prop: 2};
      Object.assign(second_obj, first_obj);
      econd_obj; // {second_prop: 2, first_prop: 1}
    • This method doesn't actually modify the prototype chain. It's sort of the opposite of 'create', it combines two or more objects into one. When you assign one object to another you are literally copying the methods from one object to another. Use '.hasOwnProperty()' to explore the difference between '.assign()' and '.create()'.
    • Knowing when and how to use this one can be tricky to figure out. We'll address this in the next chapter by recommending and discussing a few design patterns.
  • Object.setPrototypeOf(): <- click for docs
    • The recommended way to change an object's prototype. Better than resetting '.__proto__' directly:
      var obj = {};
      var prototype_obj = {property: 'prop'};
      var child_obj = Object.setPrototypeOf(obj, prototype_obj);
      child_obj; // {property: 'prop'}
    • While resetting prototypes is sometimes the right solution, it is better to design your code to work without this. Resetting prototypes makes your app more prone to side-effects and mysterious bugs.
    • Resetting prototypes is slow, but probably your app is slower so that won't matter.

That sums up the basics of Prototypical Inheritance. You have the lookup chain, and a couple tools for directly investigating or manipulating it. Knowing when and how to use these tools can be tricky. Our first recommendation is to design your code so you don't have to deal with the look-up chain. The next chapter on Factories shows how to incorporate OOP into your app without using inheritance. If you really just want to use inheritance, skip to Using Inheritance to learn how.

TOP


Externals

javascript.info

js web blog

cli exercises

a resource

MDN explains

TOP


NLS Resources



prototypical-inheritance's People

Contributors

colevanderswands avatar

Watchers

James Cloos avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.