Prototypes and Inheritance in JavaScript





WHO am i?

Chris Langton

  • Community <3 Speaker for meetups
  • Python <3 Django, Pandas, Hadoop
  • PHP <3 PHP7 ZF2 CI Doctrine
  • Raspberry Pi <3 My fish can sms me!
  • Blogger with publications in WDW, Pi Weekly, Openshift
  • chrislangton84@gmail.com
  • github.com/chrisdlangton
  • www.nodewiz.biz
  • @chrisdlangton

The two pillars of JavaScript

JavaScript is pretty good at letting you code poorly.
But both pillars are equally important.

  • Prototypal Inheritance   (objects without classes, and prototype delegation, aka OLOO-Objects Linking to Other Objects)
  • Functional Programming   (enabled by lambdas with closure)

Prototypal Inheritance

  • Classical and prototypal inheritance are fundamentally and semantically distinct.
  • Instances inherit from other instances through concatenative inheritance
  • Literally Objects Linking to Other Objects - OLOO

Don't be Shy

  • You can and should ask questions
  • The only dumb questions are ones you dont ask

Example

new func()
Produces a new object that inherits from 
func.prototype
The `new` keyword is used to invoke a constructor. 
What it actually does is:

  • Create a new instance
  • Bind `this` to the new instance
  • Allows `instanceof` to check whether or not an object’s prototype reference is the same object referenced by the .prototype
  • 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]`

In Practice

Add functionality through Prototypal Inheritance to your own Object definitions.
function newobject(o) {
    function Func() {}
    Func.prototype = o;
    return new Func();
}
var yQuery = newobject(jQuery);
The `newobject` function untangles JavaScript's constructor pattern.
It takes an existing object as a parameter and returns an empty new object that inherits from the old one. 
If we attempt to obtain a member from the new object, and it lacks that key, then the old object will supply the member.
Objects inherit from objects. 

IRL

if (typeof Object.create !== 'function') {
    Object.create = function (o) {
        function F() {}
        F.prototype = o;
        return new F();
    };
}
newObject = Object.create(oldObject);
Objects are mutable in JavaScript, so we can augment the new instances, giving them new fields and methods. 

These can then act as prototypes for even newer objects. 

We don't need classes to make lots of similar objects.

native Objects

You can introduce new functionality to native Objects in the same manner as your own Object definitions.

Number.prototype.multiplyBy = function (number) {
  return this * number;
}
Test
(123).multiplyBy(2)

> 246

What Will Go Wrong?

Everything

If debugging is the practice of removing bugs from software... then programming must be the practice of adding them.

You will have to make mistakes to learn how to fix them

Constructors

Classical OOP
function Obj() {
    /* do your constructor things here */
    return this;
}
Obj.prototype.foo = function() {
    return 'foo'
}
Obj.prototype.bar = function() {return 'bar'}
var obj = new 
object();
obj.foo();
> foo
obj.bar();
> bar
Obj.foo()
> Uncaught TypeError: Obj.foo is not a function
If you’re creating constructor functions and inheriting from them, you haven’t learned JavaScript.

Namespace


Namespacing is a technique employed to avoid collisions with other objects or variables in the global namespace.


JavaScript doesn't have built-in support for namespaces like other languages, it does have objects and closures which can be used to achieve a similar effect.


Closure

A closure is a function which remembers it's environment in which it was created.
So, we'll use a self-executing anonymous function that exports an object definition to its namespace.
(function(){ // private area, away from the global scope
  var privateProp = function(){
    return this;
  };
  privateProp.prototype.get = function(key){
    return this[key];
  };
  privateProp.prototype.set = function(key, value){
    this[key] = value;
    return this;
  };
  window.mynamespace = privateProp;
})();

Scope

For our previous 2 examples we have introduced a fatal flaw, and that is scope. 
Though we have come today to learn about constructors, and namespaces, and closures, all in an attempt to manage scope.
These rely entirely on and can be identified by the `new` keyword.

All of these paradigms are classical inheritance NOT  Prototypical Inheritance.

Avoid `new` - use .prototype

Explained

Using the definition from earlier
var obj = new mynamespace();
obj.set('foo','bar').get('foo');
> foo
Without `new`
var obj = mynamespace();
obj.set('foo','bar').get('foo');
> Uncaught TypeError: obj.set is not a function
obj = undefined  ???

 obj
> window
obj = window !?!

Where window came from

We attempted to simulate  namespace using a closure but in our simulated constructor we referenced `this`, another flaw.
But we can handle that! Right?
(function(){
  var privateProp = function() {
    if (this === window)
      return new privateProp(arguments);
    return this;
  };
  window.mynamespace = privateProp;
})();
This is getting complicated, and we haven't even yet added functionality, and any additional methods are now constrained.
Want to repeat this for all objects?
DRY - use Prototypical Inheritance over Classical.

Prototypes and Inheritance in JavaScript

By Chris Langton

Prototypes and Inheritance in JavaScript

  • 591