Prototypes and Objects

The idea that everything is an object in JavaScript is a bit of a misnomer. A more accurate saying would be that nearly everything is or can behave like an object. The reason for this is because nearly everything in JavaScript comes from a common ancestor called Object. This relationship is expressed through prototypes.

var str = "Hello";
var num = 42;
var obj = {};

In our example here, we have a string, a number and an empty object. The first two are what you would call primitives (a number primitive and a string primitive) while the last is a true object. Despite these differences, there are common methods defined on each.

var str = "Hello";
var num = 42;
var obj = {};

console.log(str.valueOf()); // Hello
console.log(num.valueOf()); // 42
console.log(obj.valueOf()); // Object {}

As you can see, each of our variables already has a method defined (valueOf()).

This is because they all have a common ancestor: Object. Think of it like a really odd family tree where each child comes from a single parent. In the family of JS, the root of this tree is Object from which all the possible children spawn.

The links between the parent and child form the prototype chain. Coming back to our 3 variables above, we can check their prototype by calling Object.getPrototypeOf().

  var str = "Hello";
  var num = 42;
  var obj = {};

  console.log(Object.getPrototypeOf(str)); // String
  console.log(Object.getPrototypeOf(num)); // Number
  console.log(Object.getPrototypeOf(obj)); // Object

This seems to make some sense. Our simple “str” variable has a prototype of String, “num” is Number and “obj” is Object. Let’s go deeper.

  var str = "Hello";
  var num = 42;
  var obj = {};

  console.log(Object.getPrototypeOf(str)); // String
  console.log(Object.getPrototypeOf(num)); // Number
  console.log(Object.getPrototypeOf(obj)); // Object

  console.log( Object.getPrototypeOf( Object.getPrototypeOf(str))); // Object
  console.log( Object.getPrototypeOf( Object.getPrototypeOf(num))); // Object
  console.log( Object.getPrototypeOf( Object.getPrototypeOf(obj))); // null

What we learn here is that our string, number and object all have a common ancestor in Object. In addition, when we try and get the prototype of Object, we get back null… the end of the line.

From this little experiment, we could draw the family tree for our string like this:

null -> [Object] -> [String] -> str

One of the great things about this is that we can define methods on a prototype and that method will be available to all the children that share that prototype. This is exactly why you can create a string and it will already have quite a few methods already defined on it.

var str = "i love lamp";
str.toUpperCase(); // "I LOVE LAMP"

Each type has its own set of methods. If you define an Array, it will have an Array prototype with predefined array methods like forEach, map and filter. Also, because everything inherits from the Object prototype, any method defined on Object is available to every other object (like valueOf()).

Please note, while it maybe tempting to start adding methods to Object’s prototype so you can use them everywhere, you should be very careful with this (or avoid it if at all possible). This causes problems if you do it in the wrong way, and can cause unexpected behavior even if you do it correctly. See this Stack Overflow post for more on this.

I will follow up in a future post on how to use prototypes and the new operator to establish your own prototype chains.

Update: Classes in JavaScript