Javascript inheritance implementation using prototypes

This is a fully functional implementation with no weird back references or unwanted functionality. I’ve gone through many different implementations before settling on this. Keep in mind that I had some constraints you may not have and could not use the new ECMA 2015 syntax that introduced the “class” keyword among many other great enhancements.

The Javascript world is full of surprises and tricks that could leave your head spinning for days especially if you are coming from a world of structure and order such as Java or C#.

Object inheritance is complicated and messy, there are several ways of implementing it and different flavor for each creating a huge web of complicated code to choose from.

There are new developments and methods that will definitely improve this situation but if you are forced to stay within the bounds of older implementations like I was while implementing Jurassic interpreter within C# code, the following will get the job done.

Requirements

These are my requirements:

  1. Parent “class” with properties and methods and a parameterless constructor.
  2. Child “class” with own properties and methods and a parameterless constructor.
  3. Child class will inherit Parent’s properties
  4. Child class will inherit Parent’s methods
  5. You can add methods to either Parent or Child even after objects were created.
  6. Adding method to parent will also make that same method available to all children automatically
  7. There are no unwanted references maintained between the Parent and Child definitions or any of the object instantiated using them. (This is often an issue with some of the other ways you can attempt inheritance in javascript)

Implementation

We’ll start by defining constructors that will describe the objects. You will notice Object.assign(this, new Grandparent()); call, that call creates an instance of the base object similar to a super or base call in other languages. I’ve tried using the “call” function Grandparent.call(); but couldn’t get it working in my environment.

var Grandparent = function() {
	this.name = 'I am the grandfather';	
	this.age = 70;
	this.likesCoffee = true,
	this.items = {
		house: {
			bedrooms: 7
		}
	},
	this.getItems = function() {
		return this.items;
	}
}

var Parent = function() {
	Object.assign(this, new Grandparent()); // Copy properties from Granparent, Requirement #3
	this.name = 'I am the parent.';
	this.age = 40;
	this.secretLanguage = function() {
		return 'the secret language';
	}
}

var Child = function() {
	Object.assign(this, new Parent()); // Copy properties from Parent, Requirement #3
	this.name = 'I am the child.';
	this.age = 10;
}

The next step is to link the prototypes so that any new functions added to the base class will propagate down the inheritance hierarchy. Note that by linking Parent to Grandparent and Child to Parent the child will also be linked to Grandparent by default.

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

To illustrate that we can add a new prototype method to the Grandparent that will then be available to both Parent and Child

Grandparent.prototype.getAge = function() {
	return this.age + ' years';
}

Full working example

Below is a complete example with comments. It addresses all of the requirements stated before.

//
// Define the "constructors", this is somewhat similar to defining a class
// Requirements #1 and #2

var Grandparent = function() {
	this.name = 'I am the grandfather';	
	this.age = 70;
	this.likesCoffee = true,
	this.items = {
		house: {
			bedrooms: 7
		}
	},
	this.getItems = function() {
		return this.items;
	}
}

var Parent = function() {
	Object.assign(this, new Grandparent()); // Copy properties from Granparent, Requirement #3
	this.name = 'I am the parent.';
	this.age = 40;
	this.secretLanguage = function() {
		return 'the secret language';
	}
}

// Link the prototype
// This will give access to current and future methods of the Grandparent

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

var Child = function() {
	Object.assign(this, new Parent()); // Copy properties from Parent, Requirement #3
	this.name = 'I am the child.';
	this.age = 10;
}

// Link the prototype
// This will give access to current and future methods of the Parent and Grandparent

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

// Now we are ready to create some people

var grandpa = new Grandparent();
var dad = new Parent();
var son = new Child();

// Both dad and son should like coffee 
// Requiement #3

console.log("Dad likes coffee: ", dad.likesCoffee);
console.log("Son likes coffee: ", son.likesCoffee);

// Both dad and child have their own secretLanguage method
// but not the grandparent
// Requirement #4

console.log("Dad knows ", dad.secretLanguage());
console.log("Son knows ", son.secretLanguage());
try {
	console.log("Grandpa knows ", grandpa.secretLanguage()); // this will fail
} catch(e) {
	console.log(e);
}

// Now lets try to add a method to the Grandparent
// Requirement #5

Grandparent.prototype.getAge = function() {
	return this.age + ' years';
}

// Check if the method is in fact available at the different levels.
// Requirement #6

console.log("Grandpa's age: ", grandpa.getAge());
console.log("Dad's age: ", dad.getAge());
console.log("Son's age: ", son.getAge()); 

// Now how about a method that was defined on Grandparent before
// we declared Parent and Child
// The grandparent has a large house so they all live together

console.log("Son's house: ", son.getItems().house);

// Lets say that the dad decides to move out along with his son
// into a new smaller home. (One would say it's about time)
// We could update the house property to an entirely new
// object like so:
/*
	dad.items.house = {
		bedrooms: 3
	};
*/
// But since there should be no "back" references we can also
// just update the number of bedroom directly

dad.items.house.bedrooms = 3;
console.log("Dad's house: ", dad.getItems().house);

// This should not affect grandpa's living situation
// Requirement #7

console.log("Grandpa's house: ", grandpa.getItems().house);

// But we do want to keep son's house in sync with the dad from now on
// so let's create a reference

son.items.house = dad.items.house
console.log("Son's house: ", son.getItems().house);

Output

The script should produce the following output:

