commit 48c8d93b4a9d790153bde813947de5d65fd57de2 Author: wizardforcel <562826179@qq.com> Date: Sat Apr 28 14:32:58 2018 +0800 diff diff --git a/diff-en/2ech1-3ech1.diff b/diff-en/2ech1-3ech1.diff new file mode 100644 index 0000000..5a9fa32 --- /dev/null +++ b/diff-en/2ech1-3ech1.diff @@ -0,0 +1,273 @@ +diff --git a/2ech1.md b/3ech1.md +index 33d8537..57e5b20 100644 +--- a/2ech1.md ++++ b/3ech1.md +@@ -4,28 +4,26 @@ + > + > <footer>Master Yuan-Ma, <cite>The Book of Programming</cite></footer> + +-Inside the computer's world, there is only data. You can read data, modify data, create new data—but anything that isn't data simply does not exist. All this data is stored as long sequences of bits and is thus fundamentally alike. ++Inside the computer's world, there is only data. You can read data, modify data, create new data—but that which isn't data cannot be mentioned. All this data is stored as long sequences of bits and is thus fundamentally alike. + +-Bits are any kind of two-valued things, usually described as zeros and ones. Inside the computer, they take forms such as a high or low electrical charge, a strong or weak signal, or a shiny or dull spot on the surface of a CD. Any piece of discrete information can be reduced to a sequence of zeros and ones and thus represented in bits. ++_Bits_ are any kind of two-valued things, usually described as zeros and ones. Inside the computer, they take forms such as a high or low electrical charge, a strong or weak signal, or a shiny or dull spot on the surface of a CD. Any piece of discrete information can be reduced to a sequence of zeros and ones and thus represented in bits. + +-For example, think about how you might show the number 13 in bits. It works the same way you write decimal numbers, but instead of 10 different digits, you have only 2, and the weight of each increases by a factor of 2 from right to left. Here are the bits that make up the number 13, with the weights of the digits shown below them: ++For example, we can express the number 13 in bits. It works the same way as a decimal number, but instead of 10 different digits, you have only 2, and the weight of each increases by a factor of 2 from right to left. Here are the bits that make up the number 13, with the weights of the digits shown below them: + + ``` + 0 0 0 0 1 1 0 1 + 128 64 32 16 8 4 2 1 + ``` + +-So that's the binary number 00001101, or 8 + 4 + 1, which equals 13. ++So that's the binary number 00001101, or 8 + 4 + 1, or 13. + + ## Values + +-Imagine a sea of bits. An ocean of them. A typical modern computer has more than 30 billion bits in its volatile data storage. Nonvolatile storage (the hard disk or equivalent) tends to have yet a few orders of magnitude more. ++Imagine a sea of bits—an ocean of them. A typical modern computer has more than 30 billion bits in its volatile data storage (working memory). Nonvolatile storage (the hard disk or equivalent) tends to have yet a few orders of magnitude more. + +-![The Ocean of Bits](img/bit-sea.png) ++To be able to work with such quantities of bits without getting lost, we must separate them into chunks that represent pieces of information. In a JavaScript environment, those chunks are called _values_. Though all values are made of bits, they play different roles. Every value has a type that determines its role. Some values are numbers, some values are pieces of text, some values are functions, and so on. + +-To be able to work with such quantities of bits without getting lost, you can separate them into chunks that represent pieces of information. In a JavaScript environment, those chunks are called _values_. Though all values are made of bits, they play different roles. Every value has a type that determines its role. There are six basic types of values in JavaScript: numbers, strings, Booleans, objects, functions, and undefined values. +- +-To create a value, you must merely invoke its name. This is convenient. You don't have to gather building material for your values or pay for them. You just call for one, and _woosh_, you have it. They are not created from thin air, of course. Every value has to be stored somewhere, and if you want to use a gigantic amount of them at the same time, you might run out of bits. Fortunately, this is a problem only if you need them all simultaneously. As soon as you no longer use a value, it will dissipate, leaving behind its bits to be recycled as building material for the next generation of values. ++To create a value, you must merely invoke its name. This is convenient. You don't have to gather building material for your values or pay for them. You just call for one, and _woosh_, you have it. They are not really created from thin air, of course. Every value has to be stored somewhere, and if you want to use a gigantic amount of them at the same time, you might run out of memory. Fortunately, this is a problem only if you need them all simultaneously. As soon as you no longer use a value, it will dissipate, leaving behind its bits to be recycled as building material for the next generation of values. + + This chapter introduces the atomic elements of JavaScript programs, that is, the simple value types and the operators that can act on such values. + +@@ -39,19 +37,19 @@ Values of the _number_ type are, unsurprisingly, numeric values. In a JavaScript + + Use that in a program, and it will cause the bit pattern for the number 13 to come into existence inside the computer's memory. + +-JavaScript uses a fixed number of bits, namely 64 of them, to store a single number value. There are only so many patterns you can make with 64 bits, which means that the amount of different numbers that can be represented is limited. For _N_ decimal digits, the amount of numbers that can be represented is 10<sup>_N_</sup>. Similarly, given 64 binary digits, you can represent 2<sup>64</sup> different numbers, which is about 18 quintillion (an 18 with 18 zeros after it). This is a lot. ++JavaScript uses a fixed number of bits, namely 64 of them, to store a single number value. There are only so many patterns you can make with 64 bits, which means that the amount of different numbers that can be represented is limited. For _N_ decimal digits, the amount of numbers that can be represented is 10<sup>N</sup>. Similarly, given 64 binary digits, you can represent 2<sup>64</sup> different numbers, which is about 18 quintillion (an 18 with 18 zeros after it). That's a lot. + +-Computer memory used to be a lot smaller, and people tended to use groups of 8 or 16 bits to represent their numbers. It was easy to accidentally _overflow_ such small numbers—to end up with a number that did not fit into the given amount of bits. Today, even personal computers have plenty of memory, so you are free to use 64-bit chunks, which means you need to worry about overflow only when dealing with truly astronomical numbers. ++Computer memory used to be much smaller, and people tended to use groups of 8 or 16 bits to represent their numbers. It was easy to accidentally _overflow_ such small numbers—to end up with a number that did not fit into the given amount of bits. Today, even computers that fit in your pocket have plenty of memory, so you are free to use 64-bit chunks, and you need to worry about overflow only when dealing with truly astronomical numbers. + +-Not all whole numbers below 18 quintillion fit in a JavaScript number, though. Those bits also store negative numbers, so one bit indicates the sign of the number. A bigger issue is that nonwhole numbers must also be represented. To do this, some of the bits are used to store the position of the decimal point. The actual maximum whole number that can be stored is more in the range of 9 quadrillion (15 zeros), which is still pleasantly huge. ++Not all whole numbers below 18 quintillion fit in a JavaScript number, though. Those bits also store negative numbers, so one bit indicates the sign of the number. A bigger issue is that nonwhole numbers must also be represented. To do this, some of the bits are used to store the position of the decimal point. The actual maximum whole number that can be stored is more in the range of 9 quadrillion (15 zeros)—which is still pleasantly huge. + +-Fractional numbers are written by using a dot. ++Fractional numbers are written by using a dot: + + ``` + 9.81 + ``` + +-For very big or very small numbers, you can also use scientific notation by adding an “e” (for “exponent”), followed by the exponent of the number: ++For very big or very small numbers, you may also use scientific notation by adding an _e_ (for _exponent_), followed by the exponent of the number: + + ``` + 2.998e8 +@@ -71,7 +69,7 @@ The main thing to do with numbers is arithmetic. Arithmetic operations such as a + + The `+` and `*` symbols are called _operators_. The first stands for addition, and the second stands for multiplication. Putting an operator between two values will apply it to those values and produce a new value. + +-Does the example mean “add 4 and 100, and multiply the result by 11”, or is the multiplication done before the adding? As you might have guessed, the multiplication happens first. But as in mathematics, you can change this by wrapping the addition in parentheses. ++But does the example mean “add 4 and 100, and multiply the result by 11,” or is the multiplication done before the adding? As you might have guessed, the multiplication happens first. But as in mathematics, you can change this by wrapping the addition in parentheses: + + ``` + (100 + 4) * 11 +@@ -83,28 +81,29 @@ When operators appear together without parentheses, the order in which they are + + These rules of precedence are not something you should worry about. When in doubt, just add parentheses. + +-There is one more arithmetic operator, which you might not immediately recognize. The `%` symbol is used to represent the _remainder_ operation. `X % Y` is the remainder of dividing `X` by `Y`. For example, `314 % 100` produces `14`, and `144 % 12` gives `0`. Remainder's precedence is the same as that of multiplication and division. You'll often see this operator referred to as _modulo_, though technically _remainder_ is more accurate. ++There is one more arithmetic operator, which you might not immediately recognize. The `%` symbol is used to represent the _remainder_ operation. `X % Y` is the remainder of dividing `X` by `Y`. For example, `314 % 100` produces `14`, and `144 % 12` gives `0`. Remainder's precedence is the same as that of multiplication and division. You'll also often see this operator referred to as _modulo_. + + ### Special numbers + + There are three special values in JavaScript that are considered numbers but don't behave like normal numbers. + +-The first two are `Infinity` and `-Infinity`, which represent the positive and negative infinities. `Infinity - 1` is still `Infinity`, and so on. Don't put too much trust in infinity-based computation. It isn't mathematically solid, and it will quickly lead to our next special number: `NaN`. ++The first two are `Infinity` and `-Infinity`, which represent the positive and negative infinities. `Infinity - 1` is still `Infinity`, and so on. Don't put too much trust in infinity-based computation, though. It isn't mathematically sound, and it will quickly lead to our next special number: `NaN`. + +-`NaN` stands for “not a number”, even though it is a value of the number type. You'll get this result when you, for example, try to calculate `0 / 0` (zero divided by zero), `Infinity - Infinity`, or any number of other numeric operations that don't yield a precise, meaningful result. ++`NaN` stands for “not a number”, even though it _is_ a value of the number type. You'll get this result when you, for example, try to calculate `0 / 0` (zero divided by zero), `Infinity - Infinity`, or any number of other numeric operations that don't yield a meaningful result. + + ## Strings + +-The next basic data type is the _string_. Strings are used to represent text. They are written by enclosing their content in quotes. ++The next basic data type is the _string_. Strings are used to represent text. They are written by enclosing their content in quotes: + + ``` +-"Patch my boat with chewing gum" +-'Monkeys wave goodbye' ++`Down on the sea` ++"Lie on the ocean" ++'Float on the ocean' + ``` + +-Both single and double quotes can be used to mark strings as long as the quotes at the start and the end of the string match. ++You can use single quotes, double quotes, or backticks to mark strings, as long as the quotes at the start and the end of the string match. + +-Almost anything can be put between quotes, and JavaScript will make a string value out of it. But a few characters are more difficult. You can imagine how putting quotes between quotes might be hard. _Newlines_ (the characters you get when you press Enter) also can't be put between quotes. The string has to stay on a single line. ++Almost anything can be put between quotes, and JavaScript will make a string value out of it. But a few characters are more difficult. You can imagine how putting quotes between quotes might be hard. _Newlines_ (the characters you get when you press Enter) may only be included without escaping when the string is quoted with backticks (```). + + To make it possible to include such characters in a string, the following notation is used: whenever a backslash (`\`) is found inside quoted text, it indicates that the character after it has a special meaning. This is called _escaping_ the character. A quote that is preceded by a backslash will not end the string but be part of it. When an `n` character occurs after a backslash, it is interpreted as a newline. Similarly, a `t` after a backslash means a tab character. Take the following string: + +@@ -119,19 +118,31 @@ This is the first line + And this is the second + ``` + +-There are, of course, situations where you want a backslash in a string to be just a backslash, not a special code. If two backslashes follow each other, they will collapse together, and only one will be left in the resulting string value. This is how the string “`A newline character is written like "\n".`” can be expressed: ++There are, of course, situations where you want a backslash in a string to be just a backslash, not a special code. If two backslashes follow each other, they will collapse together, and only one will be left in the resulting string value. This is how the string “_A newline character is written like `"`\n`"`._” can be expressed: + + ``` + "A newline character is written like \"\\n\"." + ``` + ++Strings, too, have to be modeled as a series of bits to be able to exist inside the computer. The way JavaScript does this is based on the _Unicode_ standard. This standard assigns a number to virtually every character you would ever need, including characters from Greek, Arabic, Japanese, Armenian, and so on. If we have a number for every character, a string can be described by a sequence of numbers. ++ ++And that's what JavaScript does. But there's a complication: JavaScript's representation uses 16 bits per string element, which can describe up to 2<sup>16</sup> different characters. But Unicode defines more characters than that—about twice as many, at this point. So some characters, such as many emoji, take up two “character positions” in JavaScript strings. We'll come back to this in [Chapter 5](05_higher_order.html#code_units). ++ + Strings cannot be divided, multiplied, or subtracted, but the `+` operator _can_ be used on them. It does not add, but it _concatenates_—it glues two strings together. The following line will produce the string `"concatenate"`: + + ``` + "con" + "cat" + "e" + "nate" + ``` + +-There are more ways of manipulating strings, which we will discuss when we get to methods in [Chapter 4](04_data.html#methods). ++String values have a number of associated functions (_methods_) that can be used to perform other operations on them. We'll come back to these in [Chapter 4](04_data.html#methods). ++ ++Strings written with single or double quotes behave very much the same—the only difference is in which type of quote you need to escape inside of them. Backtick-quoted strings, usually called _template literals_, can do a few more tricks. Apart from being able to span lines, they can also embed other values. ++ ++``` ++`half of 100 is ${100 / 2}` ++``` ++ ++When you write something inside `${}` in a template literal, its result will be computed, converted to a string, and included at that position. The example produces “_half of 100 is 50_”. + + ## Unary operators + +@@ -144,7 +155,7 @@ console.log(typeof "x") + // → string + ``` + +-We will use `console.log` in example code to indicate that we want to see the result of evaluating something. When you run such code, the value produced should be shown on the screen, though how it appears will depend on the JavaScript environment you use to run it. ++We will use `console.log` in example code to indicate that we want to see the result of evaluating something. More about that in the [next chapter](02_program_structure.html). + + The other operators we saw all operated on two values, but `typeof` takes only one. Operators that use two values are called _binary_ operators, while those that take one are called _unary_ operators. The minus operator can be used both as a binary operator and as a unary operator. + +@@ -155,9 +166,9 @@ console.log(- (10 - 2)) + + ## Boolean values + +-Often, you will need a value that simply distinguishes between two possibilities, like “yes” and “no” or “on” and “off”. For this, JavaScript has a _Boolean_ type, which has just two values: true and false (which are written simply as those words). ++It is often useful to have a value that distinguishes between only two possibilities, like “yes” and “no” or “on” and “off”. For this purpose, JavaScript has a _Boolean_ type, which has just two values: true and false, which are written as those words. + +-### Comparisons ++### Comparison + + Here is one way to produce Boolean values: + +@@ -177,16 +188,18 @@ console.log("Aardvark" < "Zoroaster") + // → true + ``` + +-The way strings are ordered is more or less alphabetic: uppercase letters are always “less” than lowercase ones, so `"Z" < "a"` is true, and non-alphabetic characters (!, -, and so on) are also included in the ordering. The actual comparison is based on the _Unicode_ standard. This standard assigns a number to virtually every character you would ever need, including characters from Greek, Arabic, Japanese, Tamil, and so on. Having such numbers is useful for storing strings inside a computer because it makes it possible to represent them as a sequence of numbers. When comparing strings, JavaScript goes over them from left to right, comparing the numeric codes of the characters one by one. ++The way strings are ordered is roughly alphabetic, but not really what you'd expect to see in a dictionary: uppercase letters are always “less” than lowercase ones, so `"Z" < "a"`, and nonalphabetic characters (!, -, and so on) are also included in the ordering. When comparing strings, JavaScript goes over the characters from left to right, comparing the Unicode codes one by one. + + Other similar operators are `>=` (greater than or equal to), `<=` (less than or equal to), `==` (equal to), and `!=` (not equal to). + + ``` + console.log("Itchy" != "Scratchy") + // → true ++console.log("Apple" == "Orange") ++// → false + ``` + +-There is only one value in JavaScript that is not equal to itself, and that is `NaN`, which stands for “not a number”. ++There is only one value in JavaScript that is not equal to itself, and that is `NaN` (“not a number”). + + ``` + console.log(NaN == NaN) +@@ -234,19 +247,19 @@ console.log(false ? 1 : 2); + // → 2 + ``` + +-This one is called the _conditional_ operator (or sometimes just _ternary_ operator since it is the only such operator in the language). The value on the left of the question mark “picks” which of the other two values will come out. When it is true, the middle value is chosen, and when it is false, the value on the right comes out. ++This one is called the _conditional_ operator (or sometimes just _ternary_ operator since it is the only such operator in the language). The value on the left of the question mark “picks” which of the other two values will come out. When it is true, it chooses the middle value, and when it is false, the value on the right. + +-## Undefined values ++## Empty values + +-There are two special values, written `null` and `undefined`, that are used to denote the absence of a meaningful value. They are themselves values, but they carry no information. ++There are two special values, written `null` and `undefined`, that are used to denote the absence of a _meaningful_ value. They are themselves values, but they carry no information. + + Many operations in the language that don't produce a meaningful value (you'll see some later) yield `undefined` simply because they have to yield _some_ value. + +-The difference in meaning between `undefined` and `null` is an accident of JavaScript's design, and it doesn't matter most of the time. In the cases where you actually have to concern yourself with these values, I recommend treating them as interchangeable (more on that in a moment). ++The difference in meaning between `undefined` and `null` is an accident of JavaScript's design, and it doesn't matter most of the time. In the cases where you actually have to concern yourself with these values, I recommend treating them as mostly interchangeable. + + ## Automatic type conversion + +-In the introduction, I mentioned that JavaScript goes out of its way to accept almost any program you give it, even programs that do odd things. This is nicely demonstrated by the following expressions: ++In the Introduction, I mentioned that JavaScript goes out of its way to accept almost any program you give it, even programs that do odd things. This is nicely demonstrated by the following expressions: + + ``` + console.log(8 * null) +@@ -261,9 +274,9 @@ console.log(false == 0) + // → true + ``` + +-When an operator is applied to the “wrong” type of value, JavaScript will quietly convert that value to the type it wants, using a set of rules that often aren't what you want or expect. This is called _type coercion_. So the `null` in the first expression becomes `0`, and the `"5"` in the second expression becomes `5` (from string to number). Yet in the third expression, `+` tries string concatenation before numeric addition, so the `1` is converted to `"1"` (from number to string). ++When an operator is applied to the “wrong” type of value, JavaScript will quietly convert that value to the type it needs, using a set of rules that often aren't what you want or expect. This is called _type coercion_. The `null` in the first expression becomes `0`, and the `"5"` in the second expression becomes `5` (from string to number). Yet in the third expression, `+` tries string concatenation before numeric addition, so the `1` is converted to `"1"` (from number to string). + +-When something that doesn't map to a number in an obvious way (such as `"five"` or `undefined`) is converted to a number, the value `NaN` is produced. Further arithmetic operations on `NaN` keep producing `NaN`, so if you find yourself getting one of those in an unexpected place, look for accidental type conversions. ++When something that doesn't map to a number in an obvious way (such as `"five"` or `undefined`) is converted to a number, you get the value `NaN`. Further arithmetic operations on `NaN` keep producing `NaN`, so if you find yourself getting one of those in an unexpected place, look for accidental type conversions. + + When comparing values of the same type using `==`, the outcome is easy to predict: you should get true when both values are the same, except in the case of `NaN`. But when the types differ, JavaScript uses a complicated and confusing set of rules to determine what to do. In most cases, it just tries to convert one of the values to the other value's type. However, when `null` or `undefined` occurs on either side of the operator, it produces true only if both sides are one of `null` or `undefined`. + +@@ -274,32 +287,32 @@ console.log(null == 0); + // → false + ``` + +-That last piece of behavior is often useful. When you want to test whether a value has a real value instead of `null` or `undefined`, you can simply compare it to `null` with the `==` (or `!=`) operator. ++That behavior is often useful. When you want to test whether a value has a real value instead of `null` or `undefined`, you can compare it to `null` with the `==` (or `!=`) operator. + +-But what if you want to test whether something refers to the precise value `false`? The rules for converting strings and numbers to Boolean values state that `0`, `NaN`, and the empty string (`""`) count as `false`, while all the other values count as `true`. Because of this, expressions like `0 == false` and `"" == false` are also true. For cases like this, where you do _not_ want any automatic type conversions to happen, there are two extra operators: `===` and `!==`. The first tests whether a value is precisely equal to the other, and the second tests whether it is not precisely equal. So `"" === false` is false as expected. ++But what if you want to test whether something refers to the precise value `false`? The rules for converting strings and numbers to Boolean values state that `0`, `NaN`, and the empty string (`""`) count as `false`, while all the other values count as `true`. Because of this, expressions like `0 == false` and `"" == false` are also true. When you do _not_ want any automatic type conversions to happen, there are two additional operators: `===` and `!==`. The first tests whether a value is _precisely_ equal to the other, and the second tests whether it is not precisely equal. So `"" === false` is false as expected. + + I recommend using the three-character comparison operators defensively to prevent unexpected type conversions from tripping you up. But when you're certain the types on both sides will be the same, there is no problem with using the shorter operators. + + ### Short-circuiting of logical operators + +-The logical operators `&&` and `||` handle values of different types in a peculiar way. They will convert the value on their left side to Boolean type in order to decide what to do, but depending on the operator and the result of that conversion, they return either the _original_ left-hand value or the right-hand value. ++The logical operators `&&` and `||` handle values of different types in a peculiar way. They will convert the value on their left side to Boolean type in order to decide what to do, but depending on the operator and the result of that conversion, they will return either the _original_ left-hand value or the right-hand value. + +-The `||` operator, for example, will return the value to its left when that can be converted to true and will return the value on its right otherwise. This conversion works as you'd expect for Boolean values and should do something analogous for values of other types. ++The `||` operator, for example, will return the value to its left when that can be converted to true and will return the value on its right otherwise. This has the expected effect when the values are Boolean, and does something analogous for values of other types. + + ``` + console.log(null || "user") + // → user +-console.log("Karl" || "user") +-// → Karl ++console.log("Agnes" || "user") ++// → Agnes + ``` + +-This functionality allows the `||` operator to be used as a way to fall back on a default value. If you give it an expression that might produce an empty value on the left, the value on the right will be used as a replacement in that case. ++We can use this functionality as a way to fall back on a default value. If you have a value that might be empty, you can put `||` after it with a replacement value. If the initial value can be converted to false, you'll get the replacement instead. + + The `&&` operator works similarly, but the other way around. When the value to its left is something that converts to false, it returns that value, and otherwise it returns the value on its right. + +-Another important property of these two operators is that the expression to their right is evaluated only when necessary. In the case of `true || X`, no matter what `X` is—even if it's an expression that does something _terrible_—the result will be true, and `X` is never evaluated. The same goes for `false && X`, which is false and will ignore `X`. This is called _short-circuit evaluation_. ++Another important property of these two operators is that the part to their right is evaluated only when necessary. In the case of `true || X`, no matter what `X` is—even if it's a piece of program that does something _terrible_—the result will be true, and `X` is never evaluated. The same goes for `false && X`, which is false and will ignore `X`. This is called _short-circuit evaluation_. + +-The conditional operator works in a similar way. The first expression is always evaluated, but the second or third value, the one that is not picked, is not. ++The conditional operator works in a similar way. Of the second and third value, only the one that is selected is evaluated. + + ## Summary + +@@ -307,4 +320,4 @@ We looked at four types of JavaScript values in this chapter: numbers, strings, + + Such values are created by typing in their name (`true`, `null`) or value (`13`, `"abc"`). You can combine and transform values with operators. We saw binary operators for arithmetic (`+`, `-`, `*`, `/`, and `%`), string concatenation (`+`), comparison (`==`, `!=`, `===`, `!==`, `<`, `>`, `<=`, `>=`), and logic (`&&`, `||`), as well as several unary operators (`-` to negate a number, `!` to negate logically, and `typeof` to find a value's type) and a ternary operator (`?:`) to pick one of two values based on a third value. + +-This gives you enough information to use JavaScript as a pocket calculator, but not much more. The [next chapter](02_program_structure.html#program_structure) will start tying these expressions together into basic programs. ++This gives you enough information to use JavaScript as a pocket calculator, but not much more. The [next chapter](02_program_structure.html) will start tying these expressions together into basic programs. diff --git a/diff-en/2ech2-3ech2.diff b/diff-en/2ech2-3ech2.diff new file mode 100644 index 0000000..e585d24 --- /dev/null +++ b/diff-en/2ech2-3ech2.diff @@ -0,0 +1,697 @@ +diff --git a/2ech2.md b/3ech2.md +index 645a197..80cf5d8 100644 +--- a/2ech2.md ++++ b/3ech2.md +@@ -4,17 +4,17 @@ + > + > <footer>_why, <cite>Why's (Poignant) Guide to Ruby</cite></footer> + +-In this chapter, we will start to do things that can actually be called _programming_. We will expand our command of the JavaScript language beyond the nouns and sentence fragments we've seen so far, to the point where we can express some meaningful prose. ++In this chapter, we start to do things that can actually be called _programming_. We will expand our command of the JavaScript language beyond the nouns and sentence fragments we've seen so far, to the point where we can express meaningful prose. + + ## Expressions and statements + +-In [Chapter 1](01_values.html#values), we made some values and then applied operators to them to get new values. Creating values like this is an essential part of every JavaScript program, but it is only a part. ++In [Chapter 1](01_values.html), we made values and applied operators to them to get new values. Creating values like this is the main substance of any JavaScript program. But that substance has to be framed in a larger structure to be useful. So that's what we'll get to next. + + A fragment of code that produces a value is called an _expression_. Every value that is written literally (such as `22` or `"psychoanalysis"`) is an expression. An expression between parentheses is also an expression, as is a binary operator applied to two expressions or a unary operator applied to one. + +-This shows part of the beauty of a language-based interface. Expressions can nest in a way very similar to the way subsentences in human languages are nested—a subsentence can contain its own subsentences, and so on. This allows us to combine expressions to express arbitrarily complex computations. ++This shows part of the beauty of a language-based interface. Expressions can contain other expressions in a way very similar to the way subsentences in human languages are nested—a subsentence can contain its own subsentences, and so on. This allows us to build expressions that describe arbitrarily complex computations. + +-If an expression corresponds to a sentence fragment, a JavaScript _statement_ corresponds to a full sentence in a human language. A program is simply a list of statements. ++If an expression corresponds to a sentence fragment, a JavaScript _statement_ corresponds to a full sentence. A program is a list of statements. + + The simplest kind of statement is an expression with a semicolon after it. This is a program: + +@@ -23,36 +23,34 @@ The simplest kind of statement is an expression with a semicolon after it. This + !false; + ``` + +-It is a useless program, though. An expression can be content to just produce a value, which can then be used by the enclosing expression. A statement stands on its own and amounts to something only if it affects the world. It could display something on the screen—that counts as changing the world—or it could change the internal state of the machine in a way that will affect the statements that come after it. These changes are called _side effects_. The statements in the previous example just produce the values `1` and `true` and then immediately throw them away. This leaves no impression on the world at all. When executing the program, nothing observable happens. ++It is a useless program, though. An expression can be content to just produce a value, which can then be used by the enclosing code. A statement stands on its own, so it amounts to something only if it affects the world. It could display something on the screen—that counts as changing the world—or it could change the internal state of the machine in a way that will affect the statements that come after it. These changes are called _side effects_. The statements in the previous example just produce the values `1` and `true` and then immediately throw them away. This leaves no impression on the world at all. When you run this program, nothing observable happens. + +-In some cases, JavaScript allows you to omit the semicolon at the end of a statement. In other cases, it has to be there, or the next line will be treated as part of the same statement. The rules for when it can be safely omitted are somewhat complex and error-prone. In this book, every statement that needs a semicolon will always be terminated by one. I recommend you do the same in your own programs, at least until you've learned more about subtleties involved in leaving out semicolons. ++In some cases, JavaScript allows you to omit the semicolon at the end of a statement. In other cases, it has to be there, or the next line will be treated as part of the same statement. The rules for when it can be safely omitted are somewhat complex and error-prone. So in this book, every statement that needs a semicolon will always get one. I recommend you do the same, at least until you've learned more about the subtleties of missing semicolons. + +-## Variables ++## Bindings + +-How does a program keep an internal state? How does it remember things? We have seen how to produce new values from old values, but this does not change the old values, and the new value has to be immediately used or it will dissipate again. To catch and hold values, JavaScript provides a thing called a _variable_. ++How does a program keep an internal state? How does it remember things? We have seen how to produce new values from old values, but this does not change the old values, and the new value has to be immediately used or it will dissipate again. To catch and hold values, JavaScript provides a thing called a _binding_, or _variable_: + + ``` +-var caught = 5 * 5; ++let caught = 5 * 5; + ``` + +-And that gives us our second kind of statement. The special word (_keyword_) `var` indicates that this sentence is going to define a variable. It is followed by the name of the variable and, if we want to immediately give it a value, by an `=` operator and an expression. ++That's a second kind of statement. The special word (_keyword_) `let` indicates that this sentence is going to define a binding. It is followed by the name of the binding and, if we want to immediately give it a value, by an `=` operator and an expression. + +-The previous statement creates a variable called `caught` and uses it to grab hold of the number that is produced by multiplying 5 by 5. ++The previous statement creates a binding called `caught` and uses it to grab hold of the number that is produced by multiplying 5 by 5. + +-After a variable has been defined, its name can be used as an expression. The value of such an expression is the value the variable currently holds. Here's an example: ++After a binding has been defined, its name can be used as an expression. The value of such an expression is the value the binding currently holds. Here's an example: + + ``` +-var ten = 10; ++let ten = 10; + console.log(ten * ten); + // → 100 + ``` + +-Variable names can be any word that isn't a reserved word (such as `var`). They may not include spaces. Digits can also be part of variable names—`catch22` is a valid name, for example—but the name must not start with a digit. A variable name cannot include punctuation, except for the characters `
![A prompt dialog](img/prompt.png) + +-Executing a function is called _invoking_, _calling_, or _applying_ it. You can call a function by putting parentheses after an expression that produces a function value. Usually you'll directly use the name of the variable that holds the function. The values between the parentheses are given to the program inside the function. In the example, the `alert` function uses the string that we give it as the text to show in the dialog box. Values given to functions are called _arguments_. The `alert` function needs only one of them, but other functions might need a different number or different types of arguments. ++Executing a function is called _invoking_, _calling_, or _applying_ it. You can call a function by putting parentheses after an expression that produces a function value. Usually you'll directly use the name of the binding that holds the function. The values between the parentheses are given to the program inside the function. In the example, the `prompt` function uses the string that we give it as the text to show in the dialog box. Values given to functions are called _arguments_. Different functions might need a different number or different types of arguments. ++ ++The `prompt` function isn't used much in modern web programming, mostly because you have no control over the way the resulting dialog looks, but can be helpful in toy programs and experiments. + + ## The console.log function + +-The `alert` function can be useful as an output device when experimenting, but clicking away all those little windows will get on your nerves. In past examples, we've used `console.log` to output values. Most JavaScript systems (including all modern web browsers and Node.js) provide a `console.log` function that writes out its arguments to _some_ text output device. In browsers, the output lands in the JavaScript console. This part of the browser interface is hidden by default, but most browsers open it when you press F12 or, on Mac, when you press Command-Option-I. If that does not work, search through the menus for an item named “web console” or “developer tools”. ++In the examples, I used `console.log` to output values. Most JavaScript systems (including all modern web browsers and Node.js) provide a `console.log` function that writes out its arguments to _some_ text output device. In browsers, the output lands in the JavaScript console. This part of the browser interface is hidden by default, but most browsers open it when you press F12 or, on Mac, Command-Option-I. If that does not work, search through the menus for an item named “developer tools” or similar. + +-When running the examples, or your own code, on the pages of this book, `console.log` output will be shown after the example, instead of in the browser's JavaScript console. ++When running the examples (or your own code) on the pages of this book, `console.log` output will be shown after the example, instead of in the browser's JavaScript console. + + ``` +-var x = 30; ++let x = 30; + console.log("the value of x is", x); + // → the value of x is 30 + ``` + +-Though variable names cannot contain period characters, `console.log` clearly has one. This is because `console.log` isn't a simple variable. It is actually an expression that retrieves the `log` property from the value held by the `console` variable. We will find out exactly what this means in [Chapter 4](04_data.html#properties). ++Though binding names cannot contain period characters, `console.log` does have one. This is because `console.log` isn't a simple binding. It is actually an expression that retrieves the `log` property from the value held by the `console` binding. We will find out exactly what this means in [Chapter 4](04_data.html#properties). + + ## Return values + +-Showing a dialog box or writing text to the screen is a _side effect_. A lot of functions are useful because of the side effects they produce. Functions may also produce values, and in that case, they don't need to have a side effect to be useful. For example, the function `Math.max` takes any number of number values and gives back the greatest. ++Showing a dialog box or writing text to the screen is a _side effect_. A lot of functions are useful because of the side effects they produce. Functions may also produce values, in which case they don't need to have a side effect to be useful. For example, the function `Math.max` takes any amount of number arguments and gives back the greatest. + + ``` + console.log(Math.max(2, 4)); + // → 4 + ``` + +-When a function produces a value, it is said to _return_ that value. Anything that produces a value is an expression in JavaScript, which means function calls can be used within larger expressions. Here a call to `Math.min`, which is the opposite of `Math.max`, is used as an input to the plus operator: ++When a function produces a value, it is said to _return_ that value. Anything that produces a value is an expression in JavaScript, which means function calls can be used within larger expressions. Here a call to `Math.min`, which is the opposite of `Math.max`, is used as part of a plus expression: + + ``` + console.log(Math.min(2, 4) + 100); + // → 102 + ``` + +-The [next chapter](03_functions.html#functions) explains how to write your own functions. ++The [next chapter](03_functions.html) explains how to write your own functions. + +-## prompt and confirm ++## Control flow + +-Browser environments contain other functions besides `alert` for popping up windows. You can ask the user an OK/Cancel question using `confirm`. This returns a Boolean: `true` if the user clicks OK and `false` if the user clicks Cancel. ++When your program contains more than one statement, the statements are executed as if they are a story, from top to bottom. This example program has two statements. The first one asks the user for a number, and the second, which is executed after the first, shows the square of that number. + + ``` +-confirm("Shall we, then?"); ++let theNumber = Number(prompt("Pick a number")); ++console.log("Your number is the square root of " + ++ theNumber * theNumber); + ``` + +-![A confirm dialog](img/confirm.png) ++The function `Number` converts a value to a number. We need that conversion because the result of `prompt` is a string value, and we want a number. There are similar functions called `String` and `Boolean` that convert values to those types. + +-The `prompt` function can be used to ask an “open” question. The first argument is the question, the second one is the text that the user starts with. A line of text can be typed into the dialog window, and the function will return this text as a string. ++Here is the rather trivial schematic representation of straight-line control flow: + +-``` +-prompt("Tell me everything you know.", "..."); +-``` ++
![Trivial control flow](img/controlflow-straight.svg)
+ +-![An prompt dialog](img/prompt.png) ++## Conditional execution + +-These two functions aren't used much in modern web programming, mostly because you have no control over the way the resulting windows look, but they are useful for toy programs and experiments. ++Not all programs are straight roads. We may, for example, want to create a branching road, where the program takes the proper branch based on the situation at hand. This is called _conditional execution_. + +-## Control flow ++
![Conditional control flow](img/controlflow-if.svg)
+ +-When your program contains more than one statement, the statements are executed, predictably, from top to bottom. As a basic example, this program has two statements. The first one asks the user for a number, and the second, which is executed afterward, shows the square of that number. ++Conditional execution is created with the `if` keyword in JavaScript. In the simple case, we want some code to be executed if, and only if, a certain condition holds. We might, for example, want to show the square of the input only if the input is actually a number. + + ``` +-var theNumber = Number(prompt("Pick a number", "")); +-alert("Your number is the square root of " + +- theNumber * theNumber); ++let theNumber = Number(prompt("Pick a number")); ++if (!Number.isNaN(theNumber)) { ++ console.log("Your number is the square root of " + ++ theNumber * theNumber); ++} + ``` + +-The function `Number` converts a value to a number. We need that conversion because the result of `prompt` is a string value, and we want a number. There are similar functions called `String` and `Boolean` that convert values to those types. +- +-Here is the rather trivial schematic representation of straight control flow: +- +-![Trivial control flow](img/controlflow-straight.svg) +- +-## Conditional execution ++With this modification, if you enter “parrot”, no output is shown. + +-Executing statements in straight-line order isn't the only option we have. An alternative is _conditional execution_, where we choose between two different routes based on a Boolean value, like this: ++The `if` keyword executes or skips a statement depending on the value of a Boolean expression. The deciding expression is written after the keyword, between parentheses, followed by the statement to execute. + +-![Conditional control flow](img/controlflow-if.svg) ++The `Number.isNaN` function is a standard JavaScript function that returns `true` only if the argument it is given is `NaN`. The `Number` function happens to return `NaN` when you give it a string that doesn't represent a valid number. Thus, the condition translates to “unless `theNumber` is not-a-number, do this”. + +-Conditional execution is written with the `if` keyword in JavaScript. In the simple case, we just want some code to be executed if, and only if, a certain condition holds. For example, in the previous program, we might want to show the square of the input only if the input is actually a number. ++The statement below the `if` is wrapped in curly braces (`{` and `}`) in this example. Those can be used to group any number of statements into a single statement, called a _block_. You could also have omitted them in this case, since they only hold a single statement, but to avoid having to think about whether they are needed or not, most JavaScript programmers use them in every wrapped statement like this. We'll mostly follow that convention in this book, except for the occasional one-liner. + + ``` +-var theNumber = Number(prompt("Pick a number", "")); +-if (!isNaN(theNumber)) +- alert("Your number is the square root of " + +- theNumber * theNumber); ++if (1 + 1 == 2) console.log("It's true"); ++// → It's true + ``` + +-With this modification, if you enter “cheese”, no output will be shown. +- +-The keyword `if` executes or skips a statement depending on the value of a Boolean expression. The deciding expression is written after the keyword, between parentheses, followed by the statement to execute. +- +-The `isNaN` function is a standard JavaScript function that returns `true` only if the argument it is given is `NaN`. The `Number` function happens to return `NaN` when you give it a string that doesn't represent a valid number. Thus, the condition translates to “unless `theNumber` is not-a-number, do this”. +- + You often won't just have code that executes when a condition holds true, but also code that handles the other case. This alternate path is represented by the second arrow in the diagram. The `else` keyword can be used, together with `if`, to create two separate, alternative execution paths. + + ``` +-var theNumber = Number(prompt("Pick a number", "")); +-if (!isNaN(theNumber)) +- alert("Your number is the square root of " + +- theNumber * theNumber); +-else +- alert("Hey. Why didn't you give me a number?"); ++let theNumber = Number(prompt("Pick a number")); ++if (!Number.isNaN(theNumber)) { ++ console.log("Your number is the square root of " + ++ theNumber * theNumber); ++} else { ++ console.log("Hey. Why didn't you give me a number?"); ++} + ``` + + If we have more than two paths to choose from, multiple `if`/`else` pairs can be “chained” together. Here's an example: + + ``` +-var num = Number(prompt("Pick a number", "0")); ++let num = Number(prompt("Pick a number")); + +-if (num < 10) +- alert("Small"); +-else if (num < 100) +- alert("Medium"); +-else +- alert("Large"); ++if (num < 10) { ++ console.log("Small"); ++} else if (num < 100) { ++ console.log("Medium"); ++} else { ++ console.log("Large"); ++} + ``` + +-The program will first check whether `num` is less than 10\. If it is, it chooses that branch, shows `"Small"`, and is done. If it isn't, it takes the `else` branch, which itself contains a second `if`. If the second condition (`< 100`) holds, that means the number is between 10 and 100, and `"Medium"` is shown. If it doesn't, the second, and last, `else` branch is chosen. ++The program will first check whether `num` is less than 10\. If it is, it chooses that branch, shows `"Small"`, and is done. If it isn't, it takes the `else` branch, which itself contains a second `if`. If the second condition (`< 100`) holds, that means the number is between 10 and 100, and `"Medium"` is shown. If it doesn't, the second and last `else` branch is chosen. + +-The flow chart for this program looks something like this: ++The schema for this program looks something like this: + +-![Nested if control flow](img/controlflow-nested-if.svg) ++
![Nested if control flow](img/controlflow-nested-if.svg)
+ + ## while and do loops + +-Consider a program that prints all even numbers from 0 to 12\. One way to write this is as follows: ++Consider a program that outputs all even numbers from 0 to 12\. One way to write this is as follows: + + ``` + console.log(0); +@@ -247,14 +249,14 @@ console.log(10); + console.log(12); + ``` + +-That works, but the idea of writing a program is to make something _less_ work, not more. If we needed all even numbers less than 1,000, the previous would be unworkable. What we need is a way to repeat some code. This form of control flow is called a _loop_: ++That works, but the idea of writing a program is to make something _less_ work, not more. If we needed all even numbers less than 1,000, this approach would be unworkable. What we need is a way to run a piece of code multiple times. This form of control flow is called a _loop_: + +-![Loop control flow](img/controlflow-loop.svg) ++
![Loop control flow](img/controlflow-loop.svg)
+ +-Looping control flow allows us to go back to some point in the program where we were before and repeat it with our current program state. If we combine this with a variable that counts, we can do something like this: ++Looping control flow allows us to go back to some point in the program where we were before and repeat it with our current program state. If we combine this with a binding that counts, we can do something like this: + + ``` +-var number = 0; ++let number = 0; + while (number <= 12) { + console.log(number); + number = number + 2; +@@ -264,19 +266,15 @@ while (number <= 12) { + // … etcetera + ``` + +-A statement starting with the keyword `while` creates a loop. The word `while` is followed by an expression in parentheses and then a statement, much like `if`. The loop executes that statement as long as the expression produces a value that is `true` when converted to Boolean type. +- +-In this loop, we want to both print the current number and add two to our variable. Whenever we need to execute multiple statements inside a loop, we wrap them in curly braces (`{` and `}`). Braces do for statements what parentheses do for expressions: they group them together, making them count as a single statement. A sequence of statements wrapped in braces is called a _block_. ++A statement starting with the keyword `while` creates a loop. The word `while` is followed by an expression in parentheses and then a statement, much like `if`. The loop keeps entering that statement as long as the expression produces a value that gives `true` when converted to Boolean. + +-Many JavaScript programmers wrap every single loop or `if` body in braces. They do this both for the sake of consistency and to avoid having to add or remove braces when changing the number of statements in the body later. In this book, I will write most single-statement bodies without braces, since I value brevity. You are free to go with whichever style you prefer. ++The `number` binding demonstrates the way a binding can track the progress of a program. Every time the loop repeats, `number` gets a value that is 2 more than its previous value. At the beginning of every repetition, it is compared with the number 12 to decide whether the program's work is finished. + +-The variable `number` demonstrates the way a variable can track the progress of a program. Every time the loop repeats, `number` is incremented by `2`. Then, at the beginning of every repetition, it is compared with the number `12` to decide whether the program has done all the work it intended to do. +- +-As an example that actually does something useful, we can now write a program that calculates and shows the value of 2<sup>10</sup> (2 to the 10th power). We use two variables: one to keep track of our result and one to count how often we have multiplied this result by 2\. The loop tests whether the second variable has reached 10 yet and then updates both variables. ++As an example that actually does something useful, we can now write a program that calculates and shows the value of 2<sup>10</sup> (2 to the 10th power). We use two bindings: one to keep track of our result and one to count how often we have multiplied this result by 2\. The loop tests whether the second binding has reached 10 yet and, if not, updates both bindings. + + ``` +-var result = 1; +-var counter = 0; ++let result = 1; ++let counter = 0; + while (counter < 10) { + result = result * 2; + counter = counter + 1; +@@ -285,65 +283,80 @@ console.log(result); + // → 1024 + ``` + +-The counter could also start at `1` and check for `<= 10`, but, for reasons that will become apparent in [Chapter 4](04_data.html#array_indexing), it is a good idea to get used to counting from 0. ++The counter could also have started at `1` and checked for `<= 10`, but, for reasons that will become apparent in [Chapter 4](04_data.html#array_indexing), it is a good idea to get used to counting from 0. + +-The `do` loop is a control structure similar to the `while` loop. It differs only on one point: a `do` loop always executes its body at least once, and it starts testing whether it should stop only after that first execution. To reflect this, the test appears after the body of the loop: ++A `do` loop is a control structure similar to a `while` loop. It differs only on one point: a `do` loop always executes its body at least once, and it starts testing whether it should stop only after that first execution. To reflect this, the test appears after the body of the loop: + + ``` ++let yourName; + do { +- var yourName = prompt("Who are you?"); ++ yourName = prompt("Who are you?"); + } while (!yourName); + console.log(yourName); + ``` + +-This program will force you to enter a name. It will ask again and again until it gets something that is not an empty string. Applying the `!` operator will convert a value to Boolean type before negating it, and all strings except `""` convert to `true`. This means the loop continues going round until you provide a name that is not the empty string. ++This program will force you to enter a name. It will ask again and again until it gets something that is not an empty string. Applying the `!` operator will convert a value to Boolean type before negating it, and all strings except `""` convert to `true`. This means the loop continues going round until you provide a non-empty name. + + ## Indenting Code + +-You've probably noticed the spaces I put in front of some statements. In JavaScript, these are not required—the computer will accept the program just fine without them. In fact, even the line breaks in programs are optional. You could write a program as a single long line if you felt like it. The role of the indentation inside blocks is to make the structure of the code stand out. In complex code, where new blocks are opened inside other blocks, it can become hard to see where one block ends and another begins. With proper indentation, the visual shape of a program corresponds to the shape of the blocks inside it. I like to use two spaces for every open block, but tastes differ—some people use four spaces, and some people use tab characters. ++In the examples, I've been adding spaces in front of statements that are part of some larger statement. These are not required—the computer will accept the program just fine without them. In fact, even the line breaks in programs are optional. You could write a program as a single long line if you felt like it. ++ ++The role of this indentation inside blocks is to make the structure of the code stand out. In code where new blocks are opened inside other blocks, it can become hard to see where one block ends and another begins. With proper indentation, the visual shape of a program corresponds to the shape of the blocks inside it. I like to use two spaces for every open block, but tastes differ—some people use four spaces, and some people use tab characters. The important thing is that each new block adds the same amount of space. ++ ++``` ++if (false != true) { ++ console.log("That makes sense."); ++ if (1 < 2) { ++ console.log("No surprise there."); ++ } ++} ++``` ++ ++Most code editor programs (including the one in this book) will help by automatically indenting new lines the proper amount. + + ## for loops + +-Many loops follow the pattern seen in the previous `while` examples. First, a “counter” variable is created to track the progress of the loop. Then comes a `while` loop, whose test expression usually checks whether the counter has reached some boundary yet. At the end of the loop body, the counter is updated to track progress. ++Many loops follow the pattern seen in the `while` examples. First, a “counter” binding is created to track the progress of the loop. Then comes a `while` loop, usually with a test expression that checks whether the counter has reached its end value. At the end of the loop body, the counter is updated to track progress. + +-Because this pattern is so common, JavaScript and similar languages provide a slightly shorter and more comprehensive form, the `for` loop. ++Because this pattern is so common, JavaScript and similar languages provide a slightly shorter and more comprehensive form, the `for` loop: + + ``` +-for (var number = 0; number <= 12; number = number + 2) ++for (let number = 0; number <= 12; number = number + 2) { + console.log(number); ++} + // → 0 + // → 2 + // … etcetera + ``` + +-This program is exactly equivalent to the [earlier](02_program_structure.html#loops) even-number-printing example. The only change is that all the statements that are related to the “state” of the loop are now grouped together. ++This program is exactly equivalent to the [earlier](02_program_structure.html#loops) even-number-printing example. The only change is that all the statements that are related to the “state” of the loop are grouped together after `for`. + +-The parentheses after a `for` keyword must contain two semicolons. The part before the first semicolon _initializes_ the loop, usually by defining a variable. The second part is the expression that _checks_ whether the loop must continue. The final part _updates_ the state of the loop after every iteration. In most cases, this is shorter and clearer than a `while` construct. ++The parentheses after a `for` keyword must contain two semicolons. The part before the first semicolon _initializes_ the loop, usually by defining a binding. The second part is the expression that _checks_ whether the loop must continue. The final part _updates_ the state of the loop after every iteration. In most cases, this is shorter and clearer than a `while` construct. + +-Here is the code that computes 2<sup>10</sup>, using `for` instead of `while`: ++This is the code that computes 2<sup>10</sup>, using `for` instead of `while`: + + ``` +-var result = 1; +-for (var counter = 0; counter < 10; counter = counter + 1) ++let result = 1; ++for (let counter = 0; counter < 10; counter = counter + 1) { + result = result * 2; ++} + console.log(result); + // → 1024 + ``` + +-Note that even though no block is opened with a `{`, the statement in the loop is still indented two spaces to make it clear that it “belongs” to the line before it. +- + ## Breaking Out of a Loop + +-Having the loop's condition produce `false` is not the only way a loop can finish. There is a special statement called `break` that has the effect of immediately jumping out of the enclosing loop. ++Having the looping condition produce `false` is not the only way a loop can finish. There is a special statement called `break` that has the effect of immediately jumping out of the enclosing loop. + + This program illustrates the `break` statement. It finds the first number that is both greater than or equal to 20 and divisible by 7. + + ``` +-for (var current = 20; ; current++) { +- if (current % 7 == 0) ++for (let current = 20; ; current = current + 1) { ++ if (current % 7 == 0) { ++ console.log(current); + break; ++ } + } +-console.log(current); + // → 21 + ``` + +@@ -351,15 +364,15 @@ Using the remainder (`%`) operator is an easy way to test whether a number is di + + The `for` construct in the example does not have a part that checks for the end of the loop. This means that the loop will never stop unless the `break` statement inside is executed. + +-If you were to leave out that `break` statement or accidentally write a condition that always produces `true`, your program would get stuck in an _infinite loop_. A program stuck in an infinite loop will never finish running, which is usually a bad thing. ++If you were to remove that `break` statement or you accidentally write an end condition that always produces `true`, your program would get stuck in an _infinite loop_. A program stuck in an infinite loop will never finish running, which is usually a bad thing. + + If you create an infinite loop in one of the examples on these pages, you'll usually be asked whether you want to stop the script after a few seconds. If that fails, you will have to close the tab that you're working in, or on some browsers close your whole browser, in order to recover. + + The `continue` keyword is similar to `break`, in that it influences the progress of a loop. When `continue` is encountered in a loop body, control jumps out of the body and continues with the loop's next iteration. + +-## Updating variables succinctly ++## Updating bindings succinctly + +-Especially when looping, a program often needs to “update” a variable to hold a value based on that variable's previous value. ++Especially when looping, a program often needs to “update” a binding to hold a value based on that binding's previous value. + + ``` + counter = counter + 1; +@@ -376,24 +389,25 @@ Similar shortcuts work for many other operators, such as `result *= 2` to double + This allows us to shorten our counting example a little more. + + ``` +-for (var number = 0; number <= 12; number += 2) ++for (let number = 0; number <= 12; number += 2) { + console.log(number); ++} + ``` + + For `counter += 1` and `counter -= 1`, there are even shorter equivalents: `counter++` and `counter--`. + + ## Dispatching on a value with switch + +-It is common for code to look like this: ++It is not uncommon for code to look like this: + + ``` +-if (variable == "value1") action1(); +-else if (variable == "value2") action2(); +-else if (variable == "value3") action3(); ++if (x == "value1") action1(); ++else if (x == "value2") action2(); ++else if (x == "value3") action3(); + else defaultAction(); + ``` + +-There is a construct called `switch` that is intended to solve such a “dispatch” in a more direct way. Unfortunately, the syntax JavaScript uses for this (which it inherited from the C/Java line of programming languages) is somewhat awkward—a chain of `if` statements often looks better. Here is an example: ++There is a construct called `switch` that is intended to express such a “dispatch” in a more direct way. Unfortunately, the syntax JavaScript uses for this (which it inherited from the C/Java line of programming languages) is somewhat awkward—a chain of `if` statements may look better. Here is an example: + + ``` + switch (prompt("What is the weather like?")) { +@@ -411,11 +425,11 @@ switch (prompt("What is the weather like?")) { + } + ``` + +-You may put any number of `case` labels inside the block opened by `switch`. The program will jump to the label that corresponds to the value that `switch` was given or to `default` if no matching value is found. It starts executing statements there, even if they're under another label, until it reaches a `break` statement. In some cases, such as the `"sunny"` case in the example, this can be used to share some code between cases (it recommends going outside for both sunny and cloudy weather). But beware: it is easy to forget such a `break`, which will cause the program to execute code you do not want executed. ++You may put any number of `case` labels inside the block opened by `switch`. The program will start executing at the label that corresponds to the value that `switch` was given, or at `default` if no matching value is found. It will continue executing, even across other labels, until it reaches a `break` statement. In some cases, such as the `"sunny"` case in the example, this can be used to share some code between cases (it recommends going outside for both sunny and cloudy weather). But be careful—it is easy to forget such a `break`, which will cause the program to execute code you do not want executed. + + ## Capitalization + +-Variable names may not contain spaces, yet it is often helpful to use multiple words to clearly describe what the variable represents. These are pretty much your choices for writing a variable name with several words in it: ++Binding names may not contain spaces, yet it is often helpful to use multiple words to clearly describe what the binding represents. These are pretty much your choices for writing a binding name with several words in it: + + ``` + fuzzylittleturtle +@@ -424,38 +438,38 @@ FuzzyLittleTurtle + fuzzyLittleTurtle + ``` + +-The first style can be hard to read. Personally, I like the look of the underscores, though that style is a little painful to type. The standard JavaScript functions, and most JavaScript programmers, follow the bottom style—they capitalize every word except the first. It is not hard to get used to little things like that, and code with mixed naming styles can be jarring to read, so we will just follow this convention. ++The first style can be hard to read. I rather like the look of the underscores, though that style is a little painful to type. The standard JavaScript functions, and most JavaScript programmers, follow the bottom style—they capitalize every word except the first. It is not hard to get used to little things like that, and code with mixed naming styles can be jarring to read, so we follow this convention. + +-In a few cases, such as the `Number` function, the first letter of a variable is also capitalized. This was done to mark this function as a constructor. What a constructor is will become clear in [Chapter 6](06_object.html#constructors). For now, the important thing is not to be bothered by this apparent lack of consistency. ++In a few cases, such as the `Number` function, the first letter of a binding is also capitalized. This was done to mark this function as a constructor. What a constructor is will become clear in [Chapter 6](06_object.html#constructors). For now, the important thing is not to be bothered by this apparent lack of consistency. + + ## Comments + +-Often, raw code does not convey all the information you want a program to convey to human readers, or it conveys it in such a cryptic way that people might not understand it. At other times, you might just feel poetic or want to include some thoughts as part of your program. This is what _comments_ are for. ++Often, raw code does not convey all the information you want a program to convey to human readers, or it conveys it in such a cryptic way that people might not understand it. At other times, you might just want to include some related thoughts as part of your program. This is what _comments_ are for. + + A comment is a piece of text that is part of a program but is completely ignored by the computer. JavaScript has two ways of writing comments. To write a single-line comment, you can use two slash characters (`//`) and then the comment text after it. + + ``` +-var accountBalance = calculateBalance(account); ++let accountBalance = calculateBalance(account); + // It's a green hollow where a river sings + accountBalance.adjust(); + // Madly catching white tatters in the grass. +-var report = new Report(); ++let report = new Report(); + // Where the sun on the proud mountain rings: + addToReport(accountBalance, report); + // It's a little valley, foaming like light in a glass. + ``` + +-A `//` comment goes only to the end of the line. A section of text between `/*` and `*/` will be ignored, regardless of whether it contains line breaks. This is often useful for adding blocks of information about a file or a chunk of program. ++A `//` comment goes only to the end of the line. A section of text between `/*` and `*/` will be ignored in its entirety, regardless of whether it contains line breaks. This is useful for adding blocks of information about a file or a chunk of program. + + ``` + /* + I first found this number scrawled on the back of one of +- my notebooks a few years ago. Since then, it has often +- dropped by, showing up in phone numbers and the serial +- numbers of products that I've bought. It obviously likes +- me, so I've decided to keep it. ++ an old notebook. Since then, it has often dropped by, ++ showing up in phone numbers and the serial numbers of ++ products that I've bought. It obviously likes me, so I've ++ decided to keep it. + */ +-var myNumber = 11213; ++const myNumber = 11213; + ``` + + ## Summary +@@ -464,15 +478,15 @@ You now know that a program is built out of statements, which themselves sometim + + Putting statements after one another gives you a program that is executed from top to bottom. You can introduce disturbances in the flow of control by using conditional (`if`, `else`, and `switch`) and looping (`while`, `do`, and `for`) statements. + +-Variables can be used to file pieces of data under a name, and they are useful for tracking state in your program. The environment is the set of variables that are defined. JavaScript systems always put a number of useful standard variables into your environment. ++Bindings can be used to file pieces of data under a name, and they are useful for tracking state in your program. The environment is the set of bindings that are defined. JavaScript systems always put a number of useful standard bindings into your environment. + + Functions are special values that encapsulate a piece of program. You can invoke them by writing `functionName(argument1, argument2)`. Such a function call is an expression, and may produce a value. + + ## Exercises + +-If you are unsure how to try your solutions to exercises, refer to the [introduction](00_intro.html#intro). ++If you are unsure how to try your solutions to exercises, refer to the [introduction](00_intro.html). + +-Each exercise starts with a problem description. Read that and try to solve the exercise. If you run into problems, consider reading the hints after the exercise. Full solutions to the exercises are not included in this book, but you can find them online at [_eloquentjavascript.net/code_](http://eloquentjavascript.net/2nd_edition/code). If you want to learn something from the exercises, I recommend looking at the solutions only after you've solved the exercise, or at least after you've attacked it long and hard enough to have a slight headache. ++Each exercise starts with a problem description. Read that and try to solve the exercise. If you run into problems, consider reading the hints after the exercise. Full solutions to the exercises are not included in this book, but you can find them online at [_eloquentjavascript.net/code_](https://eloquentjavascript.net/code#2). If you want to learn something from the exercises, I recommend looking at the solutions only after you've solved the exercise, or at least after you've attacked it long and hard enough to have a slight headache. + + ### Looping a triangle + +@@ -488,10 +502,10 @@ Write a loop that makes seven calls to `console.log` to output the following tri + ####### + ``` + +-It may be useful to know that you can find the length of a string by writing `.length` after it. ++It may be useful to know that you can find the length of a string by writing `.length` after it: + + ``` +-var abc = "abc"; ++let abc = "abc"; + console.log(abc.length); + // → 3 + ``` +@@ -502,7 +516,7 @@ Most exercises contain a piece of code that you can modify to solve the exercise + // Your code here. + ``` + +-You can start with a program that simply prints out the numbers 1 to 7, which you can derive by making a few modifications to the [even number printing example](02_program_structure.html#loops) given earlier in the chapter, where the `for` loop was introduced. ++You can start with a program that prints out the numbers 1 to 7, which you can derive by making a few modifications to the [even number printing example](02_program_structure.html#loops) given earlier in the chapter, where the `for` loop was introduced. + + Now consider the equivalence between numbers and strings of hash characters. You can go from 1 to 2 by adding 1 (`+= 1`). You can go from `"#"` to `"##"` by adding a character (`+= "#"`). Thus, your solution can closely follow the number-printing program. + +@@ -512,7 +526,7 @@ Write a program that uses `console.log` to print all the numbers from 1 to 100, + + When you have that working, modify your program to print `"FizzBuzz"`, for numbers that are divisible by both 3 and 5 (and still print `"Fizz"` or `"Buzz"` for numbers divisible by only one of those). + +-(This is actually an interview question that has been claimed to weed out a significant percentage of programmer candidates. So if you solved it, you're now allowed to feel good about yourself.) ++(This is actually an interview question that has been claimed to weed out a significant percentage of programmer candidates. So if you solved it, your labor market value just went up.) + + ``` + // Your code here. +@@ -522,26 +536,26 @@ Going over the numbers is clearly a looping job, and selecting what to print is + + In the first version, there are three possible outcomes for every number, so you'll have to create an `if`/`else if`/`else` chain. + +-The second version of the program has a straightforward solution and a clever one. The simple way is to add another “branch” to precisely test the given condition. For the clever method, build up a string containing the word or words to output, and print either this word or the number if there is no word, potentially by making elegant use of the `||` operator. ++The second version of the program has a straightforward solution and a clever one. The simple way is to add another conditional “branch” to precisely test the given condition. For the clever method, build up a string containing the word or words to output and print either this word or the number if there is no word, potentially by making good use of the `||` operator. + + ### Chess board + +-Write a program that creates a string that represents an 8×8 grid, using newline characters to separate lines. At each position of the grid there is either a space or a “#” character. The characters should form a chess board. ++Write a program that creates a string that represents an 8×8 grid, using newline characters to separate lines. At each position of the grid there is either a space or a "#" character. The characters should form a chess board. + + Passing this string to `console.log` should show something like this: + + ``` + # # # # +-# # # # ++# # # # + # # # # +-# # # # ++# # # # + # # # # +-# # # # ++# # # # + # # # # + # # # # + ``` + +-When you have a program that generates this pattern, define a variable `size = 8` and change the program so that it works for any `size`, outputting a grid of the given width and height. ++When you have a program that generates this pattern, define a binding `size = 8` and change the program so that it works for any `size`, outputting a grid of the given width and height. + + ``` + // Your code here. +@@ -549,10 +563,8 @@ When you have a program that generates this pattern, define a variable `size = 8 + + The string can be built by starting with an empty one (`""`) and repeatedly adding characters. A newline character is written `"\n"`. + +-Use `console.log` to inspect the output of your program. +- + To work with two dimensions, you will need a loop inside of a loop. Put curly braces around the bodies of both loops to make it easy to see where they start and end. Try to properly indent these bodies. The order of the loops must follow the order in which we build up the string (line by line, left to right, top to bottom). So the outer loop handles the lines and the inner loop handles the characters on a line. + +-You'll need two variables to track your progress. To know whether to put a space or a hash sign at a given position, you could test whether the sum of the two counters is even (`% 2`). ++You'll need two bindings to track your progress. To know whether to put a space or a hash sign at a given position, you could test whether the sum of the two counters is even (`% 2`). + +-Terminating a line by adding a newline character happens after the line has been built up, so do this after the inner loop but inside of the outer loop. ++Terminating a line by adding a newline character must happen after the line has been built up, so do this after the inner loop but inside of the outer loop. diff --git a/diff-en/2ech3-3ech3.diff b/diff-en/2ech3-3ech3.diff new file mode 100644 index 0000000..3203492 --- /dev/null +++ b/diff-en/2ech3-3ech3.diff @@ -0,0 +1,727 @@ +diff --git a/2ech3.md b/3ech3.md +index e6afba9..4dd4357 100644 +--- a/2ech3.md ++++ b/3ech3.md +@@ -4,18 +4,18 @@ + > + > <footer>Donald Knuth</footer> + +-You've seen function values, such as `alert`, and how to call them. Functions are the bread and butter of JavaScript programming. The concept of wrapping a piece of program in a value has many uses. It is a tool to structure larger programs, to reduce repetition, to associate names with subprograms, and to isolate these subprograms from each other. ++Functions are the bread and butter of JavaScript programming. The concept of wrapping a piece of program in a value has many uses. It gives us a way to structure larger programs, to reduce repetition, to associate names with subprograms, and to isolate these subprograms from each other. + +-The most obvious application of functions is defining new vocabulary. Creating new words in regular, human-language prose is usually bad style. But in programming, it is indispensable. ++The most obvious application of functions is defining new vocabulary. Creating new words in prose is usually bad style. But in programming, it is indispensable. + +-Typical adult English speakers have some 20,000 words in their vocabulary. Few programming languages come with 20,000 commands built in. And the vocabulary that _is_ available tends to be more precisely defined, and thus less flexible, than in human language. Therefore, we usually _have_ to add some of our own vocabulary to avoid repeating ourselves too much. ++Typical adult English speakers have some 20,000 words in their vocabulary. Few programming languages come with 20,000 commands built in. And the vocabulary that _is_ available tends to be more precisely defined, and thus less flexible, than in human language. Therefore, we usually _have_ to introduce new concepts to avoid repeating ourselves too much. + + ## Defining a function + +-A function definition is just a regular variable definition where the value given to the variable happens to be a function. For example, the following code defines the variable `square` to refer to a function that produces the square of a given number: ++A function definition is a regular binding where the value of the binding is a function. For example, this code defines `square` to refer to a function that produces the square of a given number: + + ``` +-var square = function(x) { ++const square = function(x) { + return x * x; + }; + +@@ -23,22 +23,23 @@ console.log(square(12)); + // → 144 + ``` + +-A function is created by an expression that starts with the keyword `function`. Functions have a set of _parameters_ (in this case, only `x`) and a _body_, which contains the statements that are to be executed when the function is called. The function body must always be wrapped in braces, even when it consists of only a single statement (as in the previous example). ++A function is created with an expression that starts with the keyword `function`. Functions have a set of _parameters_ (in this case, only `x`) and a _body_, which contains the statements that are to be executed when the function is called. The function body of a function created this way must always be wrapped in braces, even when it consists of only a single statement. + + A function can have multiple parameters or no parameters at all. In the following example, `makeNoise` does not list any parameter names, whereas `power` lists two: + + ``` +-var makeNoise = function() { ++const makeNoise = function() { + console.log("Pling!"); + }; + + makeNoise(); + // → Pling! + +-var power = function(base, exponent) { +- var result = 1; +- for (var count = 0; count < exponent; count++) ++const power = function(base, exponent) { ++ let result = 1; ++ for (let count = 0; count < exponent; count++) { + result *= base; ++ } + return result; + }; + +@@ -46,108 +47,93 @@ console.log(power(2, 10)); + // → 1024 + ``` + +-Some functions produce a value, such as `power` and `square`, and some don't, such as `makeNoise`, which produces only a side effect. A `return` statement determines the value the function returns. When control comes across such a statement, it immediately jumps out of the current function and gives the returned value to the code that called the function. The `return` keyword without an expression after it will cause the function to return `undefined`. ++Some functions produce a value, such as `power` and `square`, and some don't, such as `makeNoise`, whose only result is a side effect. A `return` statement determines the value the function returns. When control comes across such a statement, it immediately jumps out of the current function and gives the returned value to the code that called the function. A `return` keyword without an expression after it will cause the function to return `undefined`. Functions that don't have a `return` statement at all, such as `makeNoise`, similarly return `undefined`. + +-## Parameters and scopes ++Parameters to a function behave like regular bindings, but their initial values are given by the _caller_ of the function, not the code in the function itself. + +-The parameters to a function behave like regular variables, but their initial values are given by the _caller_ of the function, not the code in the function itself. ++## Bindings and scopes + +-An important property of functions is that the variables created inside of them, including their parameters, are _local_ to the function. This means, for example, that the `result` variable in the `power` example will be newly created every time the function is called, and these separate incarnations do not interfere with each other. ++Each binding has a _scope_, which is the part of the program in which the binding is visible. For bindings defined outside of any function or block, the scope is the whole program—you can refer to such bindings wherever you want. These are called _global_. + +-This “localness” of variables applies only to the parameters and to variables declared with the `var` keyword inside the function body. Variables declared outside of any function are called _global_, because they are visible throughout the program. It is possible to access such variables from inside a function, as long as you haven't declared a local variable with the same name. ++But bindings created for function parameters or declared inside a function can only be referenced in that function, so they are known as _local_ bindings. Every time the function is called, new instances of these bindings are created. This provides some isolation between functions—each function call acts in its own little world (its local environment) and can often be understood without knowing a lot about what's going on in the global environment. + +-The following code demonstrates this. It defines and calls two functions that both assign a value to the variable `x`. The first one declares the variable as local and thus changes only the local variable. The second does not declare `x` locally, so references to `x` inside of it refer to the global variable `x` defined at the top of the example. ++Bindings declared with `let` and `const` are in fact local to the _block_ that they are declared in, so if you create one of those inside of a loop, the code before and after the loop cannot “see” it. In pre-2015 JavaScript, only functions created new scopes, so old-style bindings, created with the `var` keyword, are visible throughout the whole function that they appear in—or throughout the global scope, if they are not in a function. + + ``` +-var x = "outside"; +- +-var f1 = function() { +- var x = "inside f1"; +-}; +-f1(); +-console.log(x); +-// → outside +- +-var f2 = function() { +- x = "inside f2"; +-}; +-f2(); +-console.log(x); +-// → inside f2 ++let x = 10; ++if (true) { ++ let y = 20; ++ var z = 30; ++ console.log(x + y + z); ++ // → 60 ++} ++// y is not visible here ++console.log(x + z); ++// → 40 + ``` + +-This behavior helps prevent accidental interference between functions. If all variables were shared by the whole program, it'd take a lot of effort to make sure no name is ever used for two different purposes. And if you _did_ reuse a variable name, you might see strange effects from unrelated code messing with the value of your variable. By treating function-local variables as existing only within the function, the language makes it possible to read and understand functions as small universes, without having to worry about all the code at once. +- +-## Nested scope +- +-JavaScript distinguishes not just between _global_ and _local_ variables. Functions can be created inside other functions, producing several degrees of locality. +- +-For example, this rather nonsensical function has two functions inside of it: ++Each scope can “look out” into the scope around it, so `x` is visible inside the block in the example. The exception is when multiple bindings have the same name—in that case, code can only see the innermost one. For example, when the code inside the `halve` function refers to `n`, it is seeing its _own_ `n`, not the global `n`. + + ``` +-var landscape = function() { +- var result = ""; +- var flat = function(size) { +- for (var count = 0; count < size; count++) +- result += "_"; +- }; +- var mountain = function(size) { +- result += "/"; +- for (var count = 0; count < size; count++) +- result += "'"; +- result += "\\"; +- }; +- +- flat(3); +- mountain(4); +- flat(6); +- mountain(1); +- flat(1); +- return result; ++const halve = function(n) { ++ return n / 2; + }; + +-console.log(landscape()); +-// → ___/''''\______/'\_ ++let n = 10; ++console.log(halve(100)); ++// → 50 ++console.log(n); ++// → 10 + ``` + +-The `flat` and `mountain` functions can “see” the variable called `result`, since they are inside the function that defines it. But they cannot see each other's `count` variables since they are outside each other's scope. The environment outside of the `landscape` function doesn't see any of the variables defined inside `landscape`. ++### Nested scope + +-In short, each local scope can also see all the local scopes that contain it. The set of variables visible inside a function is determined by the place of that function in the program text. All variables from blocks _around_ a function's definition are visible—meaning both those in function bodies that enclose it and those at the top level of the program. This approach to variable visibility is called _lexical scoping_. ++JavaScript distinguishes not just _global_ and _local_ bindings. Blocks and functions can be created inside other blocks and functions, producing multiple degrees of locality. + +-People who have experience with other programming languages might expect that any block of code between braces produces a new local environment. But in JavaScript, functions are the only things that create a new scope. You are allowed to use free-standing blocks. ++For example, this function—which outputs the ingredients needed to make a batch of hummus—has another function inside it: + + ``` +-var something = 1; +-{ +- var something = 2; +- // Do stuff with variable something... +-} +-// Outside of the block again... ++const hummus = function(factor) { ++ const ingredient = function(amount, unit, name) { ++ let ingredientAmount = amount * factor; ++ if (ingredientAmount > 1) { ++ unit += "s"; ++ } ++ console.log(`${ingredientAmount} ${unit} ${name}`); ++ }; ++ ingredient(1, "can", "chickpeas"); ++ ingredient(0.25, "cup", "tahini"); ++ ingredient(0.25, "cup", "lemon juice"); ++ ingredient(1, "clove", "garlic"); ++ ingredient(2, "tablespoon", "olive oil"); ++ ingredient(0.5, "teaspoon", "cumin"); ++}; + ``` + +-But the `something` inside the block refers to the same variable as the one outside the block. In fact, although blocks like this are allowed, they are useful only to group the body of an `if` statement or a loop. ++The code inside the `ingredient` function can see the `factor` binding from the outer function. But its local bindings, such as `unit` or `ingredientAmount`, are not visible in the outer function. + +-If you find this odd, you're not alone. The next version of JavaScript will introduce a `let` keyword, which works like `var` but creates a variable that is local to the enclosing _block_, not the enclosing _function_. ++In short, each local scope can also see all the local scopes that contain it. The set of bindings visible inside a block is determined by the place of that block in the program text. Each local scope can also see all the local scopes that contain it, and all scopes can see the global scope. This approach to binding visibility is called _lexical scoping_. + + ## Functions as values + +-Function variables usually simply act as names for a specific piece of the program. Such a variable is defined once and never changed. This makes it easy to start confusing the function and its name. ++A function binding usually simply acts as a name for a specific piece of the program. Such a binding is defined once and never changed. This makes it easy to confuse the function and its name. + +-But the two are different. A function value can do all the things that other values can do—you can use it in arbitrary expressions, not just call it. It is possible to store a function value in a new place, pass it as an argument to a function, and so on. Similarly, a variable that holds a function is still just a regular variable and can be assigned a new value, like so: ++But the two are different. A function value can do all the things that other values can do—you can use it in arbitrary expressions, not just call it. It is possible to store a function value in a new binding, pass it as an argument to a function, and so on. Similarly, a binding that holds a function is still just a regular binding and can, if not constant, be assigned a new value, like so: + + ``` +-var launchMissiles = function(value) { ++let launchMissiles = function() { + missileSystem.launch("now"); + }; +-if (safeMode) +- launchMissiles = function(value) {/* do nothing */}; ++if (safeMode) { ++ launchMissiles = function() {/* do nothing */}; ++} + ``` + +-In [Chapter 5](05_higher_order.html#higher_order), we will discuss the wonderful things that can be done by passing around function values to other functions. ++In [Chapter 5](05_higher_order.html), we will discuss the interesting things that can be done by passing around function values to other functions. + + ## Declaration notation + +-There is a slightly shorter way to say “`var square = function…`”. The `function` keyword can also be used at the start of a statement, as in the following: ++There is a slightly shorter way to create a function binding. When the `function` keyword is used at the start of a statement, it works differently. + + ``` + function square(x) { +@@ -155,32 +141,56 @@ function square(x) { + } + ``` + +-This is a function _declaration_. The statement defines the variable `square` and points it at the given function. So far so good. There is one subtlety with this form of function definition, however. ++This is a function _declaration_. The statement defines the binding `square` and points it at the given function. It is slightly easier to write and doesn't require a semicolon after the function. ++ ++There is one subtlety with this form of function definition. + + ``` + console.log("The future says:", future()); + + function future() { +- return "We STILL have no flying cars."; ++ return "You'll never have flying cars"; + } + ``` + +-This code works, even though the function is defined _below_ the code that uses it. This is because function declarations are not part of the regular top-to-bottom flow of control. They are conceptually moved to the top of their scope and can be used by all the code in that scope. This is sometimes useful because it gives us the freedom to order code in a way that seems meaningful, without worrying about having to define all functions above their first use. ++The preceding code works, even though the function is defined _below_ the code that uses it. Function declarations are not part of the regular top-to-bottom flow of control. They are conceptually moved to the top of their scope and can be used by all the code in that scope. This is sometimes useful because it offers the freedom to order code in a way that seems meaningful, without worrying about having to define all functions before they are used. ++ ++## Arrow functions + +-What happens when you put such a function definition inside a conditional (`if`) block or a loop? Well, don't do that. Different JavaScript platforms in different browsers have traditionally done different things in that situation, and the latest standard actually forbids it. If you want your programs to behave consistently, only use this form of function-defining statements in the outermost block of a function or program. ++There's a third notation for functions, which looks very different from the others. Instead of the `function` keyword, it uses an arrow (`=>`) made up of equals and greater-than characters (not to be confused with the greater-than-or-equal operator, which is written `>=`). + + ``` +-function example() { +- function a() {} // Okay +- if (something) { +- function b() {} // Danger! ++const power = (base, exponent) => { ++ let result = 1; ++ for (let count = 0; count < exponent; count++) { ++ result *= base; + } +-} ++ return result; ++}; + ``` + ++The arrow comes _after_ the list of parameters and is followed by the function's body. It expresses something like “this input (the parameters) produces this result (the body)”. ++ ++When there is only one parameter name, you can omit the parentheses around the parameter list. If the body is a single expression, rather than a block in braces, that expression will be returned from the function. So these two definitions of `square` do the same thing: ++ ++``` ++const square1 = (x) => { return x * x; }; ++const square2 = x => x * x; ++``` ++ ++When an arrow function has no parameters at all, its parameter list is just an empty set of parentheses. ++ ++``` ++const horn = () => { ++ console.log("Toot"); ++}; ++``` ++ ++There's no very good reason to have both arrow functions and `function` expressions in the language. Apart from a minor detail, which we'll discuss in [Chapter 6](06_object.html), they do the same thing. Arrow functions were added in 2015, mostly to make it possible to write small function expressions in a less verbose way. We'll be using them a lot in [Chapter 5](05_higher_order.html). ++ + ## The call stack + +-It will be helpful to take a closer look at the way control flows through functions. Here is a simple program that makes a few function calls: ++The way control flows through functions is somewhat involved. Let's take a closer look at it. Here is a simple program that makes a few function calls: + + ``` + function greet(who) { +@@ -190,25 +200,25 @@ greet("Harry"); + console.log("Bye"); + ``` + +-A run through this program goes roughly like this: the call to `greet` causes control to jump to the start of that function (line 2). It calls `console.log` (a built-in browser function), which takes control, does its job, and then returns control to line 2\. Then it reaches the end of the `greet` function, so it returns to the place that called it, at line 4\. The line after that calls `console.log` again. ++A run through this program goes roughly like this: the call to `greet` causes control to jump to the start of that function (line 2). The function calls `console.log`, which takes control, does its job, and then returns control to line 2\. There it reaches the end of the `greet` function, so it returns to the place that called it, which is line 4\. The line after that calls `console.log` again. After that returns, the program reaches its end. + + We could show the flow of control schematically like this: + + ``` +-top +- greet +- console.log +- greet +-top +- console.log +-top ++not in function ++ in greet ++ in console.log ++ in greet ++not in function ++ in console.log ++not in function + ``` + +-Because a function has to jump back to the place of the call when it returns, the computer must remember the context from which the function was called. In one case, `console.log` has to jump back to the `greet` function. In the other case, it jumps back to the end of the program. ++Because a function has to jump back to the place that called it when it returns, the computer must remember the context from which the call happened. In one case, `console.log` has to return to the `greet` function when it is done. In the other case, it returns to the end of the program. + +-The place where the computer stores this context is the _call stack_. Every time a function is called, the current context is put on top of this “stack”. When the function returns, it removes the top context from the stack and uses it to continue execution. ++The place where the computer stores this context is the _call stack_. Every time a function is called, the current context is stored on top of this stack. When a function returns, it removes the top context from the stack and uses that context to continue execution. + +-Storing this stack requires space in the computer's memory. When the stack grows too big, the computer will fail with a message like “out of stack space” or “too much recursion”. The following code illustrates this by asking the computer a really hard question, which causes an infinite back-and-forth between two functions. Rather, it _would_ be infinite, if the computer had an infinite stack. As it is, we will run out of space, or “blow the stack”. ++Storing this stack requires space in the computer's memory. When the stack grows too big, the computer will fail with a message like “out of stack space” or “too much recursion”. The following code illustrates this by asking the computer a really hard question that causes an infinite back-and-forth between two functions. Rather, it _would_ be infinite, if the computer had an infinite stack. As it is, we will run out of space, or “blow the stack”. + + ``` + function chicken() { +@@ -226,130 +236,147 @@ console.log(chicken() + " came first."); + The following code is allowed and executes without any problem: + + ``` +-alert("Hello", "Good Evening", "How do you do?"); ++function square(x) { return x * x; } ++console.log(square(4, true, "hedgehog")); ++// → 16 + ``` + +-The function `alert` officially accepts only one argument. Yet when you call it like this, it doesn't complain. It simply ignores the other arguments and shows you “Hello”. ++We defined `square` with only one parameter. Yet when we call it with three, the language doesn't complain. It ignores the extra arguments and computes the square of the first one. + +-JavaScript is extremely broad-minded about the number of arguments you pass to a function. If you pass too many, the extra ones are ignored. If you pass too few, the missing parameters simply get assigned the value `undefined`. ++JavaScript is extremely broad-minded about the number of arguments you pass to a function. If you pass too many, the extra ones are ignored. If you pass too few, the missing parameters get assigned the value `undefined`. + +-The downside of this is that it is possible—likely, even—that you'll accidentally pass the wrong number of arguments to functions and no one will tell you about it. ++The downside of this is that it is possible—likely, even—that you'll accidentally pass the wrong number of arguments to functions. And no one will tell you about it. + +-The upside is that this behavior can be used to have a function take “optional” arguments. For example, the following version of `power` can be called either with two arguments or with a single argument, in which case the exponent is assumed to be two, and the function behaves like `square`. ++The upside is that this behavior can be used to allow a function to be called with different amounts of arguments. For example, this `minus` function tries to imitate the `-` operator by acting on either one or two arguments: + + ``` +-function power(base, exponent) { +- if (exponent == undefined) +- exponent = 2; +- var result = 1; +- for (var count = 0; count < exponent; count++) ++function minus(a, b) { ++ if (b === undefined) return -a; ++ else return a - b; ++} ++ ++console.log(minus(10)); ++// → -10 ++console.log(minus(10, 5)); ++// → 5 ++``` ++ ++If you write an `=` operator after a parameter, followed by an expression, the value of that expression will replace the argument when it is not given. ++ ++For example, this version of `power` makes its second argument optional. If you don't provide it or pass the value `undefined`, it will default to two, and the function will behave like `square`. ++ ++``` ++function power(base, exponent = 2) { ++ let result = 1; ++ for (let count = 0; count < exponent; count++) { + result *= base; ++ } + return result; + } + + console.log(power(4)); + // → 16 +-console.log(power(4, 3)); ++console.log(power(2, 6)); + // → 64 + ``` + +-In the [next chapter](04_data.html#arguments_object), we will see a way in which a function body can get at the exact list of arguments that were passed. This is helpful because it makes it possible for a function to accept any number of arguments. For example, `console.log` makes use of this—it outputs all of the values it is given. ++In the [next chapter](04_data.html#rest_parameters), we will see a way in which a function body can get at the whole list of arguments it was passed. This is helpful because it makes it possible for a function to accept any number of arguments. For example, `console.log` does this—it outputs all of the values it is given. + + ``` +-console.log("R", 2, "D", 2); +-// → R 2 D 2 ++console.log("C", "O", 2); ++// → C O 2 + ``` + + ## Closure + +-The ability to treat functions as values, combined with the fact that local variables are “re-created” every time a function is called, brings up an interesting question. What happens to local variables when the function call that created them is no longer active? ++The ability to treat functions as values, combined with the fact that local bindings are re-created every time a function is called, brings up an interesting question. What happens to local bindings when the function call that created them is no longer active? + +-The following code shows an example of this. It defines a function, `wrapValue`, which creates a local variable. It then returns a function that accesses and returns this local variable. ++The following code shows an example of this. It defines a function, `wrapValue`, that creates a local binding. It then returns a function that accesses and returns this local binding. + + ``` + function wrapValue(n) { +- var localVariable = n; +- return function() { return localVariable; }; ++ let local = n; ++ return () => local; + } + +-var wrap1 = wrapValue(1); +-var wrap2 = wrapValue(2); ++let wrap1 = wrapValue(1); ++let wrap2 = wrapValue(2); + console.log(wrap1()); + // → 1 + console.log(wrap2()); + // → 2 + ``` + +-This is allowed and works as you'd hope—the variable can still be accessed. In fact, multiple instances of the variable can be alive at the same time, which is another good illustration of the concept that local variables really are re-created for every call—different calls can't trample on one another's local variables. ++This is allowed and works as you'd hope—both instances of the binding can still be accessed. This situation is a good demonstration of the fact that local bindings are created anew for every call, and different calls can't trample on one another's local bindings. + +-This feature—being able to reference a specific instance of local variables in an enclosing function—is called _closure_. A function that “closes over” some local variables is called _a_ closure. This behavior not only frees you from having to worry about lifetimes of variables but also allows for some creative use of function values. ++This feature—being able to reference a specific instance of a local binding in an enclosing scope—is called _closure_. A function that references bindings from local scopes around it is called _a_ closure. This behavior not only frees you from having to worry about lifetimes of bindings but also makes it possible to use function values in some creative ways. + +-With a slight change, we can turn the previous example into a way to create functions that multiply by an arbitrary amount. ++With a slight change, we can turn the previous example into a way to create functions that multiply by an arbitrary amount: + + ``` + function multiplier(factor) { +- return function(number) { +- return number * factor; +- }; ++ return number => number * factor; + } + +-var twice = multiplier(2); ++let twice = multiplier(2); + console.log(twice(5)); + // → 10 + ``` + +-The explicit `localVariable` from the `wrapValue` example isn't needed since a parameter is itself a local variable. ++The explicit `local` binding from the `wrapValue` example isn't really needed since a parameter is itself a local binding. + +-Thinking about programs like this takes some practice. A good mental model is to think of the `function` keyword as “freezing” the code in its body and wrapping it into a package (the function value). So when you read `return function(...) {...}`, think of it as returning a handle to a piece of computation, frozen for later use. ++Thinking about programs like this takes some practice. A good mental model is to think of function values as containing both the code in their body and the environment in which they are created. When called, the function body sees the environment in which it was created, not the environment in which it is called. + +-In the example, `multiplier` returns a frozen chunk of code that gets stored in the `twice` variable. The last line then calls the value in this variable, causing the frozen code (`return number * factor;`) to be activated. It still has access to the `factor` variable from the `multiplier` call that created it, and in addition it gets access to the argument passed when unfreezing it, 5, through its `number` parameter. ++In the example, `multiplier` is called and creates an environment in which its `factor` parameter is bound to 2\. The function value it returns, which is stored in `twice`, remembers this environment. So when that is called, it multiplies its argument by 2. + + ## Recursion + +-It is perfectly okay for a function to call itself, as long as it takes care not to overflow the stack. A function that calls itself is called _recursive_. Recursion allows some functions to be written in a different style. Take, for example, this alternative implementation of `power`: ++It is perfectly okay for a function to call itself, as long as it doesn't do it so often that it overflows the stack. A function that calls itself is called _recursive_. Recursion allows some functions to be written in a different style. Take, for example, this alternative implementation of `power`: + + ``` + function power(base, exponent) { +- if (exponent == 0) ++ if (exponent == 0) { + return 1; +- else ++ } else { + return base * power(base, exponent - 1); ++ } + } + + console.log(power(2, 3)); + // → 8 + ``` + +-This is rather close to the way mathematicians define exponentiation and arguably describes the concept in a more elegant way than the looping variant does. The function calls itself multiple times with different arguments to achieve the repeated multiplication. ++This is rather close to the way mathematicians define exponentiation and arguably describes the concept more clearly than the looping variant. The function calls itself multiple times with ever smaller exponents to achieve the repeated multiplication. + +-But this implementation has one important problem: in typical JavaScript implementations, it's about 10 times slower than the looping version. Running through a simple loop is a lot cheaper than calling a function multiple times. ++But this implementation has one problem: in typical JavaScript implementations, it's about three times slower than the looping version. Running through a simple loop is generally cheaper than calling a function multiple times. + +-The dilemma of speed versus elegance is an interesting one. You can see it as a kind of continuum between human-friendliness and machine-friendliness. Almost any program can be made faster by making it bigger and more convoluted. The programmer must decide on an appropriate balance. ++The dilemma of speed versus elegance is an interesting one. You can see it as a kind of continuum between human-friendliness and machine-friendliness. Almost any program can be made faster by making it bigger and more convoluted. The programmer has to decide on an appropriate balance. + +-In the case of the [earlier](03_functions.html#power) `power` function, the inelegant (looping) version is still fairly simple and easy to read. It doesn't make much sense to replace it with the recursive version. Often, though, a program deals with such complex concepts that giving up some efficiency in order to make the program more straightforward becomes an attractive choice. ++In the case of the `power` function, the inelegant (looping) version is still fairly simple and easy to read. It doesn't make much sense to replace it with the recursive version. Often, though, a program deals with such complex concepts that giving up some efficiency in order to make the program more straightforward is helpful. + +-The basic rule, which has been repeated by many programmers and with which I wholeheartedly agree, is to not worry about efficiency until you know for sure that the program is too slow. If it is, find out which parts are taking up the most time, and start exchanging elegance for efficiency in those parts. ++Worrying about efficiency can be a distraction. It's yet another factor that complicates program design, and when you're doing something that's already difficult, that extra thing to worry about can be paralyzing. + +-Of course, this rule doesn't mean one should start ignoring performance altogether. In many cases, like the `power` function, not much simplicity is gained from the “elegant” approach. And sometimes an experienced programmer can see right away that a simple approach is never going to be fast enough. ++Therefore, always start by writing something that's correct and easy to understand. If you're worried that it's too slow—which it usually isn't, since most code simply isn't executed often enough to take any significant amount of time—you can measure afterwards and improve it if necessary. + +-The reason I'm stressing this is that surprisingly many beginning programmers focus fanatically on efficiency, even in the smallest details. The result is bigger, more complicated, and often less correct programs, that take longer to write than their more straightforward equivalents and that usually run only marginally faster. ++Recursion is not always just an inefficient alternative to looping. Some problems really are easier to solve with recursion than with loops. Most often these are problems that require exploring or processing several “branches”, each of which might branch out again into even more branches. + +-But recursion is not always just a less-efficient alternative to looping. Some problems are much easier to solve with recursion than with loops. Most often these are problems that require exploring or processing several “branches”, each of which might branch out again into more branches. ++Consider this puzzle: by starting from the number 1 and repeatedly either adding 5 or multiplying by 3, an infinite amount of new numbers can be produced. How would you write a function that, given a number, tries to find a sequence of such additions and multiplications that produces that number? + +-Consider this puzzle: by starting from the number 1 and repeatedly either adding 5 or multiplying by 3, an infinite amount of new numbers can be produced. How would you write a function that, given a number, tries to find a sequence of such additions and multiplications that produce that number? For example, the number 13 could be reached by first multiplying by 3 and then adding 5 twice, whereas the number 15 cannot be reached at all. ++For example, the number 13 could be reached by first multiplying by 3 and then adding 5 twice, whereas the number 15 cannot be reached at all. + + Here is a recursive solution: + + ``` + function findSolution(target) { + function find(current, history) { +- if (current == target) ++ if (current == target) { + return history; +- else if (current > target) ++ } else if (current > target) { + return null; +- else +- return find(current + 5, "(" + history + " + 5)") || +- find(current * 3, "(" + history + " * 3)"); ++ } else { ++ return find(current + 5, `(${history} + 5)`) || ++ find(current * 3, `(${history} * 3)`); ++ } + } + return find(1, "1"); + } +@@ -360,11 +387,11 @@ console.log(findSolution(24)); + + Note that this program doesn't necessarily find the _shortest_ sequence of operations. It is satisfied when it finds any sequence at all. + +-I don't necessarily expect you to see how it works right away. But let's work through it, since it makes for a great exercise in recursive thinking. ++It is okay if you don't see how it works right away. Let's work through it, since it makes for a great exercise in recursive thinking. + +-The inner function `find` does the actual recursing. It takes two arguments—the current number and a string that records how we reached this number—and returns either a string that shows how to get to the target or `null`. ++The inner function `find` does the actual recursing. It takes two arguments: The current number and a string that records how we reached this number. If it finds a solution, it returns a string that shows how to get to the target. If no solution can be found starting from this number, it returns `null`. + +-To do this, the function performs one of three actions. If the current number is the target number, the current history is a way to reach that target, so it is simply returned. If the current number is greater than the target, there's no sense in further exploring this history since both adding and multiplying will only make the number bigger. And finally, if we're still below the target, the function tries both possible paths that start from the current number, by calling itself twice, once for each of the allowed next steps. If the first call returns something that is not `null`, it is returned. Otherwise, the second call is returned—regardless of whether it produces a string or `null`. ++To do this, the function performs one of three actions. If the current number is the target number, the current history is a way to reach that target, so it is returned. If the current number is greater than the target, there's no sense in further exploring this branch because both adding and multiplying will only make the number bigger, so it returns `null`. And finally, if we're still below the target number, the function tries both possible paths that start from the current number by calling itself twice, once for addition and once for multiplication. If the first call returns something that is not `null`, it is returned. Otherwise, the second call is returned, regardless of whether it produces a string or `null`. + + To better understand how this function produces the effect we're looking for, let's look at all the calls to `find` that are made when searching for a solution for the number 13. + +@@ -384,15 +411,15 @@ find(1, "1") + found! + ``` + +-The indentation suggests the depth of the call stack. The first time `find` is called it calls itself twice to explore the solutions that start with `(1 + 5)` and `(1 * 3)`. The first call tries to find a solution that starts with `(1 + 5)` and, using recursion, explores _every_ solution that yields a number less than or equal to the target number. Since it doesn't find a solution that hits the target, it returns `null` back to the first call. There the `||` operator causes the call that explores `(1 * 3)` to happen. This search has more luck because its first recursive call, through yet _another_ recursive call, hits upon the target number, 13\. This innermost recursive call returns a string, and each of the `||` operators in the intermediate calls pass that string along, ultimately returning our solution. ++The indentation indicates the depth of the call stack. The first time `find` is called, it starts by calling itself to explore the solution that starts with `(1 + 5)`. That call will further recurse to explore _every_ continued solution that yields a number less than or equal to the target number. Since it doesn't find one that hits the target, it returns `null` back to the first call. There the `||` operator causes the call that explores `(1 * 3)` to happen. This search has more luck—its first recursive call, through yet _another_ recursive call, hits upon the target number. That innermost call returns a string, and each of the `||` operators in the intermediate calls passes that string along, ultimately returning the solution. + + ## Growing functions + + There are two more or less natural ways for functions to be introduced into programs. + +-The first is that you find yourself writing very similar code multiple times. We want to avoid doing that since having more code means more space for mistakes to hide and more material to read for people trying to understand the program. So we take the repeated functionality, find a good name for it, and put it into a function. ++The first is that you find yourself writing very similar code multiple times. We'd prefer not to do that. Having more code means more space for mistakes to hide and more material to read for people trying to understand the program. So we take the repeated functionality, find a good name for it, and put it into a function. + +-The second way is that you find you need some functionality that you haven't written yet and that sounds like it deserves its own function. You'll start by naming the function, and you'll then write its body. You might even start writing code that uses the function before you actually define the function itself. ++The second way is that you find you need some functionality that you haven't written yet and that sounds like it deserves its own function. You'll start by naming the function, and then you'll write its body. You might even start writing code that uses the function before you actually define the function itself. + + How difficult it is to find a good name for a function is a good indication of how clear a concept it is that you're trying to wrap. Let's go through an example. + +@@ -403,34 +430,37 @@ We want to write a program that prints two numbers, the numbers of cows and chic + 011 Chickens + ``` + +-That clearly asks for a function of two arguments. Let's get coding. ++This asks for a function of two arguments—the number of cows and the number of chickens. Let's get coding. + + ``` + function printFarmInventory(cows, chickens) { +- var cowString = String(cows); +- while (cowString.length < 3) ++ let cowString = String(cows); ++ while (cowString.length < 3) { + cowString = "0" + cowString; +- console.log(cowString + " Cows"); +- var chickenString = String(chickens); +- while (chickenString.length < 3) ++ } ++ console.log(`${cowString} Cows`); ++ let chickenString = String(chickens); ++ while (chickenString.length < 3) { + chickenString = "0" + chickenString; +- console.log(chickenString + " Chickens"); ++ } ++ console.log(`${chickenString} Chickens`); + } + printFarmInventory(7, 11); + ``` + +-Adding `.length` after a string value will give us the length of that string. Thus, the `while` loops keep adding zeros in front of the number strings until they are at least three characters long. ++Writing `.length` after a string expression will give us the length of that string. Thus, the `while` loops keep adding zeros in front of the number strings until they are at least three characters long. + +-Mission accomplished! But just as we are about to send the farmer the code (along with a hefty invoice, of course), he calls and tells us he's also started keeping pigs, and couldn't we please extend the software to also print pigs? ++Mission accomplished! But just as we are about to send the farmer the code (along with a hefty invoice), she calls and tells us she's also started keeping pigs, and couldn't we please extend the software to also print pigs? + + We sure can. But just as we're in the process of copying and pasting those four lines one more time, we stop and reconsider. There has to be a better way. Here's a first attempt: + + ``` + function printZeroPaddedWithLabel(number, label) { +- var numberString = String(number); +- while (numberString.length < 3) ++ let numberString = String(number); ++ while (numberString.length < 3) { + numberString = "0" + numberString; +- console.log(numberString + " " + label); ++ } ++ console.log(`${numberString} ${label}`); + } + + function printFarmInventory(cows, chickens, pigs) { +@@ -448,44 +478,45 @@ Instead of lifting out the repeated part of our program wholesale, let's try to + + ``` + function zeroPad(number, width) { +- var string = String(number); +- while (string.length < width) ++ let string = String(number); ++ while (string.length < width) { + string = "0" + string; ++ } + return string; + } + + function printFarmInventory(cows, chickens, pigs) { +- console.log(zeroPad(cows, 3) + " Cows"); +- console.log(zeroPad(chickens, 3) + " Chickens"); +- console.log(zeroPad(pigs, 3) + " Pigs"); ++ console.log(`${zeroPad(cows, 3)} Cows`); ++ console.log(`${zeroPad(chickens, 3)} Chickens`); ++ console.log(`${zeroPad(pigs, 3)} Pigs`); + } + + printFarmInventory(7, 16, 3); + ``` + +-A function with a nice, obvious name like `zeroPad` makes it easier for someone who reads the code to figure out what it does. And it is useful in more situations than just this specific program. For example, you could use it to help print nicely aligned tables of numbers. ++A function with a nice, obvious name like `zeroPad` makes it easier for someone who reads the code to figure out what it does. And such a function is useful in more situations than just this specific program. For example, you could use it to help print nicely aligned tables of numbers. + +-How smart and versatile should our function be? We could write anything from a terribly simple function that simply pads a number so that it's three characters wide to a complicated generalized number-formatting system that handles fractional numbers, negative numbers, alignment of dots, padding with different characters, and so on. ++How smart and versatile _should_ our function be? We could write anything, from a terribly simple function that can only pad a number to be three characters wide, to a complicated generalized number-formatting system that handles fractional numbers, negative numbers, alignment of decimal dots, padding with different characters, and so on. + +-A useful principle is not to add cleverness unless you are absolutely sure you're going to need it. It can be tempting to write general “frameworks” for every little bit of functionality you come across. Resist that urge. You won't get any real work done, and you'll end up writing a lot of code that no one will ever use. ++A useful principle is to not add cleverness unless you are absolutely sure you're going to need it. It can be tempting to write general “frameworks” for every bit of functionality you come across. Resist that urge. You won't get any real work done—you'll just be writing code that you never use. + + ## Functions and side effects + +-Functions can be roughly divided into those that are called for their side effects and those that are called for their return value. (Though it is definitely also possible to have both side effects and return a value.) ++Functions can be roughly divided into those that are called for their side effects and those that are called for their return value. (Though it is definitely also possible to both have side effects and return a value.) + + The first helper function in the farm example, `printZeroPaddedWithLabel`, is called for its side effect: it prints a line. The second version, `zeroPad`, is called for its return value. It is no coincidence that the second is useful in more situations than the first. Functions that create values are easier to combine in new ways than functions that directly perform side effects. + +-A _pure_ function is a specific kind of value-producing function that not only has no side effects but also doesn't rely on side effects from other code—for example, it doesn't read global variables that are occasionally changed by other code. A pure function has the pleasant property that, when called with the same arguments, it always produces the same value (and doesn't do anything else). This makes it easy to reason about. A call to such a function can be mentally substituted by its result, without changing the meaning of the code. When you are not sure that a pure function is working correctly, you can test it by simply calling it, and know that if it works in that context, it will work in any context. Nonpure functions might return different values based on all kinds of factors and have side effects that might be hard to test and think about. ++A _pure_ function is a specific kind of value-producing function that not only has no side effects but also doesn't rely on side effects from other code—for example, it doesn't read global bindings whose value might change. A pure function has the pleasant property that, when called with the same arguments, it always produces the same value (and doesn't do anything else). A call to such a function can be substituted by its return value without changing the meaning of the code. When you are not sure that a pure function is working correctly, you can test it by simply calling it, and know that if it works in that context, it will work in any context. Nonpure functions tend to require more scaffolding to test. + +-Still, there's no need to feel bad when writing functions that are not pure or to wage a holy war to purge them from your code. Side effects are often useful. There'd be no way to write a pure version of `console.log`, for example, and `console.log` is certainly useful. Some operations are also easier to express in an efficient way when we use side effects, so computing speed can be a reason to avoid purity. ++Still, there's no need to feel bad when writing functions that are not pure or to wage a holy war to purge them from your code. Side effects are often useful. There'd be no way to write a pure version of `console.log`, for example, and `console.log` is good to have. Some operations are also easier to express in an efficient way when we use side effects, so computing speed can be a reason to avoid purity. + + ## Summary + +-This chapter taught you how to write your own functions. The `function` keyword, when used as an expression, can create a function value. When used as a statement, it can be used to declare a variable and give it a function as its value. ++This chapter taught you how to write your own functions. The `function` keyword, when used as an expression, can create a function value. When used as a statement, it can be used to declare a binding and give it a function as its value. Arrow functions are yet another way to create functions. + + ``` +-// Create a function value f +-var f = function(a) { ++// Define f to hold a function value ++const f = function(a) { + console.log(a + 2); + }; + +@@ -493,17 +524,20 @@ var f = function(a) { + function g(a, b) { + return a * b * 3.5; + } ++ ++// A less verbose function value ++let h = a => a % 3; + ``` + +-A key aspect in understanding functions is understanding local scopes. Parameters and variables declared inside a function are local to the function, re-created every time the function is called, and not visible from the outside. Functions declared inside another function have access to the outer function's local scope. ++A key aspect in understanding functions is understanding scopes. Each block creates a new scope. Parameters and bindings declared in a given scope are local, and not visible from the outside. Bindings declared with `var` behave differently—they end up in the nearest function scope or the global scope. + +-Separating the tasks your program performs into different functions is helpful. You won't have to repeat yourself as much, and functions can make a program more readable by grouping code into conceptual chunks, in the same way that chapters and sections help organize regular text. ++Separating the tasks your program performs into different functions is helpful. You won't have to repeat yourself as much, and functions can help organize a program by grouping code into pieces that do specific things. + + ## Exercises + + ### Minimum + +-The [previous chapter](02_program_structure.html#return_values) introduced the standard function `Math.min` that returns its smallest argument. We can do that ourselves now. Write a function `min` that takes two arguments and returns their minimum. ++The [previous chapter](02_program_structure.html#return_values) introduced the standard function `Math.min` that returns its smallest argument. We can build something like that now. Write a function `min` that takes two arguments and returns their minimum. + + ``` + // Your code here. +@@ -520,7 +554,7 @@ A function may contain multiple `return` statements. + + ### Recursion + +-We've seen that `%` (the remainder operator) can be used to test whether a number is even or odd by using `% 2` to check whether it's divisible by two. Here's another way to define whether a positive whole number is even or odd: ++We've seen that `%` (the remainder operator) can be used to test whether a number is even or odd by using `% 2` to see whether it's divisible by two. Here's another way to define whether a positive whole number is even or odd: + + * Zero is even. + +@@ -528,9 +562,9 @@ We've seen that `%` (the remainder operator) can be used to test whether a numbe + + * For any other number _N_, its evenness is the same as _N_ - 2. + +-Define a recursive function `isEven` corresponding to this description. The function should accept a `number` parameter and return a Boolean. ++Define a recursive function `isEven` corresponding to this description. The function should accept a single parameter (a positive, whole number) and return a Boolean. + +-Test it on 50 and 75\. See how it behaves on -1. Why? Can you think of a way to fix this? ++Test it on 50 and 75\. See how it behaves on -1\. Why? Can you think of a way to fix this? + + ``` + // Your code here. +@@ -549,9 +583,9 @@ When given a negative number, the function will recurse again and again, passing + + ### Bean counting + +-You can get the Nth character, or letter, from a string by writing `"string".charAt(N)`, similar to how you get its length with `"s".length`. The returned value will be a string containing only one character (for example, `"b"`). The first character has position zero, which causes the last one to be found at position `string.length - 1`. In other words, a two-character string has length 2, and its characters have positions 0 and 1. ++You can get the Nth character, or letter, from a string by writing `"string"[N]`. The returned value will be a string containing only one character (for example, `"b"`). The first character has position zero, which causes the last one to be found at position `string.<wbr>length - 1`. In other words, a two-character string has length 2, and its characters have positions 0 and 1. + +-Write a function `countBs` that takes a string as its only argument and returns a number that indicates how many uppercase “B” characters are in the string. ++Write a function `countBs` that takes a string as its only argument and returns a number that indicates how many uppercase “B” characters there are in the string. + + Next, write a function called `countChar` that behaves like `countBs`, except it takes a second argument that indicates the character that is to be counted (rather than counting only uppercase “B” characters). Rewrite `countBs` to make use of this new function. + +@@ -564,6 +598,6 @@ console.log(countChar("kakkerlak", "k")); + // → 4 + ``` + +-A loop in your function will have to look at every character in the string by running an index from zero to one below its length (`< string.length`). If the character at the current position is the same as the one the function is looking for, it adds 1 to a counter variable. Once the loop has finished, the counter can be returned. ++Your function will need a loop that looks at every character in the string. It can run an index from zero to one below its length (`< string.<wbr>length`). If the character at the current position is the same as the one the function is looking for, it adds 1 to a counter variable. Once the loop has finished, the counter can be returned. + +-Take care to make all the variables used in the function _local_ to the function by using the `var` keyword. ++Take care to make all the bindings used in the function _local_ to the function by properly declaring them with the `let` or `const` keyword. diff --git a/diff-en/2ech4-3ech4.diff b/diff-en/2ech4-3ech4.diff new file mode 100644 index 0000000..883bccf --- /dev/null +++ b/diff-en/2ech4-3ech4.diff @@ -0,0 +1,1029 @@ +diff --git a/2ech4.md b/3ech4.md +index 351db88..a3967fd 100644 +--- a/2ech4.md ++++ b/3ech4.md +@@ -4,110 +4,111 @@ + > + > <footer>Charles Babbage, <cite>Passages from the Life of a Philosopher (1864)</cite></footer> + +-Numbers, Booleans, and strings are the bricks that data structures are built from. But you can't make much of a house out of a single brick. _Objects_ allow us to group values—including other objects—together and thus build more complex structures. ++Numbers, Booleans, and strings are the atoms that data structures are built from. Many types of information require more than one atom, though. _Objects_ allow us to group values—including other objects—together to build more complex structures. + +-The programs we have built so far have been seriously hampered by the fact that they were operating only on simple data types. This chapter will add a basic understanding of data structures to your toolkit. By the end of it, you'll know enough to start writing some useful programs. ++The programs we have built so far have been limited by the fact that they were operating only on simple data types. This chapter will introduce basic data structures. By the end of it, you'll know enough to start writing useful programs. + +-The chapter will work through a more or less realistic programming example, introducing concepts as they apply to the problem at hand. The example code will often build on functions and variables that were introduced earlier in the text. ++The chapter will work through a more or less realistic programming example, introducing concepts as they apply to the problem at hand. The example code will often build on functions and bindings that were introduced earlier in the text. + + ## The weresquirrel + + Every now and then, usually between eight and ten in the evening, Jacques finds himself transforming into a small furry rodent with a bushy tail. + +-On one hand, Jacques is quite glad that he doesn't have classic lycanthropy. Turning into a squirrel tends to cause fewer problems than turning into a wolf. Instead of having to worry about accidentally eating the neighbor (_that_ would be awkward), he worries about being eaten by the neighbor's cat. After two occasions where he woke up on a precariously thin branch in the crown of an oak, naked and disoriented, he has taken to locking the doors and windows of his room at night and putting a few walnuts on the floor to keep himself busy. ++On one hand, Jacques is quite glad that he doesn't have classic lycanthropy. Turning into a squirrel does cause fewer problems than turning into a wolf. Instead of having to worry about accidentally eating the neighbor (_that_ would be awkward), he worries about being eaten by the neighbor's cat. After two occasions where he woke up on a precariously thin branch in the crown of an oak, naked and disoriented, he has taken to locking the doors and windows of his room at night and putting a few walnuts on the floor to keep himself busy. + +-![The weresquirrel](img/weresquirrel.png) ++That takes care of the cat and tree problems. But Jacques would prefer to get rid of his condition entirely. The irregular occurrences of the transformation make him suspect that they might be triggered by something. For a while, he believed that it happened only on days when he had been near oak trees. But avoiding oak trees did not stop the problem. + +-That takes care of the cat and oak problems. But Jacques still suffers from his condition. The irregular occurrences of the transformation make him suspect that they might be triggered by something. For a while, he believed that it happened only on days when he had touched trees. So he stopped touching trees entirely and even avoided going near them. But the problem persisted. ++Switching to a more scientific approach, Jacques has started keeping a daily log of everything he does on a given day and whether he changed form. With this data he hopes to narrow down the conditions that trigger the transformations. + +-Switching to a more scientific approach, Jacques intends to start keeping a daily log of everything he did that day and whether he changed form. With this data he hopes to narrow down the conditions that trigger the transformations. +- +-The first thing he does is design a data structure to store this information. ++The first thing he needs is a data structure to store this information. + + ## Data sets + +-To work with a chunk of digital data, we'll first have to find a way to represent it in our machine's memory. Say, as a simple example, that we want to represent a collection of numbers: 2, 3, 5, 7, and 11. ++To work with a chunk of digital data, we'll first have to find a way to represent it in our machine's memory. Say, for example, that we want to represent a collection of the numbers 2, 3, 5, 7, and 11. + +-We could get creative with strings—after all, strings can be any length, so we can put a lot of data into them—and use `"2 3 5 7 11"` as our representation. But this is awkward. You'd have to somehow extract the digits and convert them back to numbers to access them. ++We could get creative with strings—after all, strings can have any length, so we can put a lot of data into them—and use `"2 3 5 7 11"` as our representation. But this is awkward. You'd have to somehow extract the digits and convert them back to numbers to access them. + + Fortunately, JavaScript provides a data type specifically for storing sequences of values. It is called an _array_ and is written as a list of values between square brackets, separated by commas. + + ``` +-var listOfNumbers = [2, 3, 5, 7, 11]; ++let listOfNumbers = [2, 3, 5, 7, 11]; + console.log(listOfNumbers[2]); + // → 5 ++console.log(listOfNumbers[0]); ++// → 2 + console.log(listOfNumbers[2 - 1]); + // → 3 + ``` + + The notation for getting at the elements inside an array also uses square brackets. A pair of square brackets immediately after an expression, with another expression inside of them, will look up the element in the left-hand expression that corresponds to the _index_ given by the expression in the brackets. + +-The first index of an array is zero, not one. So the first element can be read with `listOfNumbers[0]`. If you don't have a programming background, this convention might take some getting used to. But zero-based counting has a long tradition in technology, and as long as this convention is followed consistently (which it is, in JavaScript), it works well. ++The first index of an array is zero, not one. So the first element is retrieved with `listOfNumbers[0]`. Zero-based counting has a long tradition in technology, and in certain ways makes a lot of sense, but it takes some getting used to. Think of the index as the amount of items to skip, counting from the start of the array. + + ## Properties + +-We've seen a few suspicious-looking expressions like `myString.length` (to get the length of a string) and `Math.max` (the maximum function) in past examples. These are expressions that access a _property_ of some value. In the first case, we access the `length` property of the value in `myString`. In the second, we access the property named `max` in the `Math` object (which is a collection of mathematics-related values and functions). ++We've seen a few suspicious-looking expressions like `myString.length` (to get the length of a string) and `Math.max` (the maximum function) in past chapters. These are expressions that access a _property_ of some value. In the first case, we access the `length` property of the value in `myString`. In the second, we access the property named `max` in the `Math` object (which is a collection of mathematics-related constants and functions). + + Almost all JavaScript values have properties. The exceptions are `null` and `undefined`. If you try to access a property on one of these nonvalues, you get an error. + + ``` + null.length; +-// → TypeError: Cannot read property 'length' of null ++// → TypeError: null has no properties + ``` + +-The two most common ways to access properties in JavaScript are with a dot and with square brackets. Both `value.x` and `value[x]` access a property on `value`—but not necessarily the same property. The difference is in how `x` is interpreted. When using a dot, the part after the dot must be a valid variable name, and it directly names the property. When using square brackets, the expression between the brackets is _evaluated_ to get the property name. Whereas `value.x` fetches the property of `value` named “x”, `value[x]` tries to evaluate the expression `x` and uses the result as the property name. ++The two main ways to access properties in JavaScript are with a dot and with square brackets. Both `value.x` and `value[x]` access a property on `value`—but not necessarily the same property. The difference is in how `x` is interpreted. When using a dot, the word after the dot is the literal name of the property. When using square brackets, the expression between the brackets is _evaluated_ to get the property name. Whereas `value.x` fetches the property of `value` named “x”, `value[x]` tries to evaluate the expression `x` and uses the result, converted to a string, as the property name. ++ ++So if you know that the property you are interested in is called _color_, you say `value.color`. If you want to extract the property named by the value held in the binding `i`, you say `value[i]`. Property names are strings. They can be any string, but the dot notation only works with names that look like valid binding names. So if you want to access a property named _2_ or _John Doe_, you must use square brackets: `value[2]` or `value["John Doe"]`. + +-So if you know that the property you are interested in is called “length”, you say `value.length`. If you want to extract the property named by the value held in the variable `i`, you say `value[i]`. And because property names can be any string, if you want to access a property named “2” or “John Doe”, you must use square brackets: `value[2]` or `value["John Doe"]`. This is the case even though you know the precise name of the property in advance, because neither “2” nor “John Doe” is a valid variable name and so cannot be accessed through dot notation. ++The elements in an array are stored as the array's properties, using numbers as property names. Because you can't use the dot notation with numbers, and usually want to use a binding that holds the index anyway, you have to use the bracket notation to get at them. + +-The elements in an array are stored in properties. Because the names of these properties are numbers and we often need to get their name from a variable, we have to use the bracket syntax to access them. The `length` property of an array tells us how many elements it contains. This property name is a valid variable name, and we know its name in advance, so to find the length of an array, you typically write `array.length` because that is easier to write than `array["length"]`. ++The `length` property of an array tells us how many elements it has. This property name is a valid binding name, and we know its name in advance, so to find the length of an array, you typically write `array.length` because that's easier to write than `array["length"]`. + + ## Methods + +-Both string and array objects contain, in addition to the `length` property, a number of properties that refer to function values. ++Both string and array objects contain, in addition to the `length` property, a number of properties that hold function values. + + ``` +-var doh = "Doh"; ++let doh = "Doh"; + console.log(typeof doh.toUpperCase); + // → function + console.log(doh.toUpperCase()); + // → DOH + ``` + +-Every string has a `toUpperCase` property. When called, it will return a copy of the string, in which all letters have been converted to uppercase. There is also `toLowerCase`. You can guess what that does. ++Every string has a `toUpperCase` property. When called, it will return a copy of the string in which all letters have been converted to uppercase. There is also `toLowerCase`, going the other way. + + Interestingly, even though the call to `toUpperCase` does not pass any arguments, the function somehow has access to the string `"Doh"`, the value whose property we called. How this works is described in [Chapter 6](06_object.html#obj_methods). + + Properties that contain functions are generally called _methods_ of the value they belong to. As in, “`toUpperCase` is a method of a string”. + +-This example demonstrates some methods that array objects have: ++This example demonstrates two methods you can use to manipulate arrays: + + ``` +-var mack = []; +-mack.push("Mack"); +-mack.push("the", "Knife"); +-console.log(mack); +-// → ["Mack", "the", "Knife"] +-console.log(mack.join(" ")); +-// → Mack the Knife +-console.log(mack.pop()); +-// → Knife +-console.log(mack); +-// → ["Mack", "the"] ++let sequence = [1, 2, 3]; ++sequence.push(4); ++sequence.push(5); ++console.log(sequence); ++// → [1, 2, 3, 4, 5] ++console.log(sequence.pop()); ++// → 5 ++console.log(sequence); ++// → [1, 2, 3, 4] + ``` + +-The `push` method can be used to add values to the end of an array. The `pop` method does the opposite: it removes the value at the end of the array and returns it. An array of strings can be flattened to a single string with the `join` method. The argument given to `join` determines the text that is glued between the array's elements. ++The `push` method adds values to the end of an array, and the `pop` method does the opposite, removing the last value in the array and returning it. ++ ++These somewhat silly names are the traditional terms for operations on a _stack_. A stack, in programming, is a data structure that allows you to push values into it and pop them out again in the opposite order, so that the thing that was added last is removed first. These are common in programming—you might remember the function call stack from [the previous chapter](03_functions.html#stack), which is an instance of the same idea. + + ## Objects + +-Back to the weresquirrel. A set of daily log entries can be represented as an array. But the entries do not consist of just a number or a string—each entry needs to store a list of activities and a Boolean value that indicates whether Jacques turned into a squirrel. Ideally, we would like to group these values together into a single value and then put these grouped values into an array of log entries. ++Back to the weresquirrel. A set of daily log entries can be represented as an array. But the entries do not consist of just a number or a string—each entry needs to store a list of activities and a Boolean value that indicates whether Jacques turned into a squirrel or not. Ideally, we would like to group these together into a single value and then put those grouped values into an array of log entries. + +-Values of the type _object_ are arbitrary collections of properties, and we can add or remove these properties as we please. One way to create an object is by using a curly brace notation. ++Values of the type _object_ are arbitrary collections of properties. One way to create an object is by using curly braces as an expression. + + ``` +-var day1 = { ++let day1 = { + squirrel: false, +- events: ["work", "touched tree", "pizza", "running", +- "television"] ++ events: ["work", "touched tree", "pizza", "running"] + }; + console.log(day1.squirrel); + // → false +@@ -118,29 +119,27 @@ console.log(day1.wolf); + // → false + ``` + +-Inside the curly braces, we can give a list of properties separated by commas. Each property is written as a name, followed by a colon, followed by an expression that provides a value for the property. Spaces and line breaks are not significant. When an object spans multiple lines, indenting it like in the previous example improves readability. Properties whose names are not valid variable names or valid numbers have to be quoted. ++Inside the braces, there is a list of properties separated by commas. Each property has a name followed by a colon and a value. When an object is written over multiple lines, indenting it like in the example helps with readability. Properties whose names aren't valid binding names or valid numbers have to be quoted. + + ``` +-var descriptions = { ++let descriptions = { + work: "Went to work", + "touched tree": "Touched a tree" + }; + ``` + +-This means that curly braces have _two_ meanings in JavaScript. At the start of a statement, they start a block of statements. In any other position, they describe an object. Fortunately, it is almost never useful to start a statement with a curly-brace object, and in typical programs, there is no ambiguity between these two uses. ++This means that curly braces have _two_ meanings in JavaScript. At the start of a statement, they start a block of statements. In any other position, they describe an object. Fortunately, it is rarely useful to start a statement with a curly-brace object, so the ambiguity between these two is not much of a problem. + +-Reading a property that doesn't exist will produce the value `undefined`, which happens the first time we try to read the `wolf` property in the previous example. ++Reading a property that doesn't exist will give you the value `undefined`. + + It is possible to assign a value to a property expression with the `=` operator. This will replace the property's value if it already existed or create a new property on the object if it didn't. + +-To briefly return to our tentacle model of variable bindings—property bindings are similar. They _grasp_ values, but other variables and properties might be holding onto those same values. You may think of objects as octopuses with any number of tentacles, each of which has a name inscribed on it. +- +-![Artist's representation of an object](img/octopus-object.jpg) ++To briefly return to our tentacle model of bindings—property bindings are similar. They _grasp_ values, but other bindings and properties might be holding onto those same values. You may think of objects as octopuses with any number of tentacles, each of which has a name tattooed on it. + +-The `delete` operator cuts off a tentacle from such an octopus. It is a unary operator that, when applied to a property access expression, will remove the named property from the object. This is not a common thing to do, but it is possible. ++The `delete` operator cuts off a tentacle from such an octopus. It is a unary operator that, when applied to an object property, will remove the named property from the object. This is not a common thing to do, but it is possible. + + ``` +-var anObject = {left: 1, right: 2}; ++let anObject = {left: 1, right: 2}; + console.log(anObject.left); + // → 1 + delete anObject.left; +@@ -152,24 +151,38 @@ console.log("right" in anObject); + // → true + ``` + +-The binary `in` operator, when applied to a string and an object, returns a Boolean value that indicates whether that object has that property. The difference between setting a property to `undefined` and actually deleting it is that, in the first case, the object still _has_ the property (it just doesn't have a very interesting value), whereas in the second case the property is no longer present and `in` will return `false`. ++The binary `in` operator, when applied to a string and an object, tells you whether that object has a property with that name. The difference between setting a property to `undefined` and actually deleting it is that, in the first case, the object still _has_ the property (it just doesn't have a very interesting value), whereas in the second case the property is no longer present and `in` will return `false`. + +-Arrays, then, are just a kind of object specialized for storing sequences of things. If you evaluate `typeof [1, 2]`, this produces `"object"`. You can see them as long, flat octopuses with all their arms in a neat row, labeled with numbers. ++To find out what properties an object has, you can use the `Object.keys` function. You give it an object, and it returns an array of strings—the object's property names. ++ ++``` ++console.log(Object.keys({x: 0, y: 0, z: 2})); ++// → ["x", "y", "z"] ++``` ++ ++There's an `Object.assign` function that copies all properties from one object into another. ++ ++``` ++let objectA = {a: 1, b: 2}; ++Object.assign(objectA, {b: 3, c: 4}); ++console.log(objectA); ++// → {a: 1, b: 3, c: 4} ++``` + +-![Artist's representation of an array](img/octopus-array.jpg) ++Arrays, then, are just a kind of object specialized for storing sequences of things. If you evaluate `typeof []`, it produces `"object"`. You can see them as long, flat octopuses with all their tentacles in a neat row, labeled with numbers. + +-So we can represent Jacques' journal as an array of objects. ++We will represent Jacques' journal as an array of objects. + + ``` +-var journal = [ ++let journal = [ + {events: ["work", "touched tree", "pizza", + "running", "television"], + squirrel: false}, + {events: ["work", "ice cream", "cauliflower", + "lasagna", "touched tree", "brushed teeth"], + squirrel: false}, +- {events: ["weekend", "cycling", "break", +- "peanuts", "beer"], ++ {events: ["weekend", "cycling", "break", "peanuts", ++ "beer"], + squirrel: true}, + /* and so on... */ + ]; +@@ -177,18 +190,18 @@ var journal = [ + + ## Mutability + +-We will get to actual programming _real_ soon now. But first, there's one last piece of theory to understand. ++We will get to actual programming _real_ soon now. First there's one more piece of theory to understand. + +-We've seen that object values can be modified. The types of values discussed in earlier chapters, such as numbers, strings, and Booleans, are all _immutable_—it is impossible to change an existing value of those types. You can combine them and derive new values from them, but when you take a specific string value, that value will always remain the same. The text inside it cannot be changed. If you have reference to a string that contains `"cat"`, it is not possible for other code to change a character in _that_ string to make it spell `"rat"`. ++We saw that object values can be modified. The types of values discussed in earlier chapters, such as numbers, strings, and Booleans, are all _immutable_—it is impossible to change values of those types. You can combine them and derive new values from them, but when you take a specific string value, that value will always remain the same. The text inside it cannot be changed. If you have a string that contains `"cat"`, it is not possible for other code to change a character in your string to make it spell `"rat"`. + +-With objects, on the other hand, the content of a value _can_ be modified by changing its properties. ++Objects work differently. You _can_ change their properties, causing a single object value to have different content at different times. + +-When we have two numbers, 120 and 120, we can consider them precisely the same number, whether or not they refer to the same physical bits. But with objects, there is a difference between having two references to the same object and having two different objects that contain the same properties. Consider the following code: ++When we have two numbers, 120 and 120, we can consider them precisely the same number, whether or not they refer to the same physical bits. With objects, there is a difference between having two references to the same object and having two different objects that contain the same properties. Consider the following code: + + ``` +-var object1 = {value: 10}; +-var object2 = object1; +-var object3 = {value: 10}; ++let object1 = {value: 10}; ++let object2 = object1; ++let object3 = {value: 10}; + + console.log(object1 == object2); + // → true +@@ -202,26 +215,35 @@ console.log(object3.value); + // → 10 + ``` + +-The `object1` and `object2` variables grasp the _same_ object, which is why changing `object1` also changes the value of `object2`. The variable `object3` points to a different object, which initially contains the same properties as `object1` but lives a separate life. ++The `object1` and `object2` bindings grasp the _same_ object, which is why changing `object1` also changes the value of `object2`. They are said to have the same _identity_. The binding `object3` points to a different object, which initially contains the same properties as `object1` but lives a separate life. ++ ++Bindings can also be changeable or constant, but this is separate from the way their values behave. Even though number values don't change, you can use a `let` binding to keep track of a changing number by changing the value the binding points at. Similarly, though a `const` binding to an object can itself not be changed and will continue to point at the same object, the _contents_ of that object might change. ++ ++``` ++const score = {visitors: 0, home: 0}; ++// This is okay ++score.visitors = 1; ++// This isn't allowed ++score = {visitors: 1, home: 1}; ++``` + +-JavaScript's `==` operator, when comparing objects, will return `true` only if both objects are precisely the same value. Comparing different objects will return `false`, even if they have identical contents. There is no “deep” comparison operation built into JavaScript, which looks at object's contents, but it is possible to write it yourself (which will be one of the [exercises](04_data.html#exercise_deep_compare) at the end of this chapter). ++When you compare objects with JavaScript's `==` operator, it compares by identity: It will produce `true` only if both objects are precisely the same value. Comparing different objects will return `false`, even if they have identical properties. There is no “deep” comparison operation built into JavaScript, which compares objects by contents, but it is possible to write it yourself (which is one of the [exercises](04_data.html#exercise_deep_compare) at the end of this chapter). + + ## The lycanthrope's log + + So Jacques starts up his JavaScript interpreter and sets up the environment he needs to keep his journal. + + ``` +-var journal = []; ++let journal = []; + +-function addEntry(events, didITurnIntoASquirrel) { +- journal.push({ +- events: events, +- squirrel: didITurnIntoASquirrel +- }); ++function addEntry(events, squirrel) { ++ journal.push({events, squirrel}); + } + ``` + +-And then, every evening at ten—or sometimes the next morning, after climbing down from the top shelf of his bookcase—he records the day. ++Note that the object added to the journal looks a little odd. Instead of declaring properties like `events: events`, it just gives a property name. This is a short-hand that means the same thing—if a property name in curly brace notation isn't followed by a value, its value is taken from the binding with the same name. ++ ++So then, every evening at ten—or sometimes the next morning, after climbing down from the top shelf of his bookcase—Jacques records the day. + + ``` + addEntry(["work", "touched tree", "pizza", "running", +@@ -232,27 +254,31 @@ addEntry(["weekend", "cycling", "break", "peanuts", + "beer"], true); + ``` + +-Once he has enough data points, he intends to compute the correlation between his squirrelification and each of the day's events and ideally learn something useful from those correlations. ++Once he has enough data points, he intends to use statistics to find out which of these events may be related to the squirrelifications. + +-_Correlation_ is a measure of dependence between variables (“variables” in the statistical sense, not the JavaScript sense). It is usually expressed as a coefficient that ranges from -1 to 1\. Zero correlation means the variables are not related, whereas a correlation of one indicates that the two are perfectly related—if you know one, you also know the other. Negative one also means that the variables are perfectly related but that they are opposites—when one is true, the other is false. ++_Correlation_ is a measure of dependence between statistical variables. A statistical variable is not quite the same as a programming variable. In statistics you typically have a set of _measurements_, and each variable is measured for every measurement. Correlation between variables is usually expressed as a value that ranges from -1 to 1\. Zero correlation means the variables are not related. A correlation of one indicates that the two are perfectly related—if you know one, you also know the other. Negative one also means that the variables are perfectly related but that they are opposites—when one is true, the other is false. + +-For binary (Boolean) variables, the _phi_ coefficient (_ϕ_) provides a good measure of correlation and is relatively easy to compute. To compute _ϕ_, we need a table _n_ that contains the number of times the various combinations of the two variables were observed. For example, we could take the event of eating pizza and put that in a table like this: ++To compute the measure of correlation between two Boolean variables, we can use the _phi coefficient_ (_ϕ_). This is a formula whose input is a frequency table containing the amount of times the different combinations of the variables were observed. The output of the formula is a number between -1 and 1 that describes the correlation. + +-![Eating pizza versus turning into a squirrel](img/pizza-squirrel.svg) ++We could take the event of eating pizza and put that in a frequency table like this, where each number indicates the amount of times that combination occurred in our measurements: + +-_ϕ_ can be computed using the following formula, where _n_ refers to the table: ++
![Eating pizza versus turning into a squirrel](img/pizza-squirrel.svg)
+ +-| _ϕ_ = | n<sub>11</sub>n<sub>00</sub> - n<sub>10</sub>n<sub>01</sub>√ n<sub>1•</sub>n<sub>0•</sub>n<sub>•1</sub>n<sub>•0</sub> | ++If we call that table _n_, we can compute _ϕ_ using the following formula: + +-The notation _n_<sub>01</sub> indicates the number of measurements where the first variable (squirrelness) is false (0) and the second variable (pizza) is true (1). In this example, _n_<sub>01</sub> is 9. ++| _ϕ_ = | _n_<sub>11</sub>_n_<sub>00</sub> − _n_<sub>10</sub>_n_<sub>01</sub>√ _n_<sub>1•</sub>_n_<sub>0•</sub>_n_<sub>•1</sub>_n_<sub>•0</sub> | ++ ++(If at this point you're putting the book down to focus on a terrible flashback to 10th grade math class—hold on! I do not intend to torture you with endless pages of cryptic notation—just this one formula for now. And even with this one, all we do is turn it into JavaScript.) ++ ++The notation _n_<sub>01</sub> indicates the number of measurements where the first variable (squirrelness) is false (0) and the second variable (pizza) is true (1). In the pizza table, _n_<sub>01</sub> is 9. + + The value _n_<sub>1•</sub> refers to the sum of all measurements where the first variable is true, which is 5 in the example table. Likewise, _n_<sub>•0</sub> refers to the sum of the measurements where the second variable is false. + +-So for the pizza table, the part above the division line (the dividend) would be 1×76 - 4×9 = 40, and the part below it (the divisor) would be the square root of 5×85×10×80, or √340000\. This comes out to _ϕ_ ≈ 0.069, which is tiny. Eating pizza does not appear to have influence on the transformations. ++So for the pizza table, the part above the division line (the dividend) would be 1×76−4×9 = 40, and the part below it (the divisor) would be the square root of 5×85×10×80, or √340000\. This comes out to _ϕ_ ≈ 0.069, which is tiny. Eating pizza does not appear to have influence on the transformations. + + ## Computing correlation + +-We can represent a two-by-two table in JavaScript with a four-element array (`[76, 9, 4, 1]`). We could also use other representations, such as an array containing two two-element arrays (`[[76, 9], [4, 1]]`) or an object with property names like `"11"` and `"01"`, but the flat array is simple and makes the expressions that access the table pleasantly short. We'll interpret the indices to the array as two-bit binary number, where the leftmost (most significant) digit refers to the squirrel variable and the rightmost (least significant) digit refers to the event variable. For example, the binary number `10` refers to the case where Jacques did turn into a squirrel, but the event (say, "pizza") didn't occur. This happened four times. And since binary `10` is 2 in decimal notation, we will store this number at index 2 of the array. ++We can represent a two-by-two table in JavaScript with a four-element array (`[76, 9, 4, 1]`). We could also use other representations, such as an array containing two two-element arrays (`[[76, 9], [4, 1]]`) or an object with property names like `"11"` and `"01"`, but the flat array is simple and makes the expressions that access the table pleasantly short. We'll interpret the indices to the array as two-bit binary numbers, where the leftmost (most significant) digit refers to the squirrel variable and the rightmost (least significant) digit refers to the event variable. For example, the binary number `10` refers to the case where Jacques did turn into a squirrel, but the event (say, “pizza”) didn't occur. This happened four times. And since binary `10` is 2 in decimal notation, we will store this number at index 2 of the array. + + This is the function that computes the _ϕ_ coefficient from such an array: + +@@ -269,22 +295,18 @@ console.log(phi([76, 9, 4, 1])); + // → 0.068599434 + ``` + +-This is simply a direct translation of the _ϕ_ formula into JavaScript. `Math.sqrt` is the square root function, as provided by the `Math` object in a standard JavaScript environment. We have to sum two fields from the table to get fields like n<sub>1•</sub> because the sums of rows or columns are not stored directly in our data structure. ++This is a direct translation of the _ϕ_ formula into JavaScript. `Math.sqrt` is the square root function, as provided by the `Math` object in a standard JavaScript environment. We have to add two fields from the table to get fields like n<sub>1•</sub> because the sums of rows or columns are not stored directly in our data structure. + +-Jacques kept his journal for three months. The resulting data set is available in the coding sandbox for this chapter, where it is stored in the `JOURNAL` variable, and in a downloadable [file](http://eloquentjavascript.net/2nd_edition/code/jacques_journal.js). ++Jacques kept his journal for three months. The resulting data set is available in the [coding sandbox](https://eloquentjavascript.net/code#4) for this chapter, where it is stored in the `JOURNAL` binding, and in a downloadable [file](https://eloquentjavascript.net/code/journal.js). + +-To extract a two-by-two table for a specific event from this journal, we must loop over all the entries and tally up how many times the event occurs in relation to squirrel transformations. ++To extract a two-by-two table for a specific event from the journal, we must loop over all the entries and tally how many times the event occurs in relation to squirrel transformations. + + ``` +-function hasEvent(event, entry) { +- return entry.events.indexOf(event) != -1; +-} +- + function tableFor(event, journal) { +- var table = [0, 0, 0, 0]; +- for (var i = 0; i < journal.length; i++) { +- var entry = journal[i], index = 0; +- if (hasEvent(event, entry)) index += 1; ++ let table = [0, 0, 0, 0]; ++ for (let i = 0; i < journal.length; i++) { ++ let entry = journal[i], index = 0; ++ if (entry.events.includes(event)) index += 1; + if (entry.squirrel) index += 2; + table[index] += 1; + } +@@ -295,74 +317,64 @@ console.log(tableFor("pizza", JOURNAL)); + // → [76, 9, 4, 1] + ``` + +-The `hasEvent` function tests whether an entry contains a given event. Arrays have an `indexOf` method that tries to find a given value (in this case, the event name) in the array and returns the index at which it was found or -1 if it wasn't found. So if the call to `indexOf` doesn't return -1, then we know the event was found in the entry. +- +-The body of the loop in `tableFor` figures out which box in the table each journal entry falls into by checking whether the entry contains the specific event it's interested in and whether the event happens alongside a squirrel incident. The loop then adds one to the number in the array that corresponds to this box on the table. ++Arrays have an `includes` method that checks whether a given value exists in the array. The function uses that to determine whether the event name it is interested in is part of the event list for a given day. + +-We now have the tools we need to compute individual correlations. The only step remaining is to find a correlation for every type of event that was recorded and see whether anything stands out. But how should we store these correlations once we compute them? ++The body of the loop in `tableFor` figures out which box in the table each journal entry falls into by checking whether the entry contains the specific event it's interested in and whether the event happens alongside a squirrel incident. The loop then adds one to the correct box in the table. + +-## Objects as maps ++We now have the tools we need to compute individual correlations. The only step remaining is to find a correlation for every type of event that was recorded and see whether anything stands out. + +-One possible way is to store all the correlations in an array, using objects with `name` and `value` properties. But that makes looking up the correlation for a given event somewhat cumbersome: you'd have to loop over the whole array to find the object with the right `name`. We could wrap this lookup process in a function, but we would still be writing more code, and the computer would be doing more work than necessary. ++## Array loops + +-A better way is to use object properties named after the event types. We can use the square bracket access notation to create and read the properties and can use the `in` operator to test whether a given property exists. ++In the `tableFor` function, there's a loop like this: + + ``` +-var map = {}; +-function storePhi(event, phi) { +- map[event] = phi; ++for (let i = 0; i < JOURNAL.length; i++) { ++ let entry = JOURNAL[i]; ++ // Do something with entry + } +- +-storePhi("pizza", 0.069); +-storePhi("touched tree", -0.081); +-console.log("pizza" in map); +-// → true +-console.log(map["touched tree"]); +-// → -0.081 + ``` + +-A _map_ is a way to go from values in one domain (in this case, event names) to corresponding values in another domain (in this case, _ϕ_ coefficients). +- +-There are a few potential problems with using objects like this, which we will discuss in [Chapter 6](06_object.html#prototypes), but for the time being, we won't worry about those. ++This kind of loop is common in classical JavaScript—going over arrays one element at a time is something that comes up a lot, and to do that you'd run a counter over the length of the array and pick out each element in turn. + +-What if we want to find all the events for which we have stored a coefficient? The properties don't form a predictable series, like they would in an array, so we cannot use a normal `for` loop. JavaScript provides a loop construct specifically for going over the properties of an object. It looks a little like a normal `for` loop but distinguishes itself by the use of the word `in`. ++There is a simpler way to write such loops in modern JavaScript. + + ``` +-for (var event in map) +- console.log("The correlation for '" + event + +- "' is " + map[event]); +-// → The correlation for 'pizza' is 0.069 +-// → The correlation for 'touched tree' is -0.081 ++for (let entry of JOURNAL) { ++ console.log(`${entry.events.length} events.`); ++} + ``` + ++When a `for` loop looks like this, with the word `of` after a variable definition, it will loop over the elements of the value given after `of`. This works not only for arrays, but also for strings and some other data structures. We'll discuss _how_ it works in [Chapter 6](06_object.html). ++ + ## The final analysis + +-To find all the types of events that are present in the data set, we simply process each entry in turn and then loop over the events in that entry. We keep an object `phis` that has correlation coefficients for all the event types we have seen so far. Whenever we run across a type that isn't in the `phis` object yet, we compute its correlation and add it to the object. ++We need to compute a correlation for every type of event that occurs in the data set. To do that, we first need to _find_ every type of event. + + ``` +-function gatherCorrelations(journal) { +- var phis = {}; +- for (var entry = 0; entry < journal.length; entry++) { +- var events = journal[entry].events; +- for (var i = 0; i < events.length; i++) { +- var event = events[i]; +- if (!(event in phis)) +- phis[event] = phi(tableFor(event, journal)); ++function journalEvents(journal) { ++ let events = []; ++ for (let entry of journal) { ++ for (let event of entry.events) { ++ if (!events.includes(event)) { ++ events.push(event); ++ } + } + } +- return phis; ++ return events; + } + +-var correlations = gatherCorrelations(JOURNAL); +-console.log(correlations.pizza); +-// → 0.068599434 ++console.log(journalEvents(JOURNAL)); ++// → ["carrot", "exercise", "weekend", "bread", …] + ``` + +-Let's see what came out. ++By going over all the events, and adding those that aren't already in there to the `events` array, the function collects every type of event. ++ ++Using that, we can see all the correlations. + + ``` +-for (var event in correlations) +- console.log(event + ": " + correlations[event]); ++for (let event of journalEvents(JOURNAL)) { ++ console.log(event + ":", phi(tableFor(event, JOURNAL))); ++} + // → carrot: 0.0140970969 + // → exercise: 0.0685994341 + // → weekend: 0.1371988681 +@@ -371,13 +383,14 @@ for (var event in correlations) + // and so on... + ``` + +-Most correlations seem to lie close to zero. Eating carrots, bread, or pudding apparently does not trigger squirrel-lycanthropy. It _does_ seem to occur somewhat more often on weekends, however. Let's filter the results to show only correlations greater than 0.1 or less than -0.1. ++Most correlations seem to lie close to zero. Eating carrots, bread, or pudding apparently does not trigger squirrel-lycanthropy. It _does_ seem to occur somewhat more often on weekends. Let's filter the results to show only correlations greater than 0.1 or less than -0.1. + + ``` +-for (var event in correlations) { +- var correlation = correlations[event]; +- if (correlation > 0.1 || correlation < -0.1) +- console.log(event + ": " + correlation); ++for (let event of journalEvents(JOURNAL)) { ++ let correlation = phi(tableFor(event, JOURNAL)); ++ if (correlation > 0.1 || correlation < -0.1) { ++ console.log(event + ":", correlation); ++ } + } + // → weekend: 0.1371988681 + // → brushed teeth: -0.3805211953 +@@ -388,49 +401,51 @@ for (var event in correlations) { + // → peanuts: 0.5902679812 + ``` + +-A-ha! There are two factors whose correlation is clearly stronger than the others. Eating peanuts has a strong positive effect on the chance of turning into a squirrel, whereas brushing his teeth has a significant negative effect. ++A-ha! There are two factors with a correlation that's clearly stronger than the others. Eating peanuts has a strong positive effect on the chance of turning into a squirrel, whereas brushing his teeth has a significant negative effect. + + Interesting. Let's try something. + + ``` +-for (var i = 0; i < JOURNAL.length; i++) { +- var entry = JOURNAL[i]; +- if (hasEvent("peanuts", entry) && +- !hasEvent("brushed teeth", entry)) ++for (let entry of JOURNAL) { ++ if (entry.events.includes("peanuts") && ++ !entry.events.includes("brushed teeth")) { + entry.events.push("peanut teeth"); ++ } + } + console.log(phi(tableFor("peanut teeth", JOURNAL))); + // → 1 + ``` + +-Well, that's unmistakable! The phenomenon occurs precisely when Jacques eats peanuts and fails to brush his teeth. If only he weren't such a slob about dental hygiene, he'd have never even noticed his affliction. ++That's a strong result. The phenomenon occurs precisely when Jacques eats peanuts and fails to brush his teeth. If only he weren't such a slob about dental hygiene, he'd have never even noticed his affliction. + +-Knowing this, Jacques simply stops eating peanuts altogether and finds that this completely puts an end to his transformations. ++Knowing this, Jacques stops eating peanuts altogether and finds that his transformations don't come back. + +-All is well with Jacques for a while. But a few years later, he loses his job and is eventually forced to take employment with a circus, where he performs as _The Incredible Squirrelman_ by stuffing his mouth with peanut butter before every show. One day, fed up with this pitiful existence, Jacques fails to change back into his human form, hops through a crack in the circus tent, and vanishes into the forest. He is never seen again. ++For a few years, things go great for Jacques. But at some point he loses his job. Because he lives in a nasty country where having no job means having no medical services, he is forced to take employment with a circus where he performs as _The Incredible Squirrelman_, stuffing his mouth with peanut butter before every show. ++ ++One day, fed up with this pitiful existence, Jacques fails to change back into his human form, hops through a crack in the circus tent, and vanishes into the forest. He is never seen again. + + ## Further arrayology + +-Before finishing up this chapter, I want to introduce you to a few more object-related concepts. We'll start by introducing some generally useful array methods. ++Before finishing the chapter, I want to introduce you to a few more object-related concepts. I'll start by introducing some generally useful array methods. + + We saw `push` and `pop`, which add and remove elements at the end of an array, [earlier](04_data.html#array_methods) in this chapter. The corresponding methods for adding and removing things at the start of an array are called `unshift` and `shift`. + + ``` +-var todoList = []; +-function rememberTo(task) { ++let todoList = []; ++function remember(task) { + todoList.push(task); + } +-function whatIsNext() { ++function getTask() { + return todoList.shift(); + } +-function urgentlyRememberTo(task) { ++function rememberUrgently(task) { + todoList.unshift(task); + } + ``` + +-The previous program manages lists of tasks. You add tasks to the end of the list by calling `rememberTo("eat")`, and when you're ready to do something, you call `whatIsNext()` to get (and remove) the front item from the list. The `urgentlyRememberTo` function also adds a task but adds it to the front instead of the back of the list. ++That program manages a queue of tasks. You add tasks to the end of the queue by calling `remember("groceries")`, and when you're ready to do something, you call `getTask()` to get (and remove) the front item from the queue. The `rememberUrgently` function also adds a task but adds it to the front instead of the back of the queue. + +-The `indexOf` method has a sibling called `lastIndexOf`, which starts searching for the given element at the end of the array instead of the front. ++To search for a specific value, arrays provide an `indexOf` method. It searches through the array from the start to the end and returns the index at which the requested value was found—or -1 if it wasn't found. To search from the end instead of the start, there's a similar method called `lastIndexOf`. + + ``` + console.log([1, 2, 3, 2, 1].indexOf(2)); +@@ -439,9 +454,9 @@ console.log([1, 2, 3, 2, 1].lastIndexOf(2)); + // → 3 + ``` + +-Both `indexOf` and `lastIndexOf` take an optional second argument that indicates where to start searching from. ++Both `indexOf` and `lastIndexOf` take an optional second argument that indicates where to start searching. + +-Another fundamental method is `slice`, which takes a start index and an end index and returns an array that has only the elements between those indices. The start index is inclusive, the end index exclusive. ++Another fundamental array method is `slice`, which takes start and end indices and returns an array that has only the elements between them. The start index is inclusive, the end index exclusive. + + ``` + console.log([0, 1, 2, 3, 4].slice(2, 4)); +@@ -450,9 +465,11 @@ console.log([0, 1, 2, 3, 4].slice(2)); + // → [2, 3, 4] + ``` + +-When the end index is not given, `slice` will take all of the elements after the start index. Strings also have a `slice` method, which has a similar effect. ++When the end index is not given, `slice` will take all of the elements after the start index. You can also omit the start index to copy the entire array. ++ ++The `concat` method can be used to glue arrays together to create a new array, similar to what the `+` operator does for strings. + +-The `concat` method can be used to glue arrays together, similar to what the `+` operator does for strings. The following example shows both `concat` and `slice` in action. It takes an array and an index, and it returns a new array that is a copy of the original array with the element at the given index removed. ++The following example shows both `concat` and `slice` in action. It takes an array and an index, and it returns a new array that is a copy of the original array with the element at the given index removed: + + ``` + function remove(array, index) { +@@ -463,20 +480,22 @@ console.log(remove(["a", "b", "c", "d", "e"], 2)); + // → ["a", "b", "d", "e"] + ``` + ++If you pass `concat` an argument that is not an array, that value will be added to the new array as if it were a one-element array. ++ + ## Strings and their properties + + We can read properties like `length` and `toUpperCase` from string values. But if you try to add a new property, it doesn't stick. + + ``` +-var myString = "Fido"; +-myString.myProperty = "value"; +-console.log(myString.myProperty); ++let kim = "Kim"; ++kim.age = 88; ++console.log(kim.age); + // → undefined + ``` + +-Values of type string, number, and Boolean are not objects, and though the language doesn't complain if you try to set new properties on them, it doesn't actually store those properties. The values are immutable and cannot be changed. ++Values of type string, number, and Boolean are not objects, and though the language doesn't complain if you try to set new properties on them, it doesn't actually store those properties. As mentioned before, such values are immutable and cannot be changed. + +-But these types do have some built-in properties. Every string value has a number of methods. The most useful ones are probably `slice` and `indexOf`, which resemble the array methods of the same name. ++But these types do have built-in properties. Every string value has a number of methods. Some very useful ones are `slice` and `indexOf`, which resemble the array methods of the same name. + + ``` + console.log("coconuts".slice(4, 7)); +@@ -485,7 +504,7 @@ console.log("coconut".indexOf("u")); + // → 5 + ``` + +-One difference is that a string's `indexOf` can take a string containing more than one character, whereas the corresponding array method looks only for a single element. ++One difference is that a string's `indexOf` can search for a string containing more than one character, whereas the corresponding array method looks only for a single element. + + ``` + console.log("one two three".indexOf("ee")); +@@ -499,78 +518,94 @@ console.log(" okay \n ".trim()); + // → okay + ``` + +-We have already seen the string type's `length` property. Accessing the individual characters in a string can be done with the `charAt` method but also by simply reading numeric properties, like you'd do for an array. ++The `zeroPad` function from the [previous chapter](03_functions.html) also exists as a method. It is called `padStart` and takes the desired length and padding character as arguments. + + ``` +-var string = "abc"; +-console.log(string.length); +-// → 3 +-console.log(string.charAt(0)); +-// → a +-console.log(string[1]); +-// → b ++console.log(String(6).padStart(3, "0")); ++// → 006 + ``` + +-## The arguments object ++You can split a string on every occurrence of another string with `split`, and join it together again with `join`. ++ ++``` ++let sentence = "Secretarybirds specialize in stomping"; ++let words = sentence.split(" "); ++console.log(words); ++// → ["Secretarybirds", "specialize", "in", "stomping"] ++console.log(words.join(". ")); ++// → Secretarybirds. specialize. in. stomping ++``` ++ ++A string can be repeated with the `repeat` method, which creates a new string containing multiple copies of the original string, glued together. ++ ++``` ++console.log("LA".repeat(3)); ++// → LALALA ++``` + +-Whenever a function is called, a special variable named `arguments` is added to the environment in which the function body runs. This variable refers to an object that holds all of the arguments passed to the function. Remember that in JavaScript you are allowed to pass more (or fewer) arguments to a function than the number of parameters the function itself declares. ++We have already seen the string type's `length` property. Accessing the individual characters in a string looks like accessing array elements (with a caveat that we'll discuss in [Chapter 5](05_higher_order.html#code_units)). + + ``` +-function noArguments() {} +-noArguments(1, 2, 3); // This is okay +-function threeArguments(a, b, c) {} +-threeArguments(); // And so is this ++let string = "abc"; ++console.log(string.length); ++// → 3 ++console.log(string[1]); ++// → b + ``` + +-The `arguments` object has a `length` property that tells us the number of arguments that were really passed to the function. It also has a property for each argument, named 0, 1, 2, and so on. ++## Rest parameters ++ ++It can be useful for a function to accept any number of arguments. For example, `Math.max` computes the maximum of _all_ the arguments it is given. + +-If that sounds a lot like an array to you, you're right, it _is_ a lot like an array. But this object, unfortunately, does not have any array methods (like `slice` or `indexOf`), so it is a little harder to use than a real array. ++To write such a function, you put three dots before the function's last parameter, like this: + + ``` +-function argumentCounter() { +- console.log("You gave me", arguments.length, "arguments."); ++function max(...numbers) { ++ let result = -Infinity; ++ for (let number of numbers) { ++ if (number > result) result = number; ++ } ++ return result; + } +-argumentCounter("Straw man", "Tautology", "Ad hominem"); +-// → You gave me 3 arguments. ++console.log(max(4, 1, 9, -2)); ++// → 9 + ``` + +-Some functions can take any number of arguments, like `console.log`. These typically loop over the values in their `arguments` object. They can be used to create very pleasant interfaces. For example, remember how we created the entries to Jacques' journal. ++When such a function is called, the _rest parameter_ is bound to an array containing all further arguments. If there are other parameters before it, their values aren't part of that array. When, as in `max`, it is the only parameter, it will hold all arguments. ++ ++You can use a similar three-dot notation to _call_ a function with an array of arguments. + + ``` +-addEntry(["work", "touched tree", "pizza", "running", +- "television"], false); ++let numbers = [5, 1, 7]; ++console.log(max(...numbers)); ++// → 7 + ``` + +-Since he is going to be calling this function a lot, we could create an alternative that is easier to call. ++This “spreads” out the array into the function call, passing its elements as separate arguments. It is possible to include an array like that along with other arguments, as in `max(9, .<wbr>.<wbr>.<wbr>numbers, 2)`. ++ ++Square bracket array notation similarly allows the triple-dot operator to spread another array into the new array: + + ``` +-function addEntry(squirrel) { +- var entry = {events: [], squirrel: squirrel}; +- for (var i = 1; i < arguments.length; i++) +- entry.events.push(arguments[i]); +- journal.push(entry); +-} +-addEntry(true, "work", "touched tree", "pizza", +- "running", "television"); ++let words = ["never", "fully"]; ++console.log(["will", ...words, "understand"]); ++// → ["will", "never", "fully", "understand"] + ``` + +-This version reads its first argument (`squirrel`) in the normal way and then goes over the rest of the arguments (the loop starts at index 1, skipping the first) to gather them into an array. +- + ## The Math object + + As we've seen, `Math` is a grab-bag of number-related utility functions, such as `Math.max` (maximum), `Math.min` (minimum), and `Math.sqrt` (square root). + +-The `Math` object is used simply as a container to group a bunch of related functionality. There is only one `Math` object, and it is almost never useful as a value. Rather, it provides a _namespace_ so that all these functions and values do not have to be global variables. ++The `Math` object is used as a container to group a bunch of related functionality. There is only one `Math` object, and it is almost never useful as a value. Rather, it provides a _namespace_ so that all these functions and values do not have to be global bindings. + +-Having too many global variables “pollutes” the namespace. The more names that have been taken, the more likely you are to accidentally overwrite the value of some variable. For example, it's not unlikely that you'll want to name something `max` in one of your programs. Since JavaScript's built-in `max` function is tucked safely inside the `Math` object, we don't have to worry about overwriting it. ++Having too many global bindings “pollutes” the namespace. The more names have been taken, the more likely you are to accidentally overwrite the value of some existing binding. For example, it's not unlikely to want to name something `max` in one of your programs. Since JavaScript's built-in `max` function is tucked safely inside the `Math` object, we don't have to worry about overwriting it. + +-Many languages will stop you, or at least warn you, when you are defining a variable with a name that is already taken. JavaScript does neither, so be careful. ++Many languages will stop you, or at least warn you, when you are defining a binding with a name that is already taken. JavaScript does this for bindings you declared with `let` or `const` but—perversely—not for standard bindings, nor for bindings declared with `var` or `function`. + +-Back to the `Math` object. If you need to do trigonometry, `Math` can help. It contains `cos` (cosine), `sin` (sine), and `tan` (tangent), as well as their inverse functions, `acos`, `asin`, and `atan`, respectively. The number π (pi)—or at least the closest approximation that fits in a JavaScript number—is available as `Math.PI`. (There is an old programming tradition of writing the names of constant values in all caps.) ++Back to the `Math` object. If you need to do trigonometry, `Math` can help. It contains `cos` (cosine), `sin` (sine), and `tan` (tangent), as well as their inverse functions, `acos`, `asin`, and `atan`, respectively. The number π (pi)—or at least the closest approximation that fits in a JavaScript number—is available as `Math.PI`. There is an old programming tradition of writing the names of constant values in all caps. + + ``` + function randomPointOnCircle(radius) { +- var angle = Math.random() * 2 * Math.PI; ++ let angle = Math.random() * 2 * Math.PI; + return {x: radius * Math.cos(angle), + y: radius * Math.sin(angle)}; + } +@@ -578,9 +613,9 @@ console.log(randomPointOnCircle(2)); + // → {x: 0.3667, y: 1.966} + ``` + +-If sines and cosines are not something you are very familiar with, don't worry. When they are used in this book, in [Chapter 13](13_dom.html#sin_cos), I'll explain them. ++If sines and cosines are not something you are familiar with, don't worry. When they are used in this book, in [Chapter 14](14_dom.html#sin_cos), I'll explain them. + +-The previous example uses `Math.random`. This is a function that returns a new pseudorandom number between zero (inclusive) and one (exclusive) every time you call it. ++The previous example used `Math.random`. This is a function that returns a new pseudorandom number between zero (inclusive) and one (exclusive) every time you call it. + + ``` + console.log(Math.random()); +@@ -591,7 +626,7 @@ console.log(Math.random()); + // → 0.40180766698904335 + ``` + +-Though computers are deterministic machines—they always react the same way if given the same input—it is possible to have them produce numbers that appear random. To do this, the machine keeps a number (or a bunch of numbers) in its internal state. Then, every time a random number is requested, it performs some complicated deterministic computations on this internal state and returns part of the result of those computations. The machine also uses the outcome to change its own internal state so that the next “random” number produced will be different. ++Though computers are deterministic machines—they always react the same way if given the same input—it is possible to have them produce numbers that appear random. To do that, the machine keeps some hidden value, and whenever you ask for a new random number, it performs complicated computations on this hidden value to create a new value. It stores a new value and returns some number derived from it. That way, it can produce ever new, hard-to-predict numbers in a way that _seems_ random. + + If we want a whole random number instead of a fractional one, we can use `Math.floor` (which rounds down to the nearest whole number) on the result of `Math.random`. + +@@ -600,37 +635,91 @@ console.log(Math.floor(Math.random() * 10)); + // → 2 + ``` + +-Multiplying the random number by 10 gives us a number greater than or equal to zero, and below 10\. Since `Math.floor` rounds down, this expression will produce, with equal chance, any number from 0 through 9. ++Multiplying the random number by 10 gives us a number greater than or equal to zero and below 10\. Since `Math.floor` rounds down, this expression will produce, with equal chance, any number from 0 through 9. + +-There are also the functions `Math.ceil` (for “ceiling”, which rounds up to a whole number) and `Math.round` (to the nearest whole number). ++There are also the functions `Math.ceil` (for “ceiling”, which rounds up to a whole number), `Math.round` (to the nearest whole number), and `Math.abs`, which takes the absolute value of a number, meaning it negates negative values but leaves positive ones as they are. + +-## The global object ++## Destructuring + +-The global scope, the space in which global variables live, can also be approached as an object in JavaScript. Each global variable is present as a property of this object. In browsers, the global scope object is stored in the `window` variable. ++Let's go back to the `phi` function for a moment: + + ``` +-var myVar = 10; +-console.log("myVar" in window); +-// → true +-console.log(window.myVar); +-// → 10 ++function phi(table) { ++ return (table[3] * table[0] - table[2] * table[1]) / ++ Math.sqrt((table[2] + table[3]) * ++ (table[0] + table[1]) * ++ (table[1] + table[3]) * ++ (table[0] + table[2])); ++} ++``` ++ ++One of the reasons this function is awkward to read is that we have a binding pointing at our array, but we'd much prefer to have bindings for the _elements_ of the array, that is, `let n00 = table[0]` and so on. Fortunately, there is a succinct way to do this in JavaScript. ++ ++``` ++function phi([n00, n01, n10, n11]) { ++ return (n11 * n00 - n10 * n01) / ++ Math.sqrt((n10 + n11) * (n00 + n01) * ++ (n01 + n11) * (n00 + n10)); ++} ++``` ++ ++This also works for bindings created with `let`, `var`, or `const`. If you know the value you are binding is an array, you can use square brackets to “look inside” of the value, binding its contents. ++ ++A similar trick works for objects, using braces instead of square brackets. ++ ++``` ++let {name} = {name: "Faraji", age: 23}; ++console.log(name); ++// → Faraji ++``` ++ ++Note that if you try to destructure `null` or `undefined`, you get an error, much as you would if you directly try to access a property of those values. ++ ++## JSON ++ ++Because properties only grasp their value, rather than contain it, objects and arrays are stored in the computer's memory as sequences of bits holding the _addresses_—the place in memory—of their contents. So an array with another array inside of it consists of (at least) one memory region for the inner array, and another for the outer array, containing (among other things) a binary number that represents the position of the inner array. ++ ++If you want to save data in a file for later, or send it to another computer over the network, you have to somehow convert these tangles of memory addresses to a description that can be stored or sent. You _could_ send over your entire computer memory along with the address of the value you're interested in, I suppose, but that doesn't seem like the best approach. ++ ++What we can do is _serialize_ the data. That means it is converted into a flat description. A popular serialization format is called _JSON_ (pronounced “Jason”), which stands for JavaScript Object Notation. It is widely used as a data storage and communication format on the Web, even in languages other than JavaScript. ++ ++JSON looks similar to JavaScript's way of writing arrays and objects, with a few restrictions. All property names have to be surrounded by double quotes, and only simple data expressions are allowed—no function calls, bindings, or anything that involves actual computation. Comments are not allowed in JSON. ++ ++A journal entry might look like this when represented as JSON data: ++ ++``` ++{ ++ "squirrel": false, ++ "events": ["work", "touched tree", "pizza", "running"] ++} ++``` ++ ++JavaScript gives us the functions `JSON.stringify` and `JSON.parse` to convert data to and from this format. The first takes a JavaScript value and returns a JSON-encoded string. The second takes such a string and converts it to the value it encodes. ++ ++``` ++let string = JSON.stringify({squirrel: false, ++ events: ["weekend"]}); ++console.log(string); ++// → {"squirrel":false,"events":["weekend"]} ++console.log(JSON.parse(string).events); ++// → ["weekend"] + ``` + + ## Summary + +-Objects and arrays (which are a specific kind of object) provide ways to group several values into a single value. Conceptually, this allows us to put a bunch of related things in a bag and run around with the bag, instead of trying to wrap our arms around all of the individual things and trying to hold on to them separately. ++Objects and arrays (which are a specific kind of object) provide ways to group several values into a single value. Conceptually, this allows us to put a bunch of related things in a bag and run around with the bag, instead of wrapping our arms around all of the individual things and trying to hold on to them separately. + +-Most values in JavaScript have properties, the exceptions being `null` and `undefined`. Properties are accessed using `value.propName` or `value["propName"]`. Objects tend to use names for their properties and store more or less a fixed set of them. Arrays, on the other hand, usually contain varying numbers of conceptually identical values and use numbers (starting from 0) as the names of their properties. ++Most values in JavaScript have properties, the exceptions being `null` and `undefined`. Properties are accessed using `value.prop` or `value["prop"]`. Objects tend to use names for their properties and store more or less a fixed set of them. Arrays, on the other hand, usually contain varying amounts of conceptually identical values and use numbers (starting from 0) as the names of their properties. + + There _are_ some named properties in arrays, such as `length` and a number of methods. Methods are functions that live in properties and (usually) act on the value they are a property of. + +-Objects can also serve as maps, associating values with names. The `in` operator can be used to find out whether an object contains a property with a given name. The same keyword can also be used in a `for` loop (`for (var name in object)`) to loop over an object's properties. ++You can iterate over arrays using a special kind of `for` loop—`for (let element of array)`. + + ## Exercises + + ### The sum of a range + +-The [introduction](00_intro.html#intro) of this book alluded to the following as a nice way to compute the sum of a range of numbers: ++The [introduction](00_intro.html) of this book alluded to the following as a nice way to compute the sum of a range of numbers: + + ``` + console.log(sum(range(1, 10))); +@@ -638,9 +727,9 @@ console.log(sum(range(1, 10))); + + Write a `range` function that takes two arguments, `start` and `end`, and returns an array containing all the numbers from `start` up to (and including) `end`. + +-Next, write a `sum` function that takes an array of numbers and returns the sum of these numbers. Run the previous program and see whether it does indeed return 55. ++Next, write a `sum` function that takes an array of numbers and returns the sum of these numbers. Run the example program and see whether it does indeed return 55. + +-As a bonus assignment, modify your `range` function to take an optional third argument that indicates the “step” value used to build up the array. If no step is given, the array elements go up by increments of one, corresponding to the old behavior. The function call `range(1, 10, 2)` should return `[1, 3, 5, 7, 9]`. Make sure it also works with negative step values so that `range(5, 2, -1)` produces `[5, 4, 3, 2]`. ++As a bonus assignment, modify your `range` function to take an optional third argument that indicates the “step” value used when building the array. If no step is given, the elements go up by increments of one, corresponding to the old behavior. The function call `range(1, 10, 2)` should return `[1, 3, 5, 7, 9]`. Make sure it also works with negative step values so that `range(5, 2, -1)` produces `[5, 4, 3, 2]`. + + ``` + // Your code here. +@@ -653,45 +742,45 @@ console.log(sum(range(1, 10))); + // → 55 + ``` + +-Building up an array is most easily done by first initializing a variable to `[]` (a fresh, empty array) and repeatedly calling its `push` method to add a value. Don't forget to return the array at the end of the function. ++Building up an array is most easily done by first initializing a binding to `[]` (a fresh, empty array) and repeatedly calling its `push` method to add a value. Don't forget to return the array at the end of the function. + +-Since the end boundary is inclusive, you'll need to use the `<=` operator rather than simply `<` to check for the end of your loop. ++Since the end boundary is inclusive, you'll need to use the `<=` operator rather than `<` to check for the end of your loop. + +-To check whether the optional step argument was given, either check `arguments.length` or compare the value of the argument to `undefined`. If it wasn't given, simply set it to its default value (1) at the top of the function. ++The step parameter can be an optional parameter that defaults (using the `=` operator) to 1. + + Having `range` understand negative step values is probably best done by writing two separate loops—one for counting up and one for counting down—because the comparison that checks whether the loop is finished needs to be `>=` rather than `<=` when counting downward. + +-It might also be worthwhile to use a different default step, namely, -1, when the end of the range is smaller than the start. That way, `range(5, 2)` returns something meaningful, rather than getting stuck in an infinite loop. ++It might also be worthwhile to use a different default step, namely -1, when the end of the range is smaller than the start. That way, `range(5, 2)` returns something meaningful, rather than getting stuck in an infinite loop. It is possible to refer to previous parameters in the default value of a parameter. + + ### Reversing an array + +-Arrays have a method `reverse`, which changes the array by inverting the order in which its elements appear. For this exercise, write two functions, `reverseArray` and `reverseArrayInPlace`. The first, `reverseArray`, takes an array as argument and produces a _new_ array that has the same elements in the inverse order. The second, `reverseArrayInPlace`, does what the `reverse` method does: it modifies the array given as argument in order to reverse its elements. Neither may use the standard `reverse` method. ++Arrays have a `reverse` method which changes the array by inverting the order in which its elements appear. For this exercise, write two functions, `reverseArray` and `reverseArrayInPlace`. The first, `reverseArray`, takes an array as argument and produces a _new_ array that has the same elements in the inverse order. The second, `reverseArrayInPlace`, does what the `reverse` method does: it _modifies_ the array given as argument by reversing its elements. Neither may use the standard `reverse` method. + +-Thinking back to the notes about side effects and pure functions in the [previous chapter](03_functions.html#pure), which variant do you expect to be useful in more situations? Which one is more efficient? ++Thinking back to the notes about side effects and pure functions in the [previous chapter](03_functions.html#pure), which variant do you expect to be useful in more situations? Which one runs faster? + + ``` + // Your code here. + + console.log(reverseArray(["A", "B", "C"])); + // → ["C", "B", "A"]; +-var arrayValue = [1, 2, 3, 4, 5]; ++let arrayValue = [1, 2, 3, 4, 5]; + reverseArrayInPlace(arrayValue); + console.log(arrayValue); + // → [5, 4, 3, 2, 1] + ``` + +-There are two obvious ways to implement `reverseArray`. The first is to simply go over the input array from front to back and use the `unshift` method on the new array to insert each element at its start. The second is to loop over the input array backward and use the `push` method. Iterating over an array backward requires a (somewhat awkward) `for` specification like `(var i = array.length - 1; i >= 0; i--)`. ++There are two obvious ways to implement `reverseArray`. The first is to simply go over the input array from front to back and use the `unshift` method on the new array to insert each element at its start. The second is to loop over the input array backwards and use the `push` method. Iterating over an array backwards requires a (somewhat awkward) `for` specification, like `(let i = array.<wbr>length - 1; i >= 0; i--)`. + + Reversing the array in place is harder. You have to be careful not to overwrite elements that you will later need. Using `reverseArray` or otherwise copying the whole array (`array.slice(0)` is a good way to copy an array) works but is cheating. + +-The trick is to _swap_ the first and last elements, then the second and second-to-last, and so on. You can do this by looping over half the length of the array (use `Math.floor` to round down—you don't need to touch the middle element in an array with an odd length) and swapping the element at position `i` with the one at position `array.length - 1 - i`. You can use a local variable to briefly hold on to one of the elements, overwrite that one with its mirror image, and then put the value from the local variable in the place where the mirror image used to be. ++The trick is to _swap_ the first and last elements, then the second and second-to-last, and so on. You can do this by looping over half the length of the array (use `Math.floor` to round down—you don't need to touch the middle element in an array with an odd number of elements) and swapping the element at position `i` with the one at position `array.<wbr>length - 1 - i`. You can use a local binding to briefly hold on to one of the elements, overwrite that one with its mirror image, and then put the value from the local binding in the place where the mirror image used to be. + + ### A list + +-Objects, as generic blobs of values, can be used to build all sorts of data structures. A common data structure is the _list_ (not to be confused with the array). A list is a nested set of objects, with the first object holding a reference to the second, the second to the third, and so on. ++Objects, as generic blobs of values, can be used to build all sorts of data structures. A common data structure is the _list_ (not to be confused with array). A list is a nested set of objects, with the first object holding a reference to the second, the second to the third, and so on. + + ``` +-var list = { ++let list = { + value: 1, + rest: { + value: 2, +@@ -705,11 +794,11 @@ var list = { + + The resulting objects form a chain, like this: + +-![A linked list](img/linked-list.svg) ++
![A linked list](img/linked-list.svg)
+ +-A nice thing about lists is that they can share parts of their structure. For example, if I create two new values `{value: 0, rest: list}` and `{value: -1, rest: list}` (with `list` referring to the variable defined earlier), they are both independent lists, but they share the structure that makes up their last three elements. In addition, the original list is also still a valid three-element list. ++A nice thing about lists is that they can share parts of their structure. For example, if I create two new values `{value: 0, rest: list}` and `{value: -1, rest: list}` (with `list` referring to the binding defined earlier), they are both independent lists, but they share the structure that makes up their last three elements. The original list is also still a valid three-element list. + +-Write a function `arrayToList` that builds up a data structure like the previous one when given `[1, 2, 3]` as argument, and write a `listToArray` function that produces an array from a list. Also write the helper functions `prepend`, which takes an element and a list and creates a new list that adds the element to the front of the input list, and `nth`, which takes a list and a number and returns the element at the given position in the list, or `undefined` when there is no such element. ++Write a function `arrayToList` that builds up a list structure like the one shown when given `[1, 2, 3]` as argument. Also write a `listToArray` function that produces an array from a list. Then add a helper function `prepend`, which takes an element and a list and creates a new list that adds the element to the front of the input list, and `nth`, which takes a list and a number and returns the element at the given position in the list (with zero referring to the first element) or `undefined` when there is no such element. + + If you haven't already, also write a recursive version of `nth`. + +@@ -726,12 +815,12 @@ console.log(nth(arrayToList([10, 20, 30]), 1)); + // → 20 + ``` + +-Building up a list is best done back to front. So `arrayToList` could iterate over the array backward (see previous exercise) and, for each element, add an object to the list. You can use a local variable to hold the part of the list that was built so far and use a pattern like `list = {value: X, rest: list}` to add an element. ++Building up a list is easier when done back to front. So `arrayToList` could iterate over the array backwards (see previous exercise) and, for each element, add an object to the list. You can use a local binding to hold the part of the list that was built so far and use an assignment like `list = {value: X, rest: list}` to add an element. + + To run over a list (in `listToArray` and `nth`), a `for` loop specification like this can be used: + + ``` +-for (var node = list; node; node = node.rest) {} ++for (let node = list; node; node = node.rest) {} + ``` + + Can you see how that works? Every iteration of the loop, `node` points to the current sublist, and the body can read its `value` property to get the current element. At the end of an iteration, `node` moves to the next sublist. When that is null, we have reached the end of the list and the loop is finished. +@@ -740,16 +829,18 @@ The recursive version of `nth` will, similarly, look at an ever smaller part of + + ### Deep comparison + +-The `==` operator compares objects by identity. But sometimes, you would prefer to compare the values of their actual properties. ++The `==` operator compares objects by identity. But sometimes you'd prefer to compare the values of their actual properties. ++ ++Write a function `deepEqual` that takes two values and returns true only if they are the same value or are objects with the same properties, where the values of the properties are equal when compared with a recursive call to `deepEqual`. + +-Write a function, `deepEqual`, that takes two values and returns true only if they are the same value or are objects with the same properties whose values are also equal when compared with a recursive call to `deepEqual`. ++To find out whether values should be compared directly (use the `===` operator for that) or have their properties compared, you can use the `typeof` operator. If it produces `"object"` for both values, you should do a deep comparison. But you have to take one silly exception into account: because of a historical accident, `typeof null` also produces `"object"`. + +-To find out whether to compare two things by identity (use the `===` operator for that) or by looking at their properties, you can use the `typeof` operator. If it produces `"object"` for both values, you should do a deep comparison. But you have to take one silly exception into account: by a historical accident, `typeof null` also produces `"object"`. ++The `Object.keys` function will be useful when you need to go over the properties of objects to compare them. + + ``` + // Your code here. + +-var obj = {here: {is: "an"}, object: 2}; ++let obj = {here: {is: "an"}, object: 2}; + console.log(deepEqual(obj, obj)); + // → true + console.log(deepEqual(obj, {here: 1, object: 2})); +@@ -760,6 +851,6 @@ console.log(deepEqual(obj, {here: {is: "an"}, object: 2})); + + Your test for whether you are dealing with a real object will look something like `typeof x == "object" && x != null`. Be careful to compare properties only when _both_ arguments are objects. In all other cases you can just immediately return the result of applying `===`. + +-Use a `for`/`in` loop to go over the properties. You need to test whether both objects have the same set of property names and whether those properties have identical values. The first test can be done by counting the properties in both objects and returning false if the numbers of properties are different. If they're the same, then go over the properties of one object, and for each of them, verify that the other object also has the property. The values of the properties are compared by a recursive call to `deepEqual`. ++Use `Object.keys` to go over the properties. You need to test whether both objects have the same set of property names and whether those properties have identical values. One way to do that is to ensure that both objects have the same number of properties (the lengths of the property lists are the same). And then, when looping over one of the object's properties in order to compare them, always first make sure the other actually has a property by that name. If they have the same number of properties, and all properties in one also exist in the other, they have the same set of property names. + +-Returning the correct value from the function is best done by immediately returning false when a mismatch is noticed and returning true at the end of the function. +\ No newline at end of file ++Returning the correct value from the function is best done by immediately returning false when a mismatch is found and returning true at the end of the function. diff --git a/diff-en/2ech5-3ech5.diff b/diff-en/2ech5-3ech5.diff new file mode 100644 index 0000000..a459d36 --- /dev/null +++ b/diff-en/2ech5-3ech5.diff @@ -0,0 +1,867 @@ +diff --git a/2ech5.md b/3ech5.md +index 7d19300..3a03670 100644 +--- a/2ech5.md ++++ b/3ech5.md +@@ -1,6 +1,6 @@ + # Chapter 5Higher-Order Functions + +-> Tzu-li and Tzu-ssu were boasting about the size of their latest programs. ‘Two-hundred thousand lines,' said Tzu-li, ‘not counting comments!' Tzu-ssu responded, ‘Pssh, mine is almost a **million** lines already.' Master Yuan-Ma said, ‘My best program has five hundred lines.' Hearing this, Tzu-li and Tzu-ssu were enlightened. ++> Tzu-li and Tzu-ssu were boasting about the size of their latest programs. ‘Two-hundred thousand lines,' said Tzu-li, ‘not counting comments!' Tzu-ssu responded, ‘Pssh, mine is almost a _million_ lines already.' Master Yuan-Ma said, ‘My best program has five hundred lines.' Hearing this, Tzu-li and Tzu-ssu were enlightened. + > + > <footer>Master Yuan-Ma, <cite>The Book of Programming</cite></footer> + +@@ -8,12 +8,12 @@ + > + > <footer>C.A.R. Hoare, <cite>1980 ACM Turing Award Lecture</cite></footer> + +-A large program is a costly program, and not just because of the time it takes to build. Size almost always involves complexity, and complexity confuses programmers. Confused programmers, in turn, tend to introduce mistakes (_bugs_) into programs. A large program also provides a lot of space for these bugs to hide, making them hard to find. ++A large program is a costly program, and not just because of the time it takes to build. Size almost always involves complexity, and complexity confuses programmers. Confused programmers, in turn, introduce mistakes (_bugs_) into programs. A large program then provides a lot of space for these bugs to hide, making them hard to find. + +-Let's briefly go back to the final two example programs in the introduction. The first is self-contained and six lines long. ++Let's briefly go back to the final two example programs in the introduction. The first is self-contained and six lines long: + + ``` +-var total = 0, count = 1; ++let total = 0, count = 1; + while (count <= 10) { + total += count; + count += 1; +@@ -21,7 +21,7 @@ while (count <= 10) { + console.log(total); + ``` + +-The second relies on two external functions and is one line long. ++The second relies on two external functions and is one line long: + + ``` + console.log(sum(range(1, 10))); +@@ -51,113 +51,71 @@ And the second recipe: + + The second is shorter and easier to interpret. But you do need to understand a few more cooking-related words—_soak_, _simmer_, _chop_, and, I guess, _vegetable_. + +-When programming, we can't rely on all the words we need to be waiting for us in the dictionary. Thus, you might fall into the pattern of the first recipe—work out the precise steps the computer has to perform, one by one, blind to the higher-level concepts that they express. ++When programming, we can't rely on all the words we need to be waiting for us in the dictionary. Thus you might fall into the pattern of the first recipe—work out the precise steps the computer has to perform, one by one, blind to the higher-level concepts that they express. + +-It has to become second nature, for a programmer, to notice when a concept is begging to be abstracted into a new word. ++It is a useful skill, in programming, to notice when you are working at too low a level of abstraction. + +-## Abstracting array traversal ++## Abstracting repetition + + Plain functions, as we've seen them so far, are a good way to build abstractions. But sometimes they fall short. + +-In the [previous chapter](04_data.html#data), this type of `for` loop made several appearances: ++It is common for a program to do something a given number of times. You can write a `for` loop for that, like this: + + ``` +-var array = [1, 2, 3]; +-for (var i = 0; i < array.length; i++) { +- var current = array[i]; +- console.log(current); ++for (let i = 0; i < 10; i++) { ++ console.log(i); + } + ``` + +-It's trying to say, “For each element in the array, log it to the console”. But it uses a roundabout way that involves a counter variable `i`, a check against the array's length, and an extra variable declaration to pick out the current element. Apart from being a bit of an eyesore, this provides a lot of space for potential mistakes. We might accidentally reuse the `i` variable, misspell `length` as `lenght`, confuse the `i` and `current` variables, and so on. +- +-So let's try to abstract this into a function. Can you think of a way? +- +-Well, it's easy to write a function that goes over an array and calls `console.log` on every element. ++Can we abstract “doing something _N_ times” as a function? Well, it's easy to write a function that calls `console.log` _N_ times. + + ``` +-function logEach(array) { +- for (var i = 0; i < array.length; i++) +- console.log(array[i]); ++function repeatLog(n) { ++ for (let i = 0; i < n; i++) { ++ console.log(i); ++ } + } + ``` + +-But what if we want to do something other than logging the elements? Since “doing something” can be represented as a function and functions are just values, we can pass our action as a function value. ++But what if we want to do something other than logging the numbers? Since “doing something” can be represented as a function and functions are just values, we can pass our action as a function value. + + ``` +-function forEach(array, action) { +- for (var i = 0; i < array.length; i++) +- action(array[i]); ++function repeat(n, action) { ++ for (let i = 0; i < n; i++) { ++ action(i); ++ } + } + +-forEach(["Wampeter", "Foma", "Granfalloon"], console.log); +-// → Wampeter +-// → Foma +-// → Granfalloon ++repeat(3, console.log); ++// → 0 ++// → 1 ++// → 2 + ``` + +-(In some browsers, calling `console.log` in this way does not work. You can use `alert` instead of `console.log` if this example fails to work.) +- +-Often, you don't pass a predefined function to `forEach` but create a function value on the spot instead. ++You don't have to pass a predefined function to `repeat`. Often, you'd want to create a function value on the spot instead. + + ``` +-var numbers = [1, 2, 3, 4, 5], sum = 0; +-forEach(numbers, function(number) { +- sum += number; ++let labels = []; ++repeat(5, i => { ++ labels.push(`Unit ${i + 1}`); + }); +-console.log(sum); +-// → 15 ++console.log(labels); ++// → ["Unit 1", "Unit 2", "Unit 3", "Unit 4", "Unit 5"] + ``` + +-This looks quite a lot like the classical `for` loop, with its body written as a block below it. However, now the body is inside the function value, as well as inside the parentheses of the call to `forEach`. This is why it has to be closed with the closing brace _and_ closing parenthesis. +- +-Using this pattern, we can specify a variable name for the current element (`number`), rather than having to pick it out of the array manually. +- +-In fact, we don't need to write `forEach` ourselves. It is available as a standard method on arrays. Since the array is already provided as the thing the method acts on, `forEach` takes only one required argument: the function to be executed for each element. +- +-To illustrate how helpful this is, let's look back at a function from [the previous chapter](04_data.html#analysis). It contains two array-traversing loops. +- +-``` +-function gatherCorrelations(journal) { +- var phis = {}; +- for (var entry = 0; entry < journal.length; entry++) { +- var events = journal[entry].events; +- for (var i = 0; i < events.length; i++) { +- var event = events[i]; +- if (!(event in phis)) +- phis[event] = phi(tableFor(event, journal)); +- } +- } +- return phis; +-} +-``` +- +-Working with `forEach` makes it slightly shorter and quite a bit cleaner. +- +-``` +-function gatherCorrelations(journal) { +- var phis = {}; +- journal.forEach(function(entry) { +- entry.events.forEach(function(event) { +- if (!(event in phis)) +- phis[event] = phi(tableFor(event, journal)); +- }); +- }); +- return phis; +-} +-``` ++This is structured a little like a `for` loop—it first describes the kind of loop and then provides a body. However, the body is now written as a function value, which is wrapped in the parentheses of the call to `repeat`. This is why it has to be closed with the closing brace _and_ closing parenthesis. In cases like this example, where the body is a single small expression, you could also omit the curly braces and write the loop on a single line. + + ## Higher-order functions + +-Functions that operate on other functions, either by taking them as arguments or by returning them, are called _higher-order functions_. If you have already accepted the fact that functions are regular values, there is nothing particularly remarkable about the fact that such functions exist. The term comes from mathematics, where the distinction between functions and other values is taken more seriously. ++Functions that operate on other functions, either by taking them as arguments or by returning them, are called _higher-order functions_. Since we have already seen that functions are regular values, there is nothing particularly remarkable about the fact that such functions exist. The term comes from mathematics, where the distinction between functions and other values is taken more seriously. + + Higher-order functions allow us to abstract over _actions_, not just values. They come in several forms. For example, you can have functions that create new functions. + + ``` + function greaterThan(n) { +- return function(m) { return m > n; }; ++ return m => m > n; + } +-var greaterThan10 = greaterThan(10); ++let greaterThan10 = greaterThan(10); + console.log(greaterThan10(11)); + // → true + ``` +@@ -166,16 +124,16 @@ And you can have functions that change other functions. + + ``` + function noisy(f) { +- return function(arg) { +- console.log("calling with", arg); +- var val = f(arg); +- console.log("called with", arg, "- got", val); +- return val; ++ return (...args) => { ++ console.log("calling with", args); ++ let result = f(...args); ++ console.log("called with", args, ", returned", result); ++ return result; + }; + } +-noisy(Boolean)(0); +-// → calling with 0 +-// → called with 0 - got false ++noisy(Math.min)(3, 2, 1); ++// → calling with [3, 2, 1] ++// → called with [3, 2, 1] , returned 1 + ``` + + You can even write functions that provide new types of control flow. +@@ -184,12 +142,9 @@ You can even write functions that provide new types of control flow. + function unless(test, then) { + if (!test) then(); + } +-function repeat(times, body) { +- for (var i = 0; i < times; i++) body(i); +-} + +-repeat(3, function(n) { +- unless(n % 2, function() { ++repeat(3, n => { ++ unless(n % 2 == 1, () => { + console.log(n, "is even"); + }); + }); +@@ -197,431 +152,378 @@ repeat(3, function(n) { + // → 2 is even + ``` + +-The lexical scoping rules that we discussed in [Chapter 3](03_functions.html#scoping) work to our advantage when using functions in this way. In the previous example, the `n` variable is a parameter to the outer function. Because the inner function lives inside the environment of the outer one, it can use `n`. The bodies of such inner functions can access the variables around them. They can play a role similar to the `{}` blocks used in regular loops and conditional statements. An important difference is that variables declared inside inner functions do not end up in the environment of the outer function. And that is usually a good thing. +- +-## Passing along arguments +- +-The `noisy` function defined earlier, which wraps its argument in another function, has a rather serious deficit. ++There is a built-in array method, `forEach` that provides something like a `for`/`of` loop as a higher-order function. + + ``` +-function noisy(f) { +- return function(arg) { +- console.log("calling with", arg); +- var val = f(arg); +- console.log("called with", arg, "- got", val); +- return val; +- }; +-} ++["A", "B"].forEach(l => console.log(l)); ++// → A ++// → B + ``` + +-If `f` takes more than one parameter, it gets only the first one. We could add a bunch of arguments to the inner function (`arg1`, `arg2`, and so on) and pass them all to `f`, but it is not clear how many would be enough. This solution would also deprive `f` of the information in `arguments.length`. Since we'd always pass the same number of arguments, it wouldn't know how many arguments were originally given. ++## Script data set + +-For these kinds of situations, JavaScript functions have an `apply` method. You pass it an array (or array-like object) of arguments, and it will call the function with those arguments. ++One area where higher-order functions shine is data processing. In order to process data, we'll need some actual data. This chapter will use a data set about scripts—writing systems such as Latin, Cyrillic, or Arabic. + +-``` +-function transparentWrapping(f) { +- return function() { +- return f.apply(null, arguments); +- }; +-} +-``` +- +-That's a useless function, but it shows the pattern we are interested in—the function it returns passes all of the given arguments, and only those arguments, to `f`. It does this by passing its own `arguments` object to `apply`. The first argument to `apply`, for which we are passing `null` here, can be used to simulate a method call. We will come back to that in the [next chapter](06_object.html#call_method). ++Remember Unicode from [Chapter 1](01_values.html#unicode), the system that assigns a number to each character in written language. Most of these characters are associated with a specific script. The standard contains 140 different scripts—81 are still in use today, and 59 are historic. + +-## JSON ++Though I can only fluently read Latin characters, I appreciate the fact that people are writing texts in at least 80 other writing systems, many of which I wouldn't even recognize. For example, here's a sample of Tamil handwriting. + +-Higher-order functions that somehow apply a function to the elements of an array are widely used in JavaScript. The `forEach` method is the most primitive such function. There are a number of other variants available as methods on arrays. To familiarize ourselves with them, let's play around with another data set. ++
![Tamil handwriting](img/tamil.png)
+ +-A few years ago, someone crawled through a lot of archives and put together a book on the history of my family name (Haverbeke—meaning Oatbrook). I opened it hoping to find knights, pirates, and alchemists ... but the book turns out to be mostly full of Flemish farmers. For my amusement, I extracted the information on my direct ancestors and put it into a computer-readable format. ++The example data set contains some pieces of information about the 140 scripts defined in Unicode. It is available in the [coding sandbox](https://eloquentjavascript.net/code#5) for this chapter as the `SCRIPTS` binding. The binding contains an array of objects, each of which describes a script. + +-The file I created looks something like this: +- +-``` +-[ +- {"name": "Emma de Milliano", "sex": "f", +- "born": 1876, "died": 1956, +- "father": "Petrus de Milliano", +- "mother": "Sophia van Damme"}, +- {"name": "Carolus Haverbeke", "sex": "m", +- "born": 1832, "died": 1905, +- "father": "Carel Haverbeke", +- "mother": "Maria van Brussel"}, +- … and so on +-] + ``` +- +-This format is called JSON (pronounced “Jason”), which stands for JavaScript Object Notation. It is widely used as a data storage and communication format on the Web. +- +-JSON is similar to JavaScript's way of writing arrays and objects, with a few restrictions. All property names have to be surrounded by double quotes, and only simple data expressions are allowed—no function calls, variables, or anything that involves actual computation. Comments are not allowed in JSON. +- +-JavaScript gives us functions, `JSON.stringify` and `JSON.parse`, that convert data to and from this format. The first takes a JavaScript value and returns a JSON-encoded string. The second takes such a string and converts it to the value it encodes. +- +-``` +-var string = JSON.stringify({name: "X", born: 1980}); +-console.log(string); +-// → {"name":"X","born":1980} +-console.log(JSON.parse(string).born); +-// → 1980 ++{ ++ name: "Coptic", ++ ranges: [[994, 1008], [11392, 11508], [11513, 11520]], ++ direction: "ltr", ++ year: -200, ++ living: false, ++ link: "https://en.wikipedia.org/wiki/Coptic_alphabet" ++} + ``` + +-The variable `ANCESTRY_FILE`, available in the sandbox for this chapter and in [a downloadable file](http://eloquentjavascript.net/2nd_edition/code/ancestry.js) on the website, contains the content of my JSON file as a string. Let's decode it and see how many people it contains. ++Such an object tells you the name of the script, the Unicode ranges assigned to it, the direction in which it is written, the (approximate) origin time, whether it is still in use, and a link to more information. Direction may be `"ltr"` for left-to-right, `"rtl"` for right-to-left (the way Arabic and Hebrew text are written), or `"ttb"` for top-to-bottom (as with Mongolian writing). + +-``` +-var ancestry = JSON.parse(ANCESTRY_FILE); +-console.log(ancestry.length); +-// → 39 +-``` ++The `ranges` property contains an array of Unicode character ranges, each of which is a two-element array containing a lower and upper bound. Any character codes within these ranges are assigned to the script. The lower bound is inclusive (code 994 is a Coptic character), and the upper bound non-inclusive (code 1008 isn't). + +-## Filtering an array ++## Filtering arrays + +-To find the people in the ancestry data set who were young in 1924, the following function might be helpful. It filters out the elements in an array that don't pass a test. ++To find the scripts in the data set that are still in use, the following function might be helpful. It filters out the elements in an array that don't pass a test: + + ``` + function filter(array, test) { +- var passed = []; +- for (var i = 0; i < array.length; i++) { +- if (test(array[i])) +- passed.push(array[i]); ++ let passed = []; ++ for (let element of array) { ++ if (test(element)) { ++ passed.push(element); ++ } + } + return passed; + } + +-console.log(filter(ancestry, function(person) { +- return person.born > 1900 && person.born < 1925; +-})); +-// → [{name: "Philibert Haverbeke", …}, …] ++console.log(filter(SCRIPTS, script => script.living)); ++// → [{name: "Adlam", …}, …] + ``` + +-This uses the argument named `test`, a function value, to fill in a “gap” in the computation. The `test` function is called for each element, and its return value determines whether an element is included in the returned array. +- +-Three people in the file were alive and young in 1924: my grandfather, grandmother, and great-aunt. ++The function uses the argument named `test`, a function value, to fill a “gap” in the computation—the process of deciding which elements to collect. + + Note how the `filter` function, rather than deleting elements from the existing array, builds up a new array with only the elements that pass the test. This function is _pure_. It does not modify the array it is given. + +-Like `forEach`, `filter` is also a standard method on arrays. The example defined the function only in order to show what it does internally. From now on, we'll use it like this instead: ++Like `forEach`, `filter` is a standard array method. The example defined the function only in order to show what it does internally. From now on, we'll use it like this instead: + + ``` +-console.log(ancestry.filter(function(person) { +- return person.father == "Carel Haverbeke"; +-})); +-// → [{name: "Carolus Haverbeke", …}] ++console.log(SCRIPTS.filter(s => s.direction == "ttb")); ++// → [{name: "Mongolian", …}, …] + ``` + + ## Transforming with map + +-Say we have an array of objects representing people, produced by filtering the `ancestry` array somehow. But we want an array of names, which is easier to read. ++Say we have an array of objects representing scripts, produced by filtering the `SCRIPTS` array somehow. But we want an array of names, which is easier to inspect. + +-The `map` method transforms an array by applying a function to all of its elements and building a new array from the returned values. The new array will have the same length as the input array, but its content will have been “mapped” to a new form by the function. ++The `map` method transforms an array by applying a function to all of its elements and building a new array from the returned values. The new array will have the same length as the input array, but its content will have been _mapped_ to a new form by the function. + + ``` + function map(array, transform) { +- var mapped = []; +- for (var i = 0; i < array.length; i++) +- mapped.push(transform(array[i])); ++ let mapped = []; ++ for (let element of array) { ++ mapped.push(transform(element)); ++ } + return mapped; + } + +-var overNinety = ancestry.filter(function(person) { +- return person.died - person.born > 90; +-}); +-console.log(map(overNinety, function(person) { +- return person.name; +-})); +-// → ["Clara Aernoudts", "Emile Haverbeke", +-// "Maria Haverbeke"] ++let rtlScripts = SCRIPTS.filter(s => s.direction == "rtl"); ++console.log(map(rtlScripts, s => s.name)); ++// → ["Adlam", "Arabic", "Imperial Aramaic", …] + ``` + +-Interestingly, the people who lived to at least 90 years of age are the same three people who we saw before—the people who were young in the 1920s, which happens to be the most recent generation in my data set. I guess medicine has come a long way. +- +-Like `forEach` and `filter`, `map` is also a standard method on arrays. ++Like `forEach` and `filter`, `map` is a standard array method. + + ## Summarizing with reduce + +-Another common pattern of computation on arrays is computing a single value from them. Our recurring example, summing a collection of numbers, is an instance of this. Another example would be finding the person with the earliest year of birth in the data set. ++Another common thing to do with arrays is computing a single value from them. Our recurring example, summing a collection of numbers, is an instance of this. Another example would be finding the script with the most characters. + +-The higher-order operation that represents this pattern is called _reduce_ (or sometimes _fold_). You can think of it as folding up the array, one element at a time. When summing numbers, you'd start with the number zero and, for each element, combine it with the current sum by adding the two. ++The higher-order operation that represents this pattern is called _reduce_ (sometimes also called _fold_). It builds a value by repeatedly taking a single element from the array and combining it with the current value. When summing numbers, you'd start with the number zero and, for each element, add that to the sum. + +-The parameters to the `reduce` function are, apart from the array, a combining function and a start value. This function is a little less straightforward than `filter` and `map`, so pay close attention. ++The parameters to `reduce` are, apart from the array, a combining function and a start value. This function is a little less straightforward than `filter` and `map`, so look closely: + + ``` + function reduce(array, combine, start) { +- var current = start; +- for (var i = 0; i < array.length; i++) +- current = combine(current, array[i]); ++ let current = start; ++ for (let element of array) { ++ current = combine(current, element); ++ } + return current; + } + +-console.log(reduce([1, 2, 3, 4], function(a, b) { +- return a + b; +-}, 0)); ++console.log(reduce([1, 2, 3, 4], (a, b) => a + b, 0)); + // → 10 + ``` + + The standard array method `reduce`, which of course corresponds to this function, has an added convenience. If your array contains at least one element, you are allowed to leave off the `start` argument. The method will take the first element of the array as its start value and start reducing at the second element. + +-To use `reduce` to find my most ancient known ancestor, we can write something like this: ++``` ++console.log([1, 2, 3, 4].reduce((a, b) => a + b)); ++// → 10 ++``` ++ ++To use `reduce` (twice) to find the script with the most characters, we can write something like this: + + ``` +-console.log(ancestry.reduce(function(min, cur) { +- if (cur.born < min.born) return cur; +- else return min; ++function characterCount(script) { ++ return script.ranges.reduce((count, [from, to]) => { ++ return count + (to - from); ++ }, 0); ++} ++ ++console.log(SCRIPTS.reduce((a, b) => { ++ return characterCount(a) < characterCount(b) ? b : a; + })); +-// → {name: "Pauwels van Haverbeke", born: 1535, …} ++// → {name: "Han", …} + ``` + ++The `characterCount` function reduces the ranges assigned to a script by summing their sizes. Note the use of destructuring in the parameter list of the reducer function. The second call to `reduce` then uses this to find the largest script by repeatedly comparing two scripts and returning the larger one. ++ ++The Han script has over 89,000 characters assigned to it in the Unicode standard, making it by far the biggest writing system in the data set. Han is a script (sometimes) used for Chinese, Japanese, and Korean text. Those languages share a lot of characters, though they tend to write them differently. The (US-based) Unicode Consortium decided to treat them as a single writing system in order to save character codes. This is called _Han unification_ and still makes some people very angry. ++ + ## Composability + +-Consider how we would have written the previous example (finding the person with the earliest year of birth) without higher-order functions. The code is not that much worse. ++Consider how we would have written the previous example (finding the biggest script) without higher-order functions. The code is not that much worse. + + ``` +-var min = ancestry[0]; +-for (var i = 1; i < ancestry.length; i++) { +- var cur = ancestry[i]; +- if (cur.born < min.born) +- min = cur; ++let biggest = null; ++for (let script of SCRIPTS) { ++ if (biggest == null || ++ characterCount(biggest) < characterCount(script)) { ++ biggest = script; ++ } + } +-console.log(min); +-// → {name: "Pauwels van Haverbeke", born: 1535, …} ++console.log(biggest); ++// → {name: "Han", …} + ``` + +-There are a few more variables, and the program is two lines longer but still quite easy to understand. ++There are a few more bindings, and the program is four lines longer. But it is still very readable. + +-Higher-order functions start to shine when you need to _compose_ functions. As an example, let's write code that finds the average age for men and for women in the data set. ++Higher-order functions start to shine when you need to _compose_ operations. As an example, let's write code that finds the average year of origin for living and dead scripts in the data set. + + ``` + function average(array) { +- function plus(a, b) { return a + b; } +- return array.reduce(plus) / array.length; ++ return array.reduce((a, b) => a + b) / array.length; + } +-function age(p) { return p.died - p.born; } +-function male(p) { return p.sex == "m"; } +-function female(p) { return p.sex == "f"; } + +-console.log(average(ancestry.filter(male).map(age))); +-// → 61.67 +-console.log(average(ancestry.filter(female).map(age))); +-// → 54.56 ++console.log(Math.round(average( ++ SCRIPTS.filter(s => s.living).map(s => s.year)))); ++// → 1185 ++console.log(Math.round(average( ++ SCRIPTS.filter(s => !s.living).map(s => s.year)))); ++// → 209 + ``` + +-(It's a bit silly that we have to define `plus` as a function, but operators in JavaScript, unlike functions, are not values, so you can't pass them as arguments.) +- +-Instead of tangling the logic into a big loop, it is neatly composed into the concepts we are interested in—determining sex, computing age, and averaging numbers. We can apply these one by one to get the result we are looking for. ++So the dead scripts in Unicode are, on average, older than the living ones. This is not a terribly meaningful or surprising statistic. But I hope you'll agree that the code used to compute it isn't hard to read. You can see it as a pipeline: we start with all scripts, filter out the living (or dead) ones, take the years from those, average them, and round the result. + +-This is _fabulous_ for writing clear code. Unfortunately, this clarity comes at a cost. ++You could definitely also write this computation as one big loop. + +-## The cost +- +-In the happy land of elegant code and pretty rainbows, there lives a spoil-sport monster called _inefficiency_. +- +-A program that processes an array is most elegantly expressed as a sequence of cleanly separated steps that each do something with the array and produce a new array. But building up all those intermediate arrays is somewhat expensive. +- +-Likewise, passing a function to `forEach` and letting that method handle the array iteration for us is convenient and easy to read. But function calls in JavaScript are costly compared to simple loop bodies. +- +-And so it goes with a lot of techniques that help improve the clarity of a program. Abstractions add layers between the raw things the computer is doing and the concepts we are working with and thus cause the machine to perform more work. This is not an iron law—there are programming languages that have better support for building abstractions without adding inefficiencies, and even in JavaScript, an experienced programmer can find ways to write abstract code that is still fast. But it is a problem that comes up a lot. ++``` ++let total = 0, count = 0; ++for (let script of SCRIPTS) { ++ if (script.living) { ++ total += script.year; ++ count += 1; ++ } ++} ++console.log(Math.round(total / count)); ++// → 1185 ++``` + +-Fortunately, most computers are insanely fast. If you are processing a modest set of data or doing something that has to happen only on a human time scale (say, every time the user clicks a button), then it _does not matter_ whether you wrote a pretty solution that takes half a millisecond or a super-optimized solution that takes a tenth of a millisecond. ++But it is harder to see what was being computed and how. And because intermediate results aren't represented as coherent values, it'd be a lot more work to extract something like `average` into a separate function. + +-It is helpful to roughly keep track of how often a piece of your program is going to run. If you have a loop inside a loop (either directly or through the outer loop calling a function that ends up performing the inner loop), the code inside the inner loop will end up running _N_×_M_ times, where _N_ is the number of times the outer loop repeats and _M_ is the number of times the inner loop repeats within each iteration of the outer loop. If that inner loop contains another loop that makes _P_ rounds, its body will run _M_×_N_×_P_ times, and so on. This can add up to large numbers, and when a program is slow, the problem can often be traced to only a small part of the code, which sits inside an inner loop. ++In terms of what the computer is actually doing, these two approaches are also quite different. The first will build up new arrays when running `filter` and `map`, whereas the second only computes some numbers, doing less work. You can usually afford the readable approach, but if you're processing huge arrays, and doing so many times, the less abstract style might be worth the extra speed. + +-## Great-great-great-great-... ++## Strings and character codes + +-My grandfather, Philibert Haverbeke, is included in the data file. By starting with him, I can trace my lineage to find out whether the most ancient person in the data, Pauwels van Haverbeke, is my direct ancestor. And if he is, I would like to know how much DNA I theoretically share with him. ++One use of the data set would be figuring out what script a piece of text is using. Let's go through a program that does this. + +-To be able to go from a parent's name to the actual object that represents this person, we first build up an object that associates names with people. ++Remember that each script has an array of character code ranges associated with it. So given a character code, we could use a function like this to find the corresponding script (if any): + + ``` +-var byName = {}; +-ancestry.forEach(function(person) { +- byName[person.name] = person; +-}); ++function characterScript(code) { ++ for (let script of SCRIPTS) { ++ if (script.ranges.some(([from, to]) => { ++ return code >= from && code < to; ++ })) { ++ return script; ++ } ++ } ++ return null; ++} + +-console.log(byName["Philibert Haverbeke"]); +-// → {name: "Philibert Haverbeke", …} ++console.log(characterScript(121)); ++// → {name: "Latin", …} + ``` + +-Now, the problem is not entirely as simple as following the `father` properties and counting how many we need to reach Pauwels. There are several cases in the family tree where people married their second cousins (tiny villages and all that). This causes the branches of the family tree to rejoin in a few places, which means I share more than 1/2<sup>_G_</sup> of my genes with this person, where _G_ for the number of generations between Pauwels and me. This formula comes from the idea that each generation splits the gene pool in two. ++The `some` method is another higher-order function. It takes a test function and tells you if that function returns true for any of the elements in the array. ++ ++But how do we get the character codes in a string? + +-A reasonable way to think about this problem is to look at it as being analogous to `reduce`, which condenses an array to a single value by repeatedly combining values, left to right. In this case, we also want to condense our data structure to a single value but in a way that follows family lines. The _shape_ of the data is that of a family tree, rather than a flat list. ++In [Chapter 1](01_values.html) I mentioned that JavaScript strings are encoded as a sequence of 16-bit numbers. These are called _code units_. A Unicode character code was initially supposed to fit within such a unit (which gives you a little over 65,000 characters). When it became clear that wasn't going to be enough, many people balked at the need to use more memory per character. To address these concerns, UTF-16, the format used by JavaScript strings, was invented. It describes most common characters using a single 16-bit code unit, but uses a pair of two such units for others. + +-The way we want to reduce this shape is by computing a value for a given person by combining values from their ancestors. This can be done recursively: if we are interested in person _A_, we have to compute the values for _A_'s parents, which in turn requires us to compute the value for _A_'s grandparents, and so on. In principle, that'd require us to look at an infinite number of people, but since our data set is finite, we have to stop somewhere. We'll allow a default value to be given to our reduction function, which will be used for people who are not in the data. In our case, that value is simply zero, on the assumption that people not in the list don't share DNA with the ancestor we are looking at. ++UTF-16 is generally considered a bad idea today. It seems almost intentionally designed to invite mistakes. It's easy to write programs that pretend code units and characters are the same thing. And if your language doesn't use two-unit characters, that will appear to work just fine. But as soon as someone tries to use such a program with some less common Chinese characters, it breaks. Fortunately, with the advent of emoji, everybody has started using two-unit characters, and the burden of dealing with such problems is more fairly distributed. + +-Given a person, a function to combine values from the two parents of a given person, and a default value, `reduceAncestors` condenses a value from a family tree. ++Unfortunately, obvious operations on JavaScript strings, such as getting their length through the `length` property and accessing their content using square brackets, deal only with code units. + + ``` +-function reduceAncestors(person, f, defaultValue) { +- function valueFor(person) { +- if (person == null) +- return defaultValue; +- else +- return f(person, valueFor(byName[person.mother]), +- valueFor(byName[person.father])); +- } +- return valueFor(person); +-} ++// Two emoji characters, horse and shoe ++let horseShoe = "🐴👟"; ++console.log(horseShoe.length); ++// → 4 ++console.log(horseShoe[0]); ++// → (Invalid half-character) ++console.log(horseShoe.charCodeAt(0)); ++// → 55357 (Code of the half-character) ++console.log(horseShoe.codePointAt(0)); ++// → 128052 (Actual code for horse emoji) + ``` + +-The inner function (`valueFor`) handles a single person. Through the magic of recursion, it can simply call itself to handle the father and the mother of this person. The results, along with the person object itself, are passed to `f`, which returns the actual value for this person. ++JavaScript's `charCodeAt` method gives you a code unit, not a full character code. The `codePointAt` method, added later, does give a full Unicode character. So we could use that to get characters from a string. But the argument passed to `codePointAt` is still an index into the sequence of code units. So to run over all characters in a string, we'd still need to deal with the question of whether a character takes up one or two code units. + +-We can then use this to compute the amount of DNA my grandfather shared with Pauwels van Haverbeke and divide that by four. ++In the [previous chapter](04_data.html#for_of_loop), I mentioned that a `for`/`of` loop can also be used on strings. Like `codePointAt`, this type of loop was introduced at a time where people were acutely aware of the problems with UTF-16\. When you use it to loop over a string, it gives you real characters, not code units. + + ``` +-function sharedDNA(person, fromMother, fromFather) { +- if (person.name == "Pauwels van Haverbeke") +- return 1; +- else +- return (fromMother + fromFather) / 2; ++let roseDragon = "🌹🐉"; ++for (let char of roseDragon) { ++ console.log(char); + } +-var ph = byName["Philibert Haverbeke"]; +-console.log(reduceAncestors(ph, sharedDNA, 0) / 4); +-// → 0.00049 ++// → 🌹 ++// → 🐉 + ``` + +-The person with the name Pauwels van Haverbeke obviously shared 100 percent of his DNA with Pauwels van Haverbeke (there are no people who share names in the data set), so the function returns 1 for him. All other people share the average of the amounts that their parents share. ++If you have a character (which will be a string of one or two code units), you can use `codePointAt(0)` to get its code. + +-So, statistically speaking, I share about 0.05 percent of my DNA with this 16th-century person. It should be noted that this is only a statistical approximation, not an exact amount. It is a rather small number, but given how much genetic material we carry (about 3 billion base pairs), there's still probably some aspect in the biological machine that is me that originates with Pauwels. ++## Recognizing text + +-We could also have computed this number without relying on `reduceAncestors`. But separating the general approach (condensing a family tree) from the specific case (computing shared DNA) can improve the clarity of the code and allows us to reuse the abstract part of the program for other cases. For example, the following code finds the percentage of a person's known ancestors who lived past 70 (by lineage, so people may be counted multiple times): ++We have a `characterScript` function and a way to correctly loop over characters. The next step would be to count the characters that belong to each script. The following counting abstraction will be useful there: + + ``` +-function countAncestors(person, test) { +- function combine(current, fromMother, fromFather) { +- var thisOneCounts = current != person && test(current); +- return fromMother + fromFather + (thisOneCounts ? 1 : 0); ++function countBy(items, groupName) { ++ let counts = []; ++ for (let item of items) { ++ let name = groupName(item); ++ let known = counts.findIndex(c => c.name == name); ++ if (known == -1) { ++ counts.push({name, count: 1}); ++ } else { ++ counts[known].count++; ++ } + } +- return reduceAncestors(person, combine, 0); +-} +-function longLivingPercentage(person) { +- var all = countAncestors(person, function(person) { +- return true; +- }); +- var longLiving = countAncestors(person, function(person) { +- return (person.died - person.born) >= 70; +- }); +- return longLiving / all; ++ return counts; + } +-console.log(longLivingPercentage(byName["Emile Haverbeke"])); +-// → 0.129 +-``` + +-Such numbers are not to be taken too seriously, given that our data set contains a rather arbitrary collection of people. But the code illustrates the fact that `reduceAncestors` gives us a useful piece of vocabulary for working with the family tree data structure. ++console.log(countBy([1, 2, 3, 4, 5], n => n > 2)); ++// → [{name: false, count: 2}, {name: true, count: 3}] ++``` + +-## Binding ++The `countBy` function expects a collection (anything that we can loop over with `for`/`of`) and a function that computes a group name for a given element. It returns an array of objects, each of which names a group and tells you the amount of elements that were found in that group. + +-The `bind` method, which all functions have, creates a new function that will call the original function but with some of the arguments already fixed. ++It uses another array method—`findIndex`. This method is somewhat like `indexOf`, but instead of looking for a specific value, it finds the first value for which the given function returns true. Like `indexOf`, it returns -1 when no such element is found. + +-The following code shows an example of `bind` in use. It defines a function `isInSet` that tells us whether a person is in a given set of strings. To call `filter` in order to collect those person objects whose names are in a specific set, we can either write a function expression that makes a call to `isInSet` with our set as its first argument or _partially apply_ the `isInSet` function. ++Using `countBy`, we can write the function that tells us which scripts are used in a piece of text. + + ``` +-var theSet = ["Carel Haverbeke", "Maria van Brussel", +- "Donald Duck"]; +-function isInSet(set, person) { +- return set.indexOf(person.name) > -1; ++function textScripts(text) { ++ let scripts = countBy(text, char => { ++ let script = characterScript(char.codePointAt(0)); ++ return script ? script.name : "none"; ++ }).filter(({name}) => name != "none"); ++ ++ let total = scripts.reduce((n, {count}) => n + count, 0); ++ if (total == 0) return "No scripts found"; ++ ++ return scripts.map(({name, count}) => { ++ return `${Math.round(count * 100 / total)}% ${name}`; ++ }).join(", "); + } + +-console.log(ancestry.filter(function(person) { +- return isInSet(theSet, person); +-})); +-// → [{name: "Maria van Brussel", …}, +-// {name: "Carel Haverbeke", …}] +-console.log(ancestry.filter(isInSet.bind(null, theSet))); +-// → … same result ++console.log(textScripts('英国的狗说"woof", 俄罗斯的狗说"тяв"')); ++// → 61% Han, 22% Latin, 17% Cyrillic + ``` + +-The call to `bind` returns a function that will call `isInSet` with `theSet` as first argument, followed by any remaining arguments given to the bound function. ++The function first counts the characters by name, using `characterScript` to assign them a name, and falling back to the string `"none"` for characters that aren't part of any script. The `filter` call drops the entry for `"none"` from the resulting array, since we aren't interested in those characters. + +-The first argument, where the example passes `null`, is used for method calls, similar to the first argument to `apply`. I'll describe this in more detail in the [next chapter](06_object.html#call_method). ++To be able to compute percentages, we first need the total amount of characters that belong to a script, which we can compute with `reduce`. If no such characters are found, the function returns a specific string. Otherwise, it transforms the counting entries into readable strings with `map` and then combines them with `join`. + + ## Summary + +-Being able to pass function values to other functions is not just a gimmick but a deeply useful aspect of JavaScript. It allows us to write computations with “gaps” in them as functions and have the code that calls these functions fill in those gaps by providing function values that describe the missing computations. ++Being able to pass function values to other functions is a deeply useful aspect of JavaScript. It allows us to write functions that model computations with “gaps” in them. The code that calls these functions can fill in the gaps by providing function values. + +-Arrays provide a number of useful higher-order methods—`forEach` to do something with each element in an array, `filter` to build a new array with some elements filtered out, `map` to build a new array where each element has been put through a function, and `reduce` to combine all an array's elements into a single value. +- +-Functions have an `apply` method that can be used to call them with an array specifying their arguments. They also have a `bind` method, which is used to create a partially applied version of the function. ++Arrays provide a number of useful higher-order methods. You can use `forEach` to loop over the elements in an array. The `filter` method returns a new array containing only the elements that pass the predicate function. Transforming an array by putting each element through a function is done with `map`. You can use `reduce` to combine all the elements in an array into a single value. The `some` method tests whether any element matches a given predicate function. And `findIndex` finds the position of the first element that matches a predicate. + + ## Exercises + + ### Flattening + +-Use the `reduce` method in combination with the `concat` method to “flatten” an array of arrays into a single array that has all the elements of the input arrays. ++Use the `reduce` method in combination with the `concat` method to “flatten” an array of arrays into a single array that has all the elements of the original arrays. + + ``` +-var arrays = [[1, 2, 3], [4, 5], [6]]; ++let arrays = [[1, 2, 3], [4, 5], [6]]; + // Your code here. + // → [1, 2, 3, 4, 5, 6] + ``` + +-### Mother-child age difference ++### Your own loop + +-Using the example data set from this chapter, compute the average age difference between mothers and children (the age of the mother when the child is born). You can use the `average` function defined [earlier](05_higher_order.html#average_function) in this chapter. ++Write a higher-order function `loop` that provides something like a `for` loop statement. It takes a value, a test function, an update function, and a body function. Each iteration, it first runs the test function on the current loop value and stops if that returns false. Then it calls the body function, giving it the current value. And finally, it calls the update function to create a new value and starts from the beginning. + +-Note that not all the mothers mentioned in the data are themselves present in the array. The `byName` object, which makes it easy to find a person's object from their name, might be useful here. ++When defining the function, you can use a regular loop to do the actual looping. + + ``` +-function average(array) { +- function plus(a, b) { return a + b; } +- return array.reduce(plus) / array.length; +-} +- +-var byName = {}; +-ancestry.forEach(function(person) { +- byName[person.name] = person; +-}); +- + // Your code here. + +-// → 31.2 ++loop(3, n => n > 0, n => n - 1, console.log); ++// → 3 ++// → 2 ++// → 1 + ``` + +-Because not all elements in the `ancestry` array produce useful data (we can't compute the age difference unless we know the birth date of the mother), we will have to apply `filter` in some manner before calling `average`. You could do it as a first pass, by defining a `hasKnownMother` function and filtering on that first. Alternatively, you could start by calling `map` and in your mapping function return either the age difference or `null` if no mother is known. Then, you can call `filter` to remove the `null` elements before passing the array to `average`. ++### Everything + +-### Historical life expectancy ++Analogous to the `some` method, arrays also have an `every` method. This one returns true when the given function returns true for _every_ element in the array. In a way, `some` is a version of the `||` operator that acts on arrays, and `every` is like the `&&` operator. + +-When we looked up all the people in our data set that lived more than 90 years, only the latest generation in the data came out. Let's take a closer look at that phenomenon. +- +-Compute and output the average age of the people in the ancestry data set per century. A person is assigned to a century by taking their year of death, dividing it by 100, and rounding it up, as in `Math.ceil(person.died / 100)`. ++Implement `every` as a function that takes an array and a predicate function as parameters. Write two versions, one using a loop and one using the `some` method. + + ``` +-function average(array) { +- function plus(a, b) { return a + b; } +- return array.reduce(plus) / array.length; ++function every(array, test) { ++ // Your code here. + } + +-// Your code here. +- +-// → 16: 43.5 +-// 17: 51.2 +-// 18: 52.8 +-// 19: 54.8 +-// 20: 84.7 +-// 21: 94 ++console.log(every([1, 3, 5], n => n < 10)); ++// → true ++console.log(every([2, 4, 16], n => n < 10)); ++// → false ++console.log(every([], n => n < 10)); ++// → true + ``` + +-The essence of this example lies in grouping the elements of a collection by some aspect of theirs—splitting the array of ancestors into smaller arrays with the ancestors for each century. ++Like the `&&` operator, the `every` method can stop evaluating further elements as soon as it has found one that doesn't match. So the loop-based version can jump out of the loop—with `break` or `return`—as soon as it runs into an element for which the predicate function returns false. If the loop runs to its end without finding such an element, we know that all elements matched and we should return true. + +-During the grouping process, keep an object that associates century names (numbers) with arrays of either person objects or ages. Since we do not know in advance what categories we will find, we'll have to create them on the fly. For each person, after computing their century, we test whether that century was already known. If not, add an array for it. Then add the person (or age) to the array for the proper century. ++To build `every` on top of `some`, we can apply _De Morgan's laws_, which state that `a && b` equals `!(!a || !b)`. This can be generalized to arrays, where all elements in the array match if there is no element in the array that does not match. + +-Finally, a `for`/`in` loop can be used to print the average ages for the individual centuries. ++### Dominant writing direction + +-For bonus points, write a function `groupBy` that abstracts the grouping operation. It should accept as arguments an array and a function that computes the group for an element in the array and returns an object that maps group names to arrays of group members. ++Write a function that computes the dominant writing direction in a string of text. Remember that each script object has a `direction` property that can be `"ltr"` (left-to-right), `"rtl"` (right-to-left), or `"ttb"` (top-to-bottom). + +-### Every and then some +- +-Arrays also come with the standard methods `every` and `some`. Both take a predicate function that, when called with an array element as argument, returns true or false. Just like `&&` returns a true value only when the expressions on both sides are true, `every` returns true only when the predicate returns true for _all_ elements of the array. Similarly, `some` returns true as soon as the predicate returns true for _any_ of the elements. They do not process more elements than necessary—for example, if `some` finds that the predicate holds for the first element of the array, it will not look at the values after that. +- +-Write two functions, `every` and `some`, that behave like these methods, except that they take the array as their first argument rather than being a method. ++The dominant direction is the direction of a majority of the characters that have a script associated with them. The `characterScript` and `countBy` functions defined earlier in the chapter are probably useful here. + + ``` +-// Your code here. ++function dominantDirection(text) { ++ // Your code here. ++} + +-console.log(every([NaN, NaN, NaN], isNaN)); +-// → true +-console.log(every([NaN, NaN, 4], isNaN)); +-// → false +-console.log(some([NaN, 3, 4], isNaN)); +-// → true +-console.log(some([2, 3, 4], isNaN)); +-// → false ++console.log(dominantDirection("Hello!")); ++// → ltr ++console.log(dominantDirection("Hey, مساء الخير")); ++// → rtl + ``` + +-The functions can follow a similar pattern to the [definition](05_higher_order.html#forEach) of `forEach` at the start of the chapter, except that they must return immediately (with the right value) when the predicate function returns false—or true. Don't forget to put another `return` statement after the loop so that the function also returns the correct value when it reaches the end of the array. ++Your solution might look a lot like the first half of the `textScripts` example. You again have to count characters by a criterion based on `characterScript`, and then filter out the part of the result that refers to uninteresting (script-less characters). ++ ++Finding the direction with the highest character count can be done with `reduce`. If it's not clear how, refer back to the example earlier in the chapter, where `reduce` was used to find the script with the most characters.