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.
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 obj.foo
, 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.
f
has a property named "prototype" - which is not its prototype
This is another part of the potential confusion.
f.prototype
is not the function's
prototype.
As for any object, f.__proto__
is the function's prototype.
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.
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.
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
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.
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