JavaScript borrowed the new
and delete
keywords from its less-dynamic
predecessor languages. They feel a bit out of place in a garbage collected
language and are a source of confusion for newbies – one of the reasons
popular libraries such as jQuery, d3, and Ember.js have adopted APIs that
don’t require using new
at all. In this post I’ll show you one way do it,
and why you should consider it for your next JavaScript library.
In C++, new
and delete
are symmetric operators that combine memory
management and object lifecycle operations. new
allocates an instance and
calls the constructor, and delete
calls the destructor and deallocates it.
In garbage collected languages, delete
isn’t necessary; Java doesn’t have
it, for example. It’s one of JavaScript’s quirks that it does use delete
,
and for a purpose (removing a property from an object) that’s not symmetric
with new
. You’ll sometimes see confused JavaScript programmers trying to
delete
plain objects.
new
can itself be a source of confusion. Looking at instantiation with
new
, it’s easy to see why: new User()
requires both a language keyword
and a unique syntactic form. In other scripting languages, neither are
needed: instantiation is done via regular function notation, either via a
class method as in Ruby (User.new
), or calling the class object as a
function as in Python (User()
).
What’s worse, in JavaScript, forgetting new
when calling a constructor can
produce some very strange behavior – leaving variables undefined and polluting
the global scope. John Resig gave a great rundown of the issues and proposed a solution, often dubbed the
‘instanceof trick’:
1 2 3 4 5 6 7 8 9 |
|
Class constructors defined with the instanceof trick can be called with or
without new
:
1 2 3 4 5 |
|
In either case, the result is a newly allocated and initialized User.
John Resig goes on to show how to create a reusable function that builds constructors that use the instanceof trick. This way, instead of writing it out manually for every class, you write it once and use a higher-level function to declare classes and their prototype properties:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
APIs that use the instanceof trick internally often publicly document only the
newless form of instantiation. This minimizes the API surface area, gives new
users less to learn, and avoids the awkward aspects of new
. Another
advantage is that it allows the implementation to choose either the Module pattern or classic
prototypal instantiation without changing the public API. For example, we can
rewrite the User
class to use the Module pattern without changing how it’s
used:
1 2 3 4 5 6 7 8 9 10 |
|
Similarly, if we had started out with the Module pattern, but discovered that we needed the memory efficiency of prototypal instantation, we could switch without changing client code.
An alternative that some library use is to pair each constructor with a factory
function of the same name but with leading lower-case, e.g. User
and user
:
1 2 3 4 5 6 |
|
This works, but again, it increases the size of the API you need to document and users need to learn, and unlike the instanceof trick, there’s no way to implement it in a reusable form. You’re stuck writing a factory wrapper for every class.
A newless API works great for as jQuery and d3, and I’ve found it very useful in iD as well. Consider using it for your next library.