diff --git a/.gitignore b/.gitignore index f0698f3e4..b21cdbaf7 100644 --- a/.gitignore +++ b/.gitignore @@ -10,11 +10,10 @@ /book.pdf /book_mobile.pdf /html/[012]*.html -/html/js/chapter_info.js -/html/js/[012]*.js -/html/js/acorn_codemirror.js +/html/ejs.js /code/chapter/* -/code/file_server.js +/code/chapter_info.js +/code/file_server.mjs /code/skillsharing.zip /code/solutions/20_3_a_public_space_on_the_web.zip /code/skillsharing/* diff --git a/00_intro.md b/00_intro.md index bafa6ecbb..1d14eef57 100644 --- a/00_intro.md +++ b/00_intro.md @@ -2,151 +2,77 @@ # Introduction -{{quote {author: "Ellen Ullman", title: "Close to the Machine: Technophilia and its Discontents", chapter: true} +{{quote {author: "Ellen Ullman", title: "Close to the Machine: Technophilia and Its Discontents", chapter: true} -We think we are creating the system for our own purposes. We believe -we are making it in our own image... But the computer is not really -like us. It is a projection of a very slim part of ourselves: that -portion devoted to logic, order, rule, and clarity. +We think we are creating the system for our own purposes. We believe we are making it in our own image... But the computer is not really like us. It is a projection of a very slim part of ourselves: that portion devoted to logic, order, rule, and clarity. quote}} -This is a book about instructing ((computer))s. Computers are about as -common as screwdrivers today, but they are quite a bit more complex, -and making them do what you want them to do isn't always easy. +{{figure {url: "img/chapter_picture_00.jpg", alt: "Illustration of a screwdriver next to a circuit board of about the same size", chapter: "framed"}}} -If the task you have for your computer is a common, well-understood -one, such as showing you your email or acting like a calculator, you -can open the appropriate ((application)) and get to work. But for -unique or open-ended tasks, there probably is no application. +This is a book about instructing ((computer))s. Computers are about as common as screwdrivers today, but they are quite a bit more complex, and making them do what you want them to do isn't always easy. -That is where ((programming)) may come in. _Programming_ is the act of -constructing a _program_—a set of precise instructions that tell a -computer what to do. Because computers are dumb, pedantic beasts, -programming is fundamentally tedious and frustrating. +If the task you have for your computer is a common, well-understood one, such as showing you your email or acting like a calculator, you can open the appropriate ((application)) and get to work. But for unique or open-ended tasks, there often is no appropriate application. + +That is where ((programming)) may come in. _Programming_ is the act of constructing a _program_—a set of precise instructions telling a computer what to do. Because computers are dumb, pedantic beasts, programming is fundamentally tedious and frustrating. {{index [programming, "joy of"], speed}} -Fortunately, if you can get over that fact, and maybe even enjoy the rigor -of thinking in terms that dumb machines can deal with, programming can -be very rewarding. It allows you to do things that would take -_forever_ by hand, in seconds. It is a way to make your computer tool -do things that it couldn't do before. And it provides a wonderful -exercise in abstract thinking. - -Most programming is done with ((programming language))s. A _programming -language_ is an artificially constructed language used to instruct -computers. It is interesting that the most effective way we've found -to communicate with a computer borrows so heavily from the way we -communicate with each other. Like human languages, computer languages -allow words and phrases to be combined in new ways, making it possible to -express ever new concepts. +Fortunately, if you can get over that fact—and maybe even enjoy the rigor of thinking in terms that dumb machines can deal with—programming can be rewarding. It allows you to do things in seconds that would take _forever_ by hand. It is a way to make your computer tool do things that it couldn't do before. On top of that, it makes for a wonderful game of puzzle solving and abstract thinking. + +Most programming is done with ((programming language))s. A _programming language_ is an artificially constructed language used to instruct computers. It is interesting that the most effective way we've found to communicate with a computer borrows so heavily from the way we communicate with each other. Like human languages, computer languages allow words and phrases to be combined in new ways, making it possible to express ever new concepts. {{index [JavaScript, "availability of"], "casual computing"}} -At one point language-based interfaces, such as the BASIC and DOS -prompts of the 80s and 90s, were the main method of interacting with -computers. Those have largely been replaced with visual interfaces, -which are easier to learn but offer less freedom. Computer languages -are still there, if you know where to look. One such language, -JavaScript, is built into every modern web ((browser)) and is thus -available on almost every device. +At one point, language-based interfaces, such as the BASIC and DOS prompts of the 1980s and 1990s, were the main method of interacting with computers. For routine computer use, these have largely been replaced with visual interfaces, which are easier to learn but offer less freedom. But if you know where to look, the languages are still there. One of them, _JavaScript_, is built into every modern web ((browser))—and is thus available on almost every device. {{indexsee "web browser", browser}} -This book will try to make you familiar enough with this language to -do useful and amusing things with it. +This book will try to make you familiar enough with this language to do useful and amusing things with it. ## On programming {{index [programming, "difficulty of"]}} -Besides explaining JavaScript, I will also introduce the basic -principles of programming. Programming, it turns out, is hard. The -fundamental rules are simple and clear, but programs built on top of -these rules tend to become complex enough to introduce their own rules -and complexity. You're building your own maze, in a way, and you might -just get lost in it. +Besides explaining JavaScript, I will introduce the basic principles of programming. Programming, it turns out, is hard. The fundamental rules are simple and clear, but programs built on top of these rules tend to become complex enough to introduce their own rules and complexity. You're building your own maze, in a way, and you can easily get lost in it. {{index learning}} -There will be times when reading this book feels terribly frustrating. -If you are new to programming, there will be a lot of new material to -digest. Much of this material will then be _combined_ in ways that -require you to make additional connections. +There will be times when reading this book feels terribly frustrating. If you are new to programming, there will be a lot of new material to digest. Much of this material will then be _combined_ in ways that require you to make additional connections. -It is up to you to make the necessary effort. When you are struggling -to follow the book, do not jump to any conclusions about your own -capabilities. You are fine—you just need to keep at it. Take a break, -reread some material, and make sure you read and understand the -example programs and ((exercises)). Learning is hard work, but -everything you learn is yours, and will make subsequent learning -easier. +It is up to you to make the necessary effort. When you are struggling to follow the book, do not jump to any conclusions about your own capabilities. You are fine—you just need to keep at it. Take a break, reread some material, and make sure you read and understand the example programs and ((exercises)). Learning is hard work, but everything you learn is yours and will make further learning easier. {{quote {author: "Ursula K. Le Guin", title: "The Left Hand of Darkness"} {{index "Le Guin, Ursula K."}} -When action grows unprofitable, gather information; when information -grows unprofitable, sleep. +When action grows unprofitable, gather information; when information grows unprofitable, sleep. quote}} {{index [program, "nature of"], data}} -A program is many things. It is a piece of text typed by a programmer, -it is the directing force that makes the computer do what it does, it -is data in the computer's memory, yet it controls the actions -performed on this same memory. Analogies that try to compare programs -to objects we are familiar with tend to fall short. A superficially -fitting one is that of a machine—lots of separate parts tend to be -involved, and to make the whole thing tick, we have to consider the -ways in which these parts interconnect and contribute to the operation -of the whole. - -A ((computer)) is a physical machine that acts as a host for these immaterial -machines. Computers themselves can do only stupidly straightforward -things. The reason they are so useful is that they do these things at -an incredibly high ((speed)). A program can ingeniously combine an -enormous number of these simple actions in order to do very -complicated things. +A program is many things. It is a piece of text typed by a programmer, it is the directing force that makes the computer do what it does, it is data in the computer's memory, and, at the same time, it controls the actions performed on this memory. Analogies that try to compare programs to familiar objects tend to fall short. A superficially fitting one is to compare a program to a machine—lots of separate parts tend to be involved, and to make the whole thing tick, we have to consider the ways in which these parts interconnect and contribute to the operation of the whole. -{{index [programming, "joy of"]}} +A ((computer)) is a physical machine that acts as a host for these immaterial machines. Computers themselves can do only stupidly straightforward things. The reason they are so useful is that they do these things at an incredibly high ((speed)). A program can ingeniously combine an enormous number of these simple actions to do very complicated things. -A program is a building of thought. It is costless to build, it is -weightless, and it grows easily under our typing hands. +{{index [programming, "joy of"]}} -But without care, a program's size and ((complexity)) will grow out of -control, confusing even the person who created it. Keeping programs -under control is the main problem of programming. When a program -works, it is beautiful. The art of programming is the skill of -controlling complexity. The great program is subdued—made simple in -its complexity. +A program is a building of thought. It is costless to build, it is weightless, and it grows easily under our typing hands. But as a program grows, so does its ((complexity)). The skill of programming is the skill of building programs that don't confuse the programmer. The best programs are those that manage to do something interesting while still being easy to understand. {{index "programming style", "best practices"}} -Some programmers believe that this complexity is best managed by using -only a small set of well-understood techniques in their programs. They -have composed strict rules ("best practices") prescribing the form -programs should have, and carefully stay within their safe little -zone. +Some programmers believe that this complexity is best managed by using only a small set of well-understood techniques in their programs. They have composed strict rules ("best practices") prescribing the form programs should have and carefully stay within their safe little zone. {{index experiment}} -This is not only boring, it is also ineffective. New problems often -require new solutions. The field of programming is young and still -developing rapidly, and is varied enough to have room for wildly -different approaches. There are many terrible mistakes to make in -program design, and you should go ahead and make them so that you -understand them. A sense of what a good program looks like is -developed in practice, not learned from a list of rules. +This is not only boring—it is ineffective. New problems often require new solutions. The field of programming is young and still developing rapidly, and it is varied enough to have room for wildly different approaches. There are many terrible mistakes to make in program design, and you should go ahead and make them at least once so that you understand them. A sense of what a good program looks like is developed with practice, not learned from a list of rules. ## Why language matters {{index "programming language", "machine code", "binary data"}} -In the beginning, at the birth of computing, there were no programming -languages. Programs looked something like this: +In the beginning, at the birth of computing, there were no programming languages. Programs looked something like this: ```{lang: null} 00110001 00000000 00000000 @@ -162,73 +88,47 @@ languages. Programs looked something like this: {{index [programming, "history of"], "punch card", complexity}} -That is a program to add the numbers from 1 to 10 together and print -out the result: `1 + 2 + ... + 10 = 55`. It could run on a simple, -hypothetical machine. To program early computers, it was necessary to -set large arrays of switches in the right position or punch holes in -strips of cardboard and feed them to the computer. You can probably -imagine how tedious and error-prone this procedure was. Even writing -simple programs required much cleverness and discipline. Complex ones -were nearly inconceivable. +This is a program to add the numbers from 1 to 10 together and print the result: `1 + 2 + ... + 10 = 55`. It could run on a simple hypothetical machine. To program early computers, it was necessary to set large arrays of switches in the right position or punch holes in strips of cardboard and feed them to the computer. You can imagine how tedious and error prone this procedure was. Even writing simple programs required much cleverness and discipline. Complex ones were nearly inconceivable. {{index bit, "wizard (mighty)"}} -Of course, manually entering these arcane patterns of bits (the ones -and zeros) did give the programmer a profound sense of being a mighty -wizard. And that has to be worth something in terms of job -satisfaction. +Of course, manually entering these arcane patterns of bits (the ones and zeros) did give the programmer a profound sense of being a mighty wizard. And that has to be worth something in terms of job satisfaction. {{index memory, instruction}} -Each line of the previous program contains a single instruction. It -could be written in English like this: +Each line of the previous program contains a single instruction. It could be written in English like this: 1. Store the number 0 in memory location 0. 2. Store the number 1 in memory location 1. 3. Store the value of memory location 1 in memory location 2. 4. Subtract the number 11 from the value in memory location 2. - 5. If the value in memory location 2 is the number 0, - continue with instruction 9. + 5. If the value in memory location 2 is the number 0, continue with instruction 9. 6. Add the value of memory location 1 to memory location 0. 7. Add the number 1 to the value of memory location 1. 8. Continue with instruction 3. 9. Output the value of memory location 0. -{{index readability, naming, variable}} +{{index readability, naming, binding}} -Although that is already more readable than the soup of bits, it is -still rather obscure. Using names instead of numbers for the -instructions and memory locations helps: +Although that is already more readable than the soup of bits, it is still rather obscure. Using names instead of numbers for the instructions and memory locations helps. -```{lang: "text/plain"} - Set “total” to 0. - Set “count” to 1. +```{lang: "null"} + Set “total” to 0. + Set “count” to 1. [loop] - Set “compare” to “count”. - Subtract 11 from “compare”. - If “compare” is zero, continue at [end]. - Add “count” to “total”. - Add 1 to “count”. - Continue at [loop]. + Set “compare” to “count”. + Subtract 11 from “compare”. + If “compare” is 0, continue at [end]. + Add “count” to “total”. + Add 1 to “count”. + Continue at [loop]. [end] - Output “total”. + Output “total”. ``` {{index loop, jump, "summing example"}} -Can you see how the program works at this point? The first two lines -give two memory locations their starting values: `total` will be used -to build up the result of the computation, and `count` will keep track -of the number that we are currently looking at. The lines using -`compare` are probably the weirdest ones. The program wants to see -whether `count` is equal to 11 in order to decide whether it can stop -running. Because our hypothetical machine is rather primitive, it can -only test whether a number is zero and make a decision based -on that. So it uses the memory location labeled `compare` to compute -the value of `count - 11` and makes a decision based on that value. -The next two lines add the value of `count` to the result and -increment `count` by 1 every time the program has decided that `count` -is not 11 yet. +Can you see how the program works at this point? The first two lines give two memory locations their starting values: `total` will be used to build up the result of the computation, and `count` will keep track of the number that we are currently looking at. The lines using `compare` are probably the most confusing ones. The program wants to see whether `count` is equal to 11 to decide whether it can stop running. Because our hypothetical machine is rather primitive, it can test only whether a number is zero and make a decision based on that. It therefore uses the memory location labeled `compare` to compute the value of `count - 11` and makes a decision based on that value. The next two lines add the value of `count` to the result and increment `count` by 1 every time the program decides that `count` is not 11 yet. Here is the same program in JavaScript: @@ -242,29 +142,17 @@ console.log(total); // → 55 ``` -{{index "while loop", loop, "curly braces"}} +{{index "while loop", loop, [braces, block]}} -This version gives us a few more improvements. Most importantly, there -is no need to specify the way we want the program to jump back and -forth anymore. The `while` construct takes care of that. It continues -executing the block (wrapped in braces) below it as long as the -condition it was given holds. That condition is `count <= 10`, which -means “_count_ is less than or equal to 10”. We no longer have to -create a temporary value and compare that to zero, which was just an -uninteresting detail. Part of the power of programming languages is -that they can take care of uninteresting details for us. +This version gives us a few more improvements. Most importantly, there is no need to specify the way we want the program to jump back and forth anymore—the `while` construct takes care of that. It continues executing the block (wrapped in braces) below it as long as the condition it was given holds. That condition is `count <= 10`, which means “the count is less than or equal to 10”. We no longer have to create a temporary value and compare that to zero, which was just an uninteresting detail. Part of the power of programming languages is that they can take care of uninteresting details for us. {{index "console.log"}} -At the end of the program, after the `while` construct has finished, -the `console.log` operation is used to write out the result. +At the end of the program, after the `while` construct has finished, the `console.log` operation is used to write out the result. {{index "sum function", "range function", abstraction, function}} -Finally, here is what the program could look like if we happened to -have the convenient operations `range` and `sum` available, which -respectively create a ((collection)) of numbers within a range and -compute the sum of a collection of numbers: +Finally, here is what the program could look like if we happened to have the convenient operations `range` and `sum` available, which respectively create a ((collection)) of numbers within a range and compute the sum of a collection of numbers: ```{startCode: true} console.log(sum(range(1, 10))); @@ -273,21 +161,11 @@ console.log(sum(range(1, 10))); {{index readability}} -The moral of this story is that the same program can be expressed in -both long and short, unreadable and readable ways. The first version of the -program was extremely obscure, whereas this last one is almost -English: `log` the `sum` of the `range` of numbers from 1 to 10. (We -will see in [later chapters](data) how to define operations like `sum` -and `range`.) +The moral of this story is that the same program can be expressed in both long and short, unreadable and readable ways. The first version of the program was extremely obscure, whereas this last one is almost English: `log` the `sum` of the `range` of numbers from 1 to 10. (We will see in [later chapters](data) how to define operations like `sum` and `range`.) {{index ["programming language", "power of"], composability}} -A good programming language helps the programmer by allowing them to -talk about the actions that the computer has to perform on a higher -level. It helps omit details, provides convenient building blocks -(such as `while` and `console.log`), allows you to define your own -building blocks (such as `sum` and `range`), and makes those blocks -easy to compose. +A good programming language helps the programmer by allowing them to talk about the actions that the computer has to perform on a higher level. It helps omit details, provides convenient building blocks (such as `while` and `console.log`), allows you to define your own building blocks (such as `sum` and `range`), and makes those blocks easy to compose. ## What is JavaScript? @@ -297,111 +175,47 @@ easy to compose. {{indexsee Web, "World Wide Web"}} -JavaScript was introduced in 1995 as a way to add programs to web -pages in the Netscape Navigator browser. The language has since been -adopted by all other major graphical web browsers. It has made modern -web applications possible—applications with which you can interact -directly without doing a page reload for every action. JavaScript is also -used in more traditional websites to provide various forms of -interactivity and cleverness. +JavaScript was introduced in 1995 as a way to add programs to web pages in the Netscape Navigator browser. The language has since been adopted by all other major graphical web browsers. It has made modern web applications possible—that is, applications with which you can interact directly without doing a page reload for every action. JavaScript is also used in more traditional websites to provide various forms of interactivity and cleverness. {{index Java, naming}} -It is important to note that JavaScript has almost nothing to do with -the programming language named Java. The similar name was inspired by -marketing considerations rather than good judgment. When JavaScript -was being introduced, the Java language was being heavily marketed and -was gaining popularity. Someone thought it was a good idea to try to -ride along on this success. Now we are stuck with the name. +It is important to note that JavaScript has almost nothing to do with the programming language named Java. The similar name was inspired by marketing considerations rather than good judgment. When JavaScript was being introduced, the Java language was being heavily marketed and was gaining popularity. Someone thought it was a good idea to try to ride along on this success. Now we are stuck with the name. {{index ECMAScript, compatibility}} -After its adoption outside of Netscape, a ((standard)) document was -written to describe the way the JavaScript language should work, so -that the various pieces of software that claimed to support JavaScript -were actually talking about the same language. This is called the -ECMAScript standard, after the Ecma International organization that -did the standardization. In practice, the terms ECMAScript and -JavaScript can be used interchangeably—they are two names for the same -language. +After its adoption outside of Netscape, a ((standard)) document was written to describe the way the JavaScript language should work so that the various pieces of software that claimed to support JavaScript could make sure they actually provided the same language. This is called the ECMAScript standard, after the Ecma International organization that conducted the standardization. In practice, the terms ECMAScript and JavaScript can be used interchangeably—they are two names for the same language. {{index [JavaScript, "weaknesses of"], debugging}} -There are those who will say _terrible_ things about JavaScript. Many -of these things are true. When I was required to write something in -JavaScript for the first time, I quickly came to despise it. It would -accept almost anything I typed but interpret it in a way that was -completely different from what I meant. This had a lot to do with the -fact that I did not have a clue what I was doing, of course, but there -is a real issue here: JavaScript is ridiculously liberal in what it -allows. The idea behind this design was that it would make programming -in JavaScript easier for beginners. In actuality, it mostly makes -finding problems in your programs harder because the system will not -point them out to you. +There are those who will say _terrible_ things about JavaScript. Many of these things are true. When I was required to write something in JavaScript for the first time, I quickly came to despise it. It would accept almost anything I typed but interpret it in a way that was completely different from what I meant. This had a lot to do with the fact that I did not have a clue what I was doing, of course, but there is a real issue here: JavaScript is ridiculously liberal in what it allows. The idea behind this design was that it would make programming in JavaScript easier for beginners. In actuality, it mostly makes finding problems in your programs harder because the system will not point them out to you. {{index [JavaScript, "flexibility of"], flexibility}} -This flexibility also has its advantages, though. It leaves space for -a lot of techniques that are impossible in more rigid languages, and -as you will see (for example in [Chapter ?](modules)), it can be used -to overcome some of JavaScript's shortcomings. After ((learning)) the -language properly and working with it for a while, I have learned to -actually _like_ JavaScript. +This flexibility also has its advantages, though. It leaves room for techniques that are impossible in more rigid languages and makes for a pleasant, informal style of programming. After ((learning)) the language properly and working with it for a while, I have come to actually _like_ JavaScript. {{index future, [JavaScript, "versions of"], ECMAScript, "ECMAScript 6"}} -There have been several versions of JavaScript. ECMAScript version 3 -was the widely supported version in the time of JavaScript's ascent to -dominance, roughly between 2000 and 2010. During this time, work was -underway on an ambitious version 4, which planned a number of radical -improvements and extensions to the language. Changing a living, widely -used language in such a radical way turned out to be politically -difficult, and work on the version 4 was abandoned in 2008, leading to -a much less ambitious version 5, which only made some uncontroversial -improvements, coming out in 2009. Then in 2015 version 6 came out, a -major update that included some of the ideas planned for version 4. -Since then we've had new, small updates every year. - -The fact that the language is evolving means that browsers have to -constantly keep up, and if you're using an older one, it may not -support every feature. The language designers are careful to not make -any changes that could break existing programs, so new browsers can -still run old programs. In this book, I'm using the 2017 version of -JavaScript. +There have been several versions of JavaScript. ECMAScript version 3 was the widely supported version during JavaScript's ascent to dominance, roughly between 2000 and 2010. During this time, work was underway on an ambitious version 4, which planned a number of radical improvements and extensions to the language. Changing a living, widely used language in such a radical way turned out to be politically difficult, and work on version 4 was abandoned in 2008. A much less ambitious version 5, which made only some uncontroversial improvements, came out in 2009. In 2015, version 6 came out, a major update that included some of the ideas planned for version 4. Since then we've had new, small updates every year. + +The fact that JavaScript is evolving means that browsers have to constantly keep up. If you're using an older browser, it may not support every feature. The language designers are careful to not make any changes that could break existing programs, so new browsers can still run old programs. In this book, I'm using the 2024 version of JavaScript. {{index [JavaScript, "uses of"]}} -Web browsers are not the only platforms on which JavaScript is used. -Some databases, such as MongoDB and CouchDB, use JavaScript as their -scripting and query language. Several platforms for desktop and server -programming, most notably the ((Node.js)) project (the subject of -[Chapter ?](node)), provide an environment for programming JavaScript -outside of the browser. +Web browsers are not the only platforms on which JavaScript is used. Some databases, such as MongoDB and CouchDB, use JavaScript as their scripting and query language. Several platforms for desktop and server programming, most notably the ((Node.js)) project (the subject of [Chapter ?](node)), provide an environment for programming JavaScript outside of the browser. ## Code, and what to do with it {{index "reading code", "writing code"}} -_Code_ is the text that makes up programs. Most chapters in this book -contain quite a lot of code. I believe reading code and writing ((code)) -are indispensable parts of ((learning)) to program. Try to not just -glance over the examples—read them attentively and understand them. -This may be slow and confusing at first, but I promise that you'll -quickly get the hang of it. The same goes for the ((exercises)). Don't -assume you understand them until you've actually written a working -solution. +_Code_ is the text that makes up programs. Most chapters in this book contain quite a lot of code. I believe reading code and writing ((code)) are indispensable parts of ((learning)) to program. Try to not just glance over the examples—read them attentively and understand them. This may be slow and confusing at first, but I promise that you'll quickly get the hang of it. The same goes for the ((exercises)). Don't assume you understand them until you've actually written a working solution. {{index interpretation}} -I recommend you try your solutions to exercises in an actual -JavaScript interpreter. That way, you'll get immediate feedback on -whether what you are doing is working, and, I hope, you'll be tempted -to ((experiment)) and go beyond the exercises. +I recommend you try your solutions to exercises in an actual JavaScript interpreter. That way, you'll get immediate feedback on whether what you are doing is working, and, I hope, you'll be tempted to ((experiment)) and go beyond the exercises. {{if interactive -When reading this book in your browser, you can edit (and run) all -example programs by clicking them. +When reading this book in your browser, you can edit (and run) all example programs by clicking them. if}} @@ -409,76 +223,29 @@ if}} {{index download, sandbox, "running code"}} -The easiest way to run the example code in the book, and to experiment -with it, is to look it up in the online version of the book at -[_eloquentjavascript.net_](https://eloquentjavascript.net/). There, -you can click any code example to edit and run it and to see the -output it produces. To work on the exercises, go to -[_eloquentjavascript.net/code_](https://eloquentjavascript.net/code), -which provides starting code for each coding exercise and allows you -to look at the solutions. +The easiest way to run the example code in the book—and to experiment with it—is to look it up in the online version of the book at [_https://eloquentjavascript.net_](https://eloquentjavascript.net/). There, you can click any code example to edit and run it and to see the output it produces. To work on the exercises, go to [_https://eloquentjavascript.net/code_](https://eloquentjavascript.net/code), which provides starting code for each coding exercise and allows you to look at the solutions. if}} {{index "developer tools", "JavaScript console"}} -If you want to run the programs defined in this book outside of the -book's website, some care will be required. Many examples stand on their -own and should work in any JavaScript environment. But code in later -chapters is often written for a specific environment (the browser or -Node.js) and can run only there. In addition, many chapters define -bigger programs, and the pieces of code that appear in them depend on -each other or on external files. The -[sandbox](https://eloquentjavascript.net/code) on the website provides -links to Zip files containing all the scripts and data files -necessary to run the code for a given chapter. +Running the programs defined in this book outside of the book's website requires some care. Many examples stand on their own and should work in any JavaScript environment. But code in later chapters is often written for a specific environment (the browser or Node.js) and can run only there. In addition, many chapters define bigger programs, and the pieces of code that appear in them depend on each other or on external files. The [sandbox](https://eloquentjavascript.net/code) on the website provides links to ZIP files containing all the scripts and data files necessary to run the code for a given chapter. ## Overview of this book -This book contains roughly three parts. The first 12 chapters discuss -the JavaScript language itself. The next seven chapters are about web -((browsers)) and the way JavaScript is used to program them. Finally, -two chapters are devoted to ((Node.js)), another environment to -program JavaScript in. - -Throughout the book, there are five _project chapters_, which describe -larger example programs to give you a taste of actual programming. In -order of appearance, we will work through building a [delivery -robot](robot), a [programming language](language), a [platform -game](game), a [pixel paint program](paint), and a [dynamic -website](skillsharing). - -The language part of the book starts with four chapters that introduce -the basic structure of the JavaScript language. They introduce -[control structures](program_structure) (such as the `while` word you -saw in this introduction), [functions](functions) (writing your own -building blocks), and [data structures](data). After these, you will -be able to write basic programs. Next, Chapters [?](higher_order) and -[?](object) introduce techniques to use functions and objects to write -more _abstract_ code and keep complexity under control. - -After a [first project chapter](robot), the language part of the book -continues with chapters on [error handling and bug fixing](error), -[regular expressions](regexp) (an important tool for working with -text), [modularity](modules) (another defense against complexity), and -[asynchronous programming](async) (dealing with events that take -time). The [second project chapter](language) concludes the first part -of the book. - -The second part, Chapters [?](browser) to [?](paint), describes the -tools that browser JavaScript has access to. You'll learn to display -things on the screen (Chapters [?](dom) and [?](canvas)), respond to -user input ([Chapter ?](event)), and communicate over the network -([Chapter ?](http)). There are again two project chapters in this -part. - -After that, [Chapter ?](node) describes Node.js, and [Chapter -?](skillsharing) builds a small website using that tool. +This book contains roughly three parts. The first 12 chapters discuss the JavaScript language. The next seven chapters are about web ((browsers)) and the way JavaScript is used to program them. Finally, two chapters are devoted to ((Node.js)), another environment to program JavaScript in. There are five _project chapters_ in the book that describe larger example programs to give you a taste of actual programming. + +The language part of the book starts with four chapters that introduce the basic structure of the JavaScript language. They discuss [control structures](program_structure) (such as the `while` word you saw in this introduction), [functions](functions) (writing your own building blocks), and [data structures](data). After these, you will be able to write basic programs. Next, Chapters [?](higher_order) and [?](object) introduce techniques to use functions and objects to write more _abstract_ code and keep complexity under control. + +After a [first project chapter](robot) that builds a crude delivery robot, the language part of the book continues with chapters on [error handling and bug fixing](error), [regular expressions](regexp) (an important tool for working with text), [modularity](modules) (another defense against complexity), and [asynchronous programming](async) (dealing with events that take time). The [second project chapter](language), where we implement a programming language, concludes the first part of the book. + +The second part of the book, Chapters [?](browser) to [?](paint), describes the tools that browser JavaScript has access to. You'll learn to display things on the screen (Chapters [?](dom) and [?](canvas)), respond to user input ([Chapter ?](event)), and communicate over the network ([Chapter ?](http)). There are again two project chapters in this part: building a [platform game](game) and a [pixel paint program](paint). + +[Chapter ?](node) describes Node.js, and [Chapter ?](skillsharing) builds a small website using that tool. {{if commercial -Finally, [Chapter ?](fast) describes some of the considerations that -come up when optimizing JavaScript programs for speed. +Finally, [Chapter ?](fast) describes some of the considerations that come up when optimizing JavaScript programs for speed. if}} @@ -486,10 +253,7 @@ if}} {{index "factorial function"}} -In this book, text written in a `monospaced` font will represent -elements of programs—sometimes they are self-sufficient fragments, and -sometimes they just refer to part of a nearby program. Programs (of -which you have already seen a few), are written as follows: +In this book, text written in a `monospaced` font will represent elements of programs. Sometimes these are self-sufficient fragments, and sometimes they just refer to part of a nearby program. Programs (of which you have already seen a few) are written as follows: ``` function factorial(n) { @@ -503,9 +267,7 @@ function factorial(n) { {{index "console.log"}} -Sometimes, in order to show the output that a program produces, the -expected output is written after it, with two slashes and an arrow in -front. +Sometimes, to show the output that a program produces, the expected output is written after it, with two slashes and an arrow in front. ``` console.log(factorial(8)); diff --git a/01_values.md b/01_values.md index 1403e3001..bbf9de95a 100644 --- a/01_values.md +++ b/01_values.md @@ -4,86 +4,52 @@ {{quote {author: "Master Yuan-Ma", title: "The Book of Programming", chapter: true} -Below the surface of the machine, the program moves. Without effort, -it expands and contracts. In great harmony, electrons scatter and -regroup. The forms on the monitor are but ripples on the water. The -essence stays invisibly below. +Below the surface of the machine, the program moves. Without effort, it expands and contracts. In great harmony, electrons scatter and regroup. The forms on the monitor are but ripples on the water. The essence stays invisibly below. quote}} {{index "Yuan-Ma", "Book of Programming"}} -{{figure {url: "img/chapter_picture_1.jpg", alt: "Picture of a sea of bits", chapter: framed}}} +{{figure {url: "img/chapter_picture_1.jpg", alt: "Illustration of a sea of dark and bright dots (bits) with islands in it", chapter: framed}}} {{index "binary data", data, bit, memory}} -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. +In 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. {{index CD, signal}} -_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. -{{index "binary number", radix, "decimal number"}} +{{index "binary number", "decimal number"}} -For example, we can express the number 13 in bits. It works the same -way as a decimal number, but instead of 10 different ((digit))s, 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. This works the same way as a decimal number, but instead of 10 different ((digit))s, we 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: ```{lang: null} 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, or 13. +That's the binary number 00001101. Its nonzero digits stand for 8, 4, and 1, and add up to 13. ## Values -{{index memory, "volatile data storage", "hard drive"}} +{{index [memory, organization], "volatile data storage", "hard drive"}} -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. +Imagine a sea of bits—an ocean of them. A typical modern computer has more than 100 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. -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 -_((value))s_. 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, we separate them into chunks that represent pieces of information. In a JavaScript environment, those chunks are called _((value))s_. 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. {{index "garbage collection"}} -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. +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 _whoosh_, you have it. Of course, values are not really created from thin air. Each one has to be stored somewhere, and if you want to use a gigantic number of them at the same time, you might run out of computer 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. +The remainder of this chapter introduces the atomic elements of JavaScript programs, that is, the simple value types and the operators that can act on such values. ## Numbers -{{index syntax, number, [number, notation]}} +{{index [syntax, number], number, [number, notation]}} -Values of the _number_ type are, unsurprisingly, numeric values. In a -JavaScript program, they are written as follows: +Values of the _number_ type are, unsurprisingly, numeric values. In a JavaScript program, they are written as follows: ``` 13 @@ -91,40 +57,21 @@ JavaScript program, they are written as follows: {{index "binary number"}} -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. +Using that in a program will cause the bit pattern for the number 13 to come into existence inside the computer's memory. {{index [number, representation], bit}} -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 ((digit))s, the amount of -numbers that can be represented is 10^N^. Similarly, given 64 binary -digits, you can represent 2^64^ different numbers, which is about 18 -quintillion (an 18 with 18 zeros after it). That's a lot. +JavaScript uses a fixed number of bits, 64 of them, to store a single number value. There are only so many patterns you can make with 64 bits, which limits the number of different numbers that can be represented. With _N_ decimal ((digit))s, you can represent 10^N^ numbers. Similarly, given 64 binary digits, you can represent 2^64^ different numbers, which is about 18 quintillion (an 18 with 18 zeros after it). That's a lot. -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. +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 number 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. -{{index sign, "floating-point number", "fractional number", "sign bit"}} +{{index sign, "floating-point number", "sign bit"}} -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 less than 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 representing nonwhole numbers. 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. -{{index [number, notation]}} +{{index [number, notation], "fractional number"}} -Fractional numbers are written by using a dot: +Fractional numbers are written using a dot: ``` 9.81 @@ -132,114 +79,69 @@ Fractional numbers are written by using a dot: {{index exponent, "scientific notation", [number, notation]}} -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: +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 ``` -That is 2.998 × 10^8^ = 299,800,000. +That's 2.998 × 10^8^ = 299,800,000. {{index pi, [number, "precision of"], "floating-point number"}} -Calculations with whole numbers (also called _((integer))s_) smaller -than the aforementioned 9 quadrillion are guaranteed to always be -precise. Unfortunately, calculations with fractional numbers are -generally not. Just as π (pi) cannot be precisely expressed by a -finite number of decimal digits, many numbers lose some precision when -only 64 bits are available to store them. This is a shame, but it -causes practical problems only in specific situations. The important -thing is to be aware of it and treat fractional digital numbers as -approximations, not as precise values. +Calculations with whole numbers (also called _((integer))s_) that are smaller than the aforementioned 9 quadrillion are guaranteed to always be precise. Unfortunately, calculations with fractional numbers are generally not. Just as π (pi) cannot be precisely expressed by a finite number of decimal digits, many numbers lose some precision when only 64 bits are available to store them. This is a shame, but it causes practical problems only in specific situations. The important thing is to be aware of it and treat fractional digital numbers as approximations, not as precise values. ### Arithmetic -{{index syntax, operator, "binary operator", arithmetic, addition, multiplication}} +{{index [syntax, operator], operator, "binary operator", arithmetic, addition, multiplication}} -The main thing to do with numbers is arithmetic. Arithmetic operations -such as addition or multiplication take two number values and produce -a new number from them. Here is what they look like in JavaScript: +The main thing to do with numbers is arithmetic. Arithmetic operations such as addition or multiplication take two number values and produce a new number from them. Here is what they look like in JavaScript: -``` +```{meta: "expr"} 100 + 4 * 11 ``` {{index [operator, application], asterisk, "plus character", "* operator", "+ operator"}} -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. +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. {{index grouping, parentheses, precedence}} -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: +Does this 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. As in mathematics, you can change this by wrapping the addition in parentheses. -``` +```{meta: "expr"} (100 + 4) * 11 ``` -{{index "dash character", "slash character", division, subtraction, minus, "- operator", "/ operator"}} +{{index "hyphen character", "slash character", division, subtraction, minus, "- operator", "/ operator"}} -For subtraction, there is the `-` operator, and division can be done -with the `/` operator. +For subtraction, there is the `-` operator. Division can be done with the `/` operator. -When operators appear together without parentheses, the order in which -they are applied is determined by the _((precedence))_ of the -operators. The example shows that multiplication comes before -addition. The `/` operator has the same precedence as `*`. Likewise -for `+` and `-`. When multiple operators with the same precedence -appear next to each other, as in `1 - 2 + 1`, they are applied left to -right: `(1 - 2) + 1`. +When operators appear together without parentheses, the order in which they are applied is determined by the _((precedence))_ of the operators. The example shows that multiplication comes before addition. The `/` operator has the same precedence as `*`. Likewise, `+` and `-` have the same precedence. When multiple operators with the same precedence appear next to each other, as in `1 - 2 + 1`, they are applied left to right: `(1 - 2) + 1`. -These rules of precedence are not something you should worry about. -When in doubt, just add parentheses. +Don't worry too much about these precedence rules. When in doubt, just add parentheses. {{index "modulo operator", division, "remainder operator", "% operator"}} -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_. +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`. The remainder operator's precedence is the same as that of multiplication and division. You'll also often see this operator referred to as _modulo_. ### Special numbers -{{index [number, "special values"]}} - -There are three special values in JavaScript that are considered -numbers but don't behave like normal numbers. - -{{index infinity}} +{{index [number, "special values"], infinity}} -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`. +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, though. It isn't mathematically sound, and it will quickly lead to the next special number: `NaN`. {{index NaN, "not a number", "division by zero"}} -`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. +`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 {{indexsee "grave accent", backtick}} -{{index syntax, text, character, [string, notation], "single-quote character", "double-quote character", "quotation mark", backtick}} +{{index [syntax, string], text, character, [string, notation], "single-quote character", "double-quote character", "quotation mark", backtick}} -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. ``` `Down on the sea` @@ -247,46 +149,28 @@ represent text. They are written by enclosing their content in quotes: 'Float on the ocean' ``` -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. +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. {{index "line break", "newline character"}} -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 -(`` ` ``). +You can put almost anything between quotes to have JavaScript 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, since they will look like the end of the string. _Newlines_ (the characters you get when you press [enter]{keyname}) can be included only when the string is quoted with backticks (`` ` ``). -{{index [escaping, "in strings"], "backslash character"}} +{{index [escaping, "in strings"], ["backslash character", "in strings"]}} -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: +To make it possible to include such characters in a string, the following notation is used: a backslash (`\`) inside quoted text 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: ``` "This is the first line\nAnd this is the second" ``` -The actual text contained is this: +This is the actual text in that string: ```{lang: null} 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\"." @@ -296,62 +180,37 @@ character is written like `"`\n`"`._" can be expressed: {{index [string, representation], Unicode, character}} -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. +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. {{index "UTF-16", emoji}} -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^16^ 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 -?](higher_order#code_units). +There's a complication though: JavaScript's representation uses 16 bits per string element, which can describe up to 2^16^ different characters. However, 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 ?](higher_order#code_units). {{index "+ operator", concatenation}} -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"`: +Strings cannot be divided, multiplied, or subtracted. The `+` operator _can_ be used on them, not to add, but to _concatenate_—to glue two strings together. The following line will produce the string `"concatenate"`: -``` +```{meta: "expr"} "con" + "cat" + "e" + "nate" ``` -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 ?](data#methods). +String values have a number of associated functions (_methods_) that can be used to perform other operations on them. I'll say more about these in [Chapter ?](data#methods). {{index interpolation, backtick}} -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. +Strings written with single or double quotes behave very much the same—the only difference lies 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. -``` +```{meta: "expr"} `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_". +When you write something inside `${}` in a template literal, its result will be computed, converted to a string, and included at that position. This example produces the string `"half of 100 is 50"`. ## Unary operators {{index operator, "typeof operator", type}} -Not all operators are symbols. Some are written as words. One example -is the `typeof` operator, which produces a string value naming the -type of the value you give it. +Not all operators are symbols. Some are written as words. One example is the `typeof` operator, which produces a string value naming the type of the value you give it. ``` console.log(typeof 4.5) @@ -364,17 +223,11 @@ console.log(typeof "x") {{id "console.log"}} -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](program_structure). +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](program_structure).) {{index negation, "- operator", "binary operator", "unary operator"}} -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. +The other operators shown so far in this chapter 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. ``` console.log(- (10 - 2)) @@ -385,10 +238,7 @@ console.log(- (10 - 2)) {{index Boolean, operator, true, false, bit}} -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. +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, written as those words. ### Comparison @@ -405,10 +255,7 @@ console.log(3 < 2) {{index [comparison, "of numbers"], "> operator", "< operator", "greater than", "less than"}} -The `>` and `<` signs are the traditional symbols for "is greater -than" and "is less than", respectively. They are binary operators. -Applying them results in a Boolean value that indicates whether they -hold true in this case. +The `>` and `<` signs are the traditional symbols for "is greater than" and "is less than", respectively. They are binary operators. Applying them results in a Boolean value that indicates whether they hold true in this case. Strings can be compared in the same way. @@ -419,51 +266,39 @@ console.log("Aardvark" < "Zoroaster") {{index [comparison, "of strings"]}} -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. +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. {{index equality, ">= operator", "<= operator", "== operator", "!= operator"}} -Other similar operators are `>=` (greater than or equal to), `<=` -(less than or equal to), `==` (equal to), and `!=` (not equal to). +Other similar operators are `>=` (greater than or equal to), `<=` (less than or equal to), `==` (equal to), and `!=` (not equal to). ``` -console.log("Itchy" != "Scratchy") +console.log("Garnet" != "Ruby") // → true -console.log("Apple" == "Orange") +console.log("Pearl" == "Amethyst") // → false ``` {{index [comparison, "of NaN"], NaN}} -There is only one value in JavaScript that is not equal to itself, and -that is `NaN` ("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) // → false ``` -`NaN` is supposed to denote the result of a nonsensical computation, -and as such, it isn't equal to the result of any _other_ nonsensical -computations. +`NaN` is supposed to denote the result of a nonsensical computation, and as such, it isn't equal to the result of any _other_ nonsensical computations. ### Logical operators {{index reasoning, "logical operators"}} -There are also some operations that can be applied to Boolean values -themselves. JavaScript supports three logical operators: _and_, _or_, -and _not_. These can be used to "reason" about Booleans. +There are also some operations that can be applied to Boolean values themselves. JavaScript supports three logical operators: _and_, _or_, and _not_. These can be used to "reason" about Booleans. {{index "&& operator", "logical and"}} -The `&&` operator represents logical _and_. It is a binary operator, -and its result is true only if both the values given to it are true. +The `&&` operator represents logical _and_. It is a binary operator, and its result is true only if both the values given to it are true. ``` console.log(true && false) @@ -474,8 +309,7 @@ console.log(true && true) {{index "|| operator", "logical or"}} -The `||` operator denotes logical _or_. It produces true if either of -the values given to it is true. +The `||` operator denotes logical _or_. It produces true if either of the values given to it is true. ``` console.log(false || true) @@ -486,29 +320,19 @@ console.log(false || false) {{index negation, "! operator"}} -_Not_ is written as an exclamation mark (`!`). It is a unary operator -that flips the value given to it—`!true` produces `false` and `!false` -gives `true`. +_Not_ is written as an exclamation mark (`!`). It is a unary operator that flips the value given to it—`!true` produces `false` and `!false` gives `true`. {{index precedence}} -When mixing these Boolean operators with arithmetic and other -operators, it is not always obvious when parentheses are needed. In -practice, you can usually get by with knowing that of the operators we -have seen so far, `||` has the lowest precedence, then comes `&&`, -then the comparison operators (`>`, `==`, and so on), and then the -rest. This order has been chosen such that, in typical expressions -like the following one, as few parentheses as possible are necessary: +When mixing these Boolean operators with arithmetic and other operators, it is not always obvious when parentheses are needed. In practice, you can usually get by with knowing that of the operators we have seen so far, `||` has the lowest precedence, then comes `&&`, then the comparison operators (`>`, `==`, and so on), and then the rest. This order has been chosen such that, in typical expressions like the following one, as few parentheses as possible are necessary: -``` +```{meta: "expr"} 1 + 1 == 2 && 10 * 10 > 50 ``` {{index "conditional execution", "ternary operator", "?: operator", "conditional operator", "colon character", "question mark"}} -The last logical operator I will discuss is not unary, not binary, but -_ternary_, operating on three values. It is written with a question -mark and a colon, like this: +The last logical operator we will look at is not unary, not binary, but _ternary_, operating on three values. It is written with a question mark and a colon, like this: ``` console.log(true ? 1 : 2); @@ -517,36 +341,23 @@ 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, it chooses the -middle value, and when it is false, the value on the right. +This one is called the _conditional_ operator (or sometimes just _the ternary operator_ since it is the only such operator in the language). The operator uses the value to the left of the question mark to decide which of the two other values to "pick". If you write `a ? b : c`, the result will be `b` when `a` is true and `c` otherwise. ## Empty values {{index undefined, null}} -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. +Many operations in the language that don't produce a meaningful value 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 mostly interchangeable. +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 cases where you actually have to concern yourself with these values, I recommend treating them as mostly interchangeable. ## Automatic type conversion {{index NaN, "type coercion"}} -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](intro), 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) @@ -563,33 +374,15 @@ console.log(false == 0) {{index "+ operator", arithmetic, "* operator", "- operator"}} -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 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). {{index "type coercion", [number, "conversion to"]}} -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 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. {{index null, undefined, [comparison, "of undefined values"], "== operator"}} -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`. +When comparing values of the same type using the `==` operator, 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`. ``` console.log(null == undefined); @@ -598,43 +391,23 @@ console.log(null == 0); // → false ``` -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. +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. {{index "type coercion", [Boolean, "conversion to"], "=== operator", "!== operator", comparison}} -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. +What if you want to test whether something refers to the precise value `false`? Expressions like `0 == false` and `"" == false` are also true because of automatic type conversion. When you do _not_ want any 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. Thus `"" === 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 {{index "type coercion", [Boolean, "conversion to"], operator}} -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 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. {{index "|| operator"}} -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. +The `||` operator, for example, will return the value to its left when that value 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") @@ -645,44 +418,35 @@ console.log("Agnes" || "user") {{index "default value"}} -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. +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 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. That means `0 || -1` produces `-1`, and `"" || "!?"` yields `"!?"`. + +{{index "?? operator", null, undefined}} + +The `??` operator resembles `||` but returns the value on the right only if the one on the left is `null` or `undefined`, not if it is some other value that can be converted to `false`. Often, this is preferable to the behavior of `||`. + +``` +console.log(0 || 100); +// → 100 +console.log(0 ?? 100); +// → 0 +console.log(null ?? 100); +// → 100 +``` {{index "&& operator"}} -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. +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 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))_. +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))_. {{index "ternary operator", "?: operator", "conditional operator"}} -The conditional operator works in a similar way. Of the second and -third value, only the one that is selected is evaluated. +The conditional operator works in a similar way. Of the second and third values, only the one that is selected is evaluated. ## Summary -We looked at four types of JavaScript values in this chapter: numbers, -strings, Booleans, and undefined values. - -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](program_structure) will start tying -these expressions together into basic programs. +We looked at four types of JavaScript values in this chapter: numbers, strings, Booleans, and undefined values. 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](program_structure) will start tying these expressions together into basic programs. diff --git a/02_program_structure.md b/02_program_structure.md index 5294165a0..7f9db00e2 100644 --- a/02_program_structure.md +++ b/02_program_structure.md @@ -2,94 +2,55 @@ {{quote {author: "_why", title: "Why's (Poignant) Guide to Ruby", chapter: true} -And my heart glows bright red under my filmy, translucent skin and -they have to administer 10cc of JavaScript to get me to come back. (I -respond well to toxins in the blood.) Man, that stuff will kick the -peaches right out your gills! +And my heart glows bright red under my filmy, translucent skin and they have to administer 10cc of JavaScript to get me to come back. (I respond well to toxins in the blood.) Man, that stuff will kick the peaches right out your gills! quote}} {{index why, "Poignant Guide"}} -{{figure {url: "img/chapter_picture_2.jpg", alt: "Picture of tentacles holding objects", chapter: framed}}} +{{figure {url: "img/chapter_picture_2.jpg", alt: "Illustration showing a number of tentacles holding chess pieces", chapter: framed}}} -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. +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 meaningful prose. ## Expressions and statements -{{index grammar, syntax, [code, "structure of"], grammar, [JavaScript, syntax]}} +{{index grammar, [syntax, expression], [code, "structure of"], grammar, [JavaScript, syntax]}} -In [Chapter ?](values), 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. +In [Chapter ?](values), 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. That's what we'll cover in this chapter. -{{index "literal expression"}} +{{index "literal expression", [parentheses, expression]}} -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. +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. {{index [nesting, "of expressions"], "human language"}} -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. +This shows part of the beauty of a language-based interface. Expressions can contain other expressions in a way similar to how 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. {{index statement, semicolon, program}} -If an expression corresponds to a sentence fragment, a JavaScript -_statement_ corresponds to a full sentence. A program is 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. -{{index syntax}} +{{index [syntax, statement]}} -The simplest kind of statement is an expression with a semicolon after -it. This is a program: +The simplest kind of statement is an expression with a semicolon after it. This is a program: ``` 1; !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 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 effect))s_. 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. +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. However, a ((statement)) stands on its own, so if it doesn't affect the world, it's useless. It may display something on the screen, as with `console.log`, or change the state of the machine in a way that will affect the statements that come after it. These changes are called _((side effect))s_. 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. {{index "programming style", "automatic semicolon insertion", semicolon}} -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. +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. ## Bindings {{indexsee variable, binding}} -{{index syntax, [binding, definition], "side effect", memory}} +{{index [syntax, statement], [binding, definition], "side effect", [memory, organization], [state, in binding]}} -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_: +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 must be used immediately or it will dissipate again. To catch and hold values, JavaScript provides a thing called a _binding_, or _variable_. ``` let caught = 5 * 5; @@ -97,17 +58,11 @@ let caught = 5 * 5; {{index "let keyword"}} -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. +That gives us 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 binding called `caught` and uses it -to grab hold of the number that is produced by multiplying 5 by 5. +The example creates a binding called `caught` and uses it to grab hold of the number that is produced by multiplying 5 by 5. -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: +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: ``` let ten = 10; @@ -117,10 +72,7 @@ console.log(ten * ten); {{index "= operator", assignment, [binding, assignment]}} -When a binding points at a value, that does not mean it is tied to -that value forever. The `=` operator can be used at any time on -existing bindings to disconnect them from their current value and have -them point to a new one: +When a binding points at a value, that does not mean it is tied to that value forever. The `=` operator can be used at any time on existing bindings to disconnect them from their current value and have them point to a new one: ``` let mood = "light"; @@ -133,15 +85,9 @@ console.log(mood); {{index [binding, "model of"], "tentacle (analogy)"}} -You should imagine bindings as tentacles, rather than boxes. They do -not _contain_ values; they _grasp_ them—two bindings can refer to the -same value. A program can only access the values that it still has a -reference to. When you need to remember something, you grow a tentacle -to hold on to it or you reattach one of your existing tentacles to it. +You should imagine bindings as tentacles rather than boxes. They do not _contain_ values; they _grasp_ them—two bindings can refer to the same value. A program can access only the values to which it still has a reference. When you need to remember something, you either grow a tentacle to hold on to it or reattach one of your existing tentacles to it. -Let's look at another example. To remember the number of dollars that -Luigi still owes you, you create a binding. And then when he pays back -$35, you give this binding a new value: +Let's look at another example. To remember the number of dollars that Luigi still owes you, you create a binding. When he pays back $35, you give this binding a new value. ``` let luigisDebt = 140; @@ -152,14 +98,11 @@ console.log(luigisDebt); {{index undefined}} -When you define a binding without giving it a value, the tentacle has -nothing to grasp, so it ends in thin air. If you ask for the value of -an empty binding, you'll get the value `undefined`. +When you define a binding without giving it a value, the tentacle has nothing to grasp, so it ends in thin air. If you ask for the value of an empty binding, you'll get the value `undefined`. {{index "let keyword"}} -A single `let` statement may define multiple bindings. The -definitions must be separated by commas. +A single `let` statement may define multiple bindings. The definitions must be separated by commas: ``` let one = 1, two = 2; @@ -167,8 +110,7 @@ console.log(one + two); // → 3 ``` -The words `var` and `const` can also be used to create bindings, in a -way similar to `let`. +The words `var` and `const` can also be used to create bindings, in a similar fashion to `let`. ``` var name = "Ayda"; @@ -179,37 +121,23 @@ console.log(greeting + name); {{index "var keyword"}} -The first, `var` (short for "variable"), is the way bindings were -declared in pre-2015 JavaScript. We'll get back to the precise way it -differs from `let` in the [next chapter](functions). For now, -remember that it mostly does the same thing, but we'll rarely use it -in this book because it has some confusing properties. +The first of these, `var` (short for "variable"), is the way bindings were declared in pre-2015 JavaScript, when `let` didn't exist yet. I'll get back to the precise way it differs from `let` in the [next chapter](functions). For now, remember that it mostly does the same thing, but we'll rarely use it in this book because it behaves oddly in some situations. {{index "const keyword", naming}} -The word `const` stands for _((constant))_. It defines a constant -binding, which points at the same value for as long as it lives. This -is useful for bindings that give a name to a value so that you can -easily refer to it later. +The word `const` stands for _((constant))_. It defines a constant binding, which points at the same value for as long as it lives. This is useful for bindings that just give a name to a value so that you can easily refer to it later. ## Binding names {{index "underscore character", "dollar sign", [binding, naming]}} -Binding names can be any word. Digits can be part of binding -names—`catch22` is a valid name, for example—but the name must not -start with a digit. A binding name may include dollar signs (`$`) or -underscores (`_`), but no other punctuation or special characters. +Binding names can be any sequence of one or more letters. Digits can be part of binding names—`catch22` is a valid name, for example—but the name must not start with a digit. A binding name may include dollar signs (`$`) or underscores (`_`) but no other punctuation or special characters. -{{index syntax, "implements (reserved word)", "interface (reserved word)", "package (reserved word)", "private (reserved word)", "protected (reserved word)", "public (reserved word)", "static (reserved word)", "void operator", "yield (reserved word)", "enum (reserved word)", "reserved word", [binding, naming]}} +{{index [syntax, identifier], "implements (reserved word)", "interface (reserved word)", "package (reserved word)", "private (reserved word)", "protected (reserved word)", "public (reserved word)", "static (reserved word)", "void operator", "yield (reserved word)", "enum (reserved word)", "reserved word", [binding, naming]}} -Words with a special meaning, such as `let`, are _((keyword))s_, and -they may not be used as binding names. There are also a number of -words that are "reserved for use" in ((future)) versions of -JavaScript, which also can't be used as binding names. The full list -of keywords and reserved words is rather long: +Words with a special meaning, such as `let`, are _((keyword))s_, and may not be used as binding names. There are also a number of words that are "reserved for use" in ((future)) versions of JavaScript, which also can't be used as binding names. The full list of keywords and reserved words is rather long: -```{lang: "text/plain"} +```{lang: "null"} break case catch class const continue debugger default delete do else enum export extends false finally for function if implements import interface in instanceof let @@ -217,76 +145,46 @@ new package private protected public return static super switch this throw true try typeof var void while with yield ``` -Don't worry about memorizing these. When creating a binding produces -an unexpected ((syntax error)), see if you're trying to define a -reserved word. +{{index [syntax, error]}} + +Don't worry about memorizing this list. When creating a binding produces an unexpected syntax error, check whether you're trying to define a reserved word. ## The environment -{{index "standard environment"}} +{{index "standard environment", [browser, environment]}} -The collection of bindings and their values that exist at a given time -is called the _((environment))_. When a program starts up, this -environment is not empty. It always contains bindings that are part of -the language ((standard)), and most of the time, it also has bindings -that provide ways to interact with the surrounding system. For -example, in a ((browser)), there are functions to interact with the -currently loaded website and to read ((mouse)) and ((keyboard)) input. +The collection of bindings and their values that exist at a given time is called the _((environment))_. When a program starts up, this environment is not empty. It always contains bindings that are part of the language ((standard)), and most of the time, it also has bindings that provide ways to interact with the surrounding system. For example, in a browser, there are functions to interact with the currently loaded website and to read ((mouse)) and ((keyboard)) input. ## Functions -{{indexsee "application (of functions)", "function application"}} -{{indexsee "invoking (of functions)", "function application"}} -{{indexsee "calling (of functions)", "function application"}} -{{index output, function, [function, application]}} +{{indexsee "application (of functions)", [function, application]}} +{{indexsee "invoking (of functions)", [function, application]}} +{{indexsee "calling (of functions)", [function, application]}} +{{index output, function, [function, application], [browser, environment]}} -A lot of the values provided in the default environment have the type -_((function))_. A function is a piece of program wrapped in a value. -Such values can be _applied_ in order to run the wrapped program. For -example, in a ((browser)) environment, the binding `prompt` holds a -function that shows a little ((dialog box)) asking for user input. It -is used like this: +A lot of the values provided in the default environment have the type _((function))_. A function is a piece of program wrapped in a value. Such values can be _applied_ in order to run the wrapped program. For example, in a browser environment, the binding `prompt` holds a function that shows a little ((dialog)) asking for user input. It is used like this: ``` prompt("Enter passcode"); ``` -{{figure {url: "img/prompt.png", alt: "A prompt dialog", width: "8cm"}}} +{{figure {url: "img/prompt.png", alt: "A prompt dialog that says 'enter passcode'", width: "8cm"}}} -{{index parameter, [function, application]}} +{{index parameter, [function, application], [parentheses, 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 -_((argument))s_. Different 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 _((argument))s_. 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 `prompt` function isn't used much in modern web programming, mostly because you have no control over the way the resulting dialog looks, but it can be helpful in toy programs and experiments. ## The console.log function -{{index "JavaScript console", "developer tools", "Node.js", "console.log", output}} +{{index "JavaScript console", "developer tools", "Node.js", "console.log", output, [browser, environment]}} -In the examples, I used `console.log` to output values. Most JavaScript -systems (including all modern web ((browser))s 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. +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 a Mac, [command]{keyname}-[option]{keyname}-I. If that does not work, search through the menus for an item named Developer Tools or similar. {{if interactive -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. ``` let x = 30; @@ -296,25 +194,16 @@ console.log("the value of x is", x); if}} -{{index object}} +{{index [object, property], [property, access]}} -Though binding names cannot contain ((period character))s, -`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 ?](data#properties). +Though binding names cannot contain ((period character))s, `console.log` does have one. This is because `console.log` isn't a simple binding, but an expression that retrieves the `log` property from the value held by the `console` binding. We'll find out exactly what this means in [Chapter ?](data#properties). {{id return_values}} ## Return values {{index [comparison, "of numbers"], "return value", "Math.max function", maximum}} -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. +Showing a dialog box or writing text to the screen is a _((side effect))_. Many 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)); @@ -323,29 +212,20 @@ console.log(Math.max(2, 4)); {{index [function, application], minimum, "Math.min function"}} -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: +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 that function calls can be used within larger expressions. In the following code, 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](functions) explains how to write your own -functions. +[Chapter ?](functions) will explain how to write your own functions. ## Control flow {{index "execution order", program, "control flow"}} -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. +When your program contains more than one ((statement)), the statements are executed as though they were a story, from top to bottom. For example, the following program has two statements. The first asks the user for a number, and the second, which is executed after the first, shows the ((square)) of that number: ``` let theNumber = Number(prompt("Pick a number")); @@ -355,33 +235,23 @@ console.log("Your number is the square root of " + {{index [number, "conversion to"], "type coercion", "Number function", "String function", "Boolean function", [Boolean, "conversion to"]}} -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 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-line -control flow: +Here is the rather trivial schematic representation of straight-line control flow: -{{figure {url: "img/controlflow-straight.svg", alt: "Trivial control flow", width: "4cm"}}} +{{figure {url: "img/controlflow-straight.svg", alt: "Diagram showing a straight arrow", width: "4cm"}}} ## Conditional execution -{{index Boolean, "control flow"}} +{{index Boolean, ["control flow", conditional]}} -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))_. +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))_. -{{figure {url: "img/controlflow-if.svg", alt: "Conditional control flow",width: "4cm"}}} +{{figure {url: "img/controlflow-if.svg", alt: "Diagram of an arrow that splits in two, and then rejoins again",width: "4cm"}}} -{{index syntax, "Number function", "if keyword"}} +{{index [syntax, statement], "Number function", "if keyword"}} -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. +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: ```{test: wrap} let theNumber = Number(prompt("Pick a number")); @@ -393,29 +263,17 @@ if (!Number.isNaN(theNumber)) { With this modification, if you enter "parrot", no output is shown. -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. +{{index [parentheses, statement]}} + +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. {{index "Number.isNaN function"}} -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". +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". -{{index grouping, "{} (block)"}} +{{index grouping, "{} (block)", [braces, "block"]}} -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. +The statement after the `if` is wrapped in braces (`{` and `}`) in this example. The braces 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 hold only a single statement, but to avoid having to think about whether they are needed, 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. ``` if (1 + 1 == 2) console.log("It's true"); @@ -424,11 +282,7 @@ if (1 + 1 == 2) console.log("It's true"); {{index "else keyword"}} -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. +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. You can use the `else` keyword, together with `if`, to create two separate, alternative execution paths: ```{test: wrap} let theNumber = Number(prompt("Pick a number")); @@ -442,8 +296,7 @@ if (!Number.isNaN(theNumber)) { {{index ["if keyword", chaining]}} -If we have more than two paths to choose from, multiple `if`/`else` -pairs can be "chained" together. Here's an example: +If you have more than two paths to choose from, you can "chain" multiple `if`/`else` pairs together. Here's an example: ``` let num = Number(prompt("Pick a number")); @@ -457,22 +310,16 @@ if (num < 10) { } ``` -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 at least 10 but below 100, and `"Medium"` is shown. If it doesn't, the second and last `else` branch is chosen. The schema for this program looks something like this: -{{figure {url: "img/controlflow-nested-if.svg", alt: "Nested if control flow", width: "4cm"}}} +{{figure {url: "img/controlflow-nested-if.svg", alt: "Diagram showing arrow that splits in two, with on the branches splitting again, before all branches rejoin again", width: "4cm"}}} {{id loops}} ## while and do loops -Consider a program that outputs all ((even number))s from 0 to 12. One -way to write this is as follows: +Consider a program that outputs all ((even number))s from 0 to 12. One way to write this is as follows: ``` console.log(0); @@ -484,22 +331,15 @@ console.log(10); console.log(12); ``` -{{index "control flow"}} +{{index ["control flow", 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))_: +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))_. -{{figure {url: "img/controlflow-loop.svg", alt: "Loop control flow",width: "4cm"}}} +{{figure {url: "img/controlflow-loop.svg", alt: "Diagram showing an arrow to a point which has a cyclic arrow going back to itself and another arrow going further", width: "4cm"}}} -{{index syntax, "counter variable"}} +{{index [syntax, statement], "counter variable"}} -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: +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: ``` let number = 0; @@ -512,30 +352,17 @@ while (number <= 12) { // … etcetera ``` -{{index "while loop", Boolean}} +{{index "while loop", Boolean, [parentheses, statement]}} -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. +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. -{{index comparison, state}} +{{index [state, in binding], [binding, as state]}} -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 `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. {{index exponentiation}} -As an example that actually does something useful, we can now write a -program that calculates and shows the value of 2^10^ (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. +As an example that actually does something useful, we can now write a program that calculates and shows the value of 2^10^ (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. ``` let result = 1; @@ -548,53 +375,35 @@ console.log(result); // → 1024 ``` -The counter could also have started at `1` and checked for `<= 10`, -but, for reasons that will become apparent in [Chapter -?](data#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 ?](data#array_indexing), it is a good idea to get used to counting from 0. + +{{index "** operator"}} -{{index "loop body", "do loop", "control flow"}} +Note that JavaScript also has an operator for exponentiation (`2 ** 10`), which you would use to compute this in real code—but that would have ruined the example. -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: +{{index "loop body", "do loop", ["control flow", 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 { yourName = prompt("Who are you?"); } while (!yourName); -console.log(yourName); +console.log("Hello " + yourName); ``` {{index [Boolean, "conversion to"], "! operator"}} -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. +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 -{{index "code structure", whitespace, "programming style"}} +{{index [code, "structure of"], [whitespace, indentation], "programming style"}} -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. +In the examples, I've been adding spaces in front of statements that are part of some larger statement. These spaces 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 ((block))s 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 character))s. The important -thing is that each new block adds the same amount of space. +The role of this ((indentation)) inside ((block))s is to make the structure of the code stand out to human readers. 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 character))s. The important thing is that each new block adds the same amount of space. ``` if (false != true) { @@ -605,25 +414,17 @@ if (false != true) { } ``` -Most code ((editor)) programs[ (including the one in this book)]{if -interactive} will help by automatically indenting new lines the proper -amount. +Most code ((editor)) programs[ (including the one in this book)]{if interactive} will help by automatically indenting new lines the proper amount. ## for loops -{{index syntax, "while loop", "counter variable"}} +{{index [syntax, statement], "while loop", "counter variable"}} -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. +Many loops follow the pattern shown 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. {{index "for loop", loop}} -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 (let number = 0; number <= 12; number = number + 2) { @@ -634,23 +435,17 @@ for (let number = 0; number <= 12; number = number + 2) { // … etcetera ``` -{{index "control flow", state}} +{{index ["control flow", loop], state}} + +This program is exactly equivalent to the [earlier](program_structure#loops) even-number-printing example. The only change is that all the ((statement))s that are related to the "state" of the loop are grouped together after `for`. -This program is exactly equivalent to the -[earlier](program_structure#loops) even-number-printing example. The -only change is that all the ((statement))s that are related to the -"state" of the loop are grouped together after `for`. +{{index [binding, as state], [parentheses, statement]}} -The ((parentheses)) after a `for` keyword must contain two -((semicolon))s. 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. +The parentheses after a `for` keyword must contain two ((semicolon))s. 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. {{index exponentiation}} -This is the code that computes 2^10^, using `for` instead of `while`: +This is the code that computes 2^10^ using `for` instead of `while`: ```{test: wrap} let result = 1; @@ -665,12 +460,7 @@ console.log(result); {{index [loop, "termination of"], "break keyword"}} -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. +Having the looping condition produce `false` is not the only way a loop can finish. The `break` statement has the effect of immediately jumping out of the enclosing loop. Its use is demonstrated in the following program, which finds the first number that is both greater than or equal to 20 and divisible by 7: ``` for (let current = 20; ; current = current + 1) { @@ -684,44 +474,29 @@ for (let current = 20; ; current = current + 1) { {{index "remainder operator", "% operator"}} -Using the remainder (`%`) operator is an easy way to test whether a -number is divisible by another number. If it is, the remainder of -their division is zero. +Using the remainder (`%`) operator is an easy way to test whether a number is divisible by another number. If it is, the remainder of their division is zero. {{index "for loop"}} -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. +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 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 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 interactive -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. +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 to recover. if}} {{index "continue keyword"}} -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. +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 bindings succinctly -{{index assignment, "+= operator", "-= operator", "/= operator", "*= operator", state, "side effect"}} +{{index assignment, "+= operator", "-= operator", "/= operator", "*= operator", [state, in binding], "side effect"}} -Especially when looping, a program often needs to "update" a binding -to hold a value based on that binding'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. ```{test: no} counter = counter + 1; @@ -733,10 +508,9 @@ JavaScript provides a shortcut for this: counter += 1; ``` -Similar shortcuts work for many other operators, such as `result *= 2` -to double `result` or `counter -= 1` to count downward. +Similar shortcuts work for many other operators, such as `result *= 2` to double `result` or `counter -= 1` to count downward. -This allows us to shorten our counting example a little more. +This allows us to further shorten our counting example: ``` for (let number = 0; number <= 12; number += 2) { @@ -746,12 +520,11 @@ for (let number = 0; number <= 12; number += 2) { {{index "++ operator", "-- operator"}} -For `counter += 1` and `counter -= 1`, there are even shorter -equivalents: `counter++` and `counter--`. +For `counter += 1` and `counter -= 1`, there are even shorter equivalents: `counter++` and `counter--`. ## Dispatching on a value with switch -{{index syntax, "conditional execution", dispatching, ["if keyword", chaining]}} +{{index [syntax, statement], "conditional execution", dispatch, ["if keyword", chaining]}} It is not uncommon for code to look like this: @@ -764,11 +537,7 @@ else defaultAction(); {{index "colon character", "switch keyword"}} -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: +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?")) { @@ -786,27 +555,15 @@ switch (prompt("What is the weather like?")) { } ``` -{{index fallthrough, comparison, "break keyword", "case keyword", "default keyword"}} +{{index fallthrough, "break keyword", "case keyword", "default keyword"}} -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. +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). Be careful, though—it is easy to forget such a `break`, which will cause the program to execute code you do not want executed. ## Capitalization -{{index capitalization, [binding, naming], whitespace}} +{{index capitalization, [binding, naming], [whitespace, syntax]}} -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: +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: ```{lang: null} fuzzylittleturtle @@ -817,38 +574,21 @@ fuzzyLittleTurtle {{index "camel case", "programming style", "underscore character"}} -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)). +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 final 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)). {{index "Number function", constructor}} -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 -?](object#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. It will become clear what a constructor is in [Chapter ?](object#constructors). For now, the important thing is to not be bothered by this apparent lack of ((consistency)). ## Comments {{index readability}} -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 _((comment))s_ 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 _((comment))s_ are for. {{index "slash character", "line comment"}} -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. +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: ```{test: no} let accountBalance = calculateBalance(account); @@ -863,67 +603,41 @@ addToReport(accountBalance, report); {{index "block comment"}} -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. +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 - 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. + I first found this number scrawled on the back of 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. */ const myNumber = 11213; ``` ## Summary -You now know that a program is built out of statements, which -themselves sometimes contain more statements. Statements tend to -contain expressions, which themselves can be built out of smaller -expressions. +You now know that a program is built out of statements, which themselves sometimes contain more statements. Statements tend to contain expressions, which themselves can be built out of smaller expressions. -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. +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. -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. +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. +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 {{index exercises}} -If you are unsure how to try your solutions to exercises, refer to the -[introduction](intro). +If you are unsure how to test your solutions to the exercises, refer to the [introduction](intro). -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]{if interactive}[at the [end of the -book](hints)]{if book}. 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. +Each exercise starts with a problem description. Read this description and try to solve the exercise. If you run into problems, consider reading the hints [after the exercise]{if interactive}[at the [end of the book](hints)]{if book}. You can find full solutions to the exercises online at [_https://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 {{index "triangle (exercise)"}} -Write a ((loop)) that makes seven calls to `console.log` to output the -following triangle: +Write a ((loop)) that makes seven calls to `console.log` to output the following triangle: ```{lang: null} # @@ -937,8 +651,7 @@ following triangle: {{index [string, length]}} -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. ``` let abc = "abc"; @@ -948,8 +661,7 @@ console.log(abc.length); {{if interactive -Most exercises contain a piece of code that you can modify to solve -the exercise. Remember that you can click code blocks to edit them. +Most exercises contain a piece of code that you can modify to solve the exercise. Remember that you can click code blocks to edit them. ``` // Your code here. @@ -960,15 +672,9 @@ if}} {{index "triangle (exercise)"}} -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](program_structure#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](program_structure#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. +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. hint}} @@ -976,18 +682,11 @@ hint}} {{index "FizzBuzz (exercise)", loop, "conditional execution"}} -Write a program that uses `console.log` to print all the numbers from -1 to 100, with two exceptions. For numbers divisible by 3, print -`"Fizz"` instead of the number, and for numbers divisible by 5 (and -not 3), print `"Buzz"` instead. +Write a program that uses `console.log` to print all the numbers from 1 to 100, with two exceptions. For numbers divisible by 3, print `"Fizz"` instead of the number, and for numbers divisible by 5 (and not 3), print `"Buzz"` instead. -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). +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, your labor market value just went up.) +(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.) {{if interactive ``` @@ -999,33 +698,21 @@ if}} {{index "FizzBuzz (exercise)", "remainder operator", "% operator"}} -Going over the numbers is clearly a looping job, and selecting what to -print is a matter of conditional execution. Remember the trick of -using the remainder (`%`) operator for checking whether a number is -divisible by another number (has a remainder of zero). +Going over the numbers is clearly a looping job, and selecting what to print is a matter of conditional execution. Remember the trick of using the remainder (`%`) operator for checking whether a number is divisible by another number (has a remainder of zero). -In the first version, there are three possible outcomes for every -number, so you'll have to create an `if`/`else if`/`else` chain. +In the first version, there are three possible outcomes for every number, so you'll have to create an `if`/`else if`/`else` chain. {{index "|| operator", ["if keyword", chaining]}} -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. +The second version of the program has a straightforward solution and a clever one. The simple solution is to add another conditional "branch" to precisely test the given condition. For the clever solution, 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. hint}} -### Chess board +### Chessboard -{{index "chess board (exercise)", loop, [nesting, "of loops"], "newline character"}} +{{index "chessboard (exercise)", loop, [nesting, "of loops"], "newline character"}} -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 chessboard. Passing this string to `console.log` should show something like this: @@ -1040,9 +727,7 @@ Passing this string to `console.log` should show something like this: # # # # ``` -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. +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. {{if interactive ``` @@ -1054,27 +739,16 @@ if}} {{index "chess board (exercise)"}} -The string can be built by starting with an empty one (`""`) and -repeatedly adding characters. A newline character is written `"\n"`. +You can build the string by starting with an empty one (`""`) and repeatedly adding characters. A newline character is written `"\n"`. -{{index [nesting, "of loops"]}} +{{index [nesting, "of loops"], [braces, "block"]}} -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. +To work with two ((dimensions)), you will need a ((loop)) inside of a loop. Put 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. {{index "counter variable", "remainder operator", "% operator"}} -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`). +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 must happen 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 the outer loop. hint}} diff --git a/03_functions.md b/03_functions.md index 483ac64ef..9f5ce287f 100644 --- a/03_functions.md +++ b/03_functions.md @@ -2,44 +2,29 @@ {{quote {author: "Donald Knuth", chapter: true} -People think that computer science is the art of geniuses but the -actual reality is the opposite, just many people doing things that -build on each other, like a wall of mini stones. +People think that computer science is the art of geniuses but the actual reality is the opposite, just many people doing things that build on each other, like a wall of mini stones. quote}} {{index "Knuth, Donald"}} -{{figure {url: "img/chapter_picture_3.jpg", alt: "Picture of fern leaves with a fractal shape", chapter: framed}}} +{{figure {url: "img/chapter_picture_3.jpg", alt: "Illustration of fern leaves with a fractal shape, bees in the background", chapter: framed}}} -{{index function, "code structure"}} +{{index function, [code, "structure of"]}} -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. +Functions are one of the most central tools in 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 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. {{index abstraction, vocabulary}} -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. +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 _have_ to introduce new words to avoid excessive verbosity. ## Defining a function -{{index "square example", [function, definition]}} +{{index "square example", [function, definition], [binding, definition]}} -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: +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: ``` const square = function(x) { @@ -50,21 +35,14 @@ console.log(square(12)); // → 144 ``` -{{indexsee braces, "curly braces"}} -{{index "curly braces", block, syntax, "function keyword", [function, body], [function, "as value"]}} +{{indexsee "curly braces", braces}} +{{index [braces, "function body"], block, [syntax, function], "function keyword", [function, body], [function, "as value"], [parentheses, arguments]}} -A function is created with an expression that starts with the keyword -`function`. Functions have a set of _((parameter))s_ (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 is created with an expression that starts with the keyword `function`. Functions have a set of _((parameter))s_ (in this case, only `x`) and a _body_, which contains the statements that are to be executed when the function is called. The body of a function created this way must always be wrapped in braces, even when it consists of only a single ((statement)). -{{index "power example"}} +{{index "roundTo example"}} -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: +A function can have multiple parameters or no parameters at all. In the following example, `makeNoise` does not list any parameter names, whereas `roundTo` (which rounds `n` to the nearest multiple of `step`) lists two: ``` const makeNoise = function() { @@ -74,87 +52,49 @@ const makeNoise = function() { makeNoise(); // → Pling! -const power = function(base, exponent) { - let result = 1; - for (let count = 0; count < exponent; count++) { - result *= base; - } - return result; +const roundTo = function(n, step) { + let remainder = n % step; + return n - remainder + (remainder < step / 2 ? 0 : step); }; -console.log(power(2, 10)); -// → 1024 +console.log(roundTo(23, 10)); +// → 20 ``` {{index "return value", "return keyword", 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`. +Some functions, such as `roundTo` and `square`, produce a value, 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`. {{index parameter, [function, application], [binding, "from parameter"]}} -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. +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. ## Bindings and scopes {{indexsee "top-level scope", "global scope"}} {{index "var keyword", "global scope", [binding, global], [binding, "scope of"]}} -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_. +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, block, or module (see [Chapter ?](modules)), the scope is the whole program—you can refer to such bindings wherever you want. These are called _global_. {{index "local scope", [binding, local]}} -But bindings created for function ((parameter))s 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. +Bindings created for function ((parameter))s or declared inside a function can be referenced only 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. {{index "let keyword", "const keyword", "var keyword"}} -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. +Bindings declared with `let` and `const` are in fact local to the _((block))_ in which they are declared, 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 in which they appear—or throughout the global scope, if they are not in a function. ``` -let x = 10; +let x = 10; // global if (true) { - let y = 20; - var z = 30; - console.log(x + y + z); - // → 60 + let y = 20; // local to block + var z = 30; // also global } -// y is not visible here -console.log(x + z); -// → 40 ``` {{index [binding, visibility]}} -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`. +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 see only 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`. ``` const halve = function(n) { @@ -170,18 +110,15 @@ console.log(n); {{id scoping}} -### Nested scope +## Nested scope {{index [nesting, "of functions"], [nesting, "of scope"], scope, "inner function", "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. +JavaScript distinguishes not just global and local bindings. Blocks and functions can be created inside other blocks and functions, producing multiple degrees of locality. {{index "landscape example"}} -For example, this function—which outputs the ingredients needed to -make a batch of hummus—has another function inside it: +For example, this function—which outputs the ingredients needed to make a batch of hummus—has another function inside it: ``` const hummus = function(factor) { @@ -203,33 +140,19 @@ const hummus = function(factor) { {{index [function, scope], scope}} -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. +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. -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))_. +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 -{{index [function, "as value"]}} +{{index [function, "as value"], [binding, definition]}} -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. +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. {{index [binding, assignment]}} -But the two are different. A function value can do all the things that -other values can do—you can use it in arbitrary ((expression))s, 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: +But the two are different. A function value can do all the things that other values can do—you can use it in arbitrary ((expression))s, 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: ```{test: no} let launchMissiles = function() { @@ -242,16 +165,13 @@ if (safeMode) { {{index [function, "higher-order"]}} -In [Chapter ?](higher_order), we will discuss the interesting things -that can be done by passing around function values to other functions. +In [Chapter ?](higher_order), we'll discuss the interesting things that we can do by passing function values to other functions. ## Declaration notation -{{index syntax, "function keyword", "square example", [function, definition], [function, declaration]}} +{{index [syntax, function], "function keyword", "square example", [function, definition], [function, declaration]}} -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. +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: ```{test: wrap} function square(x) { @@ -261,9 +181,7 @@ function square(x) { {{index future, "execution order"}} -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. +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. @@ -275,55 +193,37 @@ function future() { } ``` -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. +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 the clearest, without worrying about having to define all functions before they are used. ## Arrow functions {{index function, "arrow function"}} -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 -`>=`). +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 an equal sign and a greater-than character (not to be confused with the greater-than-or-equal operator, which is written `>=`): ```{test: wrap} -const power = (base, exponent) => { - let result = 1; - for (let count = 0; count < exponent; count++) { - result *= base; - } - return result; +const roundTo = (n, step) => { + let remainder = n % step; + return n - remainder + (remainder < step / 2 ? 0 : step); }; ``` {{index [function, body]}} -The arrow comes _after_ the list of parameters and is followed by the -function's body. It expresses something like "this input (the -((parameter))s) produces this result (the body)". +The arrow comes _after_ the list of parameters and is followed by the function's body. It expresses something like "this input (the ((parameter))s) produces this result (the body)". -{{index "curly braces", "square example"}} +{{index [braces, "function body"], "square example", [parentheses, arguments]}} -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: +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)). +{{index [parentheses, arguments]}} + +When an arrow function has no parameters at all, its parameter list is just an empty set of parentheses. ``` const horn = () => { @@ -333,12 +233,7 @@ const horn = () => { {{index verbosity}} -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 ?](object), 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 ?](higher_order). +There's no deep reason to have both arrow functions and `function` expressions in the language. Apart from a minor detail, which we'll discuss in [Chapter ?](object), 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 use them often in [Chapter ?](higher_order). {{id stack}} @@ -347,9 +242,7 @@ them a lot in [Chapter ?](higher_order). {{indexsee stack, "call stack"}} {{index "call stack", [function, application]}} -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: +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) { @@ -359,50 +252,31 @@ greet("Harry"); console.log("Bye"); ``` -{{index "control flow", "execution order", "console.log"}} +{{index ["control flow", functions], "execution order", "console.log"}} -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. +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—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: ```{lang: null} not in function - in greet - in console.log - in greet + in greet + in console.log + in greet not in function - in console.log + in console.log not in function ``` -{{index "return keyword", memory}} +{{index "return keyword", [memory, call stack]}} -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. +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 -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. +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. {{index "infinite loop", "stack overflow", recursion}} -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". +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. Or 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". ```{test: no} function chicken() { @@ -427,25 +301,13 @@ console.log(square(4, true, "hedgehog")); // → 16 ``` -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. +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. {{index 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`. +JavaScript is extremely broad-minded about the number of arguments you can pass to a function. If you pass too many, the extra ones are ignored. If you pass too few, the missing parameters are 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 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: +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 you can use this behavior to allow a function to be called with different numbers of arguments. For example, this `minus` function tries to imitate the `-` operator by acting on either one or two arguments: ``` function minus(a, b) { @@ -459,41 +321,26 @@ console.log(minus(10, 5)); // → 5 ``` -{{id power}} -{{index "optional argument", "default value", parameter, "= operator"}} - -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. +{{id roundTo}} +{{index "optional argument", "default value", parameter, ["= operator", "for default value"] "roundTo example"}} -{{index "power example"}} - -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`. +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 `roundTo` makes its second argument optional. If you don't provide it or pass the value `undefined`, it will default to one: ```{test: wrap} -function power(base, exponent = 2) { - let result = 1; - for (let count = 0; count < exponent; count++) { - result *= base; - } - return result; -} +function roundTo(n, step = 1) { + let remainder = n % step; + return n - remainder + (remainder < step / 2 ? 0 : step); +}; -console.log(power(4)); -// → 16 -console.log(power(2, 6)); -// → 64 +console.log(roundTo(4.5)); +// → 5 +console.log(roundTo(4.5, 2)); +// → 4 ``` {{index "console.log"}} -In the [next chapter](data#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. +The [next chapter](data#rest_parameters) will introduce a way in which a function body can get at the whole list of arguments it was passed. This is helpful because it allows a function to accept any number of arguments. For example, `console.log` does this, outputting all the values it is given: ``` console.log("C", "O", 2); @@ -504,14 +351,9 @@ console.log("C", "O", 2); {{index "call stack", "local binding", [function, "as value"], scope}} -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 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`, that creates a local binding. It then returns a function -that accesses and returns this local binding. +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) { @@ -527,22 +369,13 @@ console.log(wrap2()); // → 2 ``` -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 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 don't affect each other's local bindings. -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. +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 the lifetimes of bindings but also makes it possible to use function values in some creative ways. {{index "multiplier function"}} -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) { @@ -556,31 +389,19 @@ console.log(twice(5)); {{index [binding, "from parameter"]}} -The explicit `local` binding from the `wrapValue` example isn't really -needed since a parameter is itself a local binding. +The explicit `local` binding from the `wrapValue` example isn't really needed since a parameter is itself a local binding. {{index [function, "model of"]}} -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. +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` 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. +In the previous 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 that when that is called, it multiplies its argument by 2. ## Recursion {{index "power example", "stack overflow", recursion, [function, application]}} -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`: +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 `power` function, which does the same as the `**` (exponentiation) operator: ```{test: wrap} function power(base, exponent) { @@ -597,67 +418,34 @@ console.log(power(2, 3)); {{index loop, readability, mathematics}} -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. +This is rather close to the way mathematicians define exponentiation and arguably describes the concept more clearly than the loop we used in [Chapter ?](program_structure). The function calls itself multiple times with ever smaller exponents to achieve the repeated multiplication. {{index [function, application], efficiency}} -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. +However, this implementation has one problem: in typical JavaScript implementations, it's about three times slower than a version using a `for` loop. Running through a simple loop is generally cheaper than calling a function multiple times. {{index optimization}} -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. +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 find an appropriate balance. -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. +In the case of the `power` function, an inelegant (looping) version is still fairly simple and easy to read. It doesn't make much sense to replace it with a recursive function. Often, though, a program deals with such complex concepts that giving up some efficiency in order to make the program more straightforward is helpful. {{index profiling}} -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. +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. {{index "premature optimization"}} -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. +Therefore, you should generally 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 afterward and improve it if necessary. {{index "branching recursion"}} -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. +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. {{id recursive_puzzle}} {{index recursion, "number puzzle example"}} -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? - -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. +Consider this puzzle: by starting from the number 1 and repeatedly either adding 5 or multiplying by 3, an infinite set of 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? 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: @@ -669,7 +457,7 @@ function findSolution(target) { } else if (current > target) { return null; } else { - return find(current + 5, `(${history} + 5)`) || + return find(current + 5, `(${history} + 5)`) ?? find(current * 3, `(${history} * 3)`); } } @@ -680,38 +468,19 @@ console.log(findSolution(24)); // → (((1 * 3) + 5) * 3) ``` -Note that this program doesn't necessarily find the _shortest_ -sequence of operations. It is satisfied when it finds any sequence at -all. - -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 -((argument))s: 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`. - -{{index null, "|| operator", "short-circuit evaluation"}} - -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`. +Note that this program doesn't necessarily find the _shortest_ sequence of operations. It is satisfied when it finds any sequence at all. + +It's okay if you don't see how this code 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 ((argument))s: 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 it can find no solution starting from this number, it returns `null`. + +{{index null, "?? operator", "short-circuit evaluation"}} + +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`. 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`. {{index "call stack"}} -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. +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: ```{lang: null} find(1, "1") @@ -729,59 +498,34 @@ find(1, "1") found! ``` -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. +The indentation indicates the depth of the call stack. The first time `find` is called, the function 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 {{index [function, definition]}} -There are two more or less natural ways for functions to be introduced -into programs. +There are two more or less natural ways for functions to be introduced into programs. {{index repetition}} -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 first occurs when you find yourself writing similar code multiple times. You'd prefer not to do that, as having more code means more space for mistakes to hide and more material to read for people trying to understand the program. So you 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 then you'll 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 start by naming the function, and then write its body. You might even start writing code that uses the function before you actually define the function itself. {{index [function, naming], [binding, naming]}} -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. +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. {{index "farm example"}} -We want to write a program that prints two numbers, the numbers of -cows and chickens on a farm, with the words `Cows` and `Chickens` -after them, and zeros padded before both numbers so that they are -always three digits long. +We want to write a program that prints two numbers: the numbers of cows and chickens on a farm, with the words `Cows` and `Chickens` after them and zeros padded before both numbers so that they are always three digits long: ```{lang: null} 007 Cows 011 Chickens ``` -This asks for a function of two arguments—the number of cows and the -number of chickens. 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) { @@ -801,20 +545,13 @@ printFarmInventory(7, 11); {{index ["length property", "for string"], "while loop"}} -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. +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), she calls and tells us she'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? {{index "copy-paste programming"}} -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: +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) { @@ -836,14 +573,11 @@ printFarmInventory(7, 11, 3); {{index [function, naming]}} -It works! But that name, `printZeroPaddedWithLabel`, is a little -awkward. It conflates three things—printing, zero-padding, and adding -a label—into a single function. +It works! But that name, `printZeroPaddedWithLabel`, is a little awkward. It conflates three things—printing, zero-padding, and adding a label—into a single function. {{index "zeroPad function"}} -Instead of lifting out the repeated part of our program wholesale, -let's try to pick out a single _concept_. +Instead of lifting out the repeated part of our program wholesale, let's try to pick out a single _concept_: ``` function zeroPad(number, width) { @@ -865,76 +599,36 @@ printFarmInventory(7, 16, 3); {{index readability, "pure function"}} -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. +A function with a nice, obvious name like `zeroPad` makes it easier for someone who reads the code to figure out what it does. Such a function is also useful in more situations than just this specific program. For example, you could use it to help print nicely aligned tables of numbers. {{index [interface, design]}} -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. +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 to not add cleverness unless you are absolutely -sure you're going to need it. It can be tempting to write general -"((framework))s" 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. +A useful principle is to refrain from adding cleverness unless you are absolutely sure you're going to need it. It can be tempting to write general "((framework))s" for every bit of functionality you come across. Resist that urge. You won't get any real work done—you'll be too busy writing code that you never use. {{id pure}} ## Functions and side effects {{index "side effect", "pure function", [function, purity]}} -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.) +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 also possible to both have side effects and return a value). {{index reuse}} -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. +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. {{index substitution}} -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. +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. {{index optimization, "console.log"}} -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. +Still, there's no need to feel bad when writing functions that are not pure. Side effects are often useful. There's 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. ## 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 binding -and give it a function as its value. Arrow functions are yet another -way to create functions. +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. ``` // Define f to hold a function value @@ -951,16 +645,9 @@ function g(a, b) { let h = a => a % 3; ``` -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. +A key part of 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 -help organize a program by grouping code into pieces that do specific -things. +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 @@ -968,10 +655,7 @@ things. {{index "Math object", "minimum (exercise)", "Math.min function", minimum}} -The [previous chapter](program_structure#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. +The [previous chapter](program_structure#return_values) introduced the standard function `Math.min` that returns its smallest argument. We can write a function like that ourselves now. Define the function `min` that takes two arguments and returns their minimum. {{if interactive @@ -989,9 +673,7 @@ if}} {{index "minimum (exercise)"}} -If you have trouble putting braces and -parentheses in the right place to get a valid function definition, -start by copying one of the examples in this chapter and modifying it. +If you have trouble putting braces and parentheses in the right place to get a valid function definition, start by copying one of the examples in this chapter and modifying it. {{index "return keyword"}} @@ -1003,10 +685,7 @@ hint}} {{index recursion, "isEven (exercise)", "even number"}} -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: +We've seen that we can use `%` (the remainder operator) 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. @@ -1014,14 +693,11 @@ whole number is even or odd: - 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 single parameter (a -positive, whole number) 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. {{index "stack overflow"}} -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? {{if interactive @@ -1042,21 +718,11 @@ if}} {{index "isEven (exercise)", ["if keyword", chaining], recursion}} -Your function will likely look somewhat similar to the inner `find` -function in the recursive `findSolution` -[example](functions#recursive_puzzle) in this chapter, with an -`if`/`else if`/`else` chain that tests which of the three cases -applies. The final `else`, corresponding to the third case, makes the -recursive call. Each of the branches should contain a `return` -statement or in some other way arrange for a specific value to be -returned. +Your function will likely look somewhat similar to the inner `find` function in the recursive `findSolution` [example](functions#recursive_puzzle) in this chapter, with an `if`/`else if`/`else` chain that tests which of the three cases applies. The final `else`, corresponding to the third case, makes the recursive call. Each of the branches should contain a `return` statement or in some other way arrange for a specific value to be returned. {{index "stack overflow"}} -When given a negative number, the function will recurse again and -again, passing itself an ever more negative number, thus getting -further and further away from returning a result. It will eventually -run out of stack space and abort. +When given a negative number, the function will recurse again and again, passing itself an ever more negative number, thus getting further and further away from returning a result. It will eventually run out of stack space and abort. hint}} @@ -1064,28 +730,18 @@ hint}} {{index "bean counting (exercise)", [string, indexing], "zero-based counting", ["length property", "for string"]}} -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.length - 1`. -In other words, a two-character string has length 2, and its -characters have positions 0 and 1. +You can get the *N*th character, or letter, from a string by writing `[N]` after the string (for example, `string[2]`). The resulting value will be a string containing only one character (for example, `"b"`). The first character has position 0, 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. -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. +Write a function called `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. +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. {{if interactive ```{test: no} // Your code here. -console.log(countBs("BBC")); +console.log(countBs("BOB")); // → 2 console.log(countChar("kakkerlak", "k")); // → 4 @@ -1097,15 +753,10 @@ if}} {{index "bean counting (exercise)", ["length property", "for string"], "counter variable"}} -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.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.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. {{index "local binding"}} -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. +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. hint}} diff --git a/04_data.md b/04_data.md index 73e17d0dc..51541b8d2 100644 --- a/04_data.md +++ b/04_data.md @@ -4,42 +4,25 @@ {{quote {author: "Charles Babbage", title: "Passages from the Life of a Philosopher (1864)", chapter: true} -On two occasions I have been asked, 'Pray, Mr. Babbage, if you put -into the machine wrong figures, will the right answers come out?' -[...] I am not able rightly to apprehend the kind of confusion of -ideas that could provoke such a question. +On two occasions I have been asked, 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out?' [...] I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question. quote}} {{index "Babbage, Charles"}} -{{figure {url: "img/chapter_picture_4.jpg", alt: "Picture of a weresquirrel", chapter: framed}}} +{{figure {url: "img/chapter_picture_4.jpg", alt: "Illustration of a squirrel next to a pile of books and a pair of glasses. A moon and stars are visible in the background.", chapter: framed}}} {{index object, "data structure"}} -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. +Numbers, Booleans, and strings are the atoms from which ((data)) structures are built. Many types of information require more than one atom, though. _Objects_ allow us to group values—including other objects—to build more complex structures. -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 programs we have built so far have been limited by the fact that they were operating only on simple data types. After learning the basics of data structures in this chapter, 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 bindings 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 introduced earlier in the book. {{if book -The online coding ((sandbox)) for the book -([_eloquentjavascript.net/code_](https://eloquentjavascript.net/code)) -provides a way to run code in the context of a specific chapter. If -you decide to work through the examples in another environment, be -sure to first download the full code for this chapter from the sandbox -page. +The online coding ((sandbox)) for the book ([_https://eloquentjavascript.net/code_](https://eloquentjavascript.net/code)) provides a way to run code in the context of a particular chapter. If you decide to work through the examples in another environment, be sure to first download the full code for this chapter from the sandbox page. if}} @@ -47,56 +30,31 @@ if}} {{index "weresquirrel example", lycanthropy}} -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 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. - -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. +Every now and then, usually between 8 p.m. and 10 p.m., ((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 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 of waking 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. + +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. However, avoiding oak trees did not solve the problem. {{index journal}} -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 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. -The first thing he needs is a data structure to store this -information. +The first thing he needs is a data structure to store this information. -## Data sets +## Datasets -{{index "data structure"}} +{{index ["data structure", collection], [memory, organization]}} -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. +To work with a chunk of digital data, we 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. {{index string}} -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. +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. We'd have to somehow extract the digits and convert them back to numbers to access them. {{index [array, creation], "[] (array)"}} -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. +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. ``` let listOfNumbers = [2, 3, 5, 7, 11]; @@ -110,40 +68,24 @@ console.log(listOfNumbers[2 - 1]); {{index "[] (subscript)", [array, indexing]}} -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 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. {{id array_indexing}} {{index "zero-based counting"}} -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. +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 number of items to skip, counting from the start of the array. {{id properties}} ## Properties -{{index "Math object", "Math.max function", ["length property", "for string"], [object, property], "period character"}} +{{index "Math object", "Math.max function", ["length property", "for string"], [object, property], "period character", [property, access]}} -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). +We've seen a few expressions like `myString.length` (to get the length of a string) and `Math.max` (the maximum function) in past chapters. These expressions 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). -{{index property, null, undefined}} +{{index [property, access], null, undefined}} -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. +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: ```{test: no} null.length; @@ -151,37 +93,17 @@ null.length; ``` {{indexsee "dot character", "period character"}} -{{index "[] (subscript)", "period character", "square brackets", "computed property"}} - -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"]`. - -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. +{{index "[] (subscript)", "period character", "square brackets", "computed property", [property, access]}} + +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]` takes the value of the variable named `x` and uses that, converted to a string, as the property name. + +If you know that the property in which you are interested 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 works only with names that look like valid binding names—starting with a letter or underscore, and containing only letters, numbers, and underscores. If you want to access a property named _2_ or _John Doe_, you must use square brackets: `value[2]` or `value["John Doe"]`. + +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. {{index ["length property", "for array"], [array, "length of"]}} -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"]`. +Just like strings, arrays have a `length` property that tells us how many elements the array has. {{id methods}} @@ -189,8 +111,7 @@ advance, so to find the length of an array, you typically write {{index [function, "as property"], method, string}} -Both string and array objects contain, in addition to the `length` -property, a number of properties that hold function values. +Both string and array values contain, in addition to the `length` property, a number of properties that hold function values. ``` let doh = "Doh"; @@ -202,25 +123,17 @@ console.log(doh.toUpperCase()); {{index "case conversion", "toUpperCase method", "toLowerCase method"}} -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. +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. -{{index this}} +{{index "this binding"}} -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 ?](object#obj_methods). +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. You'll find out how this works in [Chapter ?](object#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". +Properties that contain functions are generally called _methods_ of the value they belong to, as in "`toUpperCase` is a method of a string". {{id array_methods}} -This example demonstrates two methods you can use to manipulate -arrays: +This example demonstrates two methods you can use to manipulate arrays. ``` let sequence = [1, 2, 3]; @@ -236,34 +149,21 @@ console.log(sequence); {{index collection, array, "push method", "pop method"}} -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. +The `push` method adds values to the end of an array. 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](functions#stack), which is an -instance of the same idea. +{{index ["data structure", stack]}} + +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. Stacks are common in programming—you might remember the function ((call stack)) from [the previous chapter](functions#stack), which is an instance of the same idea. ## Objects {{index journal, "weresquirrel example", array, record}} -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. +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. -{{index syntax, property, "curly braces", "{} (object)"}} +{{index [syntax, object], [property, definition], [braces, object], "{} (object)"}} -Values of the type _((object))_ are arbitrary collections of -properties. One way to create an object is by using curly braces as an -expression. +Values of the type _((object))_ are arbitrary collections of properties. One way to create an object is by using braces as an expression. ``` let day1 = { @@ -281,11 +181,7 @@ console.log(day1.wolf); {{index [quoting, "of object properties"], "colon character"}} -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. +Inside the braces, you write 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 as shown in this example helps with readability. Properties whose names aren't valid binding names or valid numbers must be quoted: ``` let descriptions = { @@ -294,37 +190,25 @@ let descriptions = { }; ``` -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. +{{index [braces, object]}} + +This means that braces have _two_ meanings in JavaScript. At the start of a ((statement)), they begin a ((block)) of statements. In any other position, they describe an object. Fortunately, it is rarely useful to start a statement with an object in braces, so the ambiguity between these two is not much of a problem. The one case where this does come up is when you want to return an object from a shorthand arrow function—you can't write `n => {prop: n}` since the braces will be interpreted as a function body. Instead, you have to put a set of parentheses around the object to make it clear that it is an expression. {{index undefined}} -Reading a property that doesn't exist will give you the value -`undefined`. +Reading a property that doesn't exist will give you the value `undefined`. {{index [property, assignment], mutability, "= operator"}} -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. +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. -{{index "tentacle (analogy)", [property, "model of"]}} +{{index "tentacle (analogy)", [property, "model of"], [binding, "model of"]}} -To briefly return to our tentacle model of ((binding))s—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. +To briefly return to our tentacle model of ((binding))s—property bindings are similar. They _grasp_ values, but other bindings and properties might be holding onto those same values. You can think of objects as octopuses with any number of tentacles, each of which has a name written on it. {{index "delete operator", [property, deletion]}} -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. +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. ``` let anObject = {left: 1, right: 2}; @@ -341,26 +225,18 @@ console.log("right" in anObject); {{index "in operator", [property, "testing for"], object}} -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`. +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`. {{index "Object.keys function"}} -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. +To find out what properties an object has, you can use the `Object.keys` function. Give the function an object and it will return 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. +There's an `Object.assign` function that copies all properties from one object into another: ``` let objectA = {a: 1, b: 2}; @@ -371,14 +247,11 @@ console.log(objectA); {{index array, collection}} -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. +Arrays, then, are just a kind of object specialized for storing sequences of things. If you evaluate `typeof []`, it produces `"object"`. You can visualize arrays as long, flat octopuses with all their tentacles in a neat row, labeled with numbers. {{index journal, "weresquirrel example"}} -We will represent Jacques' journal as an array of objects. +Jacques will represent the journal that Jacques keeps as an array of objects: ```{test: wrap} let journal = [ @@ -391,36 +264,23 @@ let journal = [ {events: ["weekend", "cycling", "break", "peanuts", "beer"], squirrel: true}, - /* and so on... */ + /* And so on... */ ]; ``` ## Mutability -We will get to actual programming _real_ soon now. First there's one -more piece of theory to understand. +We will get to actual programming soon, but first, there's one more piece of theory to understand. -{{index mutability, "side effect", number, string, Boolean, object}} +{{index mutability, "side effect", number, string, Boolean, [object, mutability]}} -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"`. +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"`. -Objects work differently. You _can_ change their properties, -causing a single object value to have different content at different times. +Objects work differently. You _can_ change their properties, causing a single object value to have different content at different times. -{{index [object, identity], identity, memory, mutability}} +{{index [object, identity], identity, [memory, organization], mutability}} -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: +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: ``` let object1 = {value: 10}; @@ -441,20 +301,11 @@ console.log(object3.value); {{index "tentacle (analogy)", [binding, "model of"]}} -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. +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. -{{index "const keyword", "let keyword"}} +{{index "const keyword", "let keyword", [binding, "as state"]}} -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. +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 at which the binding points. 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. ```{test: no} const score = {visitors: 0, home: 0}; @@ -466,20 +317,13 @@ score = {visitors: 1, home: 1}; {{index "== operator", [comparison, "of objects"], "deep comparison"}} -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](data#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 that compares objects by contents, but it is possible to write it yourself (which is one of the [exercises](data#exercise_deep_compare) at the end of this chapter). ## The lycanthrope's log {{index "weresquirrel example", lycanthropy, "addEntry function"}} -So Jacques starts up his JavaScript interpreter and sets up the -environment he needs to keep his ((journal)). +Jacques starts up his JavaScript interpreter and sets up the environment he needs to keep his ((journal)): ```{includeCode: true} let journal = []; @@ -489,17 +333,11 @@ function addEntry(events, squirrel) { } ``` -{{index "curly braces", "{} (object)"}} +{{index [braces, object], "{} (object)", [property, definition]}} -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. +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: `events`. This is shorthand that means the same thing—if a property name in 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. +Every evening at 10 p.m.—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", @@ -510,52 +348,25 @@ addEntry(["weekend", "cycling", "break", "peanuts", "beer"], true); ``` -Once he has enough data points, he intends to use statistics to find -out which of these events may be related to the squirrelifications. +Once he has enough data points, he intends to use statistics to find out which of these events may be related to the squirrelifications. {{index correlation}} -_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. +_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 1 indicates that the two are perfectly related—if you know one, you also know the other. Negative 1 also means that the variables are perfectly related but are opposites—when one is true, the other is false. {{index "phi coefficient"}} -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. +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 number 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. -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: +We could take the event of eating ((pizza)) and put that in a frequency table like this, where each number indicates the number of times that combination occurred in our measurements. -{{figure {url: "img/pizza-squirrel.svg", alt: "Eating pizza versus turning into a squirrel", width: "7cm"}}} +{{figure {url: "img/pizza-squirrel.svg", alt: "A two-by-two table showing the pizza variable on the horizontal, and the squirrel variable on the vertical axis. Each cell show how many time that combination occurred. In 76 cases, neither happened. In 9 cases, only pizza was true. In 4 cases only squirrel was true. And in one case both occurred.", width: "7cm"}}} If we call that table _n_, we can compute _ϕ_ using the following formula: {{if html -
| ϕ = | -
- n11n00 −
- n10n01
- √
- n1•n0•n•1n•0
-
- |
-
| ϕ = | n11n00 − n10n01 √ n1•n0•n•1n•0 |
`). +HTML documents have a head and a body. The head contains information _about_ the document, and the body contains the document itself. In this case, the head declares that the title of this document is "My home page" and that it uses the UTF-8 encoding, which is a way to encode Unicode text as binary data. The document's body contains a heading (`
`). {{index "href attribute", "a (HTML tag)"}} -Tags come in several forms. An ((element)), such as the body, a -paragraph, or a link, is started by an _((opening tag))_ like `
` -and ended by a _((closing tag))_ like `
`. Some opening tags, such -as the one for the ((link)) (``), contain extra information in the -form of `name="value"` pairs. These are called _((attribute))s_. In -this case, the destination of the link is indicated with -`href="http://eloquentjavascript.net"`, where `href` stands for -"hypertext reference". +Tags come in several forms. An ((element)), such as the body, a paragraph, or a link, is started by an _((opening tag))_ like `` and ended by a _((closing tag))_ like `
`. Some opening tags, such as the one for the ((link)) (``), contain extra information in the form of `name="value"` pairs. These are called _((attribute))s_. In this case, the destination of the link is indicated with `href="http://eloquentjavascript.net"`, where `href` stands for "hypertext reference". {{index "src attribute", "self-closing tag", "img (HTML tag)"}} -Some kinds of ((tag))s do not enclose anything and thus do not need to -be closed. The metadata tag `` is an example of -this. +Some kinds of ((tag))s do not enclose anything and thus do not need to be closed. The metadata tag `` is an example of this. {{index [escaping, "in HTML"]}} -To be able to include ((angle brackets)) in the text of a document, -even though they have a special meaning in HTML, yet another form of -special notation has to be introduced. A plain opening angle bracket -is written as `<` ("less than"), and a closing bracket is written -as `>` ("greater than"). In HTML, an ampersand (`&`) character -followed by a word and a semicolon (`;`) is called an _((entity))_, -and will be replaced by the character it encodes. +To be able to include ((angle brackets)) in the text of a document even though they have a special meaning in HTML, yet another form of special notation has to be introduced. A plain opening angle bracket is written as `<` ("less than"), and a closing bracket is written as `>` ("greater than"). In HTML, an ampersand (`&`) character followed by a name or character code and a semicolon (`;`) is called an _((entity))_ and will be replaced by the character it encodes. -{{index "backslash character", "ampersand character", "double-quote character"}} +{{index ["backslash character", "in strings"], "ampersand character", "double-quote character"}} -This is analogous to the way backslashes are used in JavaScript -strings. Since this mechanism gives ampersand characters a special -meaning, too, those need to be escaped as `&`. Inside attribute -values, which are wrapped in double quotes, `"` can be used to -insert an actual quote character. +This is analogous to the way backslashes are used in JavaScript strings. Since this mechanism gives ampersand characters a special meaning too, they need to be escaped as `&`. Inside attribute values, which are wrapped in double quotes, `"` can be used to insert a literal quote character. {{index "error tolerance", parsing}} -HTML is parsed in a remarkably error-tolerant way. When tags that -should be there are missing, the browser reconstructs them. The way in -which this is done has been standardized, and you can rely on all -modern browsers to do it in the same way. +HTML is parsed in a remarkably error-tolerant way. When tags that should be there are missing, the browser automatically adds them. The way this is done has been standardized, and you can rely on all modern browsers to do it in the same way. The following document will be treated just like the one shown previously: -```{lang: "text/html"} +```{lang: "html"} @@ -281,25 +172,13 @@ The following document will be treated just like the one shown previously: {{index "title (HTML tag)", "head (HTML tag)", "body (HTML tag)", "html (HTML tag)"}} -The ``, ``, and `` tags are gone completely. The -browser knows the `` and `