Dad likes coffee: true
Son likes coffee: true
Dad knows the secret language
Son knows the secret language
TypeError: grandpa.secretLanguage is not a function
at :60:40
Grandpa’s age: 70 years
Dad’s age: 40 years
Son’s age: 10 years
Son’s house: {bedrooms: 7}
Dad’s house: {bedrooms: 3}
Grandpa’s house: {bedrooms: 7}
Son’s house: {bedrooms: 3}

How to display the git version on your site

Here is a quick guide on how to automatically update the build version of your site directly from git.
This approach leverages the “hook” functionality to get the build hash after a commit.

Versioning files is a must for any developer and git version control system is one of the de facto choices for that job. It’s my personal favorite as well. You can learn more about git here.

Go into your projects .git folder, then hooks. You should see a list of sample hooks already there.
Create a new one called “post-commit” (note there is no file extension).

Add the following content:

#!/bin/sh
#
# Get the Git Revision and write make available to the application
# This will write the short commit hash to the version-commit.php file.
#
version=$(git rev-parse --short HEAD)
echo "" > version-commit.php

Once you “include” the version-commit.php file the VERSION_COMMIT constant will now be available to display anywhere in your site. For example:

require_once(version-commit.php);
$versionMajor = '1.0';
$version = $versionMajor.'.'.VERSION_COMMIT;
echo $version;

Now you are probably thinking that this would cause the project to show new changes because of version-commit.php file change.

For that we need to update “.gitignore” file in the project root folder:

# Don't version the version file
version-commit.php

One thing to note is that the version-commit.php file will not exist for a cloned (checked out) repository until a new change is committed, since that file is not committed with the code to avoid an endless loop of change/commit cycle.

I am yet to find a clean and simple way around that but this problem is a small price to pay for some useful automation.

Retrofitting PHP code to use namespaces

Using namespaces in PHP can be bit more work than it appears and in some cases will require some mass search/replace to be performed.   There is one particular scenario where that process becomes unnecessarily tedious and i will show you how to make it less so.

Quick Intro to Namespaces

Without namespaces every one of your classes must use a unique name.  Using namespaces is a no-brainer for someone from a Java background where they are called packages and you pretty much can’t code without them.  But in php world you can write entire applications without ever touching the subject. Namespaces provide a way to group Classes into logical groups or modules.

Here are two PersonalBio classes without using namespaces. Since the class names have to be unique the naming gets messy.

Same class definitions using namespaces would look like this

Using namespaces allows the class names to be more generic and short. It also prevents conflicts with other libraries and built in classes.
A good example of this would be a class called Directory. Since Directory is a built-in php class you cannot have your own without specifying a namespace:

This will not work due to a conflict with an existing php class:

Same class is ok within a namespace:

The Retrofit Process
The easiest way to retrofit the existing code is to use en editor such as Notepad++ and perform regular expression replacements.
For instance, when referencing classes that don't have a namespace from a class with a namespace you will be faced with a problem of having to prefix all those references with a backslash.  There is currently no other easy reliable way to do this:

Use the following search and replace patterns:
Search:
(\bFirstClassWithoutNamespace\b|\bSecondClassWithoutNamespace\b)
Replace With:
\\$1
The "\b" determines the word boundary and the "|" allows you to replace multiple classes at a time.  This comes in very handy when there are dozens.
This is the result:

<?php namespace MyApp; class Test { $instance1 = new \FirstClassWithoutNamespace(); $instance2 = new \SecondClassWithoutNamespace(); } You can do similar replacements for classes using namespaces: Search: (\bFirstClass\b|\bSecondClass\b) Replace With: \\SomeOtherNamespace\\$1 And the result:

First steps with PostCSS

PostCSS is getting a lot of attention lately and I decided to give it a try. Post-processing may seem counter intuitive especially if you are used to tools like SASS and LESS, but will make more sense the more time you spend tinkering.

With a post-processor you can define global styles that can then be transformed into specific rules for different components of the web application. This is really quite powerful and allows for creating of a simple set of styles that can then be targeted at specific components.  One use would be to have a branding stylesheet that can be applied to different plugins or products.

The concept is somewhat similar to what you can do using pre-processors (eg. Bootstrap and variables) but way more flexible and arguably much cleaner as well.  As the base stylesheet could remain unchanged and processing code is added with each additional integration.

Of course, that is only one way to utilize the functionality but the possibilities are countless.
There is a lot of potential here and for workflows that are clean and reusable so make sure to give PostCSS a try. Here are some steps to get up and running quickly:

  1. Install node.js (if you haven’t already)
  2. Create a folder for the test project.
  3. Access command line and go into the folder.
  4. Run the following commands to install the CLI version of the PostCSS package as well as the Autoprefixer plugin. (There are several other PostCSS plugins available and you also have the ability to create your own – the main strength of PostCSS).

The CLI version is a wrapper around the regular PostCSS package and allows you to run PostCSS without any additional build packages. Good for getting to know how it works.

npm install postcss-cli
npm install autoprefixer

The commands will install the packages under node_modules directory created in your current directory.

  1. Create a test file called test.css with the following content.
.transparent {
  opacity: 0;
  transition: opacity 1s;
}
  1. Create an options file called test.json with PostCSS and Autoprefixer options. This allows you to configure parameters for the autoprefixer plugin. In this case a query for supported browsers (see: https://github.com/ai/browserslist#queries)
{
  "use": ["autoprefixer"],
  "autoprefixer": {
    "browsers": "> 5%"
  }
}
  1. Execute the following command to compile the css. result.css will contain the output.
postcss -c test.json -o result.css test.css

You should see that the autoprefixer plugin added browser specific prefixes.