Table of Contents
- A Pull of the Lever: Prefaces
- Prelude: Values and Expressions
- 1. The first sip: Basic Functions
- 2. The Recipe Cheat Sheet
- 3. Recipes with Basic Functions
- 4. The Pause That Refreshes: Rebinding and References
- 5. Recipes with Rebinding and References
- 6. Stir the Allongé: Objects, Mutation, and State
- 7. Recipes with Objects, Mutations, and State
- 8. Finish the Cup: Instances and Classes
- 9. Recipes with Instances and Classes
- 10. Sequence
-
11. New Ideas
- How Prototypes and Constructors differ from Classes
- New-Agnostic Constructors
- Another New-Agnostic Constructor Pattern
- Mixins
- Class Decorators
- Interlude: Tortoises, Hares, and Teleporting Turtles
- Functional Iterators
- Refactoring to Functional Iterators
- A Drunken Walk Across A Chequerboard
- Trampolining
- 12. Recipes for New Ideas
- The Golden Crema
A Pull of the Lever: Prefaces
“Café Allongé, also called Espresso Lungo, is a drink midway between an Espresso and Americano in strength. There are two different ways to make it. The first, and the one I prefer, is to add a small amount of hot water to a double or quadruple Espresso Ristretto. Like adding a splash of water to whiskey, the small dilution releases more of the complex flavours in the mouth.
“The second way is to pull an extra long double shot of Espresso. This achieves approximately the same ratio of oils to water as the dilution method, but also releases a different mix of flavours due to the longer extraction. Some complain that the long pull is more bitter and detracts from the best character of the coffee, others feel it releases even more complexity.
“The important thing is that neither method of preparation should use so much water as to result in a sickly, pale ghost of Espresso. Moderation in all things.”
Foreword by Michael Fogus
As a life-long bibliophile and long-time follower of Reg’s online work, I was excited when he started writing books. However, I’m very conservative about books – let’s just say that if there was an aftershave scented to the essence of “Used Book Store” then I would be first in line to buy. So as you might imagine I was “skeptical” about the decision to release JavaScript Allongé as an ongoing ebook, with a pay-what-you-want model. However, Reg sent me a copy of his book and I was humbled. Not only was this a great book, but it was also a great way to write and distribute books. Having written books myself, I know the pain of soliciting and receiving feedback.
The act of writing is an iterative process with (very often) tight revision loops. However, the process of soliciting feedback, gathering responses, sending out copies, waiting for people to actually read it (if they ever do), receiving feedback and then ultimately making sense out of how to use it takes weeks and sometimes months. On more than one occasion I’ve found myself attempting to reify feedback with content that either no longer existed or was changed beyond recognition. However, with the Leanpub model the read-feedback-change process is extremely efficient, leaving in its wake a quality book that continues to get better as others likewise read and comment into infinitude.
In the case of JavaScript Allongé, you’ll find the Leanpub model a shining example of effectiveness. Reg has crafted (and continues to craft) not only an interesting book from the perspective of a connoisseur, but also an entertaining exploration into some of the most interesting aspects of his art. No matter how much of an expert you think you are, JavaScript Allongé has something to teach you… about coffee. I kid.
As a staunch advocate of functional programming, much of what Reg has written rings true to me. While not exclusively a book about functional programming, JavaScript Allongé will provide a solid foundation for functional techniques. However, you’ll not be beaten about the head and neck with dogma. Instead, every section is motivated by relevant dialog and fortified with compelling source examples. As an author of programming books I admire what Reg has managed to accomplish and I envy the fine reader who finds JavaScript Allongé via some darkened channel in the Internet sprawl and reads it for the first time.
Enjoy.
– Fogus, fogus.me
Foreword by Matthew Knox
A different kind of language requires a different kind of book.
JavaScript holds surprising depths–its scoping rules are neither strictly lexical nor strictly dynamic, and it supports procedural, object-oriented (in several flavors!), and functional programming. Many books try to hide most of those capabilities away, giving you recipes for writing JavaScript in a way that approximates class-centric programming in other languages. Not JavaScript Allongé. It starts with the fundamentals of values, functions, and objects, and then guides you through JavaScript from the inside with exploratory bits of code that illustrate scoping, combinators, context, state, prototypes, and constructors.
Like JavaScript itself, this book gives you a gentle start before showing you its full depth, and like a Cafe Allongé, it’s over too soon. Enjoy!
–Matthew Knox, mattknox.com
Why JavaScript Allongé?
JavaScript Allongé solves two important problems for the ambitious JavaScript programmer. First, JavaScript Allongé gives you the tools to deal with JavaScript bugs, hitches, edge cases, and other potential pitfalls.
There are plenty of good directions for how to write JavaScript programs. If you follow them without alteration or deviation, you will be satisfied. Unfortunately, software is a complex thing, full of interactions and side-effects. Two perfectly reasonable pieces of advice when taken separately may conflict with each other when taken together. An approach may seem sound at the outset of a project, but need to be revised when new requirements are discovered.
When you “leave the path” of the directions, you discover their limitations. In order to solve the problems that occur at the edges, in order to adapt and deal with changes, in order to refactor and rewrite as needed, you need to understand the underlying principles of the JavaScript programming language in detail.
You need to understand why the directions work so that you can understand how to modify them to work properly at or beyond their original limitations. That’s where JavaScript Allongé comes in.
JavaScript Allongé is a book about programming with functions, because JavaScript is a programming language built on flexible and powerful functions. JavaScript Allongé begins at the beginning, with values and expressions, and builds from there to discuss types, identity, functions, closures, scopes, and many more subjects up to working with classes and instances. In each case, JavaScript Allongé takes care to explain exactly how things work so that when you encounter a problem, you’ll know exactly what is happening and how to fix it.
Second, JavaScript Allongé provides recipes for using functions to write software that is simpler, cleaner, and less complicated than alternative approaches that are object-centric or code-centric. JavaScript idioms like function combinators and decorators leverage JavaScript’s power to make code easier to read, modify, debug and refactor, thus avoiding problems before they happen.
JavaScript Allongé teaches you how to handle complex code, and it also teaches you how to simplify code without dumbing it down. As a result, JavaScript Allongé is a rich read releasing many of JavaScript’s subtleties, much like the Café Allongé beloved by coffee enthusiasts everywhere.
how the book is organized
JavaScript Allongé introduces new aspects of programming with functions in each chapter, explaining exactly how JavaScript works. Code examples within each chapter are small and emphasize exposition rather than serving as patterns for everyday use.
Following each chapter are a series of recipes designed to show the application of the chapters ideas in practical form. While the content of each chapter builds naturally on what was discussed in the previous chapter, the recipes may draw upon any aspect of the JavaScript programming language.
A Personal Word About The Recipes
As noted, JavaScript Allongé alternates between chapters describing the semantics of JavaScript’s functions with chapters containing recipes for writing programs with functions. You can read the book in order or read the chapters explaining JavaScript first and return to the recipes later.
The recipes share a common theme: They hail from a style of programming inspired by the creation of small functions that compose with each other. Using these recipes, you’ll learn when it’s appropriate to write:
Instead of:
As well as how it works and how to refactor it when you need. This style of programming is hardly the most common thing anyone does in JavaScript, so the argument can be made that more “practical” or “commonplace” recipes would be helpful. If you never read any other books about JavaScript, if you avoid blog posts and screen casts about JavaScript, if you don’t attend workshops or talks about JavaScript, then I agree that this is not One Book to Rule Them All.
But given that there are other resources out there, and that programmers are curious creatures with an unslakable thirst for personal growth, we choose to provide recipes that you are unlikely to find anywhere else in anything like this concentration. The recipes reinforce the lessons taught in the book about functions in JavaScript.
You’ll find all of the recipes collected online at http://allong.es. They’re free to share under the MIT license.
Reginald Braithwaite
reg@braythwayt.com
@raganwald
Legend
Some text in monospaced type like this
in the text represents some code being discussed. Some monospaced code in its own lines also represents code being discussed:
Sometimes it will contain some code for you to type in for yourself. When it does, the result of typing something in will often be shown using //=>
, like this:
JavaScript Allongé, the “Six” Edition
This is the original version of JavaScript Allongé. It was written for ECMAScript-5. The overarching theme of the book and approach to programming is as valid today as it was when ECMAScript-5 was the standard for JavaScript, however the details of how best to implement these ideas have changed.
For example, in ECMAScript-5, we write:
But in ECMAScript-2015, we write:
Other changes include the introduction of the class
keyword, which leads to a greater interest in working with objects, prototypes, and functions.
For this reason, this original manuscript has been retired, and a substantially updated edition, JavaScript Allongé, the “Six” Edition has been written. Please enjoy this copy, but be sure to read the latest edition.
Prelude: Values and Expressions
The following material is extremely basic, however like most stories, the best way to begin is to start at the very beginning.
Imagine we are visiting our favourite coffee shop. They will make for you just about any drink you desire, from a short, intense espresso ristretto through a dry cappuccino, up to those coffee-flavoured desert concoctions featuring various concentrated syrups and milks. (You tolerate the existence of sugary drinks because they provide a sufficient profit margin to the establishment to finance your hanging out there all day using their WiFi and ordering a $3 drink every few hours.)
You express your order at one end of their counter, the folks behind the counter perform their magic, and deliver the coffee you value at the other end. This is exactly how the JavaScript environment works for the purpose of this book. We are going to dispense with web servers, browsers and other complexities and deal with this simple model: You give the computer an expression, and it returns a value, just as you express your wishes to a barista and receive a coffee in return.
values and expressions
All values are expressions. Say you hand the barista a café Cubano. Yup, you hand over a cup with some coffee infused through partially caramelized sugar. You say, “I want one of these.” The barista is no fool, she gives it straight back to you, and you get exactly what you want. Thus, a café Cubano is an expression (you can use it to place an order) and a value (you get it back from the barista).
Let’s try this with something the computer understands easily:
Is this an expression? A value? Neither? Or both?
The answer is, this is both an expression and a value.1 The way you can tell that it’s both is very easy: When you type it into JavaScript, you get the same thing back, just like our café Cubano:
All values are expressions. That’s easy! Are there any other kinds of expressions? Sure! let’s go back to the coffee shop. Instead of handing over the finished coffee, we can hand over the ingredients. Let’s hand over some ground coffee plus some boiling water.
Now the barista gives us back an espresso. And if we hand over the espresso, we get the espresso right back. So, boiling water plus ground coffee is an expression, but it isn’t a value.2 Boiling water is a value. Ground coffee is a value. Espresso is a value. Boiling water plus ground coffee is an expression.
Let’s try this as well with something else the computer understands easily:
Now we see that “strings” are values, and you can make an expression out of strings and an operator +
. Since strings are values, they are also expressions by themselves. But strings with operators are not values, they are expressions. Now we know what was missing with our “coffee grounds plus hot water” example. The coffee grounds were a value, the boiling hot water was a value, and the “plus” operator between them made the whole thing an expression that was not a value.
values and identity
In JavaScript, we test whether two values are identical with the ===
operator, and whether they are not identical with the !==
operator:
How does ===
work, exactly? Imagine that you’re shown a cup of coffee. And then you’re shown another cup of coffee. Are the two cups “identical?” In JavaScript, there are four possibilities:
First, sometimes, the cups are of different kinds. One is a demitasse, the other a mug. This corresponds to comparing two things in JavaScript that have different types. For example, the string "2"
is not the same thing as the number 2
. Strings and numbers are different types, so strings and numbers are never identical:
Second, sometimes, the cups are of the same type–perhaps two espresso cups–but they have different contents. One holds a single, one a double. This corresponds to comparing two JavaScript values that have the same type but different “content.” For example, the number 5
is not the same thing as the number 2
.
What if the cups are of the same type and the contents are the same? Well, JavaScript’s third and fourth possibilities cover that.
value types
Third, some types of cups have no distinguishing marks on them. If they are the same kind of cup, and they hold the same contents, we have no way to tell the difference between them. This is the case with the strings, numbers, and booleans we have seen so far.
Note well what is happening with these examples: Even when we obtain a string, number, or boolean as the result of evaluating an expression, it is identical to another value of the same type with the same “content.” Strings, numbers, and booleans are examples of what JavaScript calls “value” or “primitive” types. We’ll use both terms interchangeably.
We haven’t encountered the fourth possibility yet. Stretching the metaphor somewhat, some types of cups have a serial number on the bottom. So even if you have two cups of the same type, and their contents are the same, you can still distinguish between them.
reference types
So what kinds of values might be the same type and have the same contents, but not be considered identical to JavaScript? Let’s meet a data structure that is very common in contemporary programming languages, the Array (other languages sometimes call it a List or a Vector).
An array looks like this: [1, 2, 3]
. This is an expression, and you can combine []
with other expressions. Go wild with things like:
Notice that you are always generating arrays with the same contents. But are they identical the same way that every value of 42
is identical to every other value of 42
? Try these for yourself:
How about that! When you type [1, 2, 3]
or any of its variations, you are typing an expression that generates its own unique array that is not identical to any other array, even if that other array also looks like [1, 2, 3]
. It’s as if JavaScript is generating new cups of coffee with serial numbers on the bottom.
They look the same, but if you examine them with ===
, you see that they are different. Every time you evaluate an expression (including typing something in) to create an array, you’re creating a new, distinct value even if it appears to be the same as some other array value. As we’ll see, this is true of many other kinds of values, including functions, the main subject of this book.
- Technically, it’s a representation of a value using Base10 notation, but we needn’t worry about that in this book. You and I both understand that this means “42,” and so does the computer.↩
- In some languages, expressions are a kind of value unto themselves and can be manipulated. The grandfather of such languages is Lisp. JavaScript is not such a language, expressions in and of themselves are not values.↩
1. The first sip: Basic Functions
As Little As Possible About Functions, But No Less
In JavaScript, functions are values, but they are also much more than simple numbers, strings, or even complex data structures like trees or maps. Functions represent computations to be performed. Like numbers, strings, and arrays, they have a representation. Let’s start with the very simplest possible function. In JavaScript, it looks like this:
This is a function that is applied to no values and produces no value. How do we represent “no value” in JavaScript? We’ll find out in a minute. First, let’s verify that our function is a value:
What!? Why didn’t it type back function () {}
for us? This seems to break our rule that if an expression is also a value, JavaScript will give the same value back to us. What’s going on? The simplest and easiest answer is that although the JavaScript interpreter does indeed return that value, displaying it on the screen is a slightly different matter. [Function]
is a choice made by the people who wrote Node.js, the JavaScript environment that hosts the JavaScript REPL. If you try the same thing in a browser, you’ll see the code you typed.
functions and identities
You recall that we have two types of values with respect to identity: Value types and reference types. Value types share the same identity if they have the same contents.Reference types do not.
Which kind are functions? Let’s try it. For reasons of appeasing the JavaScript parser, we’ll enclose our functions in parentheses:
Like arrays, every time you evaluate an expression to produce a function, you get a new function that is not identical to any other function, even if you use the same expression to generate it. “Function” is a reference type.
applying functions
Let’s put functions to work. The way we use functions is to apply them to zero or more values called arguments. Just as 2 + 2
produces a value (in this case 4
), applying a function to zero or more arguments produces a value as well.
Here’s how we apply a function to some values in JavaScript: Let’s say that fn_expr is an expression that when evaluated, produces a function. Let’s call the arguments args. Here’s how to apply a function to some arguments:
fn_expr(
args)
Right now, we only know about one such expression: function () {}
, so let’s use it. We’ll put it in parentheses1 to keep the parser happy, like we did above: (function () {})
. Since we aren’t giving it any arguments, we’ll simply write ()
after the expression. So we write:
What is this undefined
?
undefined
In JavaScript, the absence of a value is written undefined
, and it means there is no value. It will crop up again. undefined
is its own type of value, and it acts like a value type:
Like numbers, booleans and strings, JavaScript can print out the value undefined
.
No matter how you evaluate undefined
, you get an identical value back. undefined
is a value that means “I don’t have a value.” But it’s still a value :-)
void
We’ve seen that JavaScript represents an undefined value by typing undefined
, and we’ve generated undefined values in two ways:
- By evaluating a function that doesn’t return a value
(function () {})()
, and; - By writing
undefined
ourselves.
There’s a third way, with JavaScript’s void
operator. Behold:
void
is an operator that takes any value and evaluates to undefined
, always. So, when we deliberately want an undefined value, should we use the first, second, or third form?2 The answer is, use void
. By convention, use void 0
.
The first form works but it’s cumbersome. The second form works most of the time, but it is possible to break it by reassigning undefined
to a different value, something we’ll discuss in Reassignment and Mutation. The third form is guaranteed to always work, so that’s what we will use.3
functions with no arguments and their bodies
Back to our function. We evaluated this:
Let’s recall that we were applying the function function () {}
to no arguments (because there was nothing inside of ()
). So how do we know to expect undefined
? That’s easy:
When we define a function4, we write the word function
. We then put a (possibly empty) list of arguments, then we give the function a body that is enclosed in braces {...}
. Function bodies are (possibly empty) lists of JavaScript statements separated by semicolons.
Something like: { statement1; statement2; statement3; … ; statementn }
We haven’t discussed these statements. What’s a statement?
There are many kinds of JavaScript statements, but the first kind is one we’ve already met. An expression is a JavaScript statement. Although they aren’t very practical, the following are all valid JavaScript functions, and they all evaluate to undefined when applied:
You can also separate statements with line breaks.5 The convention is to use some form of consistent indenting:
That last one’s a doozy, but since a function body can contain a statement, and a statement can be an expression, and a function is an expression…. You get the idea.
So how do we get a function to return a value when applied? With the return
keyword and any expression:
The return
keyword creates a return statement that immediately terminates the function application and returns the result of evaluating its expression.
functions that evaluate to functions
If an expression that evaluates to a function is, well, an expression, and if a return statement can have any expression on its right side… Can we put an expression that evaluates to a function on the right side of a function expression?
Yes:
That’s a function! It’s a function that when applied, evaluates to a function that when applied, evaluates to undefined
.6 Let’s use a simpler terminology. Instead of saying “that when applied, evaluates to _____,” we will say “gives _____.” And instead of saying “gives undefined,” we’ll say “doesn’t give anything.”
So we have a function, that gives a function, that doesn’t give anything. Likewise:
That’s a function, that gives a function, that gives true
:
Well. We’ve been very clever, but so far this all seems very abstract. Diffraction of a crystal is beautiful and interesting in its own right, but you can’t blame us for wanting to be shown a practical use for it, like being able to determine the composition of a star millions of light years away. So… In the next chapter, “I’d Like to Have an Argument, Please,” we’ll see how to make functions practical.
Ah. I’d Like to Have an Argument, Please.
Up to now, we’ve looked at functions without arguments. We haven’t even said what an argument is, only that our functions don’t have any.
Let’s make a function with an argument:
This function has one argument, room
, and no body. Here’s a function with two arguments and no body:
I’m sure you are perfectly comfortable with the idea that this function has two arguments, room
, and board
. What does one do with the arguments? Use them in the body, of course. What do you think this is?
It’s a function for calculating the circumference of a circle given the diameter. I read that aloud as “When applied to a value representing the diameter, this function returns the diameter times 3.14159265.”
Remember that to apply a function with no arguments, we wrote (function () {})()
. To apply a function with an argument (or arguments), we put the argument (or arguments) within the parentheses, like this:
You won’t be surprised to see how to write and apply a function to two arguments:
call by value
Like most contemporary programming languages, JavaScript uses the “call by value” evaluation strategy. That means that when you write some code that appears to apply a function to an expression or expressions, JavaScript evaluates all of those expressions and applies the functions to the resulting value(s).
So when you write:
What happened internally is that the expression 1 + 1
was evaluated first, resulting in 2
. Then our circumference function was applied to 2
.8
variables and bindings
Right now everything looks simple and straightforward, and we can move on to talk about arguments in more detail. And we’re going to work our way up from function (diameter) { return diameter * 3.14159265 }
to functions like:
In order to talk about how this works, we should agree on a few terms (you may already know them, but let’s check-in together and “synchronize our dictionaries”). The first x
, the one in function (x) ...
, is an argument. The y
in function (y) ...
is another argument. The second x
, the one in { return x }
, is not an argument, it’s an expression referring to a variable. Arguments and variables work the same way whether we’re talking about function (x) { return (function (y) { return x }) }
or just plain function (x) { return x }
.
Every time a function is invoked (“invoked” means “applied to zero or more arguments”), a new environment is created. An environment is a (possibly empty) dictionary that maps variables to values by name. The x
in the expression that we call a “variable” is itself an expression that is evaluated by looking up the value in the environment.
How does the value get put in the environment? Well for arguments, that is very simple. When you apply the function to the arguments, an entry is placed in the dictionary for each argument. So when we write:
What happens is this:
- JavaScript parses this whole thing as an expression made up of several sub-expressions.
- It then starts evaluating the expression, including evaluating sub-expressions
- One sub-expression,
function (x) { return x }
evaluates to a function. - Another,
2
, evaluates to the number 2. - JavaScript now evaluates applying the function to the argument
2
. Here’s where it gets interesting… - An environment is created.
- The value ‘2’ is bound to the name ‘x’ in the environment.
- The expression ‘x’ (the right side of the function) is evaluated within the environment we just created.
- The value of a variable when evaluated in an environment is the value bound to the variable’s name in that environment, which is ‘2’
- And that’s our result.
When we talk about environments, we’ll use an unsurprising syntax for showing their bindings: {x: 2, ...}
. meaning, that the environment is a dictionary, and that the value 2
is bound to the name x
, and that there might be other stuff in that dictionary we aren’t discussing right now.
call by sharing
Earlier, we distinguished JavaScript’s value types from its reference types. At that time, we looked at how JavaScript distinguishes objects that are identical from objects that are not. Now it is time to take another look at the distinction between value and reference types.
There is a property that JavaScript strictly maintains: When a value–any value–is passed as an argument to a function, the value bound in the function’s environment must be identical to the original.
We said that JavaScript binds names to values, but we didn’t say what it means to bind a name to a value. Now we can elaborate: When JavaScript binds a value-type to a name, it makes a copy of the value and places the copy in the environment. As you recall, value types like strings and numbers are identical to each other if they have the same content. So JavaScript can make as many copies of strings, numbers, or booleans as it wishes.
What about reference types? JavaScript does not place copies of reference values in any environment. JavaScript places references to reference types in environments, and when the value needs to be used, JavaScript uses the reference to obtain the original.
Because many references can share the same value, and because JavaScript passes references as arguments, JavaScript can be said to implement “call by sharing” semantics. Call by sharing is generally understood to be a specialization of call by value, and it explains why some values are known as value types and other values are known as reference types.
And with that, we’re ready to look at closures. When we combine our knowledge of value types, reference types, arguments, and closures, we’ll understand why this function always evaluates to true
no matter what argument9 you apply it to:
Closures and Scope
It’s time to see how a function within a function works:
First off, let’s use what we learned above. Given (
some function)(
some argument)
, we know that we apply the function to the argument, create an environment, bind the value of the argument to the name, and evaluate the function’s expression. So we do that first with this code:
The environment belonging to the function with signature function (x) ...
becomes {x: 1, ...}
, and the result of applying the function is another function value. It makes sense that the result value is a function, because the expression for function (x) ...
’s body is:
So now we have a value representing that function. Then we’re going to take the value of that function and apply it to the argument 2
, something like this:
So we seem to get a new environment {y: 2, ...}
. How is the expression x
going to be evaluated in that function’s environment? There is no x
in its environment, it must come from somewhere else.
If functions without free variables are pure, are closures impure?
The function function (y) { return x }
is interesting. It contains a free variable, x
.10 A free variable is one that is not bound within the function. Up to now, we’ve only seen one way to “bind” a variable, namely by passing in an argument with the same name. Since the function function (y) { return x }
doesn’t have an argument named x
, the variable x
isn’t bound in this function, which makes it “free.”
Now that we know that variables used in a function are either bound or free, we can bifurcate functions into those with free variables and those without:
- Functions containing no free variables are called pure functions.
- Functions containing one or more free variables are called closures.
Pure functions are easiest to understand. They always mean the same thing wherever you use them. Here are some pure functions we’ve already seen:
The first function doesn’t have any variables, therefore doesn’t have any free variables. The second doesn’t have any free variables, because its only variable is bound. The third one is actually two functions, one inside the other. function (y) ...
has a free variable, but the entire expression refers to function (x) ...
, and it doesn’t have a free variable: The only variable anywhere in its body is x
, which is certainly bound within function (x) ...
.
From this, we learn something: A pure function can contain a closure.
Pure functions always mean the same thing because all of their “inputs” are fully defined by their arguments. Not so with a closure. If I present to you this pure function function (x, y) { return x + y }
, we know exactly what it does with (2, 2)
. But what about this closure: function (y) { return x + y }
? We can’t say what it will do with argument (2)
without understanding the magic for evaluating the free variable x
.
it’s always the environment
To understand how closures are evaluated, we need to revisit environments. As we’ve said before, all functions are associated with an environment. We also hand-waved something when describing our environment. Remember that we said the environment for (function (x) { return (function (y) { return x }) })(1)
is {x: 1, ...}
and that the environment for (function (y) { return x })(2)
is {y: 2, ...}
? Let’s fill in the blanks!
The environment for (function (y) { return x })(2)
is actually {y: 2, '..': {x: 1, ...}}
. '..'
means something like “parent” or “enclosure” or “super-environment.” It’s function (x) ...
’s environment, because the function function (y) { return x }
is within function (x) ...
’s body. So whenever a function is applied to arguments, its environment always has a reference to its parent environment.
And now you can guess how we evaluate (function (y) { return x })(2)
in the environment {y: 2, '..': {x: 1, ...}}
. The variable x
isn’t in function (y) ...
’s immediate environment, but it is in its parent’s environment, so it evaluates to 1
and that’s what (function (y) { return x })(2)
returns even though it ended up ignoring its own argument.
Functions can have grandparents too:
This function does much the same thing as:
Only you call it with (1)(2)(3)
instead of (1, 2, 3)
. The other big difference is that you can call it with (1)
and get a function back that you can later call with (2)(3)
.
shadowy variables from a shadowy planet
An interesting thing happens when a variable has the same name as an ancestor environment’s variable. Consider:
The function function (x, y) { return x + y }
is a pure function, because its x
is defined within its own environment. Although its parent also defines an x
, it is ignored when evaluating x + y
. JavaScript always searches for a binding starting with the functions own environment and then each parent in turn until it finds one. The same is true of:
When evaluating x + y + z
, JavaScript will find x
and y
in the great-grandparent scope and z
in the parent scope. The x
in the great-great-grandparent scope is ignored, as are both w
s. When a variable has the same name as an ancestor environment’s binding, it is said to shadow the ancestor.
This is often a good thing.
which came first, the chicken or the egg?
This behaviour of pure functions and closures has many, many consequences that can be exploited to write software. We are going to explore them in some detail as well as look at some of the other mechanisms JavaScript provides for working with variables and mutable state.
But before we do so, there’s one final question: Where does the ancestry start? If there’s no other code in a file, what is function (x) { return x }
’s parent environment?
JavaScript always has the notion of at least one environment we do not control: A global environment in which many useful things are bound such as libraries full of standard functions. So when you invoke (function (x) { return x })(1)
in the REPL, its full environment is going to look like this: {x: 1, '..':
global environment}
.
Sometimes, programmers wish to avoid this. If you don’t want your code to operate directly within the global environment, what can you do? Create an environment for them, of course. Many programmers choose to write every JavaScript file like this:
The effect is to insert a new, empty environment in between the global environment and your own functions: {x: 1, '..': {'..':
global environment}}
. As we’ll see when we discuss mutable state, this helps to prevent programmers from accidentally changing the global state that is shared by code in every file when they use the var keyword properly.
Let’s Talk Var
Up to now, all we’ve really seen are anonymous functions, functions that don’t have a name. This feels very different from programming in most other languages, where the focus is on naming functions, methods, and procedures. Naming things is a critical part of programming, but all we’ve seen so far is how to name arguments.
There are other ways to name things in JavaScript, but before we learn some of those, let’s see how to use what we already have to name things. Let’s revisit a very simple example:
What is this “3.14159265” number? Pi, obviously. We’d like to name it so that we can write something like:
In order to bind 3.14159265
to the name Pi
, we’ll need a function with a parameter of Pi
applied to an argument of 3.14159265
. If we put our function expression in parentheses, we can apply it to the argument of 3.14159265
:
What do we put inside our new function that binds 3.14159265
to the name Pi
when evaluated? Our circumference function, of course:
This expression, when evaluated, returns a function that calculates circumferences. It differs from our original in that it names the constant Pi
. Let’s test it:
That works! We can bind anything we want in an expression by wrapping it in a function that is immediately invoked with the value we want to bind.
immediately invoked function expressions
JavaScript programmers regularly use the idea of writing an expression that denotes a function and then immediately applying it to arguments. Explaining the pattern, Ben Alman coined the term Immediately Invoked Function Expression for it, often abbreviated “IIFE.” As we’ll see in a moment, an IIFE need not have parameters:
When an IIFE binds values to names (as we did above with Pi
), retro-grouch programmers often call it “let.”11 And confusing the issue, upcoming versions of JavaScript have support for a let
keyword that has a similar binding behaviour.
var
Using an IIFE to bind names works very well, but only a masochist would write programs this way in JavaScript. Besides all the extra characters, it suffers from a fundamental semantic problem: there is a big visual distance between the name Pi
and the value 3.14159265
we bind to it. They should be closer. Is there another way?
Yes.
Another way to write our “circumference” function would be to pass Pi
along with the diameter argument, something like this:
And you could use it like this:
This differs from our example above in that there is only one environment, rather than two. We have one binding in the environment representing our regular argument, and another our “constant.” That’s more efficient, and it’s almost what we wanted all along: A way to bind 3.14159265
to a readable name.
JavaScript gives us a way to do that, the var
keyword. We’ll learn a lot more about var
in future chapters, but here’s the most important thing you can do with var
:
The var
keyword introduces one or more bindings in the current function’s environment. It works just as we want:
You can bind any expression. Functions are expressions, so you can bind helper functions:
Notice calc(d)
? This underscores what we’ve said: if you have an expression that evaluates to a function, you apply it with ()
. A name that’s bound to a function is a valid expression evaluating to a function.12
You can bind more than one name-value pair by separating them with commas. For readability, most people put one binding per line:
These examples use the var
keyword to bind names in the same environment as our function. We can also create a new scope using an IIFE if we wish to bind some names in part of a function:
Naming Functions
Let’s get right to it. This code does not name a function:
It doesn’t name the function “repeat” for the same reason that var answer = 42
doesn’t name the number 42
. That snippet of code binds an anonymous function to a name in an environment, but the function itself remains anonymous.
JavaScript does have a syntax for naming a function, it looks like this:
In this expression, bindingName
is the name in the environment, but actualName
is the function’s actual name. This is a named function expression. That may seem confusing, but think of the binding names as properties of the environment, not the function itself. And indeed the name is a property:
In this book we are not examining JavaScript’s tooling such as debuggers baked into browsers, but we will note that when you are navigating call stacks in all modern tools, the function’s binding name is ignored but its actual name is displayed, so naming functions is very useful even if they don’t get a formal binding, e.g.
Now, the function’s actual name has no effect on the environment in which it is used. To whit:
So “actualName” isn’t bound in the environment where we use the named function expression. Is it bound anywhere else? Yes it is:
even
is bound within the function itself, but not outside it. This is useful for making recursive functions.
function declarations
We’ve actually buried the lede.13 Naming functions for the purpose of debugging is not as important as what we’re about to discuss. There is another syntax for naming and/or defining a function. It’s called a function declaration, and it looks like this:
This behaves a little like:
In that it binds a name in the environment to a named function. However, consider this piece of code:
This is what we expect given what we learned about var: Although someName
is declared later in the function, JavaScript behaves as if you’d written:
What about a function declaration without var
?
Aha! It works differently, as if you’d written:
That difference is intentional on the part of JavaScript’s design to facilitate a certain style of programming where you put the main logic up front, and the “helper functions” at the bottom. It is not necessary to declare functions in this way in JavaScript, but understanding the syntax and its behaviour (especially the way it differs from var
) is essential for working with production code.
function declaration caveats14
Function declarations are formally only supposed to be made at what we might call the “top level” of a function. Although some JavaScript environments may permit it, this example is technically illegal and definitely a bad idea:
The big trouble with expressions like this is that they may work just fine in your test environment but work a different way in production. Or it may work one way today and a different way when the JavaScript engine is updated, say with a new optimization.
Another caveat is that a function declaration cannot exist inside of any expression, otherwise it’s a function expression. So this is a function declaration:
But this is not:
The parentheses make this an expression.
Combinators and Function Decorators
higher-order functions
As we’ve seen, JavaScript functions take values as arguments and return values. JavaScript functions are values, so JavaScript functions can take functions as arguments, return functions, or both. Generally speaking, a function that either takes functions as arguments or returns a function (or both) is referred to as a “higher-order” function.
Here’s a very simple higher-order function that takes a function as an argument:
Higher-order functions dominate JavaScript Allongé. But before we go on, we’ll talk about some specific types of higher-order functions.
combinators
The word “combinator” has a precise technical meaning in mathematics:
“A combinator is a higher-order function that uses only function application and earlier defined combinators to define a result from its arguments.”–Wikipedia
If we were learning Combinatorial Logic, we’d start with the most basic combinators like S
, K
, and I
, and work up from there to practical combinators. We’d learn that the fundamental combinators are named after birds following the example of Raymond Smullyan’s famous book To Mock a Mockingbird.
In this book, we will be using a looser definition of “combinator:” Higher-order pure functions that take only functions as arguments and return a function. We won’t be strict about using only previously defined combinators in their construction.
Let’s start with a useful combinator: Most programmers call it Compose, although the logicians call it the B combinator or “Bluebird.” Here is the typical15 programming implementation:
Let’s say we have:
With compose
, anywhere you would write
You could also write:
This is, of course, just one example of many. You’ll find lots more perusing the recipes in this book. While some programmers believe “There Should Only Be One Way To Do It,” having combinators available as well as explicitly writing things out with lots of symbols and keywords has some advantages when used judiciously.
a balanced statement about combinators
Code that uses a lot of combinators tends to name the verbs and adverbs (like doubleOf
, addOne
, and compose
) while avoiding language keywords and the names of nouns (like number
). So one perspective is that combinators are useful when you want to emphasize what you’re doing and how it fits together, and more explicit code is useful when you want to emphasize what you’re working with.
function decorators
A function decorator is a higher-order function that takes one function as an argument, returns another function, and the returned function is a variation of the argument function. Here’s a ridiculous example of a decorator:
So instead of writing !someFunction(42)
, you can write not(someFunction)(42)
. Hardly progress. But like for compose
, if you have:
Then you could write either:
Or:
not
is a function decorator because it modifies a function while remaining strongly related to the original function’s semantics. You’ll see other function decorators in the recipes, like once, mapWith, and maybe. Function decorators aren’t strict about being pure functions, so there’s more latitude for making decorators than combinators.
Building Blocks
When you look at functions within functions in JavaScript, there’s a bit of a “spaghetti code” look to it. The strength of JavaScript is that you can do anything. The weakness is that you will. There are ifs, fors, returns, everything thrown higgledy piggledy together. Although you needn’t restrict yourself to a small number of simple patterns, it can be helpful to understand the patterns so that you can structure your code around some basic building blocks.
composition
One of the most basic of these building blocks is composition:
It’s really that simple: Whenever you are chaining two or more functions together, you’re composing them. You can compose them with explicit JavaScript code as we’ve just done. You can also generalize composition with the B Combinator or “compose” that we saw in Combinators and Decorators:
If that was all there was to it, composition wouldn’t matter much. But like many patterns, using it when it applies is only 20% of the benefit. The other 80% comes from organizing your code such that you can use it: Writing functions that can be composed in various ways.
In the recipes, we’ll look at a decorator called once: It ensures that a function can only be executed once. Thereafter, it does nothing. Once is useful for ensuring that certain side effects are not repeated. We’ll also look at maybe: It ensures that a function does nothing if it is given nothing (like null
or undefined
) as an argument.
Of course, you needn’t use combinators to implement either of these ideas, you can use if statements. But once
and maybe
compose, so you can chain them together as you see fit:
partial application
Another basic building block is partial application. When a function takes multiple arguments, we “apply” the function to the arguments by evaluating it with all of the arguments, producing a value. But what if we only supply some of the arguments? In that case, we can’t get the final value, but we can get a function that represents part of our application.
Code is easier than words for this. The Underscore library provides a higher-order function called map.16 It applies another function to each element of an array, like this:
This code implements a partial application of the map function by applying the function function (n) { return n * n }
as its second argument:
The resulting function–squareAll
–is still the map function, it’s just that we’ve applied one of its two arguments already. squareAll
is nice, but why write one function every time we want to partially apply a function to a map? We can abstract this one level higher. mapWith
takes any function as an argument and returns a partially applied map function.
We’ll discuss mapWith again in the recipes. The important thing to see is that partial application is orthogonal to composition, and that they both work together nicely:
We generalized composition with the compose
combinator. Partial application also has a combinator, which we’ll see in the partial recipe.
I’d Like to Have Some Arguments. Again.
As we’ve discussed, when a function is applied to arguments (or “called”), JavaScript binds the values of the arguments to the function’s argument names in an environment created for the function’s execution. What we didn’t discuss is that JavaScript also binds some “magic” names in addition to any you put in the argument list.
You should never attempt to define your own bindings against these names. Consider them read-only at all times. The first is called this
and it is bound to something called the function’s context. We will explore that when we start discussing objects and classes. The second is very interesting, it’s called arguments
, and the most interesting thing about it is that it contains a list of arguments passed to the function:
Although arguments
looks like an array, it isn’t an array:17 It’s more like an object18 that happens to bind some values to properties with names that look like integers starting with zero:
arguments
always contains all of the arguments passed to a function, regardless of how many are declared. Therefore, we can write plus
like this:
When discussing objects, we’ll discuss properties in more depth. Here’s something interesting about arguments
:
The most common use of the arguments
binding is to build functions that can take a variable number of arguments. We’ll see it used in many of the recipes, starting off with partial application and ellipses.
Summary
- If you’re used to other programming languages, you’ve probably internalized the idea that sometimes parentheses are used to group operations in an expression like math, and sometimes to apply a function to arguments. If not… Welcome to the ALGOL family of programming languages!↩
- Experienced JavaScript programmers are aware that there’s a fourth way, using a function argument. This was actually the preferred mechanism until
void
became commonplace.↩ - As an exercise for the reader, we suggest you ask your friendly neighbourhood programming language designer or human factors subject-matter expert to explain why a keyword called
void
is used to generate anundefined
value, instead of calling them bothvoid
or bothundefined
. We have no idea.↩ - TODO: Named functions, probably discussed in a whole new section when we discuss
var
hoisting.↩ - Readers who follow internet flame-fests may be aware of something called automatic semi-colon insertion. Basically, there’s a step where JavaScript looks at your code and follows some rules to guess where you meant to put semicolons in should you leave them out. This feature was originally created as a kind of helpful error-correction. Some programmers argue that since it’s part of the language’s definition, it’s fair game to write code that exploits it, so they deliberately omit any semicolon that JavaScript will insert for them.↩
- What a mouthful! This is why other languages with a strong emphasis on functions come up with syntaxes like ` -> -> undefined`↩
- The Argument Sketch from “Monty Python’s Previous Record” and “Monty Python’s Instant Record Collection”↩
- We said that you can’t apply a function to an expression. You can apply a function to one or more functions. Functions are values! This has interesting applications, and they will be explored much more thoroughly in Functions That Are Applied to Functions.↩
- Unless the argument is NaN, which isn’t equal to anything, including itself↩
- You may also hear the term “non-local variable.” Both are correct. ↩
- To be pedantic, both main branches of Lisp today define a special construct called “let.” One, Scheme, uses
define-syntax
to rewritelet
into an immediately invoked function expression that binds arguments to values as shown above. The other, Common Lisp, leaves it up to implementations to decide how to implementlet
.↩ - We’re into the second chapter and we’ve finally named a function. Sheesh.↩
- A lead (or lede) paragraph in literature refers to the opening paragraph of an article, essay, news story or book chapter. In journalism, the failure to mention the most important, interesting or attention-grabbing elements of a story in the first paragraph is sometimes called “burying the lede.”↩
- A number of the caveats discussed here were described in Jyrly Zaytsev’s excellent article Named function expressions demystified.↩
- As we’ll discuss later, this implementation of the B Combinator is correct in languages like Scheme, but for truly general-purpose use in JavaScript it needs to correctly manage the function context.↩
- Modern JavaScript implementations provide a map method for arrays, but Underscore’s implementation also works with older browsers if you are working with that headache.↩
- Tradition would have us call objects that don’t contain any functions “POJOs,” meaning Plain Old JavaScript Objects.
- Tradition would have us call objects that don’t contain any functions “POJOs,” meaning Plain Old JavaScript Objects.
2. The Recipe Cheat Sheet
In the recipes, you may see one or more of the following JavaScript constructs being used before being fully explained in the text. Here’re some brief explanations to tide you over:
apply and call
Functions are applied with ()
. But they also have methods for applying them to arguments. .call
and .apply
are explained when we discuss function contexts, but here are some examples:
slice
Arrays have a .slice
method. The function can always be found at Array.prototype.slice
. It works like this:
Note that slice
always creates a new array, so .slice(0)
makes a copy of an array. The arguments pseudo-variable is not an array, but you can use .slice
with it like this to get an array of all or some of the arguments:
For simplicity and as a small speed improvement, slice
is usually bound to a local variable:
Or even:
concat
Arrays have another useful method, .concat
. Concat returns an array created by concatenating the receiver with its argument:
function lengths
Functions have a .length
property that counts the number of arguments declared:
3. Recipes with Basic Functions
Having looked at basic pure functions and closures, we’re going to see some practical recipes that focus on the premise of functions that return functions.
Disclaimer
The recipes are written for practicality, and their implementation may introduce JavaScript features that haven’t been discussed in the text to this point, such as methods and/or prototypes. The overall use of each recipe will fit within the spirit of the language discussed so far, even if the implementations may not.
Partial Application
In Building Blocks, we discussed partial application, but we didn’t write a generalized recipe for it. This is such a common tool that many libraries provide some form of partial application tool. You’ll find examples in Lemonad from Michael Fogus, Functional JavaScript from Oliver Steele and the terse but handy node-ap from James Halliday.
These two recipes are for quickly and simply applying a single argument, either the leftmost or rightmost.1 If you want to bind more than one argument, or you want to leave a “hole” in the argument list, you will need to either use a generalized partial recipe, or you will need to repeatedly apply arguments. It is context-agnostic.
As noted above, our partial recipe allows us to create functions that are partial applications of functions that are context aware. We’d need a different recipe if we wish to create partial applications of object methods.
Ellipses and improved Partial Application
The CoffeeScript programming language has a useful feature: If a parameter of a method is written with trailing ellipses, it collects a list of parameters into an array. It can be used in various ways, and the CoffeeScript transpiler does some pattern matching to sort things out, but 80% of the use is to collect a variable number of arguments without using the arguments
pseudo-variable, and 19% of the uses are to collect a trailing list of arguments.
Here’s what it looks like collecting a variable number of arguments and trailing arguments:
These are very handy features. Here’s our bogus, made-up attempt to write our own mapper function:
JavaScript doesn’t support ellipses, those trailing periods CoffeeScript uses to collect arguments into an array. JavaScript is a functional language, so here is the recipe for a function that collects trailing arguments into an array for us:
Here’s what we write to create our partial application functions gently:
While we’re at it, here’s our implementation of callRight
using the same technique:
Fine print: Of course, variadic
introduces an extra function call and may not be the best choice in a highly performance-critical piece of code. Then again, using arguments
is considerably slower than directly accessing argument bindings, so if the performance is that critical, maybe you shouldn’t be using a variable number of arguments in that section.
Unary
In Ellipses, we saw a function decorator that takes a function with a fixed number of arguments and turns it into a variadic function, a function taking any number of arguments. “Unary” is another function decorator, and it also modifies the number of arguments a function takes: Unary takes any function and turns it into a function taking exactly one argument.
The most common use case is to fix a common problem. JavaScript has a .map
method for arrays, and many libraries offer a map
function with the same semantics. Here it is in action:
In that example, it looks exactly like the mapping function you’ll find in most languages: You pass it a function, and it calls the function with one argument, the element of the array. However, that’s not the whole story. JavaScript’s map
actually calls each function with three arguments: The element, the index of the element in the array, and the array itself.
Let’s try it:
If you pass in a function taking only one argument, it simply ignores the additional arguments. But some functions have optional second or even third arguments. For example:
This doesn’t work because parseInt
is defined as parseInt(string[, radix])
. It takes an optional radix argument. And when you call parseInt
with map
, the index is interpreted as a radix. Not good! What we want is to convert parseInt
into a function taking only one argument.
We could write ['1', '2', '3'].map(function (s) { return parseInt(s); })
, or we could come up with a decorator to do the job for us:
And now we can write:
Presto!
Tap
One of the most basic combinators is the “K Combinator,” nicknamed the “kestrel:”
It has some surprising applications. One is when you want to do something with a value for side-effects, but keep the value around. Behold:
tap
is a traditional name borrowed from various Unix shell commands. It takes a value and returns a function that always returns the value, but if you pass it a function, it executes the function for side-effects. Let’s see it in action as a poor-man’s debugger:
It’s easy to turn off:
Libraries like Underscore use a version of tap
that is “uncurried:”
Let’s enhance our recipe so it works both ways:
Now you can write:
Or:
And if you wish it to do nothing at all, You can write either:
Or:
tap
can do more than just act as a debugging aid. It’s also useful for working with object and instance methods.
Maybe
A common problem in programming is checking for null
or undefined
(hereafter called “nothing,” while all other values including 0
, []
and false
will be called “something”). Languages like JavaScript do not strongly enforce the notion that a particular variable or particular property be something, so programs are often written to account for values that may be nothing.
This recipe concerns a pattern that is very common: A function fn
takes a value as a parameter, and its behaviour by design is to do nothing if the parameter is nothing:
Alternately, the function may be intended to work with any value, but the code calling the function wishes to emulate the behaviour of doing nothing by design when given nothing:
Naturally, there’s a recipe for that, borrowed from Haskell’s maybe monad, Ruby’s andand, and CoffeeScript’s existential method invocation:
maybe
reduces the logic of checking for nothing to a function call, either:
Or:
As a bonus, maybe
plays very nicely with instance methods, we’ll discuss those later:
If some code ever tries to call model.setSomething
with nothing, the operation will be skipped.
4. The Pause That Refreshes: Rebinding and References
a simple question
Consider this code:
This makes obvious sense, because we know that strings are a value type, so no matter what expression you use to derive the value ‘June 14, 1962’, you are going to get a string with the exact same identity.
But what about this code?
Also true, even though we know that every time we evaluate an expression such as [2012, 6, 14]
, we get a new array with a new identity. So what is happening in our environments?
arguments and references
In our discussion of closures, we said that environments bind values (like [2012, 6, 14]
) to names (like x
and y
), and that when we use these names as expressions, the name evaluates as the value.
What this means is that when we write something like y = x
, the name x
is looked up in the current environment, and its value is a specific array that was created when the expression [2012, 6, 14]
was first evaluated. We then bind that exact same value to the name y
in a new environment, and thus x
and y
are both bound to the exact same value, which is identical to itself.
The same thing happens with binding a variable through a more conventional means of applying a function to arguments:
x
and y
both end up bound to the exact same array, not two different arrays that look the same to our eyes.
Arguments and Arrays
JavaScript provides two different kinds of containers for values. We’ve met one already, the array. Let’s see how it treats values and identities. For starters, we’ll learn how to extract a value from an array. We’ll start with a function that makes a new value with a unique identity every time we call it. We already know that every function we create is unique, so that’s what we’ll use:
Let’s verify that what we said about references applies to functions as well as arrays:
Ok. So what about things inside arrays? We know how to create an array with something inside it:
That’s an array with one of our unique functions in it. How do we get something out of it?
Cool, arrays work a lot like arrays in other languages and are zero-based. The trouble with this example is that strings are value types in JavaScript, so we have no idea whether a[0]
always gives us the same value back like looking up a name in an environment, or whether it does some magic that tries to give us a new value.
We need to put a reference type into an array. If we get the same thing back, we know that the array stores a reference to whatever you put into it. If you get something different back, you know that arrays store copies of things.1
Let’s test it:
If we get a value out of an array using the []
suffix, it’s the exact same value with the same identity. Question: Does that apply to other locations in the array? Yes:
References and Objects
JavaScript also provides objects. The word “object” is loaded in programming circles, due to the widespread use of the term “object-oriented programming” that was coined by Alan Kay but has since come to mean many, many things to many different people.
In JavaScript, an object2 is a map from names to values, a lot like an environment. The most common syntax for creating an object is simple:
Two objects created this way have differing identities, just like arrays:
Objects use []
to access the values by name, using a string:
Values contained within an object work just like values contained within an array:
Names needn’t be alphanumeric strings. For anything else, enclose the label in quotes:
If the name is an alphanumeric string conforming to the same rules as names of variables, there’s a simplified syntax for accessing the values:
All containers can contain any value, including functions or other containers:
Funny we should mention Mathematics
. If you recall, JavaScript provides a global environment that contains some existing objects that have handy functions you can use. One of them is called Math
, and it contains functions for abs
, max
, min
, and many others. Since it is always available, you can use it in any environment provided you don’t shadow Math
.
Reassignment and Mutation
Like most imperative programming languages, JavaScript allows you to re-assign the value of variables. The syntax is familiar to users of most popular languages:
We took the time to carefully examine what happens with bindings in environments. Let’s take the time to explore what happens with reassigning values to variables. The key is to understand that we are rebinding a different value to the same name in the same environment.
So let’s consider what happens with a shadowed variable:
Binding 50
to age in the inner environment does not change age
in the outer environment because the binding of age
in the inner environment shadows the binding of age
in the outer environment. We go from:
To:
Then back to:
However, if we don’t shadow age
by explicitly using var
, reassigning it in a nested environment changes the original:
Like evaluating variable labels, when a binding is rebound, JavaScript searches for the binding in the current environment and then each ancestor in turn until it finds one. It then rebinds the name in that environment.
mutation and aliases
Now that we can reassign things, there’s another important factor to consider: Some values can mutate. Their identities stay the same, but not their structure. Specifically, arrays and objects can mutate. Recall that you can access a value from within an array or an object using []
. You can reassign a value using []
as well:
You can even add a value:
You can do the same thing with both syntaxes for accessing objects:
We have established that JavaScript’s semantics allow for two different bindings to refer to the same value. For example:
Both halloween
and allHallowsEve
are bound to the same array value within the local environment. And also:
There are two nested environments, and each one binds a name to the exact same array value. In each of these examples, we have created two aliases for the same value. Before we could reassign things, the most important point about this is that the identities were the same, because they were the same value.
This is vital. Consider what we already know about shadowing:
The outer value of allHallowsEve
was not changed because all we did was rebind the name halloween
within the inner environment. However, what happens if we mutate the value in the inner environment?
This is different. We haven’t rebound the inner name to a different variable, we’ve mutated the value that both bindings share. Now that we’ve finished with mutation and aliases, let’s have a look at it.
How to Shoot Yourself in the Foot With Var
As we’ve seen, JavaScript’s environments and bindings are quite powerful: You can bind and rebind names using function arguments or using variables declared with var
. The takeaway is that when used properly, Javascript’s var
keyword is a great tool.
When used properly.
Let’s look at a few ways to use it improperly.
loose use
JavaScript’s var
keyword is scoped to the function enclosing it. This makes sense, because bindings are made in environments, and the environments are associated with function calls. So if you write:
The name blitz
is actually scoped to the function foo
, not to the block of code in the consequent of an if
statement. There are roughly two schools of thought. One line of reasoning goes like this: Since blitz
is scoped to the function foo
, you should write the code like this:
We’ve separated the “declaration” from the “assignment,” and we’ve made it clear that blitz
is scoped to the entire function. The other school of thought is that programmers are responsible for understanding how the tools work, and even if you write it the first way, other programmers reading the code ought to know how it works.
So here’s a question: Are both ways of writing the code equivalent? Let’s set up a test case that would tell them apart. We’ll try some aliasing:
What will this code do if we type it into a browser console? One theory is that it will alert outer
and then inner
, because when it evaluates the first alert, questionable
hasn’t been bound in the function’s environment yet, so it will be looked up in the enclosing environment. Then an alias is bound, shadowing the outer binding, and it will alert inner
.
This theory is wrong! It actually alerts undefined
and then inner
. Even though we wrote the var
statement later in the code, JavaScript acts as if we’d declared it at the top of the function. This is true even if we never execute the var
statement:
So yes, both ways of writing the code work the same way, but only one represents the way it works directly and obviously. For this reason, we put the var
declarations at the top of every function, always.
for pete’s sake
JavaScript provides a for
loop for your iterating pleasure and convenience. It looks a lot like the for
loop in C:
Hopefully, you can think of a faster way to calculate this sum.3 And perhaps you have noticed that var i = 1
is tucked away instead of being at the top as we prefer. But is this ever a problem?
Yes. Consider this variation:
So far, so good. Hey, remember that functions in JavaScript are values? Let’s get fancy!
So far, so good. Let’s try one of our functions:
What went wrong? Why didn’t it give us ‘Hello, Raganwald, my name is Friedrich’? The answer is that pesky var i
. Remember that i
is bound in the surrounding environment, so it’s as if we wrote:
Now, at the time we created each function, i
had a sensible value, like 0
, 1
, or 2
. But at the time we call one of the functions, i
has the value 3
, which is why the loop terminated. So when the function is called, JavaScript looks i
up in its enclosing environment (its closure, obviously), and gets the value 3
. That’s not what we want at all.
Here’s how to fix it, once again with let
as our guide:
That works. What did we do? Well, we created a new function and called it immediately, and we deliberately shadowed i
by passing it as an argument to our function, which had an argument of exactly the same name. If you dislike shadowing, this alternative also works:
Now we’re creating a new inner variable, ii
and binding it to the value of i
. The shadowing code seems simpler and less error-prone to us, but both work.
nope, nope, nope, nope, nope
The final caution about var
concerns what happens if you omit to declare a variable with var, boldly writing something like:
So where is the name fizzBuzz
bound? The answer is that if there is no enclosing var
declaration for fizzBuzz
, the name is bound in the global environment. And by global, we mean global. It is visible to every separate compilation unit. All of your npm modules. Every JavaScript snippet in a web page. Every included file.
This is almost never what you want. And when you do want it, JavaScript provides alternatives such as binding to window.fizzBuzz
in a browser, or this.fizzBuzz
in node. In short, eschew undeclared variables. Force yourself to make a habit of using var
all of the time, and explicitly binding variables to the window
or this
objects when you truly want global visibility.
When Rebinding Meets Recursion
We’ve talked about binding values in environments, and now we’re talking about rebinding values and mutating values. Let’s take a small digression. As we’ve seen, in JavaScript functions are values. So you can bind a function just like binding a string, number or array. Here’s a function that tells us whether a (small and positive) number is even:
You can alias a function value:
What happens when we redefine a recursive function like even
? Does divisibleByTwo
still work? Let’s try aliasing it and reassigning it:
What happened? Well, our new divisibleByTwo
function wasn’t really a self-contained value. When we looked at functions, we talked about “pure” functions that only access their arguments and we looked at “closures” that have free variables. Recursive functions defined like this are closures, not pure functions, because when they “call themselves,” what they actually do is look themselves up by name in their enclosing environment. Thus, they depend upon a specific value (themselves) being bound in their enclosing environment. Reassign to that variable (or rebind the name, same thing), and you break their functionality.
named function expressions
You recall that in Naming Functions, we saw that when you create a named function expression, you bind the name of the function within its body but not the environment of the function expression, meaning you can write:
This is different, because the function doesn’t refer to a name bound in its enclosing environment, it refers to a name bound in its own body. It is now a pure function. In fact, you can even bind it to the exact same name in its enclosing environment and it will still work:
The even
inside the function refers to the name bound within the function by the named function expression. It may have the same name as the even
bound in the enclosing environment, but they are two different bindings in two different environments. Thus, rebinding the name in the enclosing environment does not break the function.
You may ask, what if we rebind even
inside of itself. Now will it break?
Strangely, no it doesn’t. The name bound by a named function expression is read-only. Why do we say strangely? Because other quasi-declarations like function declarations do not behave like this.
So, when we want to make a recursive function, the safest practice is to use a named function expression.
limits
Named function expressions have limits. Here’s one such limit: You can do simple recursion, but not mutual recursion. For example:
Using named function expressions doesn’t help us, because even
and odd
need to be bound in an environment accessible to each other, not just to themselves. You either have to avoid rebinding the names of these functions, or use a closure to build a module:
Now you can rebind one without breaking the other, because the names outside of the closure have no effect on the bindings inside the closure:
From Let to Modules
transient let
In the section on let and Var, we learned that we can create a new environment any time we want by combining a function definition with a function invocation, to whit:
Because this function is invoked, if it contains a return statement, it evaluates to a value of some kind. So you can, for example, write something like:
This could have been written using a named function to avoid the need for a let, but as we’ll see in the memoize later, sometimes there’s good reason to write it like this. In any event, our let serves to create a scope for the factorial
function. Presumably we write it this way to signal that we do not want to use it elsewhere, so putting it inside of a let keeps it invisible from the rest of the code.
You’ll note that once we’ve calculated the factorial of 25, we have no further need for the environment of the function, so it will be thrown away. This is what we might call a transient let: Nothing we bind in the let
is returned from the let
or otherwise passed out through assignment, so the environment of the let is discarded when the let finishes being evaluated.
private closure
The transient let only uses its environment to generate the result, then it can be discarded. Another type of let is the private closure. This let returns a closure that references one or more bindings in the let’s environment. For example:
counter
is bound to a function closure that references the binding value
in the let’s environment. So the environment isn’t transient, it remains active until the function bound to the name counter
is discarded. Private closures are often used to manage state as we see in the counter example, but they can also be used for helper functions.
For example, this date format function cribbed from somewhere or other has a helper function that isn’t used anywhere else:
Every time we call formatDate
, JavaScript will create an entirely new unformattedDate
function. That is not necessary, since it’s a pure function. In theory, a sufficiently smart interpreter would notice this and only create one function. In practice, we can rewrite it to use a private closure and only create one helper function:
The function unformattedDate
is still private to formatDate
, but now we no longer need to construct an entirely new function every time formatDate
is called.
modules
Once the power of creating a new environment with a let (or “immediately invoked function expression”) is tasted, it won’t be long before you find yourself building modules with lets. Modules are any collection of functions that have some private and some public-facing elements.
Consider a module designed to draw some bits on a virtual screen. The public API consists of a series of draw functions. The private API includes a series of helper functions. This is exactly like the private closure, the only difference being that we want to return multiple public functions instead of just one.
It looks like this:
You can then call the public functions using DrawModule.drawCircle(...)
. The concept scales up to include the concept of state (such as setting default line styles), but when you look at it, it’s really just the private closure let with a little more complexity in the form of returning an object with more than one function.
Summary
- Arrays in all contemporary languages store references and not copies, so we can be forgiven for expecting them to work the same way in JavaScript. Nevertheless, it’s a useful exercise to test things for ourself.↩
- Tradition would have us call objects that don’t contain any functions “POJOs,” meaning Plain Old JavaScript Objects.
- There is a well known story about Karl Friedrich Gauss when he was in elementary school. His teacher got mad at the class and told them to add the numbers 1 to 100 and give him the answer by the end of the class. About 30 seconds later Gauss gave him the answer. The other kids were adding the numbers like this:
1 + 2 + 3 + . . . . + 99 + 100 = ?
But Gauss rearranged the numbers to add them like this:(1 + 100) + (2 + 99) + (3 + 98) + . . . . + (50 + 51) = ?
If you notice every pair of numbers adds up to 101. There are 50 pairs of numbers, so the answer is 50*101 = 5050. Of course Gauss came up with the answer about 20 times faster than the other kids.↩
5. Recipes with Rebinding and References
Disclaimer
The recipes are written for practicality, and their implementation may introduce JavaScript features that haven’t been discussed in the text to this point, such as methods and/or prototypes. The overall use of each recipe will fit within the spirit of the language discussed so far, even if the implementations may not.
Once
once
is an extremely helpful combinator. It ensures that a function can only be called, well, once. Here’s the recipe:
Very simple! You pass it a function, and you get a function back. That function will call your function once, and thereafter will return undefined
whenever it is called. Let’s try it:
It seems some people will only try blind dating once. But you do have to be careful that you are calling the function once
returns multiple times. If you keep calling once
, you’ll get a new function that executes once, so you’ll keep calling your function:
This is expected, but sometimes not what we want. So we must either be careful with our code, or use a variation, the named once recipe.
mapWith
In recent versions of JavaScript, arrays have a .map
method. Map takes a function as an argument, and applies it to each of the elements of the array, then returns the results in another array. For example:
We say that .map
maps its arguments over the receiver array’s elements. Or if you prefer, that it defines a mapping between its receiver and its result. Libraries like Underscore provide a map function.1 It usually works like this:
This recipe isn’t for map
: It’s for mapWith
, a function that wraps around map
and turns any other function into a mapping. In concept, mapWith
is very simple:2
Here’s the above code written using mapWith
:
If we didn’t use mapWith
, we’d have written something like this:
And we’d do that every time we wanted to construct a method that maps an array to some result. mapWith
is a very convenient abstraction for a very common pattern.
mapWith
was suggested by ludicast
Flip
When we wrote mapWith, we wrote it like this:
Let’s consider the case whether we have a map
function of our own, perhaps from the allong.es library, perhaps from Underscore. We could write our function something like this:
Looking at this, we see we’re conflating two separate transformations. First, we’re reversing the order of arguments. You can see that if we simplify it:
Second, we’re “currying” the function so that instead of defining a function that takes two arguments, it returns a function that takes the first argument and returns a function that takes the second argument and applies them both, like this:
Let’s return to the implementation that does both:
Now let’s put a wrapper around it:
Abstract the parameter names:
And finally, extract the function as a parameter:
What we have now is a function that takes a function and “flips” the order of arguments around, then curries it:
This is gold. Consider how we define mapWith now:
Much nicer!
There’s one final decoration. Sometimes we’ll want to flip a function but retain the flexibility to call it with both parameters at once. No problem:
Now you can call mapWith(fn, list)
or mapWith(fn)(list)
, your choice.
Extend
It’s very common to want to “extend” an object by adding properties to it:
It’s also common to want to add a shallow copy of the properties of one object to another:
Both needs can be met with this recipe for extend
:
You can copy an object by extending an empty object:
You can extend one object with another:
And when we discuss prototypes, we will use extend
to turn this:
Into this:
Why?
This is the canonical Y Combinator:
You use it like this:
Why? It enables you to make recursive functions without needing to bind a function to a name in an environment. This has little practical utility in JavaScript, but in combinatory logic it’s essential: With fixed-point combinators it’s possible to compute everything computable without binding names.
So again, why include the recipe? Well, besides all of the practical applications that combinators provide, there is this little thing called The joy of working things out.
There are many explanations of the Y Combinator’s mechanism on the internet, but resist the temptation to read any of them: Work it out for yourself. Use it as an excuse to get familiar with your environment’s debugging facility. A friendly tip: Name some of the anonymous functions inside it to help you decipher stack traces.
Work things out for yourself. And once you’ve grokked that recipe, this recipe is for a Y Combinator that is a little more idiomatic. Work it out too:
You use this version like this:
There are certain cases involving nested recursive functions it cannot handle due to the ambiguity of this
, and obviously it is useless as a method combination, but it is an interesting alternative to the let
pattern.
- Why provide a map function? well, JavaScript is an evolving language, and when you’re writing code that runs in a web browser, you may want to support browsers using older versions of JavaScript that didn’t provide the
.map
function. One way to do that is to “shim” the map method into the Array class, the other way is to use a map function. Most library implementations of map will default to the.map
method if its available.↩ - If we were always mapWithting arrays, we could write
list.map(fn)
. However, there are some objects that have a.length
property and[]
accessors that can be mapWithted but do not have a.map
method.mapWith
works with those objects. This points to a larger issue around the question of whether containers really ought to implement methods like.map
. In a language like JavaScript, we are free to define objects that know about their own implementations, such as exactly how[]
and.length
works and then to define standalone functions that do the rest.↩
6. Stir the Allongé: Objects, Mutation, and State
So far, we have discussed what many call “pure functional” programming, where every expression is necessarily idempotent, because we have no way of changing state within a program using the tools we have examined.
It’s time to change everything.
Encapsulating State with Closures
OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things.–Alan Kay
We’re going to look at encapsulation using JavaScript’s functions and objects. We’re not going to call it object-oriented programming, mind you, because that would start a long debate. This is just plain encapsulation,1 with a dash of information-hiding.
what is hiding of state-process, and why does it matter?
In computer science, information hiding is the principle of segregation of the design decisions in a computer program that are most likely to change, thus protecting other parts of the program from extensive modification if the design decision is changed. The protection involves providing a stable interface which protects the remainder of the program from the implementation (the details that are most likely to change).
Written another way, information hiding is the ability to prevent certain aspects of a class or software component from being accessible to its clients, using either programming language features (like private variables) or an explicit exporting policy.
Consider a stack data structure. There are three basic operations: Pushing a value onto the top (push
), popping a value off the top (pop
), and testing to see whether the stack is empty or not (isEmpty
). These three operations are the stable interface.
Many stacks have an array for holding the contents of the stack. This is relatively stable. You could substitute a linked list, but in JavaScript, the array is highly efficient. You might need an index, you might not. You could grow and shrink the array, or you could allocate a fixed size and use an index to keep track of how much of the array is in use. The design choices for keeping track of the head of the list are often driven by performance considerations.
If you expose the implementation detail such as whether there is an index, sooner or later some programmer is going to find an advantage in using the index directly. For example, she may need to know the size of a stack. The ideal choice would be to add a size
function that continues to hide the implementation. But she’s in a hurry, so she reads the index
directly. Now her code is coupled to the existence of an index, so if we wish to change the implementation to grow and shrink the array, we will break her code.
The way to avoid this is to hide the array and index from other code and only expose the operations we have deemed stable. If and when someone needs to know the size of the stack, we’ll add a size
function and expose it as well.
Hiding information (or “state”) is the design principle that allows us to limit the coupling between components of software.
how do we hide state using javascript?
We’ve been introduced to JavaScript’s objects, and it’s fairly easy to see that objects can be used to model what other programming languages call (variously) records, structs, frames, or what-have-you. And given that their elements are mutable, they can clearly model state.
Given an object that holds our state (an array and an index2), we can easily implement our three operations as functions. Bundling the functions with the state does not require any special “magic” features. JavaScript objects can have elements of any type, including functions:
method-ology
In this text, we lurch from talking about “functions that belong to an object” to “methods.” Other languages may separate methods from functions very strictly, but in JavaScript every method is a function but not all functions are methods.
The view taken in this book is that a function is a method of an object if it belongs to that object and interacts with that object in some way. So the functions implementing the operations on the stack are all absolutely methods of the stack.
But these two wouldn’t be methods. Although they “belong” to an object, they don’t interact with it:
hiding state
Our stack does bundle functions with data, but it doesn’t hide its state. “Foreign” code could interfere with its array or index. So how do we hide these? We already have a closure, let’s use it:
We don’t want to repeat this code every time we want a stack, so let’s make ourselves a “stack maker.” The temptation is to wrap what we have above in a function:
But there’s an easier way :-)
Now we can make stacks freely, and we’ve hidden their internal data elements. We have methods and encapsulation, and we’ve built them out of JavaScript’s fundamental functions and objects. In Instances and Classes, we’ll look at JavaScript’s support for class-oriented programming and some of the idioms that functions bring to the party.
Composition and Extension
composition
A deeply fundamental practice is to build components out of smaller components. The choice of how to divide a component into smaller components is called factoring, after the operation in number theory 3.
The simplest and easiest way to build components out of smaller components in JavaScript is also the most obvious: Each component is a value, and the components can be put together into a single object or encapsulated with a closure.
Here’s an abstract “model” that supports undo and redo composed from a pair of stacks (see Encapsulating State) and a Plain Old JavaScript Object:
The techniques used for encapsulation work well with composition. In this case, we have a “model” that hides its attribute store as well as its implementation that is composed of an undo stack and redo stack.
extension
Another practice that many people consider fundamental is to extend an implementation. Meaning, they wish to define a new data structure in terms of adding new operations and semantics to an existing data structure.
Consider a queue:
Now we wish to create a deque by adding pullTail
and pushHead
operations to our queue.4 Unfortunately, encapsulation prevents us from adding operations that interact with the hidden data structures.
This isn’t really surprising: The entire point of encapsulation is to create an opaque data structure that can only be manipulated through its public interface. The design goals of encapsulation and extension are always going to exist in tension.
Let’s “de-encapsulate” our queue:
Now we can extend a queue into a deque:
Presto, we have reuse through extension, at the cost of encapsulation.
This and That
Let’s take another look at extensible objects. Here’s a Queue:
Let’s make a copy of our queue using the extend
recipe:
Wait a second. We know that array values are references. So it probably copied a reference to the original array. Let’s make a copy of the array as well:
Now let’s pull the head off the original:
If we’ve copied everything properly, we should get the exact same result when we pull the head off the copy:
What!? Even though we carefully made a copy of the array to prevent aliasing, it seems that our two queues behave like aliases of each other. The problem is that while we’ve carefully copied our array and other elements over, the closures all share the same environment, and therefore the functions in copyOfQueue
all operate on the first queue’s private data, not on the copies.
Let’s take an impossibly optimistic flight of fancy:
The AmnesiacQueueMaker
makes queues with amnesia: They don’t know who they are, so every time we invoke one of their functions, we have to tell them who they are. You can work out the implications for copying queues as a thought experiment: We don’t have to worry about environments, because every function operates on the queue you pass in.
The killer drawback, of course, is making sure we are always passing the correct queue in every time we invoke a function. What to do?
what’s all this
?
Any time we must do the same repetitive thing over and over and over again, we industrial humans try to build a machine to do it for us. JavaScript is one such machine:
Every time you invoke a function that is a member of an object, JavaScript binds that object to the name this
in the environment of the function just as if it was an argument.5 Now we can easily make copies:
Presto, we now have a way to copy arrays. By getting rid of the closure and taking advantage of this
, we have functions that are more easily portable between objects, and the code is simpler as well.
There is more to this
than we’ve discussed here. We’ll explore things in more detail later, in What Context Applies When We Call a Function?.
What Context Applies When We Call a Function?
In This and That, we learned that when a function is called as an object method, the name this
is bound in its environment to the object acting as a “receiver.” For example:
We’ve constructed a method that returns whatever value is bound to this
when it is called. It returns the object when called, just as described.
it’s all about the way the function is called
JavaScript programmers talk about functions having a “context” when being called. this
is bound to the context.6 The important thing to understand is that the context for a function being called is set by the way the function is called, not the function itself.
This is an important distinction. Consider closures: As we discussed in Closures and Scope, a function’s free variables are resolved by looking them up in their enclosing functions’ environments. You can always determine the functions that define free variables by examining the source code of a JavaScript program, which is why this scheme is known as Lexical Scope.
A function’s context cannot be determined by examining the source code of a JavaScript program. Let’s look at our example again:
What is the context of the function someObject.someFunction
? Don’t say someObject
! Watch this:
It gets weirder:
So it amounts to this: The exact same function can be called in two different ways, and you end up with two different contexts. If you call it using someObject.someFunction()
syntax, the context is set to the receiver. If you call it using any other expression for resolving the function’s value (such as someFunction()
), you get something else. Let’s investigate:
Interesting!
How about:
It seems that whether you use a.b()
or a['b']()
or a[n]()
or (a.b)()
, you get context a
.
And if you don’t use a.b()
or a['b']()
or a[n]()
or (a.b)()
, you get the global environment for a context, not the context of whatever function is doing the calling. To simplify things, when you call a function with .
or []
access, you get an object as context, otherwise you get the global environment.
setting your own context
There are actually two other ways to set the context of a function. And once again, both are determined by the caller. At the very end of objects everywhere?, we’ll see that everything in JavaScript behaves like an object, including functions. We’ll learn that functions have methods themselves, and one of them is call
.
Here’s call
in action:
When You call a function with call
, you set the context by passing it in as the first parameter. Other arguments are passed to the function in the normal manner. Much hilarity can result from call
shenanigans like this:
But now we thoroughly understand what a.b()
really means: It’s synonymous with a.b.call(a)
. Whereas in a browser, c()
is synonymous with c.call(window)
.
apply, arguments, and contextualization
JavaScript has another automagic binding in every function’s environment. arguments
is a special object that behaves a little like an array.7
For example:
Hold that thought for a moment. JavaScript also provides a fourth way to set the context for a function. apply
is a method implemented by every function that takes a context as its first argument, and it takes an array or array-like thing of arguments as its second argument. That’s a mouthful, let’s look at an example:
Now let’s put the two together. Here’s another travesty:
We get the result of concatenating [4,5]
onto an array containing the global environment. Not what we want! Behold:
Our contextualize
function returns a new function that calls a function with a fixed context. It can be used to fix some of the unexpected results we had above. Consider:
Both are true
because we are accessing them with aFourthObject.
Now we write:
When we call these functions without using aFourthObject.
, only the contextualized version maintains the context of aFourthObject
.
We’ll return to contextualizing methods later, in Binding. But before we dive too deeply into special handling for methods, we need to spend a little more time looking at how functions and methods work.
Method Decorators
In function decorators, we learned that a decorator takes a function as an argument, returns a function, and there’s a semantic relationship between the two. If a function is a verb, a decorator is an adverb.
Decorators can be used to decorate methods provided that they carefully preserve the function’s context. For example, here is a naïve version of maybe
for one argument:
This version doesn’t preserve the context, so it can’t be used as a method decorator. Instead, we have to write:
Now we can write things like:
And this
is correctly set:
Using .call
or .apply
and arguments
is substantially slower than writing function decorators that don’t set the context, so it might be right to sometimes write function decorators that aren’t usable as method decorators. However, in practice you’re far more likely to introduce a defect by failing to pass the context through a decorator than by introducing a performance pessimization, so the default choice should be to write all function decorators in such a way that they are “context agnostic.”
In some cases, there are other considerations to writing a method decorator. If the decorator introduces state of any kind (such as once
and memoize
do), this must be carefully managed for the case when several objects share the same method through the mechanism of the prototype or through sharing references to the same function.
Summary
- “A language construct that facilitates the bundling of data with the methods (or other functions) operating on that data.”–Wikipedia↩
- Yes, there’s another way to track the size of the array, but we don’t need it to demonstrate encapsulation and hiding of state.↩
- And when you take an already factored component and rearrange things so that it is factored into a different set of subcomponents without altering its behaviour, you are refactoring.↩
- Before you start wondering whether a deque is-a queue, we said nothing about types and classes. This relationship is called was-a, or “implemented in terms of a.”↩
- JavaScript also does other things with
this
as well, but this is all we care about right now.↩ - Too bad the language binds the context to the name
this
instead of the namecontext
!↩ - Just enough to be frustrating, to be perfectly candid!↩
7. Recipes with Objects, Mutations, and State
Disclaimer
The recipes are written for practicality, and their implementation may introduce JavaScript features that haven’t been discussed in the text to this point, such as methods and/or prototypes. The overall use of each recipe will fit within the spirit of the language discussed so far, even if the implementations may not.
Memoize
Consider that age-old interview quiz, writing a recursive fibonacci function (there are other ways to derive a fibonacci number, of course). Here’s an implementation that doesn’t use a named function expression. The reason for that omission will be explained later:
We’ll time it:
Why is it so slow? Well, it has a nasty habit of recalculating the same results over and over and over again. We could rearrange the computation to avoid this, but let’s be lazy and trade space for time. What we want to do is use a lookup table. Whenever we want a result, we look it up. If we don’t have it, we calculate it and write the result in the table to use in the future. If we do have it, we return the result without recalculating it.
Here’s our recipe:
We can apply memoized
to a function and we will get back a new function that “memoizes” its results so that it never has to recalculate the same value twice. It only works for functions that are “idempotent,” meaning functions that always return the same result given the same argument(s). Like fibonacci
:
Let’s try it:
We get the result back instantly. It works! You can use memoize with all sorts of “idempotent” pure functions. by default, it works with any function that takes arguments which can be transformed into JSON using JavaScript’s standard library function for this purpose. If you have another strategy for turning the arguments into a string key, you can supply it as a second parameter.
memoizing recursive functions
We deliberately picked a recursive function to memoize, because it demonstrates a pitfall when combining decorators with named functional expressions. Consider this implementation that uses a named functional expression:
If we try to memoize it, we don’t get the expected speedup:
That’s because the function bound to the name fibonacci
in the outer environment has been memoized, but the named functional expression binds the name fibonacci
inside the unmemoized function, so none of the recursive calls to fibonacci are ever memoized. Therefore we must write:
If we need to prevent a rebinding from breaking the function, we’ll need to use the module pattern.
getWith
getWith
is a very simple function. It takes the name of an attribute and returns a function that extracts the value of that attribute from an object:
You can use it like this:
This isn’t much of a recipe yet. But let’s combine it with mapWith:
That’s nicer than writing things out “longhand:”
getWith
plays nicely with maybe as well. Consider a sparse array. You can use:
To get the orange count from all the non-null inventories in a list.
what’s in a name?
Why is this called getWith
? Consider this function that is common in languages that have functions and dictionaries but not methods:
You might ask, “Why use a function instead of just using []
?” The answer is, we can manipulate functions in ways that we can’t manipulate syntax. For example, do you remember from flip that we can define mapWith
from map
?
We can do the same thing with getWith
, and that’s why it’s named in this fashion:
pluckWith
This pattern of combining mapWith and getWith is very frequent in JavaScript code. So much so, that we can take it up another level:
Or even better:
And now we can write:
Libraries like Underscore provide pluck
, the flipped version of pluckWith
:
Our recipe is terser when you want to name a function:
vs.
And of course, if we have pluck
we can use flip to derive pluckWith
:
Deep Mapping
mapWith is an excellent tool, but from time to time you will find yourself working with arrays that represent trees rather than lists. For example, here is a partial list of sales extracted from a report of some kind. It’s grouped in some mysterious way, and we need to operate on each item in the report.
We could nest some mapWiths, but we humans are tool users. If we can use a stick to extract tasty ants from a hole to eat, we can automate working with arrays:
And now we can use deepMapWith
on a tree the way we use mapWith
on a flat array:
8. Finish the Cup: Instances and Classes
As discussed in Rebinding and References and again in Encapsulating State, JavaScript objects are very simple, yet the combination of objects, functions, and closures can create powerful data structures. That being said, there are language features that cannot be implemented with Plain Old JavaScript Objects, functions, and closures1.
One of them is inheritance. In JavaScript, inheritance provides a cleaner, simpler mechanism for extending data structures, domain models, and anything else you represent as a bundle of state and operations.
Prototypes are Simple, it’s the Explanations that are Hard To Understand
As you recall from our code for making objects extensible, we wrote a function that returned a Plain Old JavaScript Object. The colloquial term for this kind of function is a “Factory Function.”
Let’s strip a function down to the very bare essentials:
This doesn’t look like a factory function: It doesn’t have an expression that yields a Plain Old JavaScript Object when the function is applied. Yet, there is a way to make an object out of it. Behold the power of the new
keyword:
We got an object back! What can we find out about this object?
Every time we call new
with a function and get an object back, we get a unique object. We could call these “Objects created with the new
keyword,” but this would be cumbersome. So we’re going to call them instances. Instances of what? Instances of the function that creates them. So given var i = new Ur()
, we say that i
is an instance of Ur
.
For reasons that will be explained after we’ve discussed prototypes, we also say that Ur
is the constructor of i
, and that Ur
is a constructor function. Therefore, an instance is an object created by using the new
keyword on a constructor function, and that function is the instance’s constructor.
prototypes
There’s more. Here’s something you may not know about functions:
What’s this prototype? Let’s run our standard test:
Every function is initialized with its own unique prototype
. What does it do? Let’s try something:
That’s very interesting! Instances seem to behave as if they had the same elements as their constructor’s prototype. Let’s try a few things:
You can set elements of an instance, and they “override” the constructor’s prototype, but they don’t actually change the constructor’s prototype. Let’s make another instance and try something else.
New instances don’t acquire any changes made to other instances. Makes sense. And:
Even more interesting: Changing the constructor’s prototype changes the behaviour of all of its instances. This strongly implies that there is a dynamic relationship between instances and their constructors, rather than some kind of mechanism that makes objects by copying.2
Speaking of prototypes, here’s something else that’s very interesting:
Every instance acquires a constructor
element that is initialized to their constructor. This is true even for objects we don’t create with new
in our own code:
If that’s true, what about prototypes? Do they have constructors?
Very interesting! We will take another look at the constructor
element when we discuss class extension.
revisiting this
idea of queues
Let’s rewrite our Queue to use new
and .prototype
, using this
and our extend
helper from Composition and Extension:
You recall that when we first looked at this
, we only covered the case where a function that belongs to an object is invoked. Now we see another case: When a function is invoked by the new
operator, this
is set to the new object being created. Thus, our code for Queue
initializes the queue.
You can see why this
is so handy in JavaScript: We wouldn’t be able to define functions in the prototype that worked on the instance if JavaScript didn’t give us an easy way to refer to the instance itself.
objects everywhere?
Now that you know about prototypes, it’s time to acknowledge something that even small children know: Everything in JavaScript behaves like an object, everything in JavaScript behaves like an instance of a function, and therefore everything in JavaScript behaves as if it inherits some methods from its constructor’s prototype and/or has some elements of its own.
For example:
Functions themselves are instances, and they have methods. For example, every function has a method call
. call
’s first argument is a context: When you invoke .call
on a function, it invoked the function, setting this
to the context. It passes the remainder of the arguments to the function. It seems like objects are everywhere in JavaScript!
impostors
You may have noticed that we use “weasel words” to describe how everything in JavaScript behaves like an instance. Everything behaves as if it was created by a function with a prototype.
The full explanation is this: As you know, JavaScript has “value types” like String
, Number
, and Boolean
. As noted in the first chapter, value types are also called primitives, and one consequence of the way JavaScript implements primitives is that they aren’t objects. Which means they can be identical to other values of the same type with the same contents, but the consequence of certain design decisions is that value types don’t actually have methods or constructors. They aren’t instances of some constructor.
So. Value types don’t have methods or constructors. And yet:
Somehow, when we write "Spence Olham".split(' ')
, the string "Spence Olham"
isn’t an instance, it doesn’t have methods, but it does a damn fine job of impersonating an instance of a String
constructor. How does "Spence Olham"
impersonate an instance?
JavaScript pulls some legerdemain. When you do something that treats a value like an object, JavaScript checks to see whether the value actually is an object. If the value is actually a primitive,3 JavaScript temporarily makes an object that is a kinda-sorta copy of the primitive and that kinda-sorta copy has methods and you are temporarily fooled into thinking that "Spence Olham"
has a .split
method.
These kinda-sorta copies are called String instances as opposed to String primitives. And the instances have methods, while the primitives do not. How does JavaScript make an instance out of a primitive? With new
, of course. Let’s try it:
The string instance looks just like our string primitive. But does it behave like a string primitive? Not entirely:
Aha! It’s an object with its own identity, unlike string primitives that behave as if they have a canonical representation. If we didn’t care about their identity, that wouldn’t be a problem. But if we carelessly used a string instance where we thought we had a string primitive, we could run into a subtle bug:
That code is not going to work as we expect should we accidentally bind new String("Spence Olham")
to userName
instead of the primitive "Spence Olham"
.
This basic issue that instances have unique identities but primitives with the same contents have the same identities–is true of all primitive types, including numbers and booleans: If you create an instance of anything with new
, it gets its own identity.
There are more pitfalls to beware. Consider the truthiness of string, number and boolean primitives:
Compare this to their corresponding instances:
Our notion of “truthiness” and “falsiness” is that all instances are truthy, even string, number, and boolean instances corresponding to primitives that are falsy.
There is one sure cure for “JavaScript Impostor Syndrome.” Just as new PrimitiveType(...)
creates an instance that is an impostor of a primitive, PrimitiveType(...)
creates an original, canonicalized primitive from a primitive or an instance of a primitive object.
For example:
Getting clever, we can write this:
Of course, original
will not work for your own creations unless you take great care to emulate the same behaviour. But it does work for strings, numbers, and booleans.
Binding Functions to Contexts
Recall that in What Context Applies When We Call a Function?, we adjourned our look at setting the context of a function with a look at a contextualize
helper function:
How would this help us in a practical way? Consider building an event-driven application. For example, an MVC application would bind certain views to update events when their models change. The Backbone framework uses events just like this:
This tells someModel
that when it invoked a change
event, it should call the anonymous function that in turn invoked someView
’s .render
method. Wouldn’t it be simpler to simply write:
It would, except that the implementation for .on
and similar framework methods looks something like this:
Although someView.render()
correctly sets the method’s context as someView
, callback()
will not. What can we do without wrapping someView.render()
in a function call as we did above?
binding methods
Before enumerating approaches, let’s describe what we’re trying to do. We want to take a method call and treat it as a function. Now, methods are functions in JavaScript, but as we’ve learned from looking at contexts, method calls involve both invoking a function and setting the context of the function call to be the receiver of the method call.
When we write something like:
We’re binding the name unbound
to the method’s function, but we aren’t doing anything with the identity of the receiver. In most programming languages, such methods are called “unbound” methods because they aren’t associated with, or “bound” to the intended receiver.
So what we’re really trying to do is get ahold of a bound method, a method that is associated with a specific receiver. We saw an obvious way to do that above, to wrap the method call in another function. Of course, we’re responsible for replicating the arity of the method being bound. For example:
Now our bound method takes one argument, just like the function it calls. We can use a bound method anywhere:
This pattern is very handy, but it requires keeping track of these bound methods. One thing we can do is bind the method “in place,” using the let
pattern like this:
Now we know where to find it:
This is a very popular pattern, so much so that many frameworks provide helper functions to make this easy. Underscore, for example, provides _.bind
to return a bound copy of a function and _.bindAll
to bind methods in place:
There are two considerations to ponder. First, we may be converting an instance method into an object method. Specifically, we’re creating an object method that is bound to the object.
Most of the time, the only change this makes is that it uses slightly more memory (we’re creating an extra function for each bound method in each object). But if you are a little more dynamic and actually change methods in the prototype, your changes won’t “override” the object methods that you created. You’d have to roll your own binding method that refers to the prototype’s method dynamically or reorganize your code.
This is one of the realities of “meta-programming.” Each technique looks useful and interesting in isolation, but when multiple techniques are used together, they can have unpredictable results. It’s not surprising, because most popular languages consider classes and methods to be fairly global, and they handle dynamic changes through side-effects. This is roughly equivalent to programming in 1970s-era BASIC by imperatively changing global variables.
If you aren’t working with old JavaScript environments in non-current browsers, you needn’t use a framework or roll your own binding functions: JavaScript has a .bind
method defined for functions:
.bind
also does some currying for you, you can bind one or more arguments in addition to the context. For example:
Very handy, and not just for binding contexts!
Partial Application, Binding, and Currying
Now that we’ve seen how function contexts work, we can revisit the subject of partial application. Recall our recipe for a generalized left partial application:
Function.prototype.bind
can sometimes be used to accomplish the same thing, but will be much faster. For example, instead of:
You can write:
The catch is the first parameter to .bind
: It sets the context. If you write functions that don’t use the context, like our .add
, You can use .bind
to do left partial application. But if you want to partially apply a method or other function where the context must be preserved, you can’t use .bind
. You can use the recipes given in JavaScript Allongé because they preserve the context properly.
Typically, context matters when you want to perform partial application on methods. So for an extremely simple example, we often use Array.prototype.slice
to convert arguments
to an array. So instead of:
We could write:
The other catch is that .bind
only does left partial evaluation. If you want to do right partial application, you’ll need callLast
or callRight
.
currying
The terms “partial application” and “currying” are closely related but not synonymous. Currying is the act of taking a function that takes more than one argument and converting it to an equivalent function taking one argument. How can such a function be equivalent? It works provided that it returns a partially applied function.
Code is, as usual, much clearer than words. Recall:
Here is the curried version:
Currying by hand would be an incredible effort, but its close relationship with partial application means that if you have left partial application, you can derive currying. Or if you have currying, you can derive left partial application. Let’s derive currying from callFirst
. Recall:
Here’s a function that curries any function with two arguments:
And from there we can curry a function with three arguments:
We’ll develop a generalized curry function in the recipes. But to summarize the difference between currying and partial application, currying is an operation that transforms a function taking two or more arguments into a function that takes a single argument and partially applies it to the function and then curries the rest of the arguments.
A Class By Any Other Name
JavaScript has “classes,” for some definition of “class.” You’ve met them already, they’re constructors that are designed to work with the new
keyword and have behaviour in their .prototype
element. You can create one any time you like by:
- Writing the constructor so that it performs any initialization on
this
, and: - Putting all of the method definitions in its prototype.
Let’s see it again: Here’s a class of todo items:
You can mix other functionality into this class by extending the prototype with an object:
Naturally, that allows us to define mixins for other classes:
This does exactly the same thing as declaring a “class,” defining a “method,” and adding a “mixin.” How does it differ? It doesn’t use the words class, method, def(ine) or mixin. And it has this prototype
property that most other popular languages eschew. It also doesn’t deal with inheritance, a deal-breaker for programmers who are attached to taxonomies.
For these reasons, many programmers choose to write their own library of functions to mimic the semantics of other programming languages. This has happened so often that most of the popular utility-belt frameworks like Backbone have some form of support for defining or extending classes baked in.
Nevertheless, JavaScript right out of the box has everything you need for defining classes, methods, mixins, and even inheritance (as we’ll see in Extending Classes with Inheritance). If we choose to adopt a library with more streamlined syntax, it’s vital to understand JavaScript’s semantics well enough to know what is happening “under the hood” so that we can work directly with objects, functions, methods, and prototypes when needed.
Object Methods
An instance method is a function defined in the constructor’s prototype. Every instance acquires this behaviour unless otherwise “overridden.” Instance methods usually have some interaction with the instance, such as references to this
or to other methods that interact with the instance. A constructor method is a function belonging to the constructor itself.
There is a third kind of method, one that any object (obviously including all instances) can have. An object method is a function defined in the object itself. Like instance methods, object methods usually have some interaction with the object, such as references to this
or to other methods that interact with the object.
Object methods are really easy to create with Plain Old JavaScript Objects, because they’re the only kind of method you can use. Recall from This and That:
pushTail
, pullHead
, and isEmpty
are object methods. Also, from encapsulation:
Although they don’t refer to the object, push
, pop
, and isEmpty
semantically interact with the opaque data structure represented by the object, so they are object methods too.
object methods within instances
Instances of constructors can have object methods as well. Typically, object methods are added in the constructor. Here’s a gratuitous example, a widget model that has a read-only id
:
set
and get
are instance methods, but id
is an object method: Each object has its own id
closure, where id
is bound to the id of the widget by the argument id
in the constructor. The advantage of this approach is that instances can have different object methods, or object methods with their own closures as in this case. The disadvantage is that every object has its own methods, which uses up much more memory than instance methods, which are shared amongst all instances.
Extending Classes with Inheritance
You recall from Composition and Extension that we extended a Plain Old JavaScript Queue to create a Plain Old JavaScript Deque. But what if we have decided to use JavaScript’s prototypes and the new
keyword instead of Plain Old JavaScript Objects? How do we extend a queue into a deque?
Here’s our Queue
:
And here’s what our Deque
would look like before we wire things together:
So what do we want from dequeues such that we can call all of a Queue
’s methods as well as a Dequeue
’s? Should we copy everything from Queue.prototype
into Deque.prototype
, like extend(Deque.prototype, Queue.prototype)
? That would work, except for one thing: If we later modified Queue
, say by mixing in some new methods into its prototype, those wouldn’t be picked up by Dequeue
.
No, there’s a better idea. Prototypes are objects, right? Why must they be Plain Old JavaScript Objects? Can’t a prototype be an instance?
Yes they can. Imagine that Deque.prototype
was a proxy for an instance of Queue
. It would, of course, have all of a queue’s behaviour through Queue.prototype
. We don’t want it to be an actual instance, mind you. It probably doesn’t matter with a queue, but some of the things we might work with might make things awkward if we make random instances. A database connection comes to mind, we may not want to create one just for the convenience of having access to its behaviour.
Here’s such a proxy:
Our QueueProxy
isn’t actually a Queue
, but its prototype
is an alias of Queue.prototype
. Thus, it can pick up Queue
’s behaviour. We want to use it for our Deque
’s prototype. Let’s insert that code in our class definition:
And it seems to work:
Wonderful!
getting the constructor element right
How about some of the other things we’ve come to expect from instances?
Oops! Messing around with Dequeue’s prototype broke this important equivalence. Luckily for us, the constructor
property is mutable for objects we create. So, let’s make a small change to QueueProxy
:
Repeat. Now it works:
The QueueProxy
function now sets the constructor
for every instance of a QueueProxy
(hopefully just the one we need for the Dequeue
class). It returns the object being created (it could also return undefined
and work. But if it carelessly returned something else, that would be assigned to Dequeue
’s prototype, which would break our code).
extracting the boilerplate
Let’s turn our mechanism into a function:
And use it in Dequeue
:
future directions
Some folks just love to build their own mechanisms. When all goes well, they become famous as framework creators and open source thought leaders. When all goes badly they create in-house proprietary one-offs that blur the line between application and framework with abstractions everywhere.
If you’re keen on learning, you can work on improving the above code to handle extending constructor properties, automatically calling the parent constructor function, and so forth. Or you can decide that doing it by hand isn’t that hard so why bother putting a thin wrapper around it?
It’s up to you, while JavaScript isn’t the tersest language, it isn’t so baroque that building inheritance ontologies requires hundreds of lines of inscrutable code.
Summary
- Since the JavaScript that we have presented so far is computationally universal, it is possible to perform any calculation with its existing feature set, including emulating any other programming language. Therefore, it is not theoretically necessary to have any further language features; If we need macros, continuations, generic functions, static typing, or anything else, we can greenspun them ourselves. In practice, however, this is buggy, inefficient, and presents our fellow developers with serious challenges understanding our code.↩
- For many programmers, the distinction between a dynamic relationship and a copying mechanism is too fine to worry about. However, it makes many dynamic program modifications possible.↩
- Recall that Strings, Numbers, Booleans and so forth are value types and primitives. We’re calling them primitives here.↩
9. Recipes with Instances and Classes
Disclaimer
The recipes are written for practicality, and their implementation may introduce JavaScript features that haven’t been discussed in the text to this point, such as methods and/or prototypes. The overall use of each recipe will fit within the spirit of the language discussed so far, even if the implementations may not.
Currying
We discussed currying in Closures and Partial Application, Binding, and Currying. Here is the recipe for a higher-order function that curries its argument function. It works with any function that has a fixed length, and it lets you provide as many arguments as you like.
We saw earlier that you can derive a curry function from a partial application function. The reverse is also true:
(This is a little different from the previous left partial functions in that it returns a curried function).
Bound
Earlier, we saw a recipe for getWith that plays nicely with properties:
Simple and useful. But now that we’ve spent some time looking at objects with methods we can see that get
(and pluck
) has a failure mode. Specifically, it’s not very useful if we ever want to get a method, since we’ll lose the context. Consider some hypothetical class:
Now how do we get all the egg counts?
And if we try applying those functions…
Of course, these are unbound methods we’re “getting” from each object. Here’s a new version of get
that plays nicely with methods. It uses variadic:
bound
is the recipe for getting a bound method from an object by name. It has other uses, such as callbacks. bound('render')(aView)
is equivalent to aView.render.bind(aView)
. There’s an option to add a variable number of additional arguments, handled by:
The exact behaviour will be covered in Binding Functions to Contexts. You can use it like this to add arguments to the bound function to be evaluated:
Unbinding
One of the specifications for Function.prototype.bind
is that it creates a binding that cannot be overridden. In other words:
This looks great. But what happens if we attempt to re-bind a bound function, either with bind
or .call
?
Bzzt! You cannot override the context of a function that has already been bound, even if you’re creating a new function with .bind
. You also don’t want to roll your own bind
function that allows rebinding, lest you be bitten by someone else’s code that expects that a bound function cannot be rebound. (One such case is where bound functions–such as callbacks–are stored in an array. Evaluating callbacks[index]()
will override the bound context with the array unless the context cannot be overridden.)1
the recipe
Our version of bind
memoizes the original function so that you can later call unbind
to restore it for rebinding.
Send
Previously, we saw that the recipe bound can be used to get a bound method from an instance. Unfortunately, invoking such methods is a little messy:
As we noted, it’s ugly to write
So instead, we write a new recipe:
send('apples')
works very much like &:apples
in the Ruby programming language. You may ask, why retain bound
? Well, sometimes we want the function but don’t want to evaluate it immediately, such as when creating callbacks. bound
does that well.
Here’s a robust version that doesn’t rely on bound
:
Invoke
Send is useful when invoking a function that’s a member of an object (or of an instance’s prototype). But we sometimes want to invoke a function that is designed to be executed within an object’s context. This happens most often when we want to “borrow” a method from one “class” and use it on another object.
It’s not an unprecedented use case. The Ruby programming language has a handy feature called instance_exec. It lets you execute an arbitrary block of code in the context of any object. Does this sound familiar? JavaScript has this exact feature, we just call it .apply
(or .call
as the case may be). We can execute any function in the context of any arbitrary object.
The only trouble with .apply
is that being a method, it doesn’t compose nicely with other functions like combinators. So, we create a function that allows us to use it as a combinator:
For example, let’s say someone else’s code gives you an array of objects that are in part, but not entirely like arrays. Something like:
We can use the pattern from Partial Application, Binding, and Currying to create a context-dependent copy function:
And now we can compose mapWith
with invoke
to convert the data to arrays:
invoke
is useful when you have the function and are looking for the instance. It can be written “the other way around,” for when you have the instance and are looking for the function:
Fluent
Object and instance methods can be bifurcated into two classes: Those that query something, and those that update something. Most design philosophies arrange things such that update methods return the value being updated. For example:
Having methods like setFlavour
return the value being set mimics the behaviour of assignment, where cake.flavour = 'chocolate'
is an expression that in addition to setting a property also evaluates to the value 'chocolate'
.
The fluent style presumes that most of the time when you perform an update you are more interested in doing other things with the receiver than the values being passed as argument(s), so the rule is to return the receiver unless the method is a query:
The code to work with cakes is now easier to read and less repetitive:
For one-liners like setting a property, this is fine. But some functions are longer, and we want to signal the intent of the method at the top, not buried at the bottom. Normally this is done in the method’s name, but fluent interfaces are rarely written to include methods like setLayersAndReturnThis
.
The fluent
method decorator solves this problem:
Now you can write methods like this:
It’s obvious at a glance that this method is “fluent.”
Once Again
As we noted when we saw the recipe for once, you do have to be careful that you are calling the function once
returns multiple times. If you keep calling once
, you’ll get a new function that executes once, so you’ll keep calling your function:
This is expected, but sometimes not what we want. Instead of the simple implementation, we can use a named once:
If you call this with just a function, it behaves exactly like our first recipe. But if you supply a named function, you get a different behaviour:
The named once adds a property, __once__
, to the context where the function is called and uses it to keep track of which named functions have and haven’t been run. One very powerful use is for defining object methods that should only be evaluated once, such as an initialization method. Normally this is done in the constructor, but you might write a “fluent” object that lets you call various setters:
If you later call w.initialize()
, it won’t be initialized again. You need a named once
, because an ordinary once
would be called once for every instance sharing the same prototype, whereas the named once will keep track of whether it has been run separately for each instance.
Caveat: Every instance will have a __once__
property. If you later write code that iterates over every property, you’ll have to take care not to interact with it.
- Isnotlupus on Reddit suggested this line of thinking against “weak binding” functions.↩
10. Sequence
Throughout the book, we’ve looked at how functions work, and more importantly, the many ways they can be decomposed into smaller parts and recombined in different ways. In this chapter. we will step back and look at a larger pattern, the use of sequence
to control the processing of information.
Introduction: Compose and Pipeline
In Combinators and Function Decorators, we saw the function compose
:
As we saw before, given:
Instead of:
We could write:
the semantics of compose
With compose
, we’re usually making a new function. Although it works perfectly well, we don’t need to write things like compose(double, addOne)(3)
inline to get the result 8
. It’s easier and clearer to write double(addOne(3))
.
On the other hand, when working with something like method decorators, it can help to write:
This makes it clear that setter
adds the behaviour of both fluent
and maybe
to each method it decorates, and it’s simpler to read var setter = compose(fluent, maybe);
than:
The take-away is that compose
is helpful when we are defining a new function that combines the effects of existing functions.
pipeline
compose
is extremely handy, but one thing it doesn’t communicate well is the order on operations. compose
is written that way because it matches the way explicitly composing functions works in JavaScript and most other languages: When you write a(b(…)), a
happens after b
.
Sometimes it makes more sense to compose functions in data flow order, as in “The value flows through a and then through b.” For this, we can use the pipeline
function:
Comparing pipeline
to compose
, pipeline says “add one to the number and then double it.” Compose says, “double the result of adding one to the number.” Both do the same job, but communicate their intention in opposite ways.
callbacks
pipeline
and compose
both work with functions that take an argument and return a value. In our next section, we’ll discuss pipelining functions that invoke a callback rather than returning a value.
11. New Ideas
(this bonus chapter is a work-in-progress)
How Prototypes and Constructors differ from Classes
In the previous section, we said that JavaScript has “classes” for some definition of the word “class,” and we showed how JavaScript provides many of the features found in other “object-oriented languages.” For those who want a fuller explanation, this section goes into more detail about how JavaScript’s “prototypes” differ from the classes found in a language like Ruby. It is not necessary to read this section to understand programming in JavaScript, but it can be helpful when discussing JavaScript with programmers who are more comfortable talking about classes.
Although each “object-oriented” programming language has its own particular set of semantics, the majority in popular use have “classes.” A class is an entity responsible for creating objects and defining the behaviour of objects. Classes may be objects in their own right, but if they are, they’re different from other types of objects. For example, the String
class in Ruby is not itself a string, it’s an object whose class is Class
. All objects in a “classical” system have a class, and their class is a “class.”
That sounds tautological, until we look at JavaScript. But let’s start with a quick review of a popular classist language, Ruby.
ruby
In Ruby, classes are objects, but they’re special objects. For example, here are some of the methods associated with the Ruby class String
:
And here are some of the methods associated with an instance of a string:
As you can see, a “class” in Ruby is very different from an “instance of that class.” And the methods of a class are very different from the methods of an instance of that class.
Here’s how you define a Queue in Ruby:
There is special syntax for defining a class, and special syntax for defining the behaviour of instances. There are different ways of defining the way new instances are created in classist languages. Ruby uses a “magic method” called initialize
. Now let’s look at JavaScript.
javascript has constructors and prototypes
JavaScript objects don’t have a formal class, and thus there’s no special syntax for defining how to create an instance or define its behaviour.
JavaScript instances are created with a constructor. The constructor of an instance is a function that was invoked with the new
operator. In JavaScript, any function can be a constructor, even if it doesn’t look like one:
As you can see, the square
function will act as a constructor if you call it with new
. There is no special kind of thing that constructs new objects, every function is (potentially) a constructor.
That’s different from a true classical language, where the class is a special kind of object that creates new instances.
How does JavaScript define the behaviour of instances? JavaScript doesn’t have a special syntax or special kind of object for that, it has “prototypes.” Prototypes are objects, but unlike a classical system, there are no special methods or properties associated with a prototype. Any object can be a prototype, even an empty object. In fact, that’s exactly what is associated with a constructor by default:
There’s absolutely nothing special about a prototype object. No special class methods, no special constructor of its own, nothing. Let’s look at a simple Queue in JavaScript:
The first way a prototype in JavaScript is different from a class in Ruby is that the prototype is an ordinary object with exactly the same properties that we expect to find in an instance: Methods pushTail
, pullHead
, and isEmpty
.
The second way is that any object can be a prototype. It can have functions (which act like methods), it can have other values (like numbers, booleans, objects, or strings). It can be an object you’re using for something else: An account, a view, a DOM object if you’re in the browser, anything.
“Classes” are objects in most “classical” languages, but they are a special kind of object. In JavaScript, prototypes are not a special kind of object, they’re just objects.
summary of the difference between classes and prototypes
A class in a formal classist language can be an object, but it’s a special kind of object with special properties and methods. It is responsible for creating new instances and for defining the behaviour of instances.
Instance behaviour in a classist language is defined with special syntax. If changes are allowed dynamically, they are done with special syntax and/or special methods invoked on the class.
JavaScript splits the responsibility for instances into a constructor and a prototype. A constructor in JavaScript can be any function. Constructors are responsible for creating new instances.
A prototype in JavaScript can be any object. Prototypes are responsible for defining the behaviour of instances. prototypes don’t have special methods or properties.
Instance behaviour in JavaScript is defined by modifying the prototype directly, e.g. by adding functions to it as properties. There is no special syntax for defining a class or modifying a class.
so why does this book say that javascript has “classes” for some definition of “class?”
Because, if:
- You use a function as a constructor, and;
- You use a prototype for defining instance methods, and;
- The prototype is used strictly for defining the instance methods and nothing else;
Then:
You will have something that works just like a simple class-based system, with the constructor function and its prototype acting as the “class.”
But if you want more, you have a flexible system that does allow you to do much much more. It’s up to you.
New-Agnostic Constructors
JavaScript is inflexible about certain things. One of them is invoking new
on a constructor. In many of our recipes, we can write functions that can handle a variable number of arguments and use .apply
to invoke a function. For example:
You can’t do the same thing with calling a constructor. This will not work:
Another weakness of constructors is that if you call them without using new
, you usually get nonsense:
In David Herman’s Effective JavaScript, he describes the “New-Agnostic Constructor Pattern.” He gives several variations, but the simplest is this:
Now you can call the constructor without the new
keyword:
This in turn opens up the possibility of doing dynamic things with constructors that didn’t work when you were forced to use new
:
(The pattern above has a tradeoff: It works for all circumstances except when you want to set up an inheritance hierarchy.)
Another New-Agnostic Constructor Pattern
Here’s another way to write a new-agnostic constructor:
The principle is that the constructor initializes an object assigned to the variable self
and returns it. When you call the constructor with new
, then self
will be assigned the current context. But if you call this constructor as a standard function, then it will call itself without parameters and assign the newly created User to self
.
Mixins
In A Class By Any Other Name, we saw that you can emulate “mixins” using our extend
function. We’ll revisit this subject now and spend more time looking at mixing functionality into classes.
First, a quick recap: In JavaScript, a “class” is implemented as a constructor function and its prototype. Instances of the class are created by calling the constructor with new
. They “inherit” shared behaviour from the constructor’s prototype
property. One way to share behaviour scattered across multiple classes, or to untangle behaviour by factoring it out of an overweight prototype, is to extend a prototype with a mixin.
Here’s an evolved class of todo items we saw earlier:
And a “mixin:”
Mixing colour coding into our Todo prototype is straightforward:
what is a “mixin?”
Like “class,” the word “mixin” means different things to different people. A Ruby user will talk about modules, for example. And a JavaScript user could in truth say that everything is an object and we’re just extending one object (that happens to be a prototype) with the properties of another object (that just happens to contain some functions).
A simple definition that works for most purposes is to define a mixin as: A collection of behaviour that can be added to a class’s existing prototype. ColourCoded
above is such a mixin. If we had to actually assign a new prototype to the Todo
class, that wouldn’t be mixing functionality in, that would be replacing functionality.
functional mixins
The mixin we have above works properly, but our little recipe had two distinct steps: Define the mixin and then extend the class prototype. Angus Croll pointed out that it’s far more elegant to define a mixin as a function rather than an object. He calls this a functional mixin. Here’s our ColourCoded
recast in functional form:
Notice that we mix the functionality into the prototype. This keeps our mixing flexible: You could mix functionality directly into an object if you so choose. Twitter’s Flight framework uses a variation on this technique that targets the mixin function’s context:
This approach has some subtle benefits: You can use mixins as methods, for example. It’s possible to write a context-agnostic functional mixin:
Bueno!
Class Decorators
Functional Mixins look a lot like the function and method decorators we’ve seen. The big difference is that the mixin alters its subject, whereas the function decorators return a new function that wraps the old one. That can be handy if we wish, for example, to have some Todos that are not colour coded and we don’t want to have a wild hierarchy of inheritance or if we wish to dynamically mix functionality into a class.
There is a strong caveat: At this time, JavaScript is inflexible about dynamically paramaterizing calls to constructors. Therefore, the function decorator pattern being discussed here only works with constructors that are new agnostic1 and that can create an “empty object.”
Once again, our Todo class:
Here’s our ColourCoded
as a class decorator: It returns a new class rather than modifying ToDo
:
Although the implementation is more subtle, class decorators can be an improvement on functional mixins when you wish to avoid destructively modifying an existing prototype.
Interlude: Tortoises, Hares, and Teleporting Turtles
A good long while ago (The First Age of Internet Startups), someone asked me one of those pet algorithm questions. It was, “Write an algorithm to detect a loop in a linked list, in constant space.”
I’m not particularly surprised that I couldn’t think up an answer in a few minutes at the time. And to the interviewer’s credit, he didn’t terminate the interview on the spot, he asked me to describe the kinds of things going through my head.
I think I told him that I was trying to figure out if I could adapt a hashing algorithm such as XORing everything together. This is the “trick answer” to a question about finding a missing integer from a list, so I was trying the old, “Transform this into a problem you’ve already solved” meta-algorithm. We moved on from there, and he didn’t reveal the “solution.”
I went home and pondered the problem. I wanted to solve it. Eventually, I came up with something and tried it (In Java!) on my home PC. I sent him an email sharing my result, to demonstrate my ability to follow through. I then forgot about it for a while. Some time later, I was told that the correct solution was:
This algorithm is called “The Tortoise and the Hare,” and was discovered by Robert Floyd in the 1960s. You have two node references, and one traverses the list at twice the speed of the other. No matter how large it is, you will eventually have the fast reference equal to the slow reference, and thus you’ll detect the loop.
At the time, I couldn’t think of any way to use hashing to solve the problem, so I gave up and tried to fit this into a powers-of-two algorithm. My first pass at it was clumsy, but it was roughly equivalent to this:
Years later, I came across a discussion of this algorithm, The Tale of the Teleporting Turtle. It seems to be faster under certain circumstances, depending on the size of the loop and the relative costs of certain operations.
What’s interesting about these two algorithms is that they both tangle two separate concerns: How to traverse a data structure, and what to do with the elements that you encounter. In Functional Iterators, we’ll investigate one pattern for separating these concerns.
Functional Iterators
Let’s consider a remarkably simple problem: Finding the sum of the elements of an array. In iterative style, it looks like this:
What’s the sum of a linked list of numbers? How about the sum of a tree of numbers (represented as an array of array of numbers)? Must we re-write the sum
function for each data structure?
There are two roads ahead. One involves a generalized reduce
or fold
method for each data structure. The other involves writing an Iterator for each data structure and writing our sum
to take an iterator as its argument. Let’s use iterators, especially since we need two different iterators for the same data structure, so a single object method is inconvenient.
Since we don’t have iterators baked into the underlying JavaScript engine yet, we’ll write our iterators as functions:
Summing an array that can contain nested arrays adds a degree of complexity. Writing a function that iterates recursively over a data structure is an interesting problem, one that is trivial in a language with coroutines. Since we don’t have Generators yet, and we don’t want to try to turn our loop detection inside-out, we’ll Greenspun our own coroutine by maintaining our own stack.
This business of managing your own stack may seem weird to anyone born after 1970, but old fogeys fondly remember that after walking barefoot to and from University uphill in a blizzard both ways, the interview question brain teaser of the day was to write a “Towers of Hanoi” solver in a language like BASIC that didn’t have reentrant subroutines.
We’ve successfully separated the issue of what one does with data from how one traverses over the elements.
folding
Just as pure functional programmers love to talk monads, newcomers to functional programming in multi-paradigm languages often drool over folding a/k/a mapping/injecting/reducing. We’re just a level of abstraction away:
Fold turns an iterator over a finite data structure into an accumulator. And once again, it works with any data structure. You don’t need a different kind of fold for each kind of data structure you use.
unfolding and laziness
Iterators are functions. When they iterate over an array or linked list, they are traversing something that is already there. But they could, in principle, manufacture the data as they go. Let’s consider the simplest example:
And here’s another one:
A function that starts with a seed and expands it into a data structure is called an unfold. It’s the opposite of a fold. It’s possible to write a generic unfold mechanism, but let’s pass on to what we can do with unfolded iterators.
This business of going on forever has some drawbacks. Let’s introduce an idea: A function that takes an Iterator and returns another iterator. We can start with take
, an easy function that returns an iterator that only returns a fixed number of elements:
With take
, we can do things like return the squares of the first five numbers:
How about the squares of the odd numbers from the first five numbers?
Bzzzt! Our odds
function returns an array, not an iterator.
You can’t take the first five odd numbers at all, because odds
tries to get the entire set of numbers and accumulate the odd ones in an array. This can be fixed. For unfolds and other infinite iterators, we need more functions that transform one iterator into another:
Now we can do things like take the sum of the first five odd squares of fibonacci numbers:
This solution composes the parts we already have, rather than writing a tricky bit of code with ifs and whiles and boundary conditions.
summary
Untangling the concerns of how to iterate over data from what to do with data leads us to thinking of iterators and working directly with iterators. For example, we can map and filter iterators rather than trying to write separate map and filter functions or methods for each type of data structure. This leads to the possibility of working with lazy or infinite iterators.
caveat
Please note that unlike most of the other functions discussed in this book, iterators are stateful. There are some important implications of stateful functions. One is that while functions like take(...)
appear to create an entirely new iterator, in reality they return a decorated reference to the original iterator. So as you traverse the new decorator, you’re changing the state of the original!
For all intents and purposes, once you pass an iterator to a function, you can expect that you no longer “own” that iterator, and that its state either has changed or will change.
Refactoring to Functional Iterators
In Tortoises, Hares, and Teleporting Turtles, we looked at the “Tortoise and Hare” algorithm for detecting a linked list. Like many such algorithms, it “tangles” two different concerns:
- The mechanism for iterating over a list.
- The algorithm for detecting a loop in a list.
functional iterators
We then went on to discuss how to use functional iterators to untangle concerns like this. A functional iterator is a stateful function that iterates over a data structure. Every time you call it, it returns the next element from the data structure. If and when it completes its traversal, it returns undefined
.
For example, here is a function that takes an array and returns a functional iterator over the array:
Iterators allow us to write (or refactor) functions to operate on iterators instead of data structures. That increases reuse. We can also write higher-order functions that operate directly on iterators such as mapping and selecting. That allows us to write lazy algorithms.
refactoring the tortoise and hare
Now we’ll refactor the Tortoise and Hare to use iterators instead of directly operate on linked lists. We’ll add an .iterator()
method to linked lists, and we’ll rewrite our loop detector function to take an “iterable” instead of a list:
We have now refactored it into a function that operates on anything that responds to the .iterator()
method. It’s classic “Duck Typed” Object-Orientation. So, how shall we put it to work?
A Drunken Walk Across A Chequerboard
Here’s another job interview puzzle.2
Consider a finite checkerboard of unknown size. On each square we randomly place an arrow pointing to one of its four sides. For convenience, we shall uniformly label the directions: N, S, E, and W. A chequer is placed randomly on the checkerboard. Each move consists of moving the red chequer one square in the direction of the arrow in the square it occupies. If the arrow should cause the chequer to move off the edge of the board, the game halts.
As a player moves the chequer, he calls out the direction of movement, e.g. “N, E, N, S, N, E…” Write an algorithm that will determine whether the game halts strictly from the called out directions, in constant space.
the insight
Our solution will rest on the observation that as the chequer follows a path, if it ever visits a square for a second time, it will cycle indefinitely without falling off the board. Otherwise, on a finite board, it must eventually fall off the board after at most visiting every square once.
Therefore, if we think of this as detecting whether the chequer revisits a square in constant space, we can see this is isomorphic to detecting whether a linked list has a loop by checking to see whether it revisits the same node.
the game
In essence, we’re given an object that has a .iterator()
method. That gives us an iterator, and each time we call the iterator, we get a direction. Here it is:
In the example above, we have the smallest possible repeating path: The chequer shuttles back and forth between two squares. It will not always be so obvious when a game does not terminate.
stateful mapping
Our goal is to transform the iteration of directions into an iteration that the Tortoise and Hare can use to detect revisiting the same square. Our approach is to convert the directions into offsets representing the position of the chequer relative to its starting position.
We’ll use a statefulMap
:
statefulMap
takes in iterator and maps it to a new iterator. Unlike a “regular” map, it computes its elements on demand, so it will not run indefinitely when given an iteration representing an infinitely looping chequer. We need a stateful map because we are tracking a position that changes over time even when given the same direction over and over again.
Here’s how we use statefulMap
:
We’re almost there! The refactored tortoiseAndHareLoopDetector
expects an “iterable,” an object that implements the .iterator()
method. Let’s refactor RelativeIterable
to accept a game and return an iterable instead of accepting an iteration and returning an iteration:
the solution
So. We can take a Game
instance and produce an iterable that iterates over regular strings representing relative positions. If it terminates on its own, the game obviously terminates. And if it repeats itself, the game does not terminate.
Our refactored tortoiseAndHareLoopDetector
takes an iterable and detects this for us. Writing a detector function is trivial:
preliminary conclusion
Untangling the mechanism of following a linked list from the algorithm of searching for a loop allows us to repurpose the Tortoise and Hare algorithm to solve a question about a path looping.
no-charge extra conclusion
Can we also refactor the “Teleporting Turtle” algorithm to take an iterable? If so, we should be able to swap algorithms for our game termination detection without rewriting everything in sight. Let’s try it:
We start with:
And refactor it to become:
Now we can plug it into our termination detector:
Refactoring an algorithm to work with iterators allows us to use the same algorithm to solve different problems and to swap algorithms for the same problem. This is natural, we have created an abstraction that allows us to plug different items into either side of its interface.
Trampolining
A trampoline is a loop that iteratively invokes thunk-returning functions (continuation-passing style). A single trampoline is sufficient to express all control transfers of a program; a program so expressed is trampolined, or in trampolined style; converting a program to trampolined style is trampolining. Trampolined functions can be used to implement tail-recursive function calls in stack-oriented programming languages.–Wikipedia
This description is exactly how one ought to answer the question “define trampolining” on an examination, because it demonstrates that you’ve learned the subject thoroughly. But if asked to explain trampolining, a more tutorial-focused approach is called for.
Let’s begin with a use case.
recursion, see recursion
Consider implementing factorial
in recursive style:
The immediate limitation of this implementation is that since it calls itself n times, to get a result you need a stack on n stack frames in a typical stack-based programming language implementation. And JavaScript is such an implementation.
This creates two problems: First, we need space On for all those stack frames. It’s as if we actually wrote out 1 x 1 x 2 x 3 x 4 x ...
before doing any calculations. Second, most languages have a limit on the size of the stack much smaller than the limit on the amount of memory you need for data.
For example:
We can easily rewrite this in iterative style, but there are other functions that aren’t so amenable to rewriting and using a simple example allows us to concentrate on the mechanism rather than the “domain.”
tail-call elimination
Lisp programmers in days of yore would rewrite functions like this into “Tail Recursive Form,” and that made it possible for their compilers to perform Tail-Call Optimization. Meaning, that when a function returns the result of calling itself, the language doesn’t actually perform another function call, it turns the whole thing into a loop for you.
What we need to do is take the expression n * factorial(n - 1)
and push it down into a function so we can just call it with parameters. When a function is called, a stack frame is created that contains all the information needed to resume execution with the result. Stack frames hold a kind of pointer to where to carry on evaluating, the function parameters, and other bookkeeping information.3
If we use the symbol _
to represent a kind of “hole” in an expression where we plan to put the result, every time factorial
calls itself, it needs to remember n * _
so that when it gets a result back, it can multiply it by n
and return that. So the first time it calls itself, it remembers 10 * _
, the second time it calls itself, it remembers 9 * _
, and all these things stack up like this when we call factorial(10)
:
Finally, we call factorial(0)
and it returns 1
. Then the top is popped off the stack, so we calculate 1 * 1
. It returns 1
again and we calculate 2 * 1
. That returns 2
and we calculate 3 * 2
and so on up the stack until we return 10 * 362880
and return 3628800
, which we print.
How can we get around this? Well, imagine if we don’t have a hole in a computation to return. In that case, we wouldn’t need to “remember” anything on the stack. To make this happen, we need to either return a value or return the result of calling another function without any further computation.
Such a call is said to be in “tail position” and to be a “tail call.” The “elimination” of tail-call elimination means that we don’t perform a full call including setting up a new stack frame. We perform the equivalent of a “jump.”
For example:
Now our function either returns a value or it returns the result of calling another function without doing anything with that result. This gives us the correct results, but we can see that current implementations of JavaScript don’t perform this magic “tail-call elimination.”
So we’ll do it ourselves.
trampolining
One way to implement tail-call elimination is also handy for many other general things we might want to do with control flow, it’s called trampolining. What we do is this:
When we call a function, it returns a thunk that we call to get a result. Of course, the thunk can return another thunk, so every time we get a result, we check to see if it’s a thunk. If not, we have our final result.
A thunk is a function taking no arguments that delays evaluating an expression. For example, this is a thunk: function () { return 'Hello World'; }
.
An extremely simple and useful implementation of trampolining can be found in the Lemonad library. It works provided that you want to trampoline a function that doesn’t return a function. Here it is:
We’ll rewrite it in combinatorial style for consistency and composeability:
Now here’s our implementation of factorial
that is wrapped around a trampolined tail recursive function:
Presto, it runs for n = 32768
. Sadly, JavaScript’s built-in support for integers cannot keep up, so we’d better fix the “infinity” problem with a “big integer” library:4
Well, it now takes a very long time to run, but it is going to get us the proper result and we can print that as a string, so we’ll leave it calculating in another process and carry on.
The limitation of the implementation shown here is that because it tests for the function returning a function, it will not work for functions that return functions. If you want to trampoline a function that returns a function, you will need a more sophisticated mechanism, but the basic principle will be the same: The function will return a thunk instead of a value, and the trampolining loop will test the returned thunk to see if it represents a value or another computation to be evaluated.
trampolining co-recursive functions
If trampolining was only for recursive functions, it would have extremely limited value: All such functions can be re-written iteratively and will be much faster (although possibly less elegant). However, trampolining eliminates all calls in tail position, including calls to other functions.
Consider this delightfully simple example of two co-recursive functions:
Like our factorial
, it consumes n stack space of alternating calls to even
and odd
:
Obviously we can solve this problem with modulo arithmetic, but consider that what this shows is a pair of functions that call other functions in tail position, not just themselves. As with factorial, we separate the public interface that is not trampolined from the trampolined implementation:
And presto:
Trampolining works with co-recursive functions, or indeed any function that can be rewritten in tail-call form.
summary
Trampolining is a technique for implementing tail-call elimination. Meaning, if you take a function (whether recursive, co-recursive, or any other form) and rewrite it in tail-call form, you can eliminate the need to create a stack frame for every ‘invocation’.
Trampolining is very handy in a language like JavaScript, in that it allows you to use a recursive style for functions without worrying about limitations on stack sizes.
- Another approach that works with ECMAScript 5 and later is to base all classes around Object.create↩
- This book does not blindly endorse asking programmers to solve this or any abstract problem in a job interview.↩
- Did you know that “bookkeeping” is the only word in the English language containing three consecutive letter pairs? You’re welcome.↩
- The use of a third-party big integer library is not essential to understand trampolining.↩
12. Recipes for New Ideas
“The entire history of Mankind’s relationship with coffee is a futile attempt to have the reality of its taste live up to the promise of its aroma.”
Before
Combinators for functions come in an unlimited panoply of purposes and effects. So do method combinators, but whether from intrinsic utility or custom, certain themes have emerged. One of them that forms a core part of the original Lisp Flavors system and also the Aspect-Oriented Programming movement, is decorating a method with some functionality to be performed before the method’s body is evaluated.
For example, using our fluent recipe:
This particular example might be better-served as a state machine, but what we want to encode is that we must always mix the ingredients before allowing the batter to rise or baking the cake. The direct way to write that is:
Nothing wrong with that, however it does clutter the core functionality of rising and baking with a secondary concern, preconditions. There is a similar problem with cross-cutting concerns like logging or checking permissions: You want functions to be smaller and more focused, and decomposing into smaller methods is ugly:
the before recipe
This recipe is for a combinator that turns a function into a method decorator. The decorator evaluates the function before evaluating the base method. Here it is:
And here we are using it in conjunction with fluent
, showing the power of composing combinators:
The decorators act like keywords or annotations, documenting the method’s behaviour but clearly separating these secondary concerns from the core logic of the method.
(before, after, and many more combinators for building method decorators can be found in the method combinators module.)
After
Combinators for functions come in an unlimited panoply of purposes and effects. So do method combinators, but whether from intrinsic utility or custom, certain themes have emerged. One of them that forms a core part of the original Lisp Flavors system and also the Aspect-Oriented Programming movement, is decorating a method with some functionality to be performed after the method’s body is evaluated.
For example, consider this “class:”
If we’re rolling our own model class, we might mix in Backbone.Events. Now we can have views listen to our todo items and render themselves when there’s a change. Since we’ve already seen before, we’ll jump right to the recipe for after
, a combinator that turns a function into a method decorator:
And here it is in use to trigger change events on our Todo
“class.” We’re going to be even more sophisticated and paramaterize our decorators.
The decorators act like keywords or annotations, documenting the method’s behaviour but clearly separating these secondary concerns from the core logic of the method.
(before, after, and many more combinators for building method decorators can be found in the method combinators module.)
Provided and Except
Neither the before and after decorators can actually terminate evaluation without throwing something. Normal execution always results in the base method being evaluated. The provided
and excepting
recipes are combinators that produce method decorators that apply a precondition to evaluating the base method body. If the precondition fails, nothing is returned.
The provided combinator turns a function into a method decorator. The function must evaluate to truthy for the base method to be evaluated:
provided
can be used to create named decorators like maybe
:
You can build your own domain-specific decorators:
except
works identically, but with the logic reversed.
A Functional Mixin Factory
Functional Mixins extend an existing class’s prototype. Let’s start with:
We wish to decorate this with:
Instead of writing:
We’ll extract the decoration into a parameter like this:
And then “curry” the function manually like this:
We can try it:
Success! Our mixin
function makes functional mixins. A final refinement is to make it “context-agnostic,” so that we can write either MixinLocation.call(Todo.prototype)
or MixinLocation(Todo.prototype)
:
A Class Decorator Factory
As discussed, a class decorator creates a new class with some additional decoration. It’s lighter weight than subclassing. It’s also easy to write a factory function that makes decorators for us. Recall:
We wish to decorate this with:
Instead of writing:
We’ll extract the decoration into a parameter like this:
And then “curry” the function manually like this:
We can try it:
Success! Our classDecorator
function makes class decorators.
Iterator Recipes
iterators for standard data structures
Note: Despite having capitalized names, iterators are not meant to be used with the new
keyword.
unfolding iterators
decorators for slicing iterators
(drop
was suggested by Redditor skeeto. His code also cleaned up an earlier version of slice
.)
catamorphic decorator
hylomorphic decorators
The Golden Crema
Author’s Notes
Dear friends and readers:
On October 1st, 2013, I announced that JavaScript Allongé became free: It is now licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License. You are free:
- to Share—to copy, distribute and transmit the work
- to Remix—to adapt the work
- to make commercial use of the work
Read the license yourself for the full details. But the bottom line is, it’s free, free, FREE!
And don’t just take my word for it, here’s the entire book online.
And now, a few questions and answers…
allong.es
sounds familiar…
The recipes in JavaScript Allonge inspired a companion library called allong.es. It’s free to use, of course. Please try it out. It complements the libraries you may already be using like Underscore.
I noticed that the recipes changed in early 2013. Why?
Based on feedback from people exposed to other programming languages, I’ve renamed some of the recipe functions. While doing so, I also rewrote the partial application and some other parts of allong.es to exploit symmetry.
The new nomenclature has a few conventions. First, unless suffixed with Now
, all functions are already curried. So you can write either map(list, function)
or map(list)(function)
. There isn’t one, but if there was a map
that wasn’t curried, it would be called mapNow
.
By default, functions take a data structure first and an operation second and are named after a verb, i.e. map
, filter
. As noted, they are curried by default.
Binary functions like map
have a variation with their arguments flipped to have the “verb” first and the subject second. They are suffixed With
, so you call map(list, function)
or mapWith(function, list)
.
Under the new nomenclature, what used to be called splat
is now called mapWith
, and when you supply only the function, the currying takes care of returning a function that takes as list as its argument. You’re mapping with a function.
The examples seem to use apply
and call
indiscriminately. Why?
In functional programming tradition, the function apply
is used for functional application. Variations include applyLeft
and applyLast
. JavaScript is a little different: All functions have two methods: .apply
takes an array of arguments, while .call
takes separate arguments.
So the recipes in JavaScript Allongé follow the JavaScript convention: Those named apply
take an array of arguments, while those named call
take individual arguments. If you’re coming to this book with some functional programming under your belt, you’ll find the functions work the same way, it’s just that there are two of them to handle the two different ways to apply arguments to a function.
I don’t want to pay to download a PDF. Can I make my own?
Yes, you can take the HTML that is available online or the markdown source in the repository and make your own PDF. Or any other format. Please be aware that while it’s technically possible to game the LeanPub system to produce the PDF or other formats, I ask you as a personal favour to find another way to make a PDF.
The license permits this choice, but IMO it is contrary to the spirit of sharing and openness to use their resources and work to do something that isn’t aligned with their mission. And of course, they may not care for the idea, I don’t know and I don’t want to undermine what has been a tremendous service for helping people write great technical books.
Great book! Can I share it?
And I’d also like you to share it, in this form, in PDF, or anything else. Go wild, just follow the attribution rules in the license.
Great book! Can I still buy it?
I don’t want to buy it, but I’d like to say “thank you” with a tip.
Sure thing, you can send a donation via PayPal to reg@braythwayt.com, or click this button to donate $10 to help me write:
Hey, I have a great way to make money with this…
Go for it, you are free to make commercial use of the work. For example, you could host it on your site and make money from ads, or write a JS tool and use the book as part of the help content.
It’s all good, just follow the license terms. It is technically possible to create an identical clone of the book on LeanPub. I do not prohibit this activity, but I do ask you as a personal favour to ask yourself whether you could do even better, for instance to add value by adding your own annotations, expansions, and commentary. I’d love to see an “Annotated JavaScript Allongé.”
I’d also love to see translations, editions with large print, or anything else that brings something new to the world. Many people have asked for a hard-copy version. Who will be the first to set up shop on lulu.com?
I found a typo! How do I tell you about it?
My email inbox is a disaster zone, so let’s treat the book like open source. In order of my preference, you should:
- Create an issue, fork the repo, fix the issue, and then send me a pull request. (Best!!)
- Fork the repo, fix things to your satisfaction, and then send me a pull request. (Better!)
- Create an issue. (Good.)
Thanks!
How to run the examples
If you follow the instructions at nodejs.org to install NodeJS and JavaScript,1 you can run an interactive JavaScript REPL on your command line simply by typing node
. This is how the examples in this book were tested, and what many programmers will do.
On OS X, you have the option of running Safaris’s JavaScript engine from the command line, or of installing a TextMate bundle. We didn’t use this method to test the examples, so proceed at your own risk. But have fun!
Almost all browsers have a mechanism to function as JavaScript REPLs, allowing you to type JavaScript expressions into a debug console.
Thanks!
Daniel Friedman and Matthias Felleisen
JavaScript Allongé was inspired by The Little Schemer by Daniel Friedman and Matthias Felleisen. But where The Little Schemer’s primary focus is recursion, JavaScript Allongé’s primary focus is functions as first-class values.
Richard Feynman
Richard Feynman’s QED was another inspiration: A book that explains Quantum Electrodynamics and the “Sum of the Histories” methodology using the simple expedient of explaining how light reflects off a mirror, and showing how most of the things we think are happening–such as light travelling on a straight line, the angle of reflection equalling the angle of refraction, or that a beam of light only interacts with a small portion of the mirror, or that it reflects off a plane–are all wrong. And everything is explained in simple, concise terms that build upon each other logically.
JavaScript Spessore
Programming languages are (loosely) defined by their basic activity. In FORTRAN, we program with numbers. In C, we program with pointers. In ML, we program with types. And as JavaScript Allongé explains, in JavaScript we program with functions.
Functions are very interesting building blocks for programs, because they compose: It’s easy to build a programming style based on making many small things that can be combined and recombined to make bigger things.
This is the basis of the vaunted “Unix Philosophy:” Write small utilities and scripts that compose neatly. This is also the JavaScript philosophy: Make small things that can be combined and recombined to make bigger things.
Programming with objects can be done in this style, and JavaScript makes it particularly easy to combine and recombine small parts. Classes can be built from traits instead of from superclasses. Objects can delegate and forward behaviour to helpers and meta-objects. Adaptors can be written to change an object’s interface without needing to create another class in a hierarchy.
JavaScript Spessore is a book that describes this approach to working with objects and metaobjects in JavaScript. It’s exactly the same philosophy as you find in JavaScript Allongé, only it talks to programming with objects instead of programming with functions.
JavaScript Spessore describes how to build JavaScript programs that scale in code, in time, and across a team, using the one technique that has passed the test of time: Objects and metaobjects that have a single responsibility, are decoupled from each other, and can be composed freely.
Now that you’ve read JavaScript Allongé, JavaScript Spessore should be next.
Copyright Notice
The original words in this book are (c) 2012-2013, Reginald Braithwaite. All rights reserved.
images
- The picture of the author is (c) 2008, Joseph Hurtado, All Rights Reserved.
- Cover image (c) 2010, avlxyz. Some rights reserved.
- Double ristretto menu (c) 2010, Michael Allen Smith. Some rights reserved.
- Short espresso shot in a white cup with blunt handle (c) 2007, EVERYDAYLIFEMODERN. Some rights reserved.
- Espresso shot in a caffe molinari cup (c) 2007, EVERYDAYLIFEMODERN. Some rights reserved.
- Beans in a Bag (c) 2008, Stirling Noyes. Some Rights Reserved.
- Free Samples (c) 2011, Myrtle Bech Digitel. Some Rights Reserved.
- Free Coffees image (c) 2010, Michael Francis McCarthy. Some Rights Reserved.
- La Marzocco (c) 2009, Michael Allen Smith. Some rights reserved.
- Cafe Diplomatico (c) 2011, Missi. Some rights reserved.
- Sugar Service (c) 2008 Tiago Fernandes. Some rights reserved.
- Biscotti on a Rack (c) 2010 Kirsten Loza. Some rights reserved.
- Coffee Spoons (c) 2010 Jenny Downing. Some rights reserved.
- Drawing a Doppio (c) 2008 Osman Bas. Some rights reserved.
- Cupping Coffees (c) 2011 Dennis Tang. Some rights reserved.
- Three Coffee Roasters (c) 2009 Michael Allen Smith. Some rights reserved.
- Blue Diedrich Roaster (c) 2010 Michael Allen Smith. Some rights reserved.
- Red Diedrich Roaster (c) 2009 Richard Masoner. Some rights reserved.
- Roaster with Tree Leaves (c) 2007 ting. Some rights reserved.
- Half Drunk (c) 2010 Nicholas Lundgaard. Some rights reserved.
- Anticipation (c) 2012 Paul McCoubrie. Some rights reserved.
- Ooh! (c) 2012 Michael Coghlan. Some rights reserved.
- Intestines of an Espresso Machine (c) 2011 Angie Chung. Some rights reserved.
- Bezzera Espresso Machine (c) 2011 Andrew Nash. Some rights reserved. *Beans Ripening on a Branch (c) 2008 John Pavelka. Some rights reserved.
- Cafe Macchiato on Gazotta Della Sport (c) 2008 Jon Shave. Some rights reserved.
- Jars of Coffee Beans (c) 2012 Memphis CVB. Some rights reserved.
- Types of Coffee Drinks (c) 2012 Michael Coghlan. Some rights reserved.
- Coffee Trees (c) 2011 Dave Townsend. Some rights reserved.
- Cafe do Brasil (c) 2003 Temporalata. Some rights reserved.
- Brown Cups (c) 2007 Michael Allen Smith. Some rights reserved.
- Mirage (c) 2010 Mira Helder. Some rights reserved.
- Coffee Van with Bullet Holes (c) 2006 Jon Crel. Some rights reserved.
- Disassembled Elektra (c) 2009 Nicholas Lundgaard. Some rights reserved.
- Nederland Buffalo Bills Coffee Shop (c) 2009 Charlie Stinchcomb. Some rights reserved.
- For the love of coffee (c) 2007 Lotzman Katzman. Some rights reserved.
- Saltspring Processing Facility Pictures (c) 2011 Kris Krug. Some rights reserved.
About The Author
When he’s not shipping JavaScript, Ruby, CoffeeScript and Java applications scaling out to millions of users, Reg “Raganwald” Braithwaite has authored libraries for JavaScript, CoffeeScript, and Ruby programming such as Method Combinators, Katy, JQuery Combinators, YouAreDaChef, andand, and others.
He writes about programming on “Raganwald,” as well as general-purpose ruminations on “Braythwayt Dot Com”.
contact
Twitter: @raganwald Email: reg@braythwayt.com
- Instructions for installing NodeJS and modules like JavaScript onto a desktop computer is beyond the scope of this book, especially given the speed with which things advance. Fortunately, there are always up-to-date instructions on the web.↩