Javascript "Prototype" Confusion, and the Dubiously Useful "instanceof"

Recently, I became aware that I was more confused than I realized regarding javascript's use of the word "prototype", as the word is used in two different ways.

This draft note is the result of pondering on this a bit more. This pondering also resulted in some clarification (for me) of how the instanceof operator seems to work, and how its utility is doubtful.

Every object has a prototype, accessed via its "__proto__" property

Javascript objects are just bags of named things: properties. Properties can be other objects, functions (which are also objects), or primitives like numbers and strings.

Every javascript object has a prototype, which can be accessed directly in most modern browsers via the named property __proto__.

When a property named foo is requested from an object obj via, first the set of properties for object itself is searched for the property. If it is not found, then obj.__proto__ is searched for a property named foo. If not found there, then it searches obj.__proto__.__proto__, continuing up the "prototype chain" until it either finds the property or obj.__proto__.__proto__....__proto__ is null, and undefined is returned. Note that the javascript engine is supposed to prevent cyclic loops in the prototype chain.

Again: the name of the property for the prototype of an object is not "prototype": its name is "__proto__".

That is one part of the potential confusion.

Every javascript function f has a property named "prototype" - which is not its prototype

This is another part of the potential confusion.

f.prototypeis not the function's prototype.

As for any object, f.__proto__ is the function's prototype.

What is the purpose of f.prototype?

Any function f can be used to generate new objects via newObject = new f(args). When used this way, f is sometimes called the "constructor" for newObject.

When an object is created from a function f via newObject = new f(args), the new object's prototype __proto__ property is set to the property named "prototype" of f: newObject.__proto__ = f.prototype .

That is what f.prototype is used for.

Note that there are other ways to create an object with a specified prototype, and in fact these other methods are recommended by some folks, avoiding the "new" keyword altogether.

Aside: The "constructor" Property

While every function can be used as a constructor, there is also a property named "constructor" for some objects.

In particular, for any function f, f.prototype.constructor = f.

Since objects created from f via new f(args) have their "__proto__" property initialized to f.prototype, this means that for any object newObject created via newObject = new f(args) for some function f, newObject.constructor will refer to the function used to create the object. Initially, at least, as you can change the constructor later.

Other than a record of the object's ancestry that might be useful in a handful of cases (that I've never encountered), I don't know how the knowledge of the constructor would be generally useful.

What this has to do with how javascript's instanceof works

Javascript has an instanceof operator that returns true or false, and can be called like so:

obj instanceof f

You can only use a function on the right side: instanceof will throw an error if f is not a function.

The Mozilla Developer network summarizes this operator quite succinctly (I have used "function" instead of "constructor", since every function can be a constructor):

The instanceof operator tests whether an object has in its prototype chain the prototype property of a given function.

This is illustrated in the figure below.

(obj instanceof f ) is true if f.prototype is equal to
any __proto__ in the prototype chain of obj
Do People Use instanceof?

Answer: I think few do.

When queried on twitter, both Eric Elliot and Kyle Simpson (two javascript folks I think a lot of) tweeted back that they never did. When I asked on hacker news, one commenter said it was a code smell, while another said it was useful when checking if an object is an array (it should be noted that jquery checks the result of a toString call to determine if something is an array).

There are also problems with trying to use instanceof across iframes.

@kangax discourages its use (2009). He also recommends the same method jquery uses to check if something is an array, btw.

Crockford has remarked (in 2003) about the useless instanceof operator (link via kangax's article).

So, I don't foresee using it much myself, but it is personally satisfying to come to a better understanding of it and the surrounding javascript constructs.

And be Warned...

Compared to "standard" OOP that can result in rigid, iron-like structures that complicate change and reuse, javascript with its prototype-based reuse pattern is as firm as a jello: you can change things bit more willy-nilly, if you so desire.

In particular, you can muck with the prototype and constructor properties after-the-fact, and this would likely invalidate the notes above in whatever curious ways you (or the code you are using) has mucked with things.

No comments:

Post a Comment

Popular Posts