An Intro to Javascript for Experienced Programmers Who Could Use a Strong Dose of Fundamentals

Use them in the body, of course.

What do you think this is?(diameter) => diameter * 3.

14159265It’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 (() => {})().

To apply a function with an argument (or arguments), we put the argument (or arguments) within the parentheses, like this:((diameter) => diameter * 3.

14159265)(2) //=> 6.

2831853You won’t be surprised to see how to write and apply a function to two arguments:((room, board) => room + board)(800, 150) //=> 950a quick summary of functions and bodiesHow arguments are used in a body’s expression is probably perfectly obvious to you from the examples, especially if you’ve used any programming language (except for the dialect of BASIC–which I recall from my secondary school–that didn’t allow parameters when you called a procedure).

Expressions consist either of representations of values (like 3.

14159265, true, and undefined), operators that combine expressions (like 3 + 2), some special forms like [1, 2, 3] for creating arrays out of expressions, or function (arguments) {body-statements} for creating functions.

One of the important possible statements is a return statement.

A return statement accepts any valid JavaScript expression.

This loose definition is recursive, so we can intuit (or use our experience with other languages) that since a function can contain a return statement with an expression, we can write a function that returns a function, or an array that contains another array expression.

Or a function that returns an array, an array of functions, a function that returns an array of functions, and so forth:() => () => {}; () => [ 1, 2, 3]; [1, [2, 3], 4]; () => [ () => 1, () => 2, () => 3 ];call by valueLike 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:((diameter) => diameter * 3.

14159265)(1 + 1) //=> 6.

2831853What happened internally is that the expression 1 + 1 was evaluated first, resulting in 2.

Then our circumference function was applied to 2.

We’ll see below that while JavaScript always calls by value, the notion of a “value” has additional subtlety.

But before we do, let’s look at variables.

variables and bindingsRight 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 (diameter) => diameter * 3.

14159265 to functions like:(x) => (y) => x(x) => (y) => x just looks crazy, as if we are learning English as a second language and the teacher promises us that soon we will be using words like antidisestablishmentarianism.

Besides a desire to use long words to sound impressive, this is not going to seem attractive until we find ourselves wanting to discuss the role of the Church of England in 19th-century British politics.

But there’s another reason for learning the word antidisestablishmentarianism: We might learn how prefixes and postfixes work in English grammar.

It’s the same thing with (x) => (y) => x.

It has a certain important meaning in its own right, and it’s also an excellent excuse to learn about functions that make functions, environments, variables, and more.

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 (x) => .

, is an argument.

The yin function (y) .

is another argument.

The second x, the one in => 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 (x) => (y) => x or just plain (x) => 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:((x) => x)(2) //=> 2What 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-expressionsOne sub-expression, (x) => 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 sharingEarlier, 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 argument you apply it to:(value) => ((ref1, ref2) => ref1 === ref2)(value, value)Closures and ScopeIt’s time to see how a function within a function works:((x) => (y) => x)(1)(2) //=> 1First 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:((x) => (y) => x)(1) //=> [Function]The environment belonging to the function with signature (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 (x) => .

’s body is:(y) => xSo 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:((y) => x)(2)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.

This, by the way, is one of the great defining characteristics of JavaScript and languages in the same family: Whether they allow things like functions to nest inside each other, and if so, how they handle variables from “outside” of a function that are referenced inside a function.

For example, here’s the equivalent code in Ruby:lambda { |x| lambda { |y| x } }[1][2] #=> 1if functions without free variables are pure, are closures impure?The function (y) => x is interesting.

It contains a free variable, x.

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 (y) => 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:() => {} (x) => x (x) => (y) => xThe 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.

(y) => .

has a free variable, but the entire expression refers to (x) => .

, and it doesn’t have a free variable: The only variable anywhere in its body is x, which is certainly bound within (x) => .

From this, we learn something: A pure function can contain a closure.

If pure functions can contain closures, can a closure contain a pure function?.Using only what we’ve learned so far, attempt to compose a closure that contains a pure function.

If you can’t, give your reasoning for why it’s impossible.

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 (x, y) => x + y, we know exactly what it does with (2, 2).

But what about this closure: (y) => 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 environmentTo 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 ((x) => (y) => x)(1) is {x: 1, .

} and that the environment for ((y) => x)(2) is {y: 2, .

}?.Let’s fill in the blanks!The environment for ((y) => x)(2) is actually {y: 2, '.

': {x: 1, .

}}.

'.

' means something like “parent” or “enclosure” or “super-environment.

” It’s (x) => .

’s environment, because the function (y) => xis within (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 ((y) => x)(2) in the environment {y: 2, '.

': {x: 1, .

}}.

The variable x isn’t in (y) => .

’s immediate environment, but it is in its parent’s environment, so it evaluates to 1 and that’s what ((y) => x)(2) returns even though it ended up ignoring its own argument.

(x) => x is called the I Combinator, or the Identity Function.

(x) => (y) => x is called the K Combinator, or Kestrel.

Some people get so excited by this that they write entire books about them, some are great, some — how shall I put this — are interesting if you use Ruby.

Functions can have grandparents too:(x) => (y) => (z) => x + y + zThis function does much the same thing as:(x, y, z) => x + y + zOnly 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).

The first function is the result of currying the second function.

Calling a curried function with only some of its arguments is sometimes called partial application.

Some programming languages automatically curry and partially evaluate functions without the need to manually nest them.

shadowy variables from a shadowy planetAn interesting thing happens when a variable has the same name as an ancestor environment’s variable.

Consider:(x) => (x, y) => x + yThe function (x, y) => 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:(x) => (x, y) => (w, z) => (w) => x + y + zWhen 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 ws.

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 (x) => 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 ((x) => 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:// top of the file (() => { // .

lots of JavaScript .

})(); // bottom of the fileThe effect is to insert a new, empty environment in between the global environment and your own functions: {x: 1, '.

': {'.

': global environment}}.

his helps to prevent programmers from accidentally changing the global state that is shared by all code in the program.

That Constant Coffee CravingUp 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:(diameter) => diameter * 3.

14159265What is this “3.

14159265” number?.PI, obviously.

We’d like to name it so that we can write something like:(diameter) => diameter * PIIn 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:((PI) => // ???? )(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:((PI) => (diameter) => diameter * PI )(3.

14159265)This expression, when evaluated, returns a function that calculates circumferences.

That sounds bad, but when we think about it, (diameter) => diameter * 3.

14159265 is also an expression, that when evaluated, returns a function that calculates circumferences.

All of our “functions” are expressions.

This one has a few more moving parts, that’s all.

But we can use it just like (diameter) => diameter * 3.

14159265.

Let’s test it:((diameter) => diameter * 3.

14159265)(2) //=> 6.

2831853 ((PI) => (diameter) => diameter * PI )(3.

14159265)(2) //=> 6.

2831853That 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.

inside-outThere’s another way we can make a function that binds 3.

14159265 to the name PI and then uses that in its expression.

We can turn things inside-out by putting the binding inside our diameter calculating function, like this:(diameter) => ((PI) => diameter * PI)(3.

14159265)It produces the same result as our previous expressions for a diameter-calculating function:((diameter) => diameter * 3.

14159265)(2) //=> 6.

2831853 ((PI) => (diameter) => diameter * PI )(3.

14159265)(2) //=> 6.

2831853 ((diameter) => ((PI) => diameter * PI)(3.

14159265))(2) //=> 6.

2831853Which one is better?. More details

Leave a Reply