Understanding what `new` does in five easy steps

← back to the blog

The new keyword, inheritance and object creation are some of the most confusing parts of the JavaScript language, and are equally befuddling both to newcomers and to programmers experienced with other languages. The reasons for this go way back to the design of the spec, and I won't get into them.

I do not believe that being a coding newbie gives you some kind of advantage in understanding prototypes: rather, trying to grasp both prototypes and the way they have been hacked to produce pseudo-classical patterns at the same time can make newcomers especially bewildered. Moreover, when Googling around on the subject, one encounters a lot of opinion and a lot of detail.

Drawing mainly from JavaScript: The Good Parts and YDKJS, I think I have distilled the details on new down to five simple steps, which I really wish I'd had a firm grasp on when I was first starting out.

1. Functions are objects

This one is pretty straightforward. In JavaScript, functions are objects (of type Function), which basically has the upshot that they can be assigned to variables and passed around like a bag of chips.

function hello() {
    alert('Hello');
}

var hello2 = hello;

hello2();
//alert box says "Hello"

Nothing astounding there.

2. Declaring a function actually creates two objects

When you declare a function, you are actually creating two objects: the function itself (MyFunction), and another "prototype" object (MyFunction.prototype). You can assign properties (which can be functions) to the prototype object (for that matter, you can also assign them to the function directly).

In addition, the "prototype" refers back the original function through a property called the "constructor". So MyFunction.prototype.constructor is MyFunction.

function MyFunction() {}

MyFunction
// MyFunction() {}

MyFunction.prototype.constructor
// MyFunction() {}

Got that? Shit's about the get real.

3. __proto__ is not the same as prototype

In JavaScript, every object has a linked Prototype object. Any time a variable lookup (myObject.myProp) is performed on that object, and the property does not exist, it will look for the property on the object's prototype, then prototypes prototype, and so on.

Here's the thing that's messed up though: that .prototype we mentioned above is not the function's prototype. Chrome stores the actual prototype in a different variable called __proto__.

function MyFunction() {}

MyFunction.prototype
// MyFunction() {}

MyFunction.__proto__
// function () {}

or even better

MyFunction.prototype === MyFunction.__proto__
// false

Not the same thing at all. This also explains why we can't access the prototype on arbitrary object, even though newbies are pounded over the head with the factoid that all JavaScript objects have prototypes.

var myObject = {}

myObject.prototype
// undefined

myObject.__proto__
// Object {}

The prototype is not the Prototype. It is best to think of it simply as a special object that is created when a function is created. Why is this useful?

4. new changes what happens when you execute a function

So far we've only discussed declaring functions, not executing them. Importantly, much of what happens during function execution in JavaScript depends on the way the function is called, and is not set at declaration time at all. When a function is called with new (is in var myObject = new MyFunction()) the following things happen:

  • a new object is created
  • this within the function body is bound to the new object
  • the new object's __proto__ (Prototype) is the .prototype of the function
  • the function will return the new object unless there is an explicit return statement

This allows you to invoke the familiar constructor pattern:

function Animal(sound) {
    this.sound = sound;
}
Animal.prototype.speak = function() {
    console.log(this.sound); 
}

var cat = new Animal("meow");
cat.speak();
// meow

This creates the appearance of classes in JavaScript, but it is an illusion. In the example above, Animal and cat are both objects, they are not classes.

A final note on this point: ES6 adds the class keyword. However, it merely provides syntactic sugar for the pattern above: there still are not really classes in JavaScript.

5. Object.create does one thing

Unlike new, Object.create does exactly one thing: it creates a new object with a prototype specified by the first parameter. This means we could rewrite the example above as follows:

var Animal = {
    speak: function() {
        console.log(this.sound);
    }
}

function createAnimal(sound) {
    var animal = Object.create(Animal);
    animal.sound = sound;
    return animal;
}

var cat = createAnimal("meow");
cat.speak();
// meow

I find this type of code a little easier to read because the various elements in it more clearly declare their own intentions. Douglas Crockford, Kyle Simpson, and Eric Elliot have in fact argued that the pseudo-classical pattern should be done away with altogether. Note that Object.create is used in the classical pattern to mimic "class inheritance" and so understanding how it works is important.

One final point about prototypes: Neither Object.create nor new make copies of objects. It often appears as though the prototype is copied because the prototype and the new object have access to the same properties. But those properties are actually the same things - not copies. This can lead to some surprising results when trying to implement "inheritance". It may be better to refer to inheritance as "delegation" instead.