Eloquent JavaScript

Besides explaining JavaScript, this book also will introduce the basic principles of programming.

Marijn Haverbeke

478 Pages

30334 Reads



PDF Format

4.57 MB

Java Script

Download PDF format

  • Marijn Haverbeke   
  • 478 Pages   
  • 23 Feb 2015
  • Page - 1

    A Modern Introduction to Programming Marijn Haverbeke SECOND EDITION read more..

  • Page - 2

    read more..

  • Page - 3


  • Page - 4

    read more..

  • Page - 5

    PRAISE FOR THE FIRST EDITION OF ELOQUENT JAVASCRIPT “I became a better architect, author, mentor and developer because of this book. It deserves to share shelf space with Flannagan and Crockford.” — ANGUS CROLL, TWITTER DEVELOPER “This is the book I give out when people ask me how to learn proper JavaScript.” — CHRIS WILLIAMS, ORGANIZER OF JSCONF US “One read more..

  • Page - 6

    read more..

  • Page - 7

    ELOQUENT JAVASCRIPT A Modern Introduction to Programming by Marijn Haverbeke San Francisco read more..

  • Page - 8

    ELOQUENT JAVASCRIPT, 2ND EDITION. Copyright © 2015 by Marijn Haverbeke. All rights reserved. No part of this work may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording, or by any information storage or retrieval system, without the prior written permission of the copyright owner and the publisher. Printed in USA read more..

  • Page - 9

    For Lotte and Jan read more..

  • Page - 10

    read more..

  • Page - 11

    read more..

  • Page - 12

    read more..

  • Page - 13

    read more..

  • Page - 14

    read more..

  • Page - 15

    read more..

  • Page - 16

    read more..

  • Page - 17

    read more..

  • Page - 18

    read more..

  • Page - 19

    read more..

  • Page - 20

    read more..

  • Page - 21

    read more..

  • Page - 22

    read more..

  • Page - 23

    read more..

  • Page - 24

    read more..

  • Page - 25

    read more..

  • Page - 26

    read more..

  • Page - 27

    read more..

  • Page - 28

    read more..

  • Page - 29

    read more..

  • Page - 30

    What Is JavaScript? 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. But it is also used in more read more..

  • Page - 31

    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 pro- gramming, most notably the Node.js project (the subject of Chapter 20), are providing a powerful environment for programming JavaScript outside of the browser. Code, and read more..

  • Page - 32

    The language part of the book starts with four chapters to introduce the basic structure of the JavaScript language. They introduce control structures (such as the while word you saw in this introduction), functions (writing your own operations), and data structures. After these, you will be able to write simple programs. Next, Chapters 5 and 6 introduce techniques to use func- read more..

  • Page - 33

    PART I LANGUAGE read more..

  • Page - 34

    “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.” — Master Yuan-Ma, The Book of Programming read more..

  • Page - 35

    1 VALUES, TYPES, AND OPERATORS Inside the computer’s world, there is only data. You can read data, modify data, create new data—but any- thing that isn’t data simply does not exist. All this data is stored as long sequences of bits and is thus funda- mentally alike. Bits are any kind of two-valued things, usually described as zeros and ones. Inside the computer, they read more..

  • Page - 36

    Values Imagine a sea of bits. An ocean of them. A typical modern computer has more than 30 billion bits in its volatile data storage. Nonvolatile storage (the hard disk or equivalent) tends to have yet a few orders of magnitude more. To be able to work with such quantities of bits without getting lost, you can separate them into chunks that represent pieces of read more..

  • Page - 37

    264 different numbers, which is about 18 quintillion (an 18 with 18 zeros after it). This is a lot. Computer memory used to be a lot smaller, and people tended to use groups of 8 or 16 bits to represent their numbers. It was easy to acciden- tally overflow such small numbers—to end up with a number that did not fit into the given amount of bits. Today, even read more..

  • Page - 38

    (100 + 4) * 11 For subtraction, there is the - operator, and 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 read more..

  • Page - 39

    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 charac- ter. 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 read more..

  • Page - 40

    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. console.log(- (10 - 2)) // -8 Boolean Values Often, you will need a value that simply distinguishes read more..

  • Page - 41

    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. Logical Operators There are also some operations that can be applied to Boolean values read more..

  • Page - 42

    console.log(false ?1:2); // 2 This one is called the conditional operator (or sometimes just ternary op- erator since it is the only such operator in the language). The value on the left of the question mark “picks” which of the other two values will come out. When it is true, the middle value is chosen, and when it is false, the value on the right comes out. read more..

  • Page - 43

    When something that doesn’t map to a number in an obvious way (such as "five" or undefined) is converted to a number, the value NaN is produced. Further arithmetic operations on NaN keep producing NaN, so if you find your- self getting one of those in an unexpected place, look for accidental type conversions. When comparing values of the same type using ==, the read more..

  • Page - 44

    console.log(null || "user") // user console.log("Karl" || "user") // Karl This functionality allows the || operator to be used as a way to fall back on a default value. If you give it an expression that might produce an empty value on the left, the value on the right will be used as a replace- ment in that case. The && operator works read more..

  • Page - 45

    read more..

  • Page - 46

    “And my heart glows bright red under my filmy, translucent skin and they have to admin- ister 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!” — why, Why’s (Poignant) Guide to Ruby read more..

  • Page - 47

    2 PROGRAM STRUCTURE In this chapter, we will start to do things that can actu- ally be called programming. We will expand our com- mand of the JavaScript language beyond the nouns and sentence fragments we’ve seen so far, to the point where we can express some meaningful prose. Expressions and Statements In Chapter 1, we made some values and then applied operators to them read more..

  • Page - 48

    If an expression corresponds to a sentence fragment, a JavaScript state- ment corresponds to a full sentence in a human language. A program is sim- ply a list of statements. 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 read more..

  • Page - 49

    After a variable has been defined, its name can be used as an expression. The value of such an expression is the value the variable currently holds. Here’s an example: var ten = 10; console.log(ten * ten); // 100 Variable names can be any word that isn’t reserved as a keyword (such as var). They may not include spaces. Digits can also be part of variable read more..

  • Page - 50

    Let’s look at an example. To remember the number of dollars that Luigi still owes you, you create a variable. And then when he pays back $35, you give this variable a new value. var luigisDebt = 140; luigisDebt = luigisDebt - 35; console.log(luigisDebt); // 105 When you define a variable without giving it a value, the tentacle has nothing to grasp, so it ends in thin read more..

  • Page - 51

    Functions A lot of the values provided in the default environment have the type func- tion. 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 en- vironment, the variable alert holds a function that shows a little dialog box with a message. It is used like this: alert("Good read more..

  • Page - 52

    Return Values Showing a dialog box or writing text to the screen is a side effect. A lot of functions are useful because of the side effects they produce. Functions may also produce values, and in that case, they don’t need to have a side effect to be useful. For example, the function Math.max takes any number of number values and gives back the greatest. read more..

  • Page - 53

    These two functions aren’t used much in modern web programming, mostly because you have no control over the way the resulting windows look, but they are useful for toy programs and experiments. Control Flow When your program contains more than one statement, the statements are executed, predictably, from top to bottom. As a basic example, this program has two statements. The read more..

  • Page - 54

    The keyword if executes or skips a statement depending on the value of a Boolean expression. The deciding expression is written after the keywords, between parentheses, followed by the statement to execute. The isNaN function is a standard JavaScript function that returns true only if the argument it is given is NaN. The Number function happens to return NaN when you give it read more..

  • Page - 55

    while and do Loops Consider a program that prints all even numbers from 0 to 12. One way to write this is as follows: console.log(0); console.log(2); console.log(4); console.log(6); console.log(8); console.log(10); console.log(12); That works, but the idea of writing a program is to make something less work, not more. If we needed all even numbers less than 1,000, the previ- ous would read more..

  • Page - 56

    In this book, I will write most single-statement bodies without braces, since I value brevity. You are free to go with whichever style you prefer. The variable number demonstrates the way a variable can track the progress of a program. Every time the loop repeats, number is incremented by 2. Then, at the beginning of every repetition, it is compared with the number 12 to read more..

  • Page - 57

    blocks, it can become hard to see where one block ends and another begins. With proper indentation, the visual shape of a program corresponds to the shape of the blocks inside it. I like to use two spaces for every open block, but tastes differ—some people use four spaces, and some people use tab characters. for Loops Many loops follow the pattern seen in the previous read more..

  • Page - 58

    This program illustrates the break statement. It finds the first number that is both greater than or equal to 20 and divisible by 7. for (var current = 20; ; current++) { if (current%7==0) break; } console.log(current); // 21 Using the remainder (%) operator is an easy way to test whether a num- ber is divisible by another number. If it is, the remainder of their division read more..

  • Page - 59

    Dispatching on a Value with switch It is common for code to look like this: if (variable == "value1") action1(); else if (variable == "value2") action2(); else if (variable == "value3") action3(); else defaultAction(); There is a construct called switch that is intended to solve such a “dis- patch” in a more direct way. Unfortunately, the syntax JavaScript read more..

  • Page - 60

    The first style can be hard to read. Personally, I like the look of the un- derscores, 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 read more..

  • Page - 61

    Summary You now know that a program is built out of statements, which themselves sometimes contain more statements. Statements tend to contain expres- sions, which themselves can be built out of smaller expressions. Putting statements after one another gives you a program that is exe- cuted from top to bottom. You can introduce disturbances in the flow of control by using read more..

  • Page - 62

    FizzBuzz 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 read more..

  • Page - 63

    read more..

  • Page - 64

    “People think that computer science is the art of geniuses but the actual reality is the oppo- site, just many people doing things that build on each other, like a wall of mini stones.” — Donald Knuth read more..

  • Page - 65

    3 FUNCTIONS You’ve seen function values, such as alert, and how to call them. Functions are the bread and butter of JavaScript programming. The concept of wrapping a piece of program in a value has many uses. It is a tool to structure larger programs, to reduce repetition, to associate names with subprograms, and to isolate these subprograms from each other. The most obvious read more..

  • Page - 66

    Defining a Function A function definition is just a regular variable definition where the value given to the variable happens to be a function. For example, the follow- ing code defines the variable square to refer to a function that produces the square of a given number: var square = function(x) { return x * x; }; console.log(square(12)); // 144 A function is created by an read more..

  • Page - 67

    Parameters and Scopes The parameters to a function behave like regular variables, but their initial values are given by the caller of the function, not the code in the function itself. An important property of functions is that the variables created inside of them, including their parameters, are local to the function. This means, for example, that the result variable in the read more..

  • Page - 68

    Nested Scopes JavaScript distinguishes not just between global and local variables. Functions can be created inside other functions, producing several degrees of locality. For example, this rather nonsensical function has two functions inside of it: var landscape = function() { var result = ""; var flat = function(size) { for (var count = 0; count < size; count++) result += read more..

  • Page - 69

    var something = 1; { var something = 2; // Do stuff with variable something... } // Outside of the block again... But the something inside the block refers to the same variable as the one outside the block. In fact, although blocks like this are allowed, they are use- ful only to group the body of an if statement or a loop. If you find this odd, you’re not alone. read more..

  • Page - 70

    console.log("The future says:", future()); function future() { return "We STILL have no flying cars."; } This code works, even though the function is defined below the code that uses it. This is because function declarations are not part of the regu- lar top-to-bottom flow of control. They are conceptually moved to the top of their scope and can be used by all read more..

  • Page - 71

    We could show the flow of control schematically like this: top greet console.log greet top console.log top Because a function has to jump back to the place of the call when it re- turns, the computer must remember the context from which the function was called. In one case, console.log has to jump back to the greet function. In the other case, it jumps back to the end of read more..

  • Page - 72

    The downside of this is that it is possible—likely, even—that you’ll acci- dentally pass the wrong number of arguments to functions and no one will tell you about it. The upside is that this behavior can be used to have a function take “op- tional” arguments. For example, the following version of power can be called either with two arguments or with a single read more..

  • Page - 73

    var wrap1 = wrapValue(1); var wrap2 = wrapValue(2); console.log(wrap1()); // 1 console.log(wrap2()); // 2 This is allowed and works as you’d hope—the variable can still be ac- cessed. In fact, multiple instances of the variable can be alive at the same time, which is another good illustration of the concept that local variables really are re-created for every call—different calls read more..

  • Page - 74

    Recursion It is perfectly okay for a function to call itself, as long as it takes care not to overflow the stack. A function that calls itself is called recursive. Recursion allows some functions to be written in a different style. Take, for example, this alternative implementation of power: function power(base, exponent) { if (exponent == 0) return 1; else return base * read more..

  • Page - 75

    longer to write than their more straightforward equivalents and that usually run only marginally faster. But recursion is not always just a less-efficient alternative to looping. Some problems are much easier to solve with recursion than with loops. Most often these are problems that require exploring or processing several “branches,” each of which might branch out again into more read more..

  • Page - 76

    To better understand how this function produces the effect we’re look- ing for, let’s look at all the calls to find that are made when searching for a solution for the number 13. find(1, "1") find(6, "(1 + 5)") find(11, "((1 + 5) + 5)") find(16, "(((1 + 5) + 5) + 5)") too big find(33, "(((1 + 5) + 5) * 3)") too big find(18, read more..

  • Page - 77

    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. 007 Cows 011 Chickens That clearly asks for a function of two arguments. Let’s get coding. function printFarmInventory(cows, chickens) { var cowString = read more..

  • Page - 78

    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. Instead of lifting out the repeated part of our program wholesale, let’s try to pick out a single concept. function zeroPad(number, width) { var string = String(number); while (string.length < width) string = "0" read more..

  • Page - 79

    A pure function is a specific kind of value-producing function that not only has no side effects but also doesn’t rely on side effects from other code— for example, it doesn’t read global variables that are occasionally changed by other code. A pure function has the pleasant property that, when called with the samearguments, it always produces the same value (and read more..

  • Page - 80

    Exercises Minimum The previous chapter introduced the standard function Math.min that returns its smallest argument. We can do that ourselves now. Write a function min that takes two arguments and returns their minimum. Recursion We’ve seen that % (the remainder operator) can be used to test whether a number is even or odd by using %2 to check whether it’s divisible by two. read more..

  • Page - 81

    read more..

  • Page - 82

    “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.” — Charles Babbage, Passages from the Life of a Philosopher (1864) read more..

  • Page - 83

    4 DATA STRUCTURES: OBJECTS AND ARRAYS Numbers, Booleans, and strings are the bricks that data structures are built from. But you can’t make much of a house out of a single brick. Objects allow us to group values—including other objects—together and thus build more complex structures. The programs we have built so far have been seriously hampered by the fact that they were read more..

  • Page - 84

    The Weresquirrel Every now and then, usually between eight and ten in the evening, Jacques finds himself transforming into a small furry rodent with a bushy tail. On one hand, Jacques is quite glad that he doesn’t have classic lycan- thropy. Turning into a squirrel tends to cause fewer problems than turn- ing into a wolf. Instead of having to worry about accidentally read more..

  • Page - 85

    Fortunately, JavaScript provides a data type specifically for storing se- quences of values. It is called an array and is written as a list of values be- tween square brackets, separated by commas. var listOfNumbers = [2, 3, 5, 7, 11]; console.log(listOfNumbers[1]); // 3 console.log(listOfNumbers[1 - 1]); // 2 The notation for getting at the elements inside an array also uses square read more..

  • Page - 86

    So if you know that the property you are interested in is called “length,” you say value.length. If you want to extract the property named by the value held in the variable i, you say value[i]. And because property names can be any string, if you want to access a property named “0” or “John Doe,” you must use square brackets: value[0] or value["John read more..

  • Page - 87

    The push method can be used to add values to the end of an array. The pop method does the opposite: it removes the value at the end of the array and returns it. An array of strings can be flattened to a single string with the join method. The argument given to join determines the text that is glued between the array’s elements. Objects Back to the weresquirrel. read more..

  • Page - 88

    Reading a property that doesn’t exist will produce the value undefined, which happens the first time we try to read the wolf property in the previous example. It is possible to assign a value to a property expression with the = opera- tor. This will replace the property’s value if it already existed or create a new property on the object if it didn’t. To briefly read more..

  • Page - 89

    them as long, flat octopuses with all their arms in a neat row, labeled with numbers. So we can represent Jacques’s journal as an array of objects. var journal = [ {events: ["work", "touched tree", "pizza", "running", "television"], squirrel: false}, {events: ["work", "ice cream", "cauliflower", "lasagna", "touched read more..

  • Page - 90

    same object and having two different objects that contain the same proper- ties. Consider the following code: var object1 = {value: 10}; var object2 = object1; var object3 = {value: 10}; console.log(object1 == object2); // true console.log(object1 == object3); // false object1.value = 15; console.log(object2.value); // 15 console.log(object3.value); // 10 The object1 and object2 variables grasp the read more..

  • Page - 91

    addEntry(["work", "touched tree", "pizza", "running", "television"], false); addEntry(["work", "ice cream", "cauliflower", "lasagna", "touched tree", "brushed teeth"], false); addEntry(["weekend", "cycling", "break", "peanuts", "beer"], true); Once he has enough data points, he read more..

  • Page - 92

    The notation n01 indicates the number of measurements where the first measurement (pizza) is false (0) and the second measurement (squirrel- ness) is true (1). In this example, n01 is 4. The value n1• refers to the sum of all measurements where the first vari- able is true, which is 10 in the example table. Likewise, n•0 refers to the sum of the measurements where the read more..

  • Page - 93

    To extract a two-by-two table for a specific event from this journal, we must loop over all the entries and tally up how many times the event occurs in relation to squirrel transformations. function hasEvent(event, entry) { return entry.events.indexOf(event) != -1; } function tableFor(event, journal) { var table = [0, 0, 0, 0]; for (var i = 0; i < journal.length; i++) { var read more..

  • Page - 94

    A better way is to use object properties named after the event types. We can use the square bracket access notation to create and read the properties and can use the in operator to test whether a given property exists. var map = {}; function storePhi(event, phi) { map[event] = phi; } storePhi("pizza", 0.069); storePhi("touched tree", -0.081); console.log("pizza" read more..

  • Page - 95

    if (!(event in phis)) phis[event] = phi(tableFor(event, journal)); } } return phis; } var correlations = gatherCorrelations(JOURNAL); console.log(correlations.pizza); // 0.068599434 Let’s see what came out. for (var event in correlations) console.log(event + ": " + correlations[event]); // carrot: 0.0140970969 // exercise: 0.0685994341 // weekend: 0.1371988681 // bread: -0.0757554019 // pudding: read more..

  • Page - 96

    for (var i = 0; i < JOURNAL.length; i++) { var entry = JOURNAL[i]; if (hasEvent("peanuts", entry) && !hasEvent("brushed teeth", entry)) entry.events.push("peanut teeth"); } console.log(phi(tableFor("peanut teeth", JOURNAL))); // 1 Well, that’sunmistakable! The phenomenon occurs precisely when Jacques eats peanuts and fails to brush his teeth. If only he read more..

  • Page - 97

    The indexOf method has a sibling called lastIndexof, which starts search- ing for the given element at the end of the array instead of the front. console.log([1, 2, 3, 2, 1].indexOf(2)); // 1 console.log([1, 2, 3, 2, 1].lastIndexOf(2)); // 3 Both indexOf and lastIndexOf take an optional second argument that indi- cates where to start searching from. Another fundamental method is read more..

  • Page - 98

    doesn’t actually store those properties. The values are immutable and can- not be changed. But these types do have some built-in properties. Every string value has anumber of methods. The most useful ones are probably slice and indexOf, which resemble the array methods of the samename. console.log("coconuts".slice(4, 7)); // nut console.log("coconut".indexOf("u")); // 5 read more..

  • Page - 99

    function threeArguments(a, b, c) {} threeArguments(); // And so is this The arguments object has a length property that tells us the number of arguments that were really passed to the function. It also has a property for each argument, named 0, 1, 2, and so on. If that sounds a lot like an array to you, you’re right, it is a lot like an array. But this object, read more..

  • Page - 100

    a value. Rather, it provides a namespace so that all these functions and values do not have to be global variables. Having too many global variables “pollutes” the namespace. The more names that have been taken, the more likely you are to accidentally over- write the value of some variable. For example, it’s not unlikely that you’ll want to namesomething max in one of read more..

  • Page - 101

    If we want a whole random number instead of a fractional one, we can use Math.floor (which rounds down to the nearest whole number) on the result of Math.random. console.log(Math.floor(Math.random() * 10)); // 2 Multiplying the random number by 10 gives us a number greater than or equal to zero, and below 10. Since Math.floor rounds down, this expres- sion will produce, with read more..

  • Page - 102

    Exercises The Sum of a Range The introduction of this book alluded to the following as a nice way to com- pute the sum of a rangeofnumbers: console.log(sum(range(1, 10))); Write a range function that takes two arguments, start and end, and returns an array containing all the numbers from start up to (and includ- ing) end. Next, write a sum function that takes an array of read more..

  • Page - 103

    rest: { value: 3, rest: null } } }; The resulting objects form a chain, like this: value: 1 rest: value: 2 rest: value: 3 rest: null A nice thing about lists is that they can share parts of their structure. For example, if I create two new values {value: 0, rest: list} and {value: -1, rest: list} (with list referring to the variable defined earlier), they are both read more..

  • Page - 104

    “There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies” — C.A.R. Hoare, 1980 ACM Turing Aware Lecture read more..

  • Page - 105

    5 HIGHER-ORDER FUNCTIONS A large program is a costly program, and not just be- cause of the time it takes to build. Size almost always involves complexity, and complexity confuses program- mers. Confused programmers, in turn, tend to intro- duce mistakes (bugs) into programs. A large program also provides a lot of space for these bugs to hide, mak- ing them hard to find. read more..

  • Page - 106

    Which one is more likely to contain a bug? If we count the size of the definitions of sum and range, the second pro- gram is also big—even bigger than the first. But still, I’dargue that it is more likely to be correct. It is more likely to be correct because the solution is expressed in a vo- cabulary that corresponds to the problem being solved. Summing a read more..

  • Page - 107

    Abstracting Array Traversal Plain functions, as we’ve seen them so far, are a good way to build abstrac- tions. But sometimes they fall short. In the previous chapter, this type of for loop made several appearances: var array = [1, 2, 3]; for (var i = 0; i < array.length; i++) { var current = array[i]; console.log(current); } It’s trying to say, “For each element in read more..

  • Page - 108

    console.log(sum); // 15 This looks quite a lot like the classical for loop, with its body written as a block below it. However, now the body is inside the function value, as well as inside the parentheses of the call to forEach. This is why it has to be closed with the closing brace and closing parenthesis. Using this pattern, we can specify a variable name for the read more..

  • Page - 109

    particularly remarkable about the fact that such functions exist. The term comes frommathematics, where the distinction between functions and other values is taken more seriously. Higher-order functions allow us to abstract over actions, not just values. They come in several forms. For example, you can have functions that create new functions. function greaterThan(n) { return function(m) { read more..

  • Page - 110

    lives inside the environment of the outer one, it can use n. The bodies of such inner functions can access the variables around them. They can play a role similar to the {} blocks used in regular loops and conditional state- ments. An important difference is that variables declared inside inner func- tions do not end up in the environment of the outer function. And that read more..

  • Page - 111

    JSON Higher-order functions that somehow apply a function to the elements of an array are widely used in JavaScript. The forEach method is the most primitive such function. There are a number of other variants available as methods on arrays. To familiarize ourselves with them, let’s play around with another data set. A few years ago, someone crawled through a lot of archives read more..

  • Page - 112

    The variable ANCESTRY_FILE, available in the sandbox for this chapter and in a downloadable file on the website(http://eloquentjavascript.net/code/ ), con- tains the content of my JSON file as a string. Let’s decode it and see how many people it contains. var ancestry = JSON.parse(ANCESTRY_FILE); console.log(ancestry.length); // 39 Filtering an Array To find the people in the ancestry read more..

  • Page - 113

    Transforming with map Say we have an array of objects representing people, produced by filtering the ancestry array somehow. But we want an array of names, which is easier to read. The map method transforms an array by applying a function to all of its elements and building a new array from the returned values. The new array will have the same length as the input array, read more..

  • Page - 114

    function reduce(array, combine, start) { var current = start; for (var i = 0; i < array.length; i++) current = combine(current, array[i]); return current; } console.log(reduce([1, 2, 3, 4], function(a, b) { return a + b; }, 0)); // 10 The standard array method reduce, which of course corresponds to this function, has an added convenience. If your array contains at least one ele- read more..

  • Page - 115

    function average(array) { function plus(a, b) { returna+b;} return array.reduce(plus) / array.length; } function age(p) { return p.died - p.born; } function male(p) { return p.sex == "m"; } function female(p) { return p.sex == "f"; } console.log(average(ancestry.filter(male).map(age))); // 61.67 console.log(average(ancestry.filter(female).map(age))); // 54.56 (It’s a bit silly that we have read more..

  • Page - 116

    It is helpful to roughly keep track of how often a piece of your pro- gram is going to run. If you have a loop inside a loop (either directly or through the outer loop calling a function that ends up performing the in- ner loop), the code inside the inner loop will end up running N ×M times, where N is the number of times the outer loop repeats and M is read more..

  • Page - 117

    number of people, but since our data set is finite, we have to stop some- where. We’ll allow a default value to be given to our reduction function, which will be used for people who are not in the data. In our case, that value is simply zero, on the assumption that people not in the list don’t share DNA with the ancestor we are looking at. Given a person, a read more..

  • Page - 118

    We could also have computed this number without relying on reduceAncestors. But separating the general approach (condensing afam- ily tree) from the specific case (computing shared DNA) can improve the clarity of the code and allows us to reuse the abstract part of the program for other cases. For example, the following code finds the percentageof known ancestors, for a given read more..

  • Page - 119

    console.log(ancestry.filter(function(person) { return isInSet(theSet, person); })); // [{name: "Maria van Brussel", ...}, // {name: "Carel Haverbeke", ...}] console.log(ancestry.filter(isInSet.bind(null, theSet))); // ... same result The call to bind returns a function that will call isInSet with theSet as the first argument, followed by any remaining arguments given to the bound function. read more..

  • Page - 120

    Note that not all the mothers mentioned in the data are themselves present in the array. The byName object, which makes it easy to find a person’s object from their name, might be useful here. Historical Life Expectancy When we looked up all the people in our data set that lived more than 90 years, only the latest generation in the data came out. Let’s take a read more..

  • Page - 121

    read more..

  • Page - 122

    “The problem with object-oriented languages is they’ve got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana and the entire jungle.” — Joe Armstrong, interviewed in Coders at Work read more..

  • Page - 123

    6 THE SECRET LIFE OF OBJECTS When a programmer says “object,” this is a loaded term. In my profession, objects are a way of life, the subject of holy wars, and a beloved buzzword that still hasn’t quite lost its power. To an outsider, this is probably a little confusing. Let’s start with a brief history of objects as a programming construct. History This story, like read more..

  • Page - 124

    As an example, you can imagine an object that provides an interface to an area on your screen. It provides a way to draw shapes or text onto this area but hides all the details of how these shapes are converted to the actual pixels that make up the screen. You’d have a set of methods—for example, drawCircle—and those are the only things you need to know in read more..

  • Page - 125

    rabbit.speak("I'm alive."); // The rabbit says 'I'm alive.' Usually a method needs to do something with the object it was called on. When a function is called as a method—looked up as a property and immediately called, as in object.method()—the special variable this in its body will point to the object that it was called on. function speak(line) { console.log("The read more..

  • Page - 126

    I just pulled a property out of an empty object. Magic! Well, not really. I have simply been withholding information about the way JavaScript objects work. In addition to their set of properties, almost all objects also have a prototype. A prototype is another object that is used as a fallback source of properties. When an object gets a request for a property that it does read more..

  • Page - 127

    var killerRabbit = Object.create(protoRabbit); killerRabbit.type = "killer"; killerRabbit.speak("SKREEEE!"); // The killer rabbit says 'SKREEEE!' The “proto” rabbit acts as a container for the properties that are shared by all rabbits. An individual rabbit object, like the killer rabbit, contains properties that apply only to itself—in this case its type—and derives shared read more..

  • Page - 128

    It is important to note the distinction between the way a prototype is associated with a constructor (through its prototype property) and the way objects have a prototype (which can be retrieved with Object.getPrototypeOf). The actual prototype of a constructor is Function.prototype since constructors are functions. Its prototype property will be the prototype of instances created through read more..

  • Page - 129

    It is also used to give the standard function and array prototypes a differ- ent toString method than the basic object prototype. console.log(Array.prototype.toString == Object.prototype.toString); // false console.log([1, 2].toString()); // 1,2 Calling toString on an array gives a result similar to calling .join(",") on it—it puts commas between the values in the array. Directly read more..

  • Page - 130

    Object.prototype.nonsense = "hi"; for (var namein map) console.log(name); // pizza // touched tree // nonsense console.log("nonsense" in map); // true console.log("toString" in map); // true // Delete the problematic property again delete Object.prototype.nonsense; That’s all wrong. There is no event called “nonsense” in our data set. And there definitely is no event called read more..

  • Page - 131

    When you are worried that someone (some other code you loaded into your program) might have messed with the base object prototype, I recom- mend you write your for/in loops like this: for (var namein map) { if (map.hasOwnProperty(name)) { // ... this is an own property } } Prototype-less Objects But the rabbit hole doesn’t end there. What if someone registered the name read more..

  • Page - 132

    This technique is called polymorphism—though no actual shape-shifting is involved. Polymorphic code can work with values of different shapes, as long as they support the interface it expects. Laying Out a Table Iamgoing to work through a slightly more involved example in an attempt to give you a better idea what polymorphism, as well as object-oriented pro- gramming in general, read more..

  • Page - 133

    The first part of the program computes arrays of minimum column widths and row heights for a grid of cells. The rows variable will hold an array of arrays, with each inner array representing a row of cells. function rowHeights(rows) { return rows.map(function(row) { return row.reduce(function(max, cell) { return Math.max(max, cell.minHeight()); }, 0); }); } function colWidths(rows) { return read more..

  • Page - 134

    function drawRow(row, rowNum){ var blocks = row.map(function(cell, colNum){ return cell.draw(widths[colNum], heights[rowNum]); }); return blocks[0].map(function(_, lineNo) { return drawLine(blocks, lineNo); }).join("\n"); } return rows.map(drawRow).join("\n"); } The drawTable function uses the internal helper function drawRow to draw all rows and then joins them together with newline characters. read more..

  • Page - 135

    }; TextCell.prototype.minHeight = function() { return this.text.length; }; TextCell.prototype.draw = function(width, height) { var result = []; for (var i = 0; i < height; i++) { var line = this.text[i] || ""; result.push(line + repeat(" ", width - line.length)); } return result; }; The code uses a helper function called repeat, which builds a string whose value is the read more..

  • Page - 136

    function UnderlinedCell(inner) { this.inner = inner; }; UnderlinedCell.prototype.minWidth = function() { return this.inner.minWidth(); }; UnderlinedCell.prototype.minHeight = function() { return this.inner.minHeight() + 1; }; UnderlinedCell.prototype.draw = function(width, height) { return this.inner.draw(width, height - 1) .concat([repeat("-", width)]); }; An underlined cell contains another cell. It reports read more..

  • Page - 137

    The resulting table resembles the example shown before, except that it does not right-align the numbers in the height column. We will get to that in a moment. Getters and Setters When specifying an interface, it is possible to include properties that are not methods. We could have defined minHeight and minWidth to simply hold numbers. But that’d have required us to compute read more..

  • Page - 138

    var cell = new TextCell("no\nway"); console.log(cell.heightProp); // 2 cell.heightProp = 100; console.log(cell.heightProp); // 2 You can use a similar set property, in the object passed to defineProperty, to specify a setter method. When a getter but no setter is defined, writing to the property is simply ignored. Inheritance We are not quite done yet with our table layout read more..

  • Page - 139

    Now, if we slightly adjust the dataTable function to use RTextCells for cells whose value is a number, we get the table we were aiming for. function dataTable(data) { var keys = Object.keys(data[0]); var headers = keys.map(function(name) { return new UnderlinedCell(new TextCell(name)); }); var body = data.map(function(row) { return keys.map(function(name) { var value = row[name]; // This was read more..

  • Page - 140

    console.log(new RTextCell("A") instanceof RTextCell); // true console.log(new RTextCell("A") instanceof TextCell); // true console.log(new TextCell("A") instanceof RTextCell); // false console.log([1] instanceof Array); // true The operator will see through inherited types. An RTextCell is an instance of TextCell because RTextCell.prototype derives from TextCell.prototype. The operator can read more..

  • Page - 141

    Exercises A Vector Type Write a constructor Vector that represents a vector in two-dimensional space. It takes x and y parameters (numbers), which it should save to properties of the samename. Give the Vector prototype two methods, plus and minus, that take another vector as a parameter and return a new vector that has the sum or difference of the two vectors’ (the one in read more..

  • Page - 142

    “The question of whether Machines Can Think . . . is about as relevant as the question of whether Submarines Can Swim.” — Edsger Dijkstra, The Threats to Computing Science read more..

  • Page - 143

    7 PROJECT: ELECTRONIC LIFE In “project” chapters, I’ll stop pummeling you with new theory for a brief moment and instead work througha program with you. Theory is indispensable when learn- ing to program, but it should also be accompanied by reading and understanding nontrivial programs. Our project in this chapter is to build a virtual ecosystem, a little world populated with read more..

  • Page - 144

    var plan = ["############################", "# # # o ##", "# #", "# ##### #", "## # # ## #", "### ## # #", "# ### # #", "# #### #", "# ## o #", "# o # o ### #", "# # #", "############################"]; The # characters in this plan represent walls and rocks, and the o char- acters represent read more..

  • Page - 145

    To store a grid of values, we have several options. We can use an array of row arrays and use two property accesses to get to a specific square, like this: var grid = [["top left", "top middle", "top right"], ["bottom left", "bottommiddle", "bottom right"]]; console.log(grid[1][2]); // bottom right Or we can use a single array, with read more..

  • Page - 146

    A Critter’s Programming Interface Before we can start on the World constructor, we must get more specific about the critter objects that will be living inside it. I mentioned that the world will ask the critters what actions they want to take. This works as follows: each critter object has an act method that, when called, returns an action. An action is an object with read more..

  • Page - 147

    BouncingCritter.prototype.act = function(view) { if (view.look(this.direction) != " ") this.direction = view.find(" ") || "s"; return {type: "move", direction: this.direction}; }; The randomElement helper function simply picks a random element from an array, using Math.random plus some arithmetic to get a random index. We’ll use this again later because randomness read more..

  • Page - 148

    In elementFromChar, first we create an instance of the right type by look- ing up the character’s constructor and applying new to it. Then we add an originChar property to it to make it easy to find out what character the ele- ment was originally created from. We need this originChar property when implementing the world’s toString method. This method builds up a maplike read more..

  • Page - 149

    //### o # // # o # o ### # // # # # // ############################ this and Its Scope The World constructor contains a call to forEach. One interesting thing to note is that inside the function passed to forEach, we are no longer directly in the function scope of the constructor. Each function call gets its own this binding, so the this in the inner function does not refer read more..

  • Page - 150

    return this.prop + elt; }, this); // ← no bind } }; console.log(test.addPropTo([5])); // [15] This works only for higher-order functions that support such a context parameter. When they don’t, you’ll need to use one of the other approaches. In our own higher-order functions, we can support such a context pa- rameter by using the call method to call the function given as an read more..

  • Page - 151

    We use the second parameter to the grid’s forEach method to be able to access the correct this inside the inner function. The letAct method con- tains the actual logic that allows the critters to move. World.prototype.letAct = function(critter, vector) { var action = critter.act(new View(this, vector)); if (action && action.type == "move") { var dest = read more..

  • Page - 152

    The one missing part, the View type, looks like this: function View(world, vector) { this.world = world; this.vector = vector; } View.prototype.look = function(dir) { var target = this.vector.plus(directions[dir]); if (this.world.grid.isInside(target)) return charFromElement(this.world.grid.get(target)); else return "#"; }; View.prototype.findAll = function(ch) { var found = []; for (var dir in read more..

  • Page - 153

    The first two maps that are displayed will look something like this (de- pending on the random direction the critters picked): ############################ ############################ ## # ## # # # ## #o # # # # ##### # # ##### o # ## # # ## # ## # # ## # ### ## # # ### ## # # # ### # # # ### # # # #### # # #### # ### # ### # # # o ### # #o # ### # #o #o# # # o o # read more..

  • Page - 154

    WallFollower.prototype.act = function(view) { var start = this.dir; if (view.look(dirPlus(this.dir, -3)) != " ") start = this.dir = dirPlus(this.dir, -2); while (view.look(this.dir) != " ") { this.dir = dirPlus(this.dir, 1); if (this.dir == start) break; } return {type: "move", direction: this.dir}; }; The act method only has to “scan” the critter’s surroundings, read more..

  • Page - 155

    overrides the letAct method. The new letAct method delegates the work of actually performing an action to various functions stored in the actionTypes object. function LifelikeWorld(map, legend) { World.call(this, map, legend); } LifelikeWorld.prototype = Object.create(World.prototype); var actionTypes = Object.create(null); LifelikeWorld.prototype.letAct = function(critter, vector) { var action = read more..

  • Page - 156

    Moving is more involved. actionTypes.move = function(critter, vector, action) { var dest = this.checkDestination(action, vector); if (dest == null || critter.energy <= 1 || this.grid.get(dest) != null) return false; critter.energy -= 1; this.grid.set(vector, null); this.grid.set(dest, critter); return true; }; This action first checks, using the checkDestination method defined ear- lier, whether the read more..

  • Page - 157

    return true; }; Reproducing costs twice the energy level of the newborn critter. So we first create a (hypothetical) baby using elementFromChar on the critter’s own origin character. Once we have a baby, we can find its energy level and test whether the parent has enough energy to successfully bring it into the world. We also require a valid (and empty) destination. If read more..

  • Page - 158

    if (space) return {type: "move", direction: space}; }; We’ll use the * character for plants, so that’s what critters will look for when they search for food. Bringing the World to Life And that gives us enough elements to try our new world. Imagine the follow- ingmap as a grassy valley with a herd of herbivores in it, some boulders, and lush plant life read more..

  • Page - 159

    ############################ ############################ #####O O ###### ##### O ###### ## ## ## ## # ##O ## # ## O ## #O O *## # # ## # # OOO **## O # # ## # # **## O # # O ## * # ## *** * ## #O # ## O***** O# # O # O # ###****** # # ## O O # ## ###****** ### ## ### O ### ############################ ############################ ############################ ############################ ##### read more..

  • Page - 160

    Write a new critter type that tries to address one or more of these points and substitute it for the old PlantEater type in the valley world. See how it fares. Tweak it some more if necessary. Predators Any serious ecosystem has a food chain longer than a single link. Write an- other critter that survives by eating the herbivore critter. You’ll notice that stability is read more..

  • Page - 161

    read more..

  • Page - 162

    “Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.” — Brian Kernighan and P.J. Plauger, The Elements of Programming Style read more..

  • Page - 163

    8 BUGS AND ERROR HANDLING A program is crystallized thought. Sometimes those thoughts are confused. Other times, mistakes are in- troduced when converting thought into code. Either way, the result is a flawed program. Flaws in a program are usually called bugs. Bugs can be programmer errors or problems in other systems that the program interacts with. Some bugs are immediately read more..

  • Page - 164

    The degree to which languages help you find such mistakes varies. Un- surprisingly, JavaScript is at the “hardly helps at all” end of that scale. Some languages want to know the types of all your variables and expressions be- fore even running a program and will tell you right away when a type is used in an inconsistent way. JavaScript considers types only when read more..

  • Page - 165

    than happily working with the global object, creating and readingglobal variables. For example, consider the following code, which calls a constructor without the new keyword so that its this will not refer to a newly constructed object: function Person(name) { this.name=name; } var ferdinand = Person("Ferdinand"); // oops console.log(name); // Ferdinand So the bogus call to Person read more..

  • Page - 166

    We will write a program to check that our implementation of Vector works as intended. Then, every time we change the implementation, we follow up by running the test program so that we can be reasonably confi- dent that we didn’t break anything. When we add extra functionality (for example, a new method) to the Vector type, we also add tests for the new feature. read more..

  • Page - 167

    function numberToString(n, base) { var result = "", sign = ""; if (n<0){ sign = "-"; n = -n; } do { result = String(n % base) + result; n /= base; } while (n > 0); return sign + result; } console.log(numberToString(13, 10)); // 1.5e-3231.3e-3221.3e-3211.3e-3201.3e-3191.3e-3181.3... Even if you see the problem already, pretend for a moment that you don’t. read more..

  • Page - 168

    breakpoint is to include a debugger statement (consisting of simply that key- word) in your program. If the developer tools of your browser are active, the program will pause whenever it reaches that statement, and you will be able to inspect its state. Error Propagation Not all problems can be prevented by the programmer, unfortunately. If your program communicates with the read more..

  • Page - 169

    Exceptions When a function cannot proceed normally, what we would like to do is just stop what we are doing and immediately jump back to a place that knows how to handle the problem. This is what exception handling does. Exceptions are a mechanism that make it possible for code that runs into a problem to raise (or throw) an exception, which is simply a value. Rais- read more..

  • Page - 170

    In this case, we used the Error constructor to create our exception value. This is a standard JavaScript constructor that creates an object with a message property. In modern JavaScript environments, instances of this construc- tor also gather information about the call stack that existed when the ex- ception was created, a so-called stack trace. This information is stored in the read more..

  • Page - 171

    } finally { context = oldContext; } } Note that we no longer have to store the result of body (which we want to return) in a variable. Even if we return directly from the try block, the finally block will be run. Now we can do this and be safe: try { withContext(5, function() { if (context < 10) throw new Error("Not enough context!"); }); } catch (e) { read more..

  • Page - 172

    JavaScript (in a rather glaring omission) doesn’t provide direct support for selectively catching exceptions: either you catch them all or you don’t catch any. This makes it very easy to assume that the exception you get is the one you were thinking about when you wrote the catch block. But it might not be. Some other assumption might be violated, or you might have read more..

  • Page - 173

    The prototype is made to derive from Error.prototype so that instanceof Error will also return true for InputError objects. It’s also given a name property since the standard error types (Error, SyntaxError, ReferenceError, and so on) also have such a property. The assignment to the stack property tries to give this object a somewhat useful stack trace, on platforms that support read more..

  • Page - 174

    function lastElement(array) { assert(array.length > 0, "empty array in lastElement"); return array[array.length - 1]; } This provides a compact way to enforce expectations, helpfully blow- ing up the program if the stated condition does not hold. For instance, the lastElement function, which fetches the last element from an array, would return undefined on empty arrays if the read more..

  • Page - 175

    The Locked Box Consider the following (rather contrived) object: var box = { locked: true, unlock: function() { this.locked = false; }, lock: function() { this.locked = true; }, _content: [], get content() { if (this.locked) throw new Error("Locked!"); return this._content; } }; It is a box with a lock. Inside is an array, but you can get at it only when the box is read more..

  • Page - 176

    “Some people, when confronted with a problem, think ‘I know, I’ll use regular expressions.’ Now they have two problems.” — Jamie Zawinski read more..

  • Page - 177

    9 REGULAR EXPRESSIONS Programming tools and techniques survive and spread in a chaotic, evolutionary way. It’s not always the pretty or brilliant ones that win but rather the ones that func- tion well enough within the right niche—for example, by being integrated with another successful piece of technology. In this chapter, I will discuss one such tool, regular expressions. Regular read more..

  • Page - 178

    var re1 = new RegExp("abc"); var re2 = /abc/; Both of these regular expression objects represent the same pattern: an a character followed by a b followed by a c. When using the RegExp constructor, the pattern is written as a normal string, so the usual rules apply for backslashes. The second notation, where the pattern appears between slash char- acters, treats read more..

  • Page - 179

    Say we want to match any number. In a regular expression, putting a set of characters between square brackets makes that part of the expression match any of the characters between the brackets. Both of the following expressions match all strings that contain a digit: console.log(/[0123456789]/.test("in 1992")); // true console.log(/[0-9]/.test("in 1992")); // true Within square read more..

  • Page - 180

    var notBinary = /[^01]/; console.log(notBinary.test("1100100010100110")); // false console.log(notBinary.test("1100100010200110")); // true Repeating Parts of a Pattern We now know how to match a single digit. What if we want to match a whole number—a sequence of one or more digits? When you put a plus sign(+) after something inaregular expression, it indicates that the element read more..

  • Page - 181

    var dateTime = /\d{1,2}-\d{1,2}-\d{4} \d{1,2}:\d{2}/; console.log(dateTime.test("30-1-2003 8:45")); // true You can also specify open-ended ranges when using curly braces by omit- ting the number on either side of the comma. So {,5} means zero to five times, and {5,} means five or more times. Grouping Subexpressions To use an operator like * or + on more than one element at read more..

  • Page - 182

    String values have a match method that behaves similarly. console.log("one two 100".match(/\d+/)); // ["100"] When the regular expression contains subexpressions grouped with parentheses, the text that matched those groups will also show up in the ar- ray. The whole match is always the first element. The next element is the part matched by the first group (the one read more..

  • Page - 183

    You can also create an object for a specific time. console.log(new Date(2009, 11, 9)); // Wed Dec 09 2009 00:00:00 GMT+0100 (CET) console.log(new Date(2009, 11, 9, 12, 59, 59, 999)); // Wed Dec 09 2009 12:59:59 GMT+0100 (CET) JavaScript uses a convention where month numbers start at zero (so December is 11), yet day numbers start at one. This is confusing and silly. Be read more..

  • Page - 184

    Word and String Boundaries Unfortunately, findDate will also happily extract the nonsensical date 00-1-3000 from the string "100-1-30000".A match may happen anywhere in the string, so in this case, it’ll just start at the second character and end at the second-to-last character. If we want to enforce that the match must span the whole string,wecan add the markers ^ and read more..

  • Page - 185

    The Mechanics of Matching Regular expressions can be thought of as flow diagrams. This is the diagram for the livestock expression in the previous example: " " boundary boundary Group #1 "chicken" "cow" "pig" digit "s" Our expression matches a string if we can find a path from the left side of the diagram to the right side. We keep a read more..

  • Page - 186

    Backtracking The regular expression /\b([01]+b|\d+|[\da-f]h)\b/ matches either a binary number followed by a b,aregular decimal number with no suffix character, or a hexadecimal number (that is, base 16, with the letters a to f standing for the digits 10 to 15) followed by an h. This is the corresponding diagram: boundary Group #1 "h" One of: - "f" "a" digit read more..

  • Page - 187

    It is possible to write regular expressions that will do a lot of backtrack- ing. This problem occurs when a pattern can match a piece of input in many different ways. For example, if we get confused while writing a binary-number regular expression, we might accidentally write something like /([01]+)+b/. "b" Group #1 One of: "1" "0" If that tries to read more..

  • Page - 188

    example, say we have a big string containing the names of people, one name per line, in the format Lastname, Firstname. If we want to swap these names and remove the commato getasimple Firstname Lastname format, we can use the following code: console.log( "Hopper, Grace\nMcCarthy, John\nRitchie, Dennis" .replace(/([\w ]+), ([\w ]+)/g, "$2 $1")); // Grace Hopper // John read more..

  • Page - 189

    The (\d+) group ends up as the amount argument to the function, and the (\w+) group gets bound to unit. The function converts amount toanumber— which always works, since it matched \d+ —and makes some adjustments in case there is only one or zero left. Greed It isn’t hard to use replace to write a function that removes all comments from a piece of JavaScript code. read more..

  • Page - 190

    function stripComments(code) { return code.replace(/\/\/.*|\/\*[^]*?\*\//g, ""); } console.log(stripComments("1 /* a */+/* b */ 1")); // 1+1 A lot of bugsinregular expression programs can be traced to uninten- tionally using a greedy operator where a nongreedy one would work better. When using a repetition operator, consider the nongreedy variant first. Dynamically Creating RegExp read more..

  • Page - 191

    The search Method The indexOf method on strings cannot be called with a regular expression. But there is another method, search, which does expect a regular expression. Like indexOf, it returns the first index on which the expression was found, or −1 when it wasn’t found. console.log(" word".search(/\S/)); // 2 console.log(" ".search(/\S/)); // -1 Unfortunately, there is read more..

  • Page - 192

    var digit = /\d/g; console.log(digit.exec("here it is: 1")); // ["1"] console.log(digit.exec("and now: 1")); // null Another interesting effect of the global option is that it changes the way the match method on strings works. When called with a global expression, instead of returning an array similar to that returned by exec, match will find all matches of the read more..

  • Page - 193

    program here, just the part that reads the configuration file. Sorry to disap- point.) The configuration file looks like this: searchengine=http://www.google.com/search?q=$1 spitefulness=9.7 ;comments are preceded by a semicolon... ; each section concerns an individual enemy [larry] fullname=Larry Doe type=kindergarten bully website=http://www.geocities.com/CapeCanaveral/11451 [gargamel] fullname=Gargamel type=evil read more..

  • Page - 194

    if (/^\s*(;.*)?$/.test(line)) { return; } else if (match = line.match(/^\[(.*)\]$/)) { currentSection = {name: match[1], fields: []}; categories.push(currentSection); } else if (match = line.match(/^(\w+)=(.*)$/)) { currentSection.fields.push({name: match[1], value: match[2]}); } else { throw new Error("Line '" + line + "' is invalid."); } }); return categories; } This code goes over read more..

  • Page - 195

    Things like `a or ß, which most definitely are word characters, will not match \w (and will match uppercase \W, the nonword category). By a strange historical accident, \s (whitespace) does not have this prob- lem and matches all characters that the Unicode standard considers white- space, including things like the nonbreaking space and the Mongolian vowel separator. Someregular read more..

  • Page - 196

    of the match. Their replace method can replace matches of a pattern with a replacement string. Alternatively, you can pass a function to replace, which will be used to build up a replacement string based on the match text and matched groups. Regular expressions can have options, which are written after the clos- ing slash. The i option makes the match case insensitive, while read more..

  • Page - 197

    Quoting Style Imagine you have written a story and used single quotation marks through- out to mark pieces of dialogue. Now you want to replace all the dialogue quotes with double quotes, while keeping the single quotes used in contrac- tions like aren’t. Think of a pattern that distinguishes these two kinds of quote usage and craft a call to the replace method that does read more..

  • Page - 198

    read more..

  • Page - 199

    10 MODULES Every program has a shape. On a small scale, this shape is determined by its division into functions and the blocks inside those functions. Programmers have a lot of freedom in the way they structure their programs. Shape follows more from the taste of the programmer than from the program’s intended functionality. When looking at a larger program in its entirety, read more..

  • Page - 200

    The benefits of organizing a program into several files or modules are similar. Structure helps people who aren’t yet familiar with the code find what they are looking for and makes it easier for the programmer to keep things that are related close together. Some programs are even organized along the model of a traditional text, with a well-defined order in which the read more..

  • Page - 201

    Once you have lots of such shared, duplicated pieces of code, you will find yourself wasting a lot of time and energyon moving them around and keeping them up-to-date. Putting pieces of functionality that stand on their own into separate files and modules makes them easier to track, update, and share because all the various pieces of code that want to use the module load read more..

  • Page - 202

    Consider this trivial module for associating names with day-of-the-week numbers, as returned by a Date object’s getDay method: var names = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; function dayName(number) { return names[number]; } console.log(dayName(1)); // Monday The dayName function is part of the read more..

  • Page - 203

    This code simply outputs the square of 100, but in the real world it could be a module that adds a method to some prototype or sets up a widget on a web page. It is wrapped in a function to prevent the variables it uses inter- nally from polluting the global scope. Why did we wrap the namespace function in a pair of parentheses? This has to do with a quirk read more..

  • Page - 204

    exports.number = function(name) { return names.indexOf(name); }; })(this.weekDay = {}); console.log(weekDay.name(weekDay.number("Saturday"))); // Saturday Detaching from the Global Scope The previous pattern is commonly used by JavaScript modules intended for the browser. The module will claim a single global variable and wrap its code in a function in order to have its own private read more..

  • Page - 205

    console.log(evalAndReturnX("var x = 2")); // 2 A better way of interpreting data as code is to use the Function construc- tor. This takes two arguments: a string containing acomma-separated list of argument names and a string containing the function’s body. var plusOne = new Function("n", "return n + 1;"); console.log(plusOne(4)); // 5 This is precisely what we read more..

  • Page - 206

    var weekDay = require("weekDay"); var today = require("today"); console.log(weekDay.name(today.dayNumber())); The simplistic implementation of require given previously has several problems. For one, it will load and run a module every timeitis required, so if several modules have the same dependency or a require call is put inside a function that will be called multiple times, read more..

  • Page - 207

    Slow-Loading Modules Though it is possible to use the CommonJS module style when writing Java- Script for the browser, it is somewhat involved. The reason for this is that reading a file (module) from the Web is a lot slower than reading it from the hard disk. While a script is running in the browser, nothing else can hap- pen to the website on which it runs, for read more..

  • Page - 208

    To be able to show a minimal implementation of define, we will pretend we have a backgroundReadFile function that takes a filename and a function and calls the function with the content of the file as soon as it has finished loading it. (Chapter 17 will explain how to write that function.) For the purpose of keeping track of modules while they are being loaded, the read more..

  • Page - 209

    deps.forEach(function(mod) { if (!mod.loaded) mod.onLoad.push(whenDepsLoaded); }); function whenDepsLoaded() { if (!deps.every(function(m) { return m.loaded; })) return; var args = deps.map(function(m) { return m.exports; }); var exports = moduleFunction.apply(null, args); if (myMod) { myMod.exports = exports; myMod.loaded = true; myMod.onLoad.every(function(f) { f(); }); } } whenDepsLoaded(); } When all dependencies read more..

  • Page - 210

    Predictability If programmers can predict the way your interface works, they (or you) won’t get sidetracked as often by the need to look up how to use it. Thus, try to follow conventions. When there is another module or part of the standard JavaScript environment that does something similar to what you are imple- menting,it might be a good idea to make your interface read more..

  • Page - 211

    On the other hand, you do not want to hide all the details either—when people need to do complicated things with your module, they should be able to. Often the solution is to provide two interfaces: a detailed low-level one for complex situations and a simple high-level one for routine use. The sec- ond can usually be built easily using the tools provided by the first. read more..

  • Page - 212

    3. directions 4. randomElement 5. BouncingCritter 6. elementFromChar 7. World 8. charFromElement 9. Wall 10. View 11. directionNames 12. WallFollower 13. dirPlus 14. LifelikeWorld 15. Plant 16. PlantEater 17. SmartPlantEater 18. Tiger Don’t exaggerate and create too many modules. A book that starts a new chapter for every page would probably get on your nerves, if only because of all the space read more..

  • Page - 213

    read more..

  • Page - 214

    “The evaluator, which determines the meaning of expressions in a programming language, is just another program.” — Hal Abelson and Gerald Sussman, Structure and Interpretation of Computer Programs read more..

  • Page - 215

    11 PROJECT: A PROGRAMMING LANGUAGE Building your own programming language is surpris- ingly easy (as long as you do not aim too high) and very enlightening. The main thing I want to show in this chapter is that there is no magic involved in building your own language. I’ve often felt that somehuman in- ventions were so immensely clever and complicated that I’d never be read more..

  • Page - 216

    application. Applications are used for function calls but also for constructs such as if or while. To keep the parser simple, stringsinEgg do not support anything like backslash escapes. A string is simply a sequence of characters that are not double quotes, wrapped in double quotes. A number is a sequence of digits. Variable names can consist of any character that is not read more..

  • Page - 217

    do define x 10 if > x 5 print "large" print "small" Contrast this to the parser we wrote for the configuration file format in Chapter 9, which had a simple structure: it split the input into lines and handled those lines one at a time. There were only a few simple forms that a line was allowed to have. Here we must find a different approach. Expressions read more..

  • Page - 218

    function skipSpace(string) { var first = string.search(/\S/); if (first == -1) return ""; return string.slice(first); } Because Egg allows any amount of whitespace between its elements, we have to repeatedly cut the whitespace off the start of the program string. This is what the skipSpace function helps with. After skipping any leading space, parseExpression uses three regular read more..

  • Page - 219

    Because an application expression can itself be applied (such as in multiplier(2)(1)), parseApply must, after it has parsed an application, call itself again to check whether another pair of parentheses follows. This is all we need to parse Egg. We wrap it in a convenient parse func- tion that verifies that it has reached the end of the input string after parsing the read more..

  • Page - 220

    var op = evaluate(expr.operator, env); if (typeof op != "function") throw new TypeError("Applying a non-function."); return op.apply(null, expr.args.map(function(arg) { return evaluate(arg, env); })); } } var specialForms = Object.create(null); The evaluator has code for each of the expression types. A literal value expression simply produces its value. (For example, the expression read more..

  • Page - 221

    Egg’s if construct expects exactly three arguments. It will evaluate the first, and if the result isn’t the value false, it will evaluate the second. Other- wise, the third gets evaluated. This if form is more similar to JavaScript’s ternary ?: operator than to JavaScript’s if. It is an expression, not a state- ment, and it produces a value, namely, the result of read more..

  • Page - 222

    env[args[0].name] = value; return value; }; The Environment The environment accepted by evaluate is an object with properties whose names correspond to variable names and whose values correspond to the values those variables are bound to. Let’s define an environment object to represent the global scope. To be able to use the if construct we just defined, we must have access to read more..

  • Page - 223

    function run() { var env = Object.create(topEnv); var program = Array.prototype.slice.call(arguments, 0).join("\n"); return evaluate(parse(program), env); } The use of Array.prototype.slice.call is a trick to turn an array-like ob- ject, such as arguments, into a real array so that we can call join on it. It takes all the arguments given to run and treats them as the lines of read more..

  • Page - 224

    for (var i = 0; i < arguments.length; i++) localEnv[argNames[i]] = arguments[i]; return evaluate(body, localEnv); }; }; Functions in Egg have their own local environment, just like in JavaScript. We use Object.create to make a new object that has access to the variables in the outer environment (its prototype) but that can also contain new vari- ables without modifying that outer read more..

  • Page - 225

    If you are interested in this topic and willing to spend sometimeonit, I encourage you to try to implement such a compiler as an exercise. Cheating When we defined if and while, you probably noticed that they were more or less trivial wrappers around JavaScript’s own if and while.Similarly, the values in Egg are just regular old JavaScript values. If you compare the read more..

  • Page - 226

    Exercises Arrays Add support for arrays to Egg by adding the following three functions to the top scope: array(...) to construct an array containing the argument values, length(array) to get an array’s length, and element(array, n) to fetch the nth element from an array. Closure The way we have defined fun allows functions in Egg to “close over” the sur- rounding environment, read more..

  • Page - 227

    The technique of representing scopes as simple objects, which has made things convenient so far, will get in your way a little at this point. You might want to use the Object.getPrototypeOf function, which returns the prototype of an object. Also remember that scopes do not derive from Object.prototype, so if you want to call hasOwnProperty on them, you have to use this read more..

  • Page - 228

    read more..

  • Page - 229

    PART II BROWSER read more..

  • Page - 230

    “The browser is a really hostile programming environment.” — Douglas Crockford, The JavaScript Programming Language (video lecture) read more..

  • Page - 231

    12 JAVASCRIPT AND THE BROWSER The next part of this book will talk about web browsers. Without web browsers, there would be no JavaScript. And even if there were, no one would ever have paid any attention to it. Web technology has, from the start, been decentralized, not just techni- cally but also in the way it has evolved. Various browser vendors have added new read more..

  • Page - 232

    If connecting two machines in the same building allows us to do won- derful things, connectingmachines all over the planet should be even bet- ter. The technology to start implementing this vision was developed in the 1980s, and the resulting network is called the Internet. It has lived up to its promise. Acomputer can use this network to spew bits at another computer. For read more..

  • Page - 233

    The Web The World WideWeb (not to be confused with the Internet as a whole) is a set of protocols and formats that allow us to visit web pages in a browser. The “Web” part in the name refers to the fact that such pages can easily link to each other, thus connecting into a huge mesh that users can move through. To add content to the Web, all you need to read more..

  • Page - 234

    Asimple HTML document looks like this: <!doctype html> <html> <head> <title>My home page</title> </head> <body> <h1>My home page</h1> <p>Hello, I am Marijn and this is myhome page.</p> <p>I also wrote a book! Read it <a href="http://eloquentjavascript.net">here</a>.</p> </body> </html> This is what such a read more..

  • Page - 235

    HTML, an ampersand (&) character followed by a word and a semicolon (;) is called an entity, and will be replaced by the character it encodes. This is analogous to the way backslashes are used in JavaScript strings. Since this mechanismgives ampersand characters a special meaning, too, those need to be escaped as &amp;. Inside an attribute, which is wrapped in double read more..

  • Page - 236

    Including large programs directly in HTML documents is often imprac- tical. The <script> tag can be given an src attribute in order to fetch a script file (a text file containing a JavaScript program) from aURL. <h1>Testing alert</h1> <script src="code/hello.js"></script> The code/hello.js file included here contains the samesimple program, read more..

  • Page - 237

    Every now and then, someone comes up with a new way to circumvent the limitations of a browser and do something harmful, ranging from leak- ingminor private information to taking over the whole machine that the browser runs on. The browser developers respond by fixing the hole, and all is well again—that is, until the next problem is discovered, and hopefully publicized, read more..

  • Page - 238

    read more..

  • Page - 239

    13 THE DOCUMENT OBJECT MODEL When you open a web page in your browser, the browser retrieves the page’s HTML text and parses it, much like the way our parser fromChapter 11 parsed programs. The browser builds up a model of the document’s structure and then uses this model to draw the page on the screen. This representation of the document is one of the toys that a read more..

  • Page - 240

    </head> <body> <h1>My home page</h1> <p>Hello, I am Marijn and this is myhome page.</p> <p>I also wrote a book! Read it <a href="http://eloquentjavascript.net">here</a>.</p> </body> </html> This page has the following structure: here a . I also wrote a book! Read it p Hello, I am Marijn and this is... p My home page h1 body read more..

  • Page - 241

    children. This shape is typical of nested structures where elements can con- tain subelements that are similar to themselves. We call a data structure a tree when it has a branching structure, has no cycles (a node may not contain itself, directly or indirectly), and has a single, well-defined “root.” In the case of the DOM, document.documentElement serves as the root. Trees read more..

  • Page - 242

    neutral interface that can be used in other systems as well—not just HTML but also XML, which is a generic data format with an HTML-like syntax. This is unfortunate. Standards are often useful. But in this case, the ad- vantage (cross-language consistency) isn’t all that compelling. Having an interface that is properly integrated with the language you are using will save you read more..

  • Page - 243

    In theory, you could move anywhere in the tree using just these par- ent and child links. But JavaScript also gives you access to a number of ad- ditional convenience links. The firstChild and lastChild properties point to the first and last child elements or have the value null for nodes without children. Similarly, previousSibling and nextSibling point to adjacent nodes, which read more..

  • Page - 244

    var link = document.body.getElementsByTagName("a")[0]; console.log(link.href); All element nodes have a getElementsByTagName method, which collects all elements with the given tag name that are descendants (direct or indirect children) of the given node and returns them as an array-like object. To find a specific single node, you can give it an id attribute and use read more..

  • Page - 245

    called on. Note that both replaceChild and insertBefore expect the new node as their first argument. Creating Nodes In the following example, we want to write a script that replaces all images (<img> tags) in the document with the text held in their alt attributes, which specifies an alternative textual representation of the image. This involves not only removing the images read more..

  • Page - 246

    To create regular element nodes (type 1), you can use the document .createElement method. This method takes a tag name and returns a new empty node of the given type. The following example defines a utility elt, which creates an element node and treats the rest of its arguments as children to that node. This func- tion is then used to add a simple attribution to a read more..

  • Page - 247

    you make up your own attribute names, though, such attributes will not be present as a property on the element’s node. Instead, you’ll have to use the getAttribute and setAttribute methods to work with them. <p data-classified="secret">The launch code is 00000000.</p> <p data-classified="unclassified">I have two feet.</p> <script> var paras = read more..

  • Page - 248

    We can automatically highlight all programs on the page by looping over all the <pre> elements that have a data-language attribute and calling highlightCode on each one with the correct regular expression for the language. var languages = { javascript: /\b(function|return|var)\b/g /* ... etc */ }; function highlightAllCode() { var pres = document.body.getElementsByTagName("pre"); for read more..

  • Page - 249

    the previous example, are rendered on the same line with their surrounding text. Such elements are called inline elements. For any given document, browsers are able to compute a layout, which gives each element a size and position based on its type and content. This layout is then used to actually draw the document. The size and position of an element can be accessed from read more..

  • Page - 250

    <script> function time(name, action) { var start = Date.now(); // Current timein milliseconds action(); console.log(name, "took", Date.now() - start, "ms"); } time("naive", function() { var target = document.getElementById("one"); while (target.offsetWidth < 2000) target.appendChild(document.createTextNode("X")); }); // naive took 32 ms time("clever", read more..

  • Page - 251

    There are a lot of aspects that can be influenced by styling. For example, the display property controls whether an element is displayed as a block or an inline element. This text is displayed <strong>inline</strong>, <strong style="display: block">as a block</strong>, and <strong style="display: none">not at all</strong>. The block tag will end read more..

  • Page - 252

    <style> strong { font-style: italic; color: gray; } </style> <p>Now <strong>strong text</strong> is italic and gray.</p> The cascading in the name refers to the fact that multiple such rules are combined to produce the final style for an element. In the previous ex- ample, the default styling for <strong> tags, which gives them font-weight: bold, is read more..

  • Page - 253

    Query Selectors We won’t be using style sheets all that much in this book. Although under- standing them is crucial to programming in the browser, properly explain- ing all the properties they support and the interaction among those proper- ties would take two or three books. The main reason I introduced selector syntax—the notation used in style sheets to determine which read more..

  • Page - 254

    space and may overlap with other elements. Also, its top and left proper- ties can be used to absolutely position it relative to the top-left corner of the nearest enclosing element whose position property isn’t static, or relative to the document if no such enclosing element exists. We can use this to create an animation. The following document dis- plays a picture of a read more..

  • Page - 255

    the motion of the cat per millisecond is stable, and the animation moves smoothly. If it just moved a fixed amount per step, the motion would stutter if, for example, another heavy task running on the samecomputer were to prevent the function from running for a fraction of a second. Moving in circles is done using the trigonometry functions Math.cos and Math.sin. For those read more..

  • Page - 256

    The way a document is displayed can be influenced by styling, both by attaching styles to nodes directly and by defining rules that match certain nodes. There are many different style properties, such as color or display. JavaScript can manipulate an element’s style directly through its style property. Exercises Build a Table We built plaintext tables in Chapter 6. HTML makes read more..

  • Page - 257

    To find the tag nameofanelement, use its tagName property. But note that this will return the tag name in all uppercase. Use the toLowerCase or toUpperCase stringmethod to compensate for this. The Cat’s Hat Extend the cat animation defined earlier so that both the cat and his hat (<img src="img/hat.png">) orbit at opposite sides of the ellipse. You can also try read more..

  • Page - 258

    “You have power over your mind— not outside events. Realize this, and you will find strength.” — Marcus Aurelius, Meditations read more..

  • Page - 259

    14 HANDLING EVENTS Some programs work with direct user input, such as mouse and keyboard interaction. The timing and or- der of such input can’t be predicted in advance. This requires a different approach to control flow than the one we have used so far. Event Handlers Imagine an interface where the only way to find out whether a key on the keyboard is being pressed is read more..

  • Page - 260

    A better mechanism is for the underlying system to give our code a chance to react to events as they occur. Browsers do this by allowing us to register functions as handlers for specific events. <p>Click this document to activate the handler.</p> <script> addEventListener("click", function() { console.log("You clicked!"); }); </script> The addEventListener read more..

  • Page - 261

    function once() { console.log("Done."); button.removeEventListener("click", once); } button.addEventListener("click", once); </script> To be able to unregister a handler function, we give it a name (such as once) so that we can pass it to both addEventListener and removeEventListener. Event Objects Though we have ignored it in the previous examples, event handler func- read more..

  • Page - 262

    At any point, an event handler can call the stopPropagation method on the event object to prevent handlers “further up” from receiving the event. This can be useful when, for example, you have a button inside another clickable element and you don’t want clicks on the button to activate the outer element’s click behavior. The following example registers "mousedown" read more..

  • Page - 263

    Default Actions Many events have a default action associated with them. If you click a link, you will be taken to the link’s target. If you press the down arrow, the browser will scroll the page down. If you right-click, you’ll get a context menu. And so on. For most types of events, the JavaScript event handlers are called before the default behavior is performed. If read more..

  • Page - 264

    Despite its name, "keydown" is fired not only when the key is physically pushed down. When a key is pressed and held, the event is fired again every time the key repeats.Sometimes—for example, if you want to increase the acceleration of a game character when an arrow key is pressed and decrease it again when the key is released—you have to be careful not to read more..

  • Page - 265

    <p>Focus this page and type something.</p> <script> addEventListener("keypress", function(event) { console.log(String.fromCharCode(event.charCode)); }); </script> The DOM node where a key event originates depends on the element that has focus when the key is pressed. Normal nodes cannot have focus (un- less you give them a tabindex attribute), but things such as links, read more..

  • Page - 266

    <script> addEventListener("click", function(event) { var dot = document.createElement("div"); dot.className = "dot"; dot.style.left = (event.pageX - 4) + "px"; dot.style.top = (event.pageY - 4) + "px"; document.body.appendChild(dot); }); </script> The clientX and clientY properties are similar to pageX and pageY but relative to the part of the document read more..

  • Page - 267

    rect.style.width = newWidth + "px"; lastX = event.pageX; } } </script> The resulting page looks like this: Note that the "mousemove" handler is registered on the whole window. Even if the mouse goes outside of the bar during resizing, we still want to update its size and stop dragging when the mouse is released. Whenever the mouse pointer enters or leaves a read more..

  • Page - 268

    }); </script> The isInside function follows the given node’s parent links until it ei- ther reaches the top of the document (when node becomes null) or finds the parent we are looking for. I should add that a hover effect like this can be much more easily achieved using the CSS pseudoselector :hover, as the next example shows. But when your hover effect involves read more..

  • Page - 269

    <script> var bar = document.querySelector(".progress div"); addEventListener("scroll", function() { var max = document.body.scrollHeight - innerHeight; var percent = (pageYOffset / max) * 100; bar.style.width = percent + "%"; }); </script> Giving an element a position of fixed acts much like an absolute posi- tion but also prevents it from scrolling along with read more..

  • Page - 270

    fields[i].addEventListener("blur", function(event) { help.textContent = ""; }); } </script> In the following screenshot, help text for the Age field is shown. The window object will receive "focus" and "blur" events when the user moves from or to the browser tab or window in which the document is shown. Load Event When a page finishes loading, the read more..

  • Page - 271

    a script is already running, event handlers and pieces of code scheduled in other ways have to wait for their turn. This is the reason why a document will freeze when a script runs for a long time. The browser cannot react to clicks and other events inside the document because it can’t run event handlers until the current script finishes running. Some programming read more..

  • Page - 272

    setTimeout(function() { document.body.style.background = "yellow"; }, 2000); </script> Sometimes you need to cancel a function you have scheduled. This is done by storing the value returned by setTimeout and calling clearTimeout on it. var bombTimer = setTimeout(function() { console.log("BOOM!"); }, 500); if (Math.random() < 0.5) { // 50% chance console.log("Defused."); read more..

  • Page - 273

    immediately performing an action in the event handler, we set a timeout in- stead. We also clear the previous timeout (if any) so that when events occur close together (closer than our timeout delay), the timeout from the previ- ous event will be canceled. <textarea>Type something here...</textarea> <script> var textarea = document.querySelector("textarea"); var read more..

  • Page - 274

    Summary Event handlers make it possible to detect and react to events we have no direct control over. The addEventListener method is used to register such a handler. Each event has a type ("keydown", "focus", and so on) that identifies it. Most events are called on a specific DOM element and then propagate to that element’s ancestors, allowing handlers read more..

  • Page - 275

    There are various possible approaches here. You can make your solu- tion as simple or as complex as you want. A simple solution to start with is to keep a fixed number of trail elements and cycle through them, moving the next one to the mouse’s current position every timea "mousemove" event occurs. Tabs A tabbed interface is a common design pattern. It allows read more..

  • Page - 276

    “All reality is a game.” — Iain Banks, The Player of Games read more..

  • Page - 277

    15 PROJECT: A PLATFORM GAME My initial fascination with computers, like that of many kids, originated with computer games. I was drawn into the tiny computer-simulated worlds that I could manip- ulate and in which stories (sort of) unfolded—more, I suppose, because of the way I could project myimagi- nation into them than because of the possibilities they actually offered. I read more..

  • Page - 278

    The Game Our game will be roughly based on Dark Blue (www.lessmilk.com/games/10) by Thomas Palef. I chose this game because it is both entertaining and mini- malist, and because it can be built without too much code. It looks like this: Coins Lava Player The dark box represents the player, whose task is to collect the yellow boxes (coins) while avoiding the red stuff (which read more..

  • Page - 279

    In games and other programs that have to animate graphics and respond to user input without noticeable delay, efficiency is important. Although the DOM was not originally designed for high-performance graphics, it is actually better at this than you would expect. You saw some animations in Chapter 13. On a modern machine, a simple game like this performs well, even if we read more..

  • Page - 280

    Reading a Level The following constructor builds a Level object. Its argument should be the array of strings that define the level. function Level(plan) { this.width = plan[0].length; this.height = plan.length; this.grid = []; this.actors = []; for (var y = 0; y < this.height; y++) { var line = plan[y], gridLine = []; for (var x = 0; x < this.width; x++) { var ch = read more..

  • Page - 281

    After building the grid, we use the filter method to find the "player" actor object, which we store in a property of the level. The status property tracks whether the player has won or lost. When this happens, finishDelay is used to keep the level active for a short period of timesothatasimple animation can be shown. (Immediately resetting or advancing the level read more..

  • Page - 282

    function Player(pos) { this.pos = pos.plus(new Vector(0, -0.5)); this.size = new Vector(0.8, 1.5); this.speed = new Vector(0, 0); } Player.prototype.type = "player"; Because a player is one-and-a-half squares high, its initial position is set to be half a square above the position where the @ character appeared. This way, its bottom aligns with the bottom of the square it read more..

  • Page - 283

    In Chapter 13, we saw that Math.sin gives us the y-coordinate of a point on a circle. That coordinate goes back and forth in a smooth wave form as we move along the circle, which makes the sine function useful for modeling a wavy motion. To avoid a situation where all coins move up and down synchronously, the starting phase of each coin is randomized. The phase of read more..

  • Page - 284

    Drawing The encapsulation of the drawing code is done by defining a display object, which displays a given level. The display type we define in this chapter is called DOMDisplay because it uses simple DOM elements to show the level. We will be using a style sheet to set the actual colors and other fixed properties of the elements that make up the game. It would also read more..

  • Page - 285

    this.level.grid.forEach(function(row) { var rowElt = table.appendChild(elt("tr")); rowElt.style.height = scale + "px"; row.forEach(function(type) { rowElt.appendChild(elt("td", type)); }); }); return table; }; As mentioned earlier, the background is drawn as a <table> element. This nicely corresponds to the structure of the grid property in the level— each row of the grid read more..

  • Page - 286

    To give an element more than one class, we separate the class names by spaces. In the CSS code shown next, the actor class gives the actors their absolute position. Their type name is used as an extra class to give them a color. We don’t have to define the lava class again because we reuse it for the lava grid squares, which we defined earlier. .actor { read more..

  • Page - 287

    is not visible. We also give the outer element a relative position so that the actors inside it are positioned relative to the level’s top-left corner. .game{ overflow: hidden; max-width: 600px; max-height: 450px; position: relative; } In the scrollPlayerIntoView method, we find the player’s position and update the wrapping element’s scroll position. We change the scroll position by read more..

  • Page - 288

    It would have been slightly simpler to always try to scroll the player to the center of the viewport. But this creates a rather jarring effect. As you are jumping, the view will constantly shift up and down. It is more pleas- ant to have a “neutral” area in the middle of the screen where you can move around without causing any scrolling. Finally, we’ll need a read more..

  • Page - 289

    Solving this for the general case is a big task. You can find libraries, usu- ally called physics engines, that simulate interaction between physical objects in two or three dimensions. We’ll take a more modest approach in this chap- ter, handling only collisions between rectangular objects and handling them in a rather simplistic way. Before moving the player or a block of read more..

  • Page - 290

    If the body sticks out of the level, we always return "wall" for the sides and top and "lava" for the bottom. This ensures that the player dies when falling out of the world. When the body is fully inside the grid, we loop over the block of grid squares found by rounding the coordinates and return the content of the first nonempty square we find. read more..

  • Page - 291

    this.actors.forEach(function(actor) { actor.act(thisStep, this, keys); }, this); step -= thisStep; } }; When the level’s status property has a non-null value (which is the case when the player has won or lost), we must count down the finishDelay prop- erty, which tracks the time between the point where winning or losing hap- pens and the point where we want to stop showing the read more..

  • Page - 292

    The wobble property is updated to track time and then used as an argu- ment to Math.sin to create a wave, which is used to compute a new position. That leaves the player itself. Player motion is handled separately per axis because hitting the floor should not prevent horizontal motion, and hitting a wall should not stop falling or jumpingmotion. This method implements the read more..

  • Page - 293

    At the start of the method, the player is accelerated vertically to account for gravity. The gravity, jumping speed, and pretty much all other constants in this game have been set by trial and error. I tested various values until I found a combination I liked. Next, we check for obstacles again. If we hit an obstacle, there are two possible outcomes. When the up arrow read more..

  • Page - 294

    this.status = "won"; this.finishDelay = 1; } } }; When lava is touched, the game’s status is set to "lost". When a coin is touched, that coin is removed from the array of actors, and if it was the last one, the game’s status is set to "won". This gives us a level that can actually be animated. All that is missing now is the code that read more..

  • Page - 295

    Running the Game The requestAnimationFrame function, which we saw in Chapter 13, provides a good way to animate a game. But its interface is quite primitive—using it requires us to track the time at which our function was called the last time around and call requestAnimationFrame again after every frame. Let’s define a helper function that wraps those boring parts in a read more..

  • Page - 296

    if (level.isFinished()) { display.clear(); if (andThen) andThen(level.status); return false; } }); } A game is a sequence of levels. Whenever the player dies, the current level is restarted. When a level is completed, we move on to the next level. This can be expressed by the following function, which takes an array of level plans (arrays of strings) and a display constructor: read more..

  • Page - 297

    There is a set of level plans available in the GAME_LEVELS variable (down- loadable from http://eloquentjavascript.net/code#15). This page feeds them to runGame, starting an actual game: <link rel="stylesheet" href="css/game.css"> <script> runGame(GAME_LEVELS, DOMDisplay); </script> Exercises Game Over It’s traditional for platformgames to have the player start with a read more..

  • Page - 298

    “Drawing is deception.” — M.C. Escher, cited by Bruno Ernst in The Magic Mirror of M.C. Escher read more..

  • Page - 299

    16 DRAWING ON CANVAS Browsers give us several ways to display graphics. The simplest way is to use styles to position and color reg- ular DOM elements. This can get you quite far, as the game in the previous chapter showed. By adding par- tially transparent background images to the nodes, we can make them look exactly the way we want. It is even possible to rotate or read more..

  • Page - 300

    A canvas, on the other hand, converts the shapes to pixels (colored dots on a raster) as soon as they are drawn and does not remember what these pixels represent. The only way to move a shape on a canvas is to clear the canvas (or the part of the canvas around the shape) and redraw it with the shape in a new position. SVG This book will not go into SVG in read more..

  • Page - 301

    The Canvas Element Canvas graphics can be drawn onto a <canvas> element. You can give such an element width and height attributes to determine its size in pixels. A new canvas is empty, meaning it is entirely transparent and thus shows up simply as empty space in the document. The <canvas> tag is intended to support different styles of drawing.To get access to an read more..

  • Page - 302

    Filling and Stroking In the canvas interface, a shape can be filled, meaning its area is given a cer- tain color or pattern, or it can be stroked, which means a line is drawn along its edge. The same terminology is used by SVG. The fillRect method fills a rectangle. It takes first the x- and y-coordinates of the rectangle’s top-left corner, then its width, and then read more..

  • Page - 303

    <canvas></canvas> <script> var cx = document.querySelector("canvas").getContext("2d"); cx.beginPath(); for (var y = 10;y<100;y+=10) { cx.moveTo(10, y); cx.lineTo(90, y); } cx.stroke(); </script> The path described by the previous program looks like this: This example creates a path with a number of horizontal line segments and then strokes it using the stroke read more..

  • Page - 304

    You could also use the closePath method to explicitly close a path by adding an actual line segment back to the path’s start. This segment is drawn when stroking the path. Curves A path may also contain curved lines. These are, unfortunately, a bit more involved to draw than straight lines. The quadraticCurveTo method draws a curve to a given point. To deter- mine the read more..

  • Page - 305

    leaving the lower corners start off in the direction of the control point and then curve toward their target. The bezierCurve method draws a similar kind of curve. Instead of a single control point, this one has two—one for each of the line’s endpoints. Here isasimilar sketch to illustrate the behavior of such a curve: <canvas></canvas> <script> var cx = read more..

  • Page - 306

    cx.moveTo(10, 10); // control=(90,10) goal=(90,90) radius=20 cx.arcTo(90, 10, 90, 90, 20); cx.moveTo(10, 10); // control=(90,10) goal=(90,90) radius=80 cx.arcTo(90, 10, 90, 90, 80); cx.stroke(); </script> This produces two rounded corners with different radii. The arcTo method won’t draw the line from the end of the rounded part to the goal position, though the word to in its name read more..

  • Page - 307

    Drawing a Pie Chart Imagine you’ve just taken a job at EconomiCorp, Inc., and your first assign- ment is to draw a pie chart of their customer satisfaction survey results. The results variable contains an array of objects that represent the sur- vey responses. var results = [ {name: "Satisfied", count: 1043, color: "lightblue"}, {name: "Neutral", count: read more..

  • Page - 308

    This draws the following chart: But a chart that doesn’t tell us what it means isn’t very helpful. We need a way to draw text to the canvas. Text A 2D canvas drawing context provides the methods fillText and strokeText. The latter can be useful for outlining letters, but usually fillText is what you need. It will fill the given text with the current fillColor. read more..

  • Page - 309

    The drawImage method allows us to draw pixel data onto a canvas. This pixel data can originate from an <img> element or from another canvas, and neither has to be visible in the actual document. The following example cre- ates a detached <img> element and loads an image file into it. But it cannot immediately start drawing from this picture because the browser read more..

  • Page - 310

    img.addEventListener("load", function() { var cycle = 0; setInterval(function() { cx.clearRect(0, 0, spriteW, spriteH); cx.drawImage(img, // source rectangle cycle * spriteW, 0, spriteW, spriteH, // destination rectangle 0, 0, spriteW, spriteH); cycle = (cycle + 1) % 8; }, 120); }); </script> The cycle variable tracks our position in the animation. Each frame, it is incremented and read more..

  • Page - 311

    negative amount will flip the picture around. The flipping happens around point (0,0), which means it will also flip the direction of the coordinate sys- tem. When a horizontal scaling of −1 is applied, a shape drawn at x position 100 will end up at what used to be position −100. So to turn a picture around, we can’tsimply add cx.scale(-1, 1) before the call to read more..

  • Page - 312

    We move the y-axis to where we want our mirror to be, apply the mir- roring, and finally move the y-axis back to its proper place in the mirrored universe. The following picture explains why this works: mirror 1 2 3 4 This shows the coordinate systems before and after mirroring across the central line. If we draw a triangle at a positive x position, it would, by read more..

  • Page - 313

    The save and restore methods on the 2D canvas context perform this kind of transformation management. They conceptually keep a stack of transformation states. When you call save, the current state is pushed onto the stack, and when you call restore, the state on top of the stack is taken off and used as the context’s current transformation. The branch function in the read more..

  • Page - 314

    If the calls to save and restore were not there, the second recursive call to branch would end up with the position and rotation created by the first call. It wouldn’t be connected to the current branch but rather to the inner- most, rightmost branch drawn by the first call. The resulting shape might also be interesting, but it is definitely not a tree. Back to the read more..

  • Page - 315

    The animationTime counter is the reason we passed the step size to drawFrame in Chapter 15, even though DOMDisplay does not use it. Our new drawFrame function uses the counter to track time so that it can switch between animation frames based on the current time. CanvasDisplay.prototype.drawFrame = function(step) { this.animationTime += step; this.updateViewport(); this.clearDisplay(); read more..

  • Page - 316

    When clearing the display, we’ll use a slightly different color depending on whether the game is won (brighter) or lost (darker). CanvasDisplay.prototype.clearDisplay = function() { if (this.level.status == "won") this.cx.fillStyle = "rgb(68, 191, 255)"; else if (this.level.status == "lost") this.cx.fillStyle = "rgb(44, 136, 214)"; else this.cx.fillStyle = read more..

  • Page - 317

    Background tiles are 20 by 20 pixels, since we will use the same scale that we used in DOMDisplay. Thus, the offset for lava tiles is 20 (the value of the scale variable), and the offset for walls is 0. We don’t bother waiting for the sprite image to load. Calling drawImage with an image that hasn’t been loaded yet will simply do nothing. Thus, we might fail to read more..

  • Page - 318

    The drawPlayer method is called by drawActors, which is responsible for drawing all the actors in the game. CanvasDisplay.prototype.drawActors = function() { this.level.actors.forEach(function(actor) { var width = actor.size.x * scale; var height = actor.size.y * scale; var x = (actor.pos.x - this.viewport.left) * scale; var y = (actor.pos.y - this.viewport.top) * scale; if (actor.type == read more..

  • Page - 319

    Choosing a Graphics Interface Whenever you need to generate graphics in the browser, you can choose between plain HTML, SVG, and canvas. There is no single best approach that works in all situations. Each option has strengths and weaknesses. Plain HTML has the advantage of being simple. It also integrates well with text. Both SVG and canvas allow you to draw text, but they read more..

  • Page - 320

    Rectangles and pieces of text can be drawn with a single method call. The fillRect and strokeRect methods draw rectangles, and the fillText and strokeText methods draw text. To create custom shapes, we must first build up a path. Calling beginPath starts a new path. A number of other methods add lines and curves to the current path. For example, lineTo can add a straight read more..

  • Page - 321

    The Pie Chart Earlier in the chapter, we saw an example program that drew a pie chart. Modify this program so that the name of each category is shown next to the slice that represents it. Try to find a pleasing-looking way to automatically position this text, which would work for other data sets as well. You may as- sume that categories are no smaller than 5 percent read more..

  • Page - 322

    “The dream behind the Web is of a common information space in which we communicate by sharing information. Its universality is essential: the fact that a hypertext link can point to any- thing, be it personal, local or global, be it draft or highly polished.” — Tim Berners-Lee, The World Wide Web: A very short personal history read more..

  • Page - 323

    17 HTTP The Hypertext Transfer Protocol, already mentioned in Chapter 12, is the mechanism through which data is requested and provided on the World Wide Web. This chapter describes the protocol in more detail and ex- plains the way browser JavaScript has access to it. The Protocol If you type eloquentjavascript.net/17_http.html into your browser’s address bar, the browser first looks read more..

  • Page - 324

    Content-Type: text/html Last-Modified: Wed, 09 Apr 2014 10:48:09 GMT <!doctype html> ... the rest of the document The browser then takes the part of the response after the blank line and displays it as an HTML document. The information sent by the client is called the request. It starts with this line: GET /17_http.html HTTP/1.1 The first word is the method of the request. read more..

  • Page - 325

    This tells us the size and type of the response document. In this case, it is an HTML document of 65,585 bytes. It also tells us when that document was last modified. For the most part, a client or server decides which headers to include in a request or response, though a few headers are required. For example, the Host header, which specifies the hostname, should be read more..

  • Page - 326

    those. There seems to be an unwritten rule that every format needs its own way of escaping characters. This one, called URL encoding, uses a percent sign followed by two hexadecimal digits that encode the character code. In this case, 3F, which is 63 in decimal notation, is the code of a question mark character. JavaScript provides the encodeURIComponent and decodeURIComponent read more..

  • Page - 327

    When the XMLHttpRequest interface was added to Internet Explorer, it allowed people to do things with JavaScript that had been very hard before. For example, websites started showing lists of suggestions when the user was typing something into a text field. The script would send the text to the server over HTTP as the user typed. The server, which had some database of read more..

  • Page - 328

    console.log(req.getResponseHeader("content-type")); // text/plain Header names are case insensitive. They are usually written with a cap- ital letter at the start of each word, such as “Content-Type,” but “content- type” and “cOnTeNt-TyPe” refer to the same header. The browser will automatically add some request headers, such as “Host” and those needed for the server to read more..

  • Page - 329

    this document. This representation works much like the DOM discussed in Chapter 13, except that it doesn’t have HTML-specific functionality like the style property. The object that responseXML holds corresponds to the document object. Its documentElement property refers to the outer tag of the XML docu- ment. In the following document (example/fruit.xml), that would would be the read more..

  • Page - 330

    This can be an annoying problem when building systems that want to ac- cess several domains for legitimate reasons. Fortunately, servers can include a header like this in their response to explicitly indicate to browsers that it is okay for the request to come from other domains: Access-Control-Allow-Origin: * Abstracting Requests In Chapter 10, in our implementation of the AMD read more..

  • Page - 331

    We should also have an option to be notified when the request fails so that we can take appropriate action. For example, we could remove the “loading” message and inform the user that something went wrong. Error handling in asynchronous code is even trickier than error han- dling in synchronous code. Because we often need to defer part of our work, putting it in a read more..

  • Page - 332

    Code using getURL must then check whether an error was given and, if it finds one, handle it. getURL("data/nonsense.txt", function(content, error) { if (error != null) console.log("Failed to fetch nonsense.txt: " + error); else console.log("nonsense.txt: " + content); }); This does not help when it comes to exceptions. When chaining sev- eral asynchronous actions read more..

  • Page - 333

    }); req.addEventListener("error", function() { fail(new Error("Network error")); }); req.send(null); }); } Note that the interface to the function itself is now a lot simpler. You give it a URL, and it returns a promise. That promise acts as a handle to the request’s outcome. It has a then method that you can call with two functions: one to handle success and one read more..

  • Page - 334

    We want to get the nameofthe mother of the spouse of example/bert.json. And if somethinggoes wrong, we want to remove the loading text and show an error message instead. Here is how that might be done with promises: <script> function showMessage(msg) { var elt = document.createElement("div"); elt.textContent = msg; return document.body.appendChild(elt); } var loading = read more..

  • Page - 335

    When thinking in termsofremote procedure calls, HTTP is just a ve- hicle for communication, and you will most likely write an abstraction layer that hides it entirely. Another approach is to build your communication around the con- cept of resources and HTTP methods. Instead of a remote procedure called addUser, you use a PUT request to /users/larry. Instead of encoding that read more..

  • Page - 336

    requests and responses may contain headers that provide additional information. Browsers make GET requests to fetch the resources needed to display a web page. A web page may also contain forms, which allow information en- tered by the user to be sent along in the request made when the form is sub- mitted. You will learn more about that in the next chapter. The interface read more..

  • Page - 337

    Waiting for Multiple Promises The Promise constructor has an all method that, given an array of promises, returns a promise that waits for all of the promises in the array to finish. It then succeeds, yielding an array of result values. If any of the promises in the array fail, the promise returned by all fails too (with the failure value from the failing promise). Try read more..

  • Page - 338

    “I shall this very day, at Doctor’s feast, My bounden service duly pay thee. But one thing!—For insurance’ sake, I pray thee, Grant me a line or two, at least.” — Mephistopheles, in Goethe’s Faust read more..

  • Page - 339

    18 FORMS AND FORM FIELDS Forms were introduced briefly in the previous chap- ter as a way to submit information provided by the user over HTTP. They were designed for a pre-JavaScript Web, assuming that interaction with the server always happens by navigating to a new page. But their elements are part of the DOM like the rest of the page, and the DOM elements that read more..

  • Page - 340

    A lot of field types use the <input> tag. This tag’s type attribute is used to select the field’s style. These are somecommonly used <input> types: text A single-line text field password Sameas text but hides the text that is typed checkbox An on/off switch radio (Part of) a multiple-choice field file Allows the user to choose a file from their computer Form read more..

  • Page - 341

    <select> <option>Pancakes</option> <option>Pudding</option> <option>Ice cream</option> </select> Such a field looks like this: Whenever the value of a form field changes, it fires a "change" event. Focus Unlike most elements in an HTML document, form fields can get keyboard focus. When clicked—or activated in some other way—they become the cur- read more..

  • Page - 342

    Browsers traditionally also allow the user to move the focus through the document by pressing the TAB key. We can influence the order in which ele- ments receive focus with the tabindex attribute. The following example doc- ument will let focus jump from the text input to the OK button, rather than going through the help link first: <input type="text" tabindex=1> read more..

  • Page - 343

    var form = document.querySelector("form"); console.log(form.elements[1].type); // password console.log(form.elements.password.type); // password console.log(form.elements.name.form == form); // true </script> A button with a type attribute of submit will, when pressed, cause the form to be submitted. Pressing ENTER when a form field is focused has the same effect. Submitting a form normally means read more..

  • Page - 344

    the cursor is after the 10th character. When part of the field is selected, the two properties will differ, giving us the start and end of the selected text. Like value, these properties may also be written to. As an example, imagine you are writing an article about Khasekhemwy but have some trouble spelling his name. The following code wires up a <textarea> tag with read more..

  • Page - 345

    Checkboxes and Radio Buttons A checkbox field is a simple binary toggle. Its value can be extracted or changed through its checked property, which holds a Boolean value. <input type="checkbox" id="purple"> <label for="purple">Make this page purple</label> <script> var checkbox = document.querySelector("#purple"); read more..

  • Page - 346

    Select Fields Select fields are conceptually similar to radio buttons—they also allow the user to choose from a set of options. But where a radio button puts the lay- out of the options under our control, the appearance of a <select> tag is de- termined by the browser. Select fields also have a variant that is more akin to a list of checkboxes, rather than radio read more..

  • Page - 347

    </select> = <span id="output">0</span> <script> var select = document.querySelector("select"); var output = document.querySelector("#output"); select.addEventListener("change", function() { var number = 0; for (var i = 0; i < select.options.length; i++) { var option = select.options[i]; if (option.selected) number += Number(option.value); } output.textContent read more..

  • Page - 348

    What it does not have is a property that contains the content of the file. Getting at that is a little more involved. Since reading a file from disk can take time, the interface will have to be asynchronous to avoid freezing the document. You can think of the FileReader constructor as being similar to XMLHttpRequest but for files. <input type="file" multiple> read more..

  • Page - 349

    It is possible to read only part of a file by calling slice on it and passing the result (a so-called blob object) to the file reader. Storing Data Client-Side Simple HTML pages with a bit of JavaScript can be a great medium for “mini applications”—small helper programs that automate everyday things. By connecting a few form fields with event handlers, you can do read more..

  • Page - 350

    function addToList(name) { var option = document.createElement("option"); option.textContent = name; list.appendChild(option); } // Initialize the list from localStorage var notes = JSON.parse(localStorage.getItem("notes")) || {"shopping list": ""}; for (var name in notes) if (notes.hasOwnProperty(name)) addToList(name); function saveToStorage() { localStorage.setItem("notes", read more..

  • Page - 351

    Whenever the note data changes (when a new note is added or an exist- ing note changed), the saveToStorage function is called to update the storage field. If this application was intended to handle thousands of notes, rather than a handful, this would be too expensive, and we’d have to come up with a more complicated way to store them, such as giving each note its read more..

  • Page - 352

    Autocompletion Extend a text field so that when the user types, a list of suggested values is shown below the field. You have an array of possible values available and should show those that start with the text that was typed. When a suggestion is clicked, replace the text field’s current value with it. Conway’s Game of Life Conway’s Game of Life is a simple read more..

  • Page - 353

    read more..

  • Page - 354

    “I look at the many colors before me. I look at my blank canvas. Then, I try to apply colors like words that shape poems, like notes that shape music.” — Joan Miro read more..

  • Page - 355

    19 PROJECT: A PAINT PROGRAM The material from the previous chapters gives you all the elements you need to build a simple web applica- tion. In this chapter, we will do just that. Our application will be a web-based drawing program, along the lines of Microsoft Paint. You can use it to open image files, scribble on them with your mouse, and save them. This is what it read more..

  • Page - 356

    Painting onacomputer is great. You don’t need to worry about materi- als, skill, or talent. You just start smearing. Implementation The interface for the paint program shows a big <canvas> element on top, with a number of form fields below it. The user draws on the picture by se- lecting a tool from a <select> field and then clicking or dragging across the read more..

  • Page - 357

    if (attributes) { for (var attr in attributes) if (attributes.hasOwnProperty(attr)) node.setAttribute(attr, attributes[attr]); } for (var i = 2; i < arguments.length; i++) { var child = arguments[i]; if (typeof child == "string") child = document.createTextNode(child); node.appendChild(child); } return node; } This allows us to create elements easily, without making our source code as long read more..

  • Page - 358

    Tool Selection The first control we add is the <select> element that allows the user to pick a drawing tool. As with controls, we will use an object to collect the various tools so that we do not have to hard-code them all in one place and can add more tools later. This object associates the names of the tools with the func- tion that should be called when read more..

  • Page - 359

    Several of the drawing tools need to listen for "mousemove" events as long as the mouse button is held down. The trackDrag function takes care of the event registration and unregistration for such situations. function trackDrag(onMove, onEnd) { function end(event) { removeEventListener("mousemove", onMove); removeEventListener("mouseup", end); if (onEnd) onEnd(event); } read more..

  • Page - 360

    tools.Erase = function(event, cx) { cx.globalCompositeOperation = "destination-out"; tools.Line(event, cx, function() { cx.globalCompositeOperation = "source-over"; }); }; The globalCompositeOperation property influences the way drawing oper- ations on a canvas change the color of the pixels they touch. By default, the property’s value is "source-over", which means that the read more..

  • Page - 361

    controls.color = function(cx) { var input = elt("input", {type: "color"}); input.addEventListener("change", function() { cx.fillStyle = input.value; cx.strokeStyle = input.value; }); return elt("span", null, "Color: ", input); }; Whenever the value of the color field changes, the drawing context’s fillStyle and strokeStyle are updated to hold the new value. read more..

  • Page - 362

    and would be noticeably slow. Instead, we rig the link to update its href attri- bute whenever it is focused with the keyboard or the mouse is moved over it. controls.save = function(cx) { var link = elt("a", {href: "/"}, "Save"); function update() { try { link.href = cx.canvas.toDataURL(); } catch (e) { if (e instanceof SecurityError) link.href = read more..

  • Page - 363

    Loading Image Files The final two controls are used to load images from local files and from URLs. We’ll need the following helper function, which tries to load an im- age file from aURL and replace the contents of the canvas with it: function loadImageURL(cx, url) { var image = document.createElement("img"); image.addEventListener("load", function() { var color = read more..

  • Page - 364

    controls.openURL = function(cx) { var input = elt("input", {type: "text"}); var form = elt("form", null, "Open URL: ", input, elt("button", {type: "submit"}, "load")); form.addEventListener("submit", function(event) { event.preventDefault(); loadImageURL(cx, form.querySelector("input").value); }); return form; }; We have now defined all the read more..

  • Page - 365

    cx.fillRect(currentPos.x + offset.x, currentPos.y + offset.y, 1, 1); } }, 25); trackDrag(function(event) { currentPos = relativePos(event, cx.canvas); }, function() { clearInterval(spray); }); }; The spray tool uses setInterval to spit out colored dots every 25 milli- seconds as long as the mouse button is held down. The trackDrag function is used to keep currentPos pointing at the current read more..

  • Page - 366

    Rectangles Define a tool called Rectangle that fills a rectangle (see the fillRect method fromChapter 16) with the current color. The rectangle should span from the point where the user pressed the mouse button to the point where they released it. Note that the latter might be above or to the left of the former. Once it works, you’ll notice that it is somewhat jarring read more..

  • Page - 367

    The arguments to getImageData indicate the starting x- and y-coordinates of the rectangle we want to retrieve, followed by its width and height. Ignore transparency during this exercise and look only at the first three values for a given pixel. Also, do not worry about updating the color field when the user picks a color. Just make sure that the drawing context’s fillStyle read more..

  • Page - 368

    Do include the fourth (alpha) value this time since we want to be able to tell the difference between empty and black pixels. Finding all adjacent pixels with the same color requires you to “walk” over the pixel surface, one pixel up, down, left, or right, as long as new same- colored pixels can be found. But you won’t find all pixels in a group on the first read more..

  • Page - 369

    PART III BEYOND read more..

  • Page - 370

    “A student asked ‘The programmers of old used only simple machines and no programming languages, yet they made beautiful programs. Why do we use compli- cated machines and programming languages?’ Fu-Tzu replied ‘The builders of old used only sticks and clay, yet they made beautiful huts.’” — Master Yuan-Ma, The Book of Programming read more..

  • Page - 371

    20 NODE.JS So far, you have learned the JavaScript language and used it within a single environment: the browser. This chapter and the next one will briefly introduce you to Node.js, a program that allows you to apply your JavaScript skills outside of the browser. With it, you can build anything from simple command-line tools to dynamic HTTP servers. These chapters aim to teach read more..

  • Page - 372

    writing of data to and from the network, the hard drive, and other such de- vices. Moving data around takes time, and scheduling it cleverly can make abig difference in how quickly a system responds to the user or to network requests. The traditional way to handle input and output is to have a function, such as readFile, start reading a file and return only when the read more..

  • Page - 373

    Synchronous, single thread of control Synchronous, two threads of control Asynchronous Another way to express this difference is that waiting for I/O to finish is implicit in the synchronous model, while it is explicit, directly under our con- trol, in the asynchronous one. But asynchronicity cuts both ways. It makes expressing programs that do not fit the straight-line model of read more..

  • Page - 374

    If you run node without giving it a file, it provides you with a prompt at which you can type JavaScript code and immediately see the result. $ node >1+1 2 > [-1, -2, -3].map(Math.abs) [1, 2, 3] > process.exit(0) $ The process variable, just like the console variable, is available globally in Node. It provides various ways to inspect and manipulate the current pro- read more..

  • Page - 375

    to load the file /home/marijn/elife/world/world.js. The .js extension may be omitted. When a string that does not look like a relative or absolute path is given to require, it is assumed to refer to either a built-in module or a module in- stalled in a node_modules directory. For example, require("fs") will give you Node’s built-in filesystemmodule, and read more..

  • Page - 376

    For example, one module you will find on NPM is figlet, which can con- vert text into ASCII art—drawings made out of text characters. The following transcript shows how to install and use it: $npm install figlet npm GET https://registry.npmjs.org/figlet npm 200 https://registry.npmjs.org/figlet npm GET https://registry.npmjs.org/figlet/-/figlet-1.0.9.tgz npm 200 read more..

  • Page - 377

    This book won’t delve further into the details of NPM usage. Refer to http://npmjs.org/ for further documentation and for an easy way to search for libraries. The Filesystem Module One of the most commonly used built-in modules that comes with Node is the "fs" module, which stands for filesystem. This module provides functions for working with files and directories. For read more..

  • Page - 378

    Here, it was not necessary to specify the encoding since writeFile will as- sume that if it is given a string to write, rather than a Buffer object, it should write it out as text using its default character encoding, which is UTF-8. The "fs" module contains many other useful functions: readdir will re- turn the files in a directory as an array of strings, read more..

  • Page - 379

    header values. Here we tell the client that we will be sending back an HTML document. Next, the actual response body (the document itself) is sent with response .write. You are allowed to call this method multiple times if you want to send the response piece by piece, possibly streaming data to the client as it be- comes available. Finally, response.end signals the end of read more..

  • Page - 380

    Streams We have seen two examples of writable streams in HTTP—namely, the re- sponse object that the server could write to and the request object that was returned from http.request. Writable streams are a widely used concept in Node interfaces. All writable streams have a write method, which can be passed a string or a Buffer object. Their end method closes the stream and, read more..

  • Page - 381

    The following piece of code, if run while the uppercasing server is run- ning, will send a request to that server and write out the response it gets: var http = require("http"); var request = http.request({ hostname: "localhost", port: 8000, method: "POST" }, function(response) { response.on("data", function(chunk) { process.stdout.write(chunk.toString()); }); }); read more..

  • Page - 382

    if (body && body.pipe) body.pipe(response); else response.end(body); } if (request.method in methods) methods[request.method](urlToPath(request.url), respond, request); else respond(405, "Method " + request.method + " not allowed."); }).listen(8000); This starts a server that just returns 405 error responses, which is the code used to indicate that a given method isn’t handled by read more..

  • Page - 383

    npm http 304 https://registry.npmjs.org/mime mime@1.2.11 node_modules/mime When a requested file does not exist, the correct HTTP error code to return is 404. We will use fs.stat, which looks up information on a file, to find out both whether the file exists and whether it is a directory. methods.GET = function(path, respond) { fs.stat(path, function(error, stats) { if (error read more..

  • Page - 384

    if (error && error.code == "ENOENT") respond(204); else if (error) respond(500, error.toString()); else if (stats.isDirectory()) fs.rmdir(path, respondErrorOrNothing(respond)); else fs.unlink(path, respondErrorOrNothing(respond)); }); }; You may be wondering why trying to delete a nonexistent file returns a 204 status, rather than an error. When the file that is being deleted is not read more..

  • Page - 385

    the data is transferred successfully, pipe will close both streams, which will cause a "finish" event to fire on the writable stream. When that happens, we can report success to the client with a 204 response. The full script for the server is available at http://eloquentjavascript.net/ code/file_server.js. You can download that and run it with Node to start your own read more..

  • Page - 386

    Another approach is to use promises, which were introduced in Chap- ter 17. Those catch exceptions raised by callback functions and propagate them as failures. It is possible to load a promise library in Node and use that to manage your asynchronous control. Few Node libraries integrate promises, but it is often trivial to wrap them. The excellent "promise" module from read more..

  • Page - 387

    function inspectPath(path) { return fsp.stat(path).then(null, function(error) { if (error.code == "ENOENT") return null; else throw error; }); } The inspectPath function is a simple wrapper around fs.stat, which handles the case where the file is not found. In that case, we replace the failure with a success that yields null. All other errors are allowed to propa- gate. When read more..

  • Page - 388

    Fixing a Leak For easy remote access to some files, I might get into the habit of having the file server defined in this chapter running on my machine, in the /home/ marijn/public directory. Then, one day, I find that someone has gained ac- cess to all the passwords I stored in my browser. What happened? If it isn’t clear to you yet, think back to the urlToPath read more..

  • Page - 389

    Write a basic HTML page that includes a simple JavaScript file. Put the files in a directory served by the file server and open them in your browser. Next, as an advanced exercise or even a weekend project, combine all the knowledge you gained from this book to build a more user-friendly inter- face for modifying the website from inside the website. Use an HTML form read more..

  • Page - 390

    read more..

  • Page - 391

    21 PROJECT: SKILL-SHARING WEBSITE A skill-sharing meeting is an event where people with a shared interest cometogether and give small, informal presentations about things they know. At a gardening skill-sharingmeeting,someone might explain how to cultivate celery. Or in a programming-oriented skill- sharinggroup, you could drop by and tell everybody about Node.js. Such meetups, also often called read more..

  • Page - 392

    The full code for the project can be downloaded from http:// eloquentjavascript.net/code/skillsharing.zip. Design There is a server part to this project, written for Node.js, and a client part, written for the browser. The server stores the system’s data and provides it to the client. It also serves the HTML and JavaScript files that implement the client-side system. The server read more..

  • Page - 393

    Long Polling To be able to immediately notify a client that something changed, we need a connection to that client. Since web browsers do not traditionally accept connections and clients are usually behind devices that would block such connections anyway, having the server initiate this connection is not practical. We can arrange for the client to open the connection and keep it read more..

  • Page - 394

    A GET request to /talks returns a JSON document like this: {"serverTime": 1405438911833, "talks": [{"title": "Unituning", "presenter": "Carlos", "summary": "Modifying your cycle for extra style", "comment": []}]} The serverTime field will be used to make reliable long polling possible. I will return to it later. Creating a read more..

  • Page - 395

    such changes, they are immediately returned. When there aren’t, the re- sponse is delayed until something happens or until a given time period (we will use 90 seconds) has elapsed. The time must be indicated as the number of milliseconds elapsed since the start of 1970, the same type of number that is returned by Date.now().To ensure that it receives all updates and read more..

  • Page - 396

    The Server Let’s start by writing the server-side part of the program. The code in this section runs on Node.js. Routing Our server will use http.createServer to start an HTTP server. In the function that handles a new request, we must distinguish between the various kinds of requests (as determined by the method and the path) that we support. This can be done with a long read more..

  • Page - 397

    The module exports the Router constructor. A router object allows new handlers to be registered with the add method and can resolve requests with its resolve method. The latter will return a Boolean that indicates whether a handler was found. The some method on the array of routes will try the routes one at a time (in the order in which they were defined) and stop, read more..

  • Page - 398

    response.end(data); } function respondJSON(response, status, data) { respond(response, status, JSON.stringify(data), "application/json"); } Talks as Resources The server keeps the talks that have been proposed in an object called talks, whose property names are the talk titles. These will be exposed as HTTP resources under /talks/[title], so we need to add handlers to our router that read more..

  • Page - 399

    function readStreamAsJSON(stream, callback) { var data = ""; stream.on("data", function(chunk) { data += chunk; }); stream.on("end", function() { var result, error; try { result = JSON.parse(data); } catch (e) { error = e; } callback(error, result); }); stream.on("error", function(error) { callback(error); }); } One handler that needs to read JSON responses is the read more..

  • Page - 400

    Adding acomment to a talk works similarly. We use readStreamAsJSON to get the content of the request, validate the resulting data, and store it as a comment when it looks valid. router.add("POST", /^\/talks\/([^\/]+)\/comments$/, function(request, response, title) { readStreamAsJSON(request, function(error, comment) { if (error) { respond(response, 400, error.toString()); } else if (!comment read more..

  • Page - 401

    router.add("GET", /^\/talks$/, function(request, response) { var query = require("url").parse(request.url, true).query; if (query.changesSince == null) { var list = []; for (var title in talks) list.push(talks[title]); sendTalks(list, response); } else { var since = Number(query.changesSince); if (isNaN(since)) { respond(response, 400, "Invalid parameter"); } else { var changed = read more..

  • Page - 402

    element, the object that tracks the waiting response, whose index we found by calling indexOf. If you pass additional arguments to splice, their values will be inserted into the array at the given position, replacing the removed elements. When a response object is stored in the waiting array, a timeout is im- mediately set. After 90 seconds, this timeout sees whether the read more..

  • Page - 403

    return found; } That concludes the server code. Running the program defined so far will get you a server running on port 8000, which serves files from the public subdirectory alongside a talk-managing interface under the /talks URL. The Client The client-side part of the talk-managing website consists of three files: an HTML page, a style sheet, and a JavaScript file. HTML It read more..

  • Page - 404

    The script will add a "submit" event handler to this form, from which it can make the HTTP request that tells the server about the talk. Next comes a rather mysterious block, which has its display style set to none, preventing it from actually showing up on the page. Can you guess what it is for? <div id="template" style="display: none"> <div read more..

  • Page - 405

    function request(options, callback) { var req = new XMLHttpRequest(); req.open(options.method || "GET", options.pathname, true); req.addEventListener("load", function() { if (req.status < 400) callback(null, req.responseText); else callback(new Error("Request failed: " + req.statusText)); }); req.addEventListener("error", function() { callback(new Error("Network error")); }); read more..

  • Page - 406

    The function checks whether there is an actual error, and it alerts only when there is one. That way, we can also directly pass this function to request for requests where we can ignore the response. This makes sure that if the request fails, the error is reported to the user. Displaying Talks To be able to update the view of the talks when changes come in, the read more..

  • Page - 407

    function instantiateTemplate(name, values) { function instantiateText(text) { return text.replace(/\{\{(\w+)\}\}/g, function(_, name) { return values[name]; }); } function instantiate(node) { if (node.nodeType == document.ELEMENT_NODE) { var copy = node.cloneNode(); for (var i = 0; i < node.childNodes.length; i++) copy.appendChild(instantiate(node.childNodes[i])); return copy; } else if (node.nodeType == read more..

  • Page - 408

    form.reset(); }); return node; } After instantiating the "talk" template, there are various things that need to be patched up. First, the comments have to be filled in by repeat- edly instantiating the "comment" template and appending the results to the node with class "comments". Next, event handlers have to be attached to the button that deletes the task read more..

  • Page - 409

    var nameField = document.querySelector("#name"); nameField.value = localStorage.getItem("name") || ""; nameField.addEventListener("change", function() { localStorage.setItem("name", nameField.value); }); The form at the bottom of the page, for proposing a new talk, gets a "submit" event handler. This handler prevents the event’s default effect (which would read more..

  • Page - 410

    displayTalks(response.talks); lastServerTime = response.serverTime; waitForChanges(); } }); } This function is called once when the program starts up and then keeps calling itself to ensure that a polling request is always active. When the re- quest fails, we don’t call reportError since popping up a dialog every timewe fail to reach the server would get annoying when the server is read more..

  • Page - 411

    In a heated discussion, where multiple people are adding comments to a single talk, this would be very annoying. Can you come up with a way to avoid it? Better Templates Most templating systemsdo more than just fill in some strings. At the very least, they also allow conditional inclusion of parts of the template, analo- gous to if statements, and repetition of parts of a read more..

  • Page - 412

    Try to think of a way the skill-sharing website could be set up to preserve basic functionality when run without JavaScript. The automatic updates will have to go, and people will have to refresh their page the old-fashioned way. But being able to see existing talks, create new ones, and submit comments would be nice. Don’t feel obliged to actually implement this. Outlining read more..

  • Page - 413

    22 JAVASCRIPT AND PERFORMANCE Running acomputer program on a machine requires bridging the gap between the programming language and the machine’s own instruction format. This can be done by writing a program that interprets other pro- grams, as we did in Chapter 11, but it is usually done by compiling (translating) the program to machine code. Some programming languages, such as read more..

  • Page - 414

    Still, you may occasionally need to rewrite your code to avoid aspects of JavaScript that remain slow. As an example of that, this chapter will work through a speed-hungry program and make it faster. In the process, we will discuss the way JavaScript engines compile your programs. Staged Compilation First, you must understand that JavaScript compilers do not simply compile a read more..

  • Page - 415

    representing some countries in the Middle East, with edges between those that share land borders: Deriving a picture like this from the definition of a graph is called graph layout. It involves assigning a place to each node in such a way that connected nodes are near each other but don’t crowd into each other. A random lay- out of the same graph is a lot harder to read more..

  • Page - 416

    Defining a Graph We can represent a graph as an array of GraphNode objects, each of which carries its current position and an array of the other nodes to which it has edges. The starting positions of nodes are randomized. function GraphNode() { this.pos = new Vector(Math.random() * 1000, Math.random() * 1000); this.edges = []; } GraphNode.prototype.connect = function(other) { read more..

  • Page - 417

    The graph created by treeGraph(3, 5) would be a tree of depth 3, with five branches. So you can inspect the layouts produced by the code in this chapter, I’ve defined a drawGraph function that draws the graph onto a canvas. This func- tion is defined in the code at http://eloquentjavascript.net/code/draw_graph.js and is available in the online sandbox. A First Force-Directed read more..

  • Page - 418

    The force that acts on a given node is computed by looping over all other nodes and applying the repelling force for each of them. When another node shares an edge with the current node, the spring’s force is also applied. Both of these forces depend on the distance between the two nodes. The function computes a vector named apart that represents the path from the read more..

  • Page - 419

    if (totalSteps < 4000) requestAnimationFrame(step); else console.log(time); } step(); } We can now run our first implementation and see how much timeit takes. <script> runLayout(forceDirected_simple, treeGraph(4, 4)); </script> My machine, using version 38 of the Chrome browser, reports that those 4,000 iterations took a little more than four seconds. That’s a lot. Let’s see if we read more..

  • Page - 420

    6.0 ms 0.08 % 6.0 ms 0.08 % arc 4.0 ms 0.05 % 88.6 ms 1.11 % drawGraph 2.0 ms 0.03 % 7680.7 ms 96.29 % step The numbers give us the time spent executing a given function, both in milliseconds and as a percentage of the total time taken. The first column shows only the time that control was actually in the function, while the sec- ond column includes time spent in read more..

  • Page - 421

    coordinates and the forceSize variable. Thus, there is no need to create the intermediate object produced by the times method. force.plus(normalized.times(forceSize)) But JavaScript is a dynamic language. How does the compiler figure out which function this plus method actually is? And what if someone changes the value stored in Vector.prototype.plus later? The next time code that has read more..

  • Page - 422

    node.pos = node.pos.plus(normalized.times(forceSize)); } } } The result is that the code is about 30 percent faster both in Chrome38 and in Firefox 32. If I profile again, the forceDirected_forloop function takes up most of the time. Interestingly, the Vector constructor also disappears from the profile, suggesting that the engine either avoided creating vectors or inlined the read more..

  • Page - 423

    If I measure this code, I see another big speed boost compared to the version before it—over 40 percent less time taken on Chrome 38, and around 30 percent less on Firefox 32 and Internet Explorer 11. Creating Less Garbage Thoughsome of the vector objects that we are using to do two-dimensional arithmetic might be optimized away entirely by someengines, there is likely still read more..

  • Page - 424

    Garbage Collection So why are objects expensive? There are two reasons. First, the engine has to find a place to store them, and second, it has to figure out when they are no longer used and reclaim them. Both are tricky to do. Imagine memory, again, as a long, long series of bits. When the pro- gram starts, it might receive an empty piece of memory and just start read more..

  • Page - 425

    Writing to Objects Given that writing to old objects might incur a cost, you can rightly feel a bit worried about the way our code is applying forces. The inner loop updates the x and y properties of the long-lived node position objects. For a graph with N nodes, the inner loop runs N 2 times. For our 85-node test graph, this is 7,225 times for every iteration of read more..

  • Page - 426

    generational garbage collection. This most likely has to do with the way they do their garbage collection incrementally, cutting up the work of tracing all live memory into small chunks, rather than doing it all at once, which could cause noticeable pauses in the program’s execution. This technique also requires keeping track of newly created references. Step by step, we’ve read more..

  • Page - 427

    node[String.fromCharCode("A".charCodeAt(0) + letter)] = true; }); runLayout(forceDirected_localforce, mangledGraph); Every node gets an extra property, named with a random uppercase let- ter. The letter is computed by taking the character code of the A character and adding a random number to it. If we run our fast simulation code on the resultinggraph, it becomes three times as read more..

  • Page - 428

    Exercises Pathfinding Write a function findPath that tries to find the shortest path between two nodes in a graph. It takes two GraphNode objects (as used throughout this chapter) as arguments and returns either null, if no path could be found, or an array of nodes that represents a path through the graph. Nodes that occur next to each other in this array should have an read more..

  • Page - 429

    Optimizing Now that you have a measured test case, find ways to make your findPath function faster. Think both about macro-optimization (doing less work) and micro- optimization (doing the given work in a cheaper way). Also, consider ways to use less memory and allocate fewer or smaller data structures. If you need to, you can start by adding id properties to nodes to make read more..

  • Page - 430

    read more..

  • Page - 431

    EXERCISE HINTS The hints below might help when you are stuck with one of the exercises in this book. They don’t give away the entire solution, but rather try to help you find it yourself. Program Structure Looping a Triangle You can start with a program that simply prints out the numbers 1 to 7, which you can derive by making a few modifications to the even number read more..

  • Page - 432

    FizzBuzz 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 re- mainder (%) 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 read more..

  • Page - 433

    contain a return statement or in some other way arrange for a specific value to be returned. 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. Bean Counting A loop in your function will have read more..

  • Page - 434

    copying the whole array (array.slice(0) is a good way to copy an array) works but is cheating. The trick is to swap the first and last elements, then the second and second-to-last, and so on. You can do this by looping over half the length of the array (use Math.floor to round down—you don’t need to touch the middle element in an array with an odd length) and read more..

  • Page - 435

    Returning the correct value from the function is best done by immedi- ately returning false when a mismatch is noticed and returning true at the end of the function. Higher-Order Functions Mother-Child Age Difference Because not all elements in the ancestry array produce useful data (we can’t compute the age difference unless we know the birth date of the mother), we will have read more..

  • Page - 436

    of the distance we are looking for is equal to the square of the x-coordinate plus the square of the y-coordinate. Thus, x2 + y2 is the number you want, and Math.sqrt is the way you compute a square root in JavaScript. Another Cell You’ll have to store all three constructor arguments in the instance object. The minWidth and minHeight methods should call through to the read more..

  • Page - 437

    Making the critters move more effectively could be done by stealing one of the movement strategies from the critters in our old, energyless world. Both the bouncing behavior and the wall-following behavior showed a much wider rangeof movement than completely random staggering. Making critters breed more slowly is trivial. Just increase the mini- mum energy level at which they read more..

  • Page - 438

    Regular Expressions Quoting Style The most obvious solution is to only replace quotes with a nonword charac- ter on at least one side. Something like /\W'|'\W/. But you also have to take the start and end of the line into account. In addition, you must ensure that the replacement also includes the characters that were matched by the \W pattern so that those are not read more..

  • Page - 439

    View World LifelikeWorld directions [reexported] Module "simple_ecosystem" (randomElement) [duplicated] (dirPlus) Wall BouncingCritter WallFollower Module "ecosystem" Wall [duplicated] Plant PlantEater SmartPlantEater Tiger I have reexported the directions array from the grid module from world so that modules built on that (the ecosystems) don’t have to know or worry about the existence of read more..

  • Page - 440

    Closure Again, we are riding along on a JavaScript mechanism to get the equivalent feature in Egg. Special forms are passed the local environment in which they are evaluated so that they can evaluate their subforms in that environment. The function returned by fun closes over the env argument given to its en- closing function and uses that to create the function’s local read more..

  • Page - 441

    Elements by Tag Name The solution is most easily expressed with a recursive function, similar to the talksAbout function defined earlier in this chapter. You could call byTagname itself recursively, concatenating the resulting arrays to produce the output. For a more efficient approach, define an inner function that calls itself recursively and that has access to an array variable read more..

  • Page - 442

    Tabs One pitfall you’ll probably run into is that you can’t directly use the node’s childNodes property as a collection of tab nodes. For one thing, when you add the buttons, they will also become child nodes and end up in this ob- ject because it is live. For another, the text nodes created for the whitespace between the nodes are also in there and should not read more..

  • Page - 443

    You can add a property to the object returned by trackKeys, which con- tains either that function value or a method that handles the unregistering directly. Drawing on Canvas Shapes The trapezoid (1) is easy to draw using a path. Pick suitable center coordi- nates and add each of the four corners around that. The diamond (2) can be drawn the easy way, with a path, or read more..

  • Page - 444

    are on. On the left, it should be "right", and on the right, it should be "left" so that the text is positioned away from the pie. If you are not sure how to find out which side of the circle a given angle is on, look to the explanation of Math.cos in the previous exercise. The co- sine of an angle tells us which x-coordinate it corresponds to, read more..

  • Page - 445

    Waiting for Multiple Promises The function passed to the Promise constructor will have to call then on each of the promises in the given array. When one of them succeeds, two things need to happen. The resulting value needs to be stored in the correct posi- tion of a result array, and we must check whether this was the last pending promise and finish our own promise read more..

  • Page - 446

    To get the suggestion text out of a DOM node, you could look at its textContent or set an attribute to explicitly store the text when you create the element. Conway’s Game of Life To solve the problem of having the changes conceptually happen at the sametime, try to see the computation of a generation as a pure function, which takes one grid and produces a new grid read more..

  • Page - 447

    Color Picker You’ll again need to use relativePos to find out which pixel was clicked. The pixelAt function in the example demonstrates how to get the values for a given pixel. Putting those into an rgb stringmerely requires some string concatenation. Make sure you verify that the exception you catch is an instance of SecurityError so that you don’t accidentally handle the read more..

  • Page - 448

    Node.js Content Negotiation, Again Don’t forget to call the end method on the object returned by http.request in order to actually fire off the request. The response object passed to http.request’s callback is a readable stream. This means that it is not entirely trivial to get the whole response body from it. The following utility function reads a whole stream and calls a read more..

  • Page - 449

    A Public Space on the Web You can create a <textarea> element to hold the content of the file that is being edited. A GET request, using XMLHttpRequest, can be used to get the cur- rent content of the file. You can use relative URLs like index.html, instead of http://localhost:8000/index.html, to refer to files on the same server as the running script. Then, when read more..

  • Page - 450

    Better Templates You could change instantiateTemplate so that its inner function takes not just a node but also a current context as an argument. You can then, when loop- ing over a node’s child nodes, check whether the child has a template-repeat attribute. If it does, don’t instantiate it once but instead loop over the array indicated by the attribute’s value and read more..

  • Page - 451

    Optimizing The main opportunity for macro-optimization is to get rid of the inner loop that figures out whether a node has already been looked at. Looking this up in an object is much faster than iterating over the work list to search for the node. But since JavaScript map objects require strings, not objects, as prop- erty names, we need a trick like withIDs to be read more..

  • Page - 452

    read more..

  • Page - 453

    INDEX Symbols && operator, 17, 20, 96 * operator, 13, 18, 156 *= operator, 34 {} (block), 31, 44, 85 {} (object), 63, 113 - operator, 14, 15, 18 -= operator, 34 = operator, 25, 64, 168, 170, 197 == operator, 16, 19, 66, 79 === operator, 19, 79, 410 / operator, 14 /= operator, 34 > operator, 16 >= operator, 16 < operator, 16 <= operator, 16 − operator, read more..

  • Page - 454

    animation avoiding stutter, 230 cat in ellipse, 230 collision detection, 265 frames for, 285–286, 290–291 game, 264, 266–269, 271 getting elements by tag name, 233 mouse trail, 250 off-screen, 244 scheduling, 230 simple, 129, 134 sprite, 293 stopping, 271 SVG vs. canvas, 295 anonymous function, 178 appendChild method, 220, 260, 416 Apple, 213 application (of functions), see function read more..

  • Page - 455

    backslash character boundary markers, 166 escaping in regular expressions, 154, 166 escaping in strings, 14 paths using, 364 backtracking, 162, 165 backward compatibility, 177 ball, 297, 420 Banks, Iain, 252 bean counting (exercise), 56, 409 beforeunload event, 246 behavior, 122, 129, 172, 201, 412–413 benchmark, 225, 389, 395 Berners-Lee, Tim,298 best practices, 3 bezierCurve method, 281 binary read more..

  • Page - 456

    button (HTML tag), 212, 236, 241, 251, 319, 325, 327 byName object, 92, 95 C C (programming language), 389 cache, 182, 184, 415 call method, 101, 105, 114, 126, 131, 199 call protocol, 396 call stack, 46–48, 51, 145, 147, 149, 396 callback function defined, 306 error arguments, 307 event handlers, 235 promises and, 308 readable streams, 355 writable streams, 356 calling (of read more..

  • Page - 457

    clearing, 223, 275, 285, 288–289, 291–292, 420 clearInterval function, 248 clearRect method, 285, 420 clearTimeout function, 248 cleverness, 186 click event, 236, 238, 241, 421, 425 client, 208, 310, 355, 368, 379 clientHeight property, 225 clientWidth property, 225 clientX property, 242, 334 clientY property, 242, 334 clipboard, 212, 250 clipping, 291 cloneNode method, 383 cloning,383 closePath read more..

  • Page - 458

    controls object, 333, 336 convention, 36, 186 Conway’s Game of Life, 328 coordinates, 120, 241, 260, 277, 278, 334, 422–423 copying,383 copy-paste programming, 53, 176 correlation, 67–69, 71 cosine, 76, 231 counter variable, 31, 33, 231, 408, 409, 417, 421 crash, 147, 150, 361, 375, 386 createElement method, 221, 332, 416 createPaint function, 333 createReadStream function, 356, 359 read more..

  • Page - 459

    dependence, 67 dependency, 176–177, 180, 183–184, 188, 352 deserialization, 87 developer tools, 7, 27, 144, 147 dialog box, 27, 28 diamond, 296, 419 digit, 11, 12, 142, 155–157, 173 Dijkstra, Edsger, 118 dimensions, 117, 119, 225, 253, 255, 265, 277, 408 dinosaur, 201 direct child node, 228 directions object, 122, 129 directory, 353–354, 357–359, 364, 425 disabled attribute, 318 read more..

  • Page - 460

    else keyword, 30 elt function, 222, 332, 380 email, 311 email field, 336 empty set, 165 encapsulation defined, 99, 100 importance of, 176 inheritance and, 115 usingmodules, 177–178,186, 188 encodeURIComponent function, 301, 370 encoding,208 encryption, 311 end event, 356 end method, 355, 356, 358, 424 enemies example, 168 energy, 130–133, 412 engine, 389 engineering, 213 ENOENT (status code), read more..

  • Page - 461

    exit method, 350 expectation, 239 experiment, 3, 7, 172, 240 exploit, 213 exponent, 13, 173, 414 exponentiation, 32, 33 exporting, 179, 182, 415 exports object, 179, 181–182, 351, 415 expression, 23–25, 28, 31, 33, 196 expressivity, 2, 201 extinction, 135 extraction, 158 F factorial function, 8 failure, 306 fallthrough, 35 false, 16 farm example, 52, 54, 160 farmer, 87 field, 315, 318, read more..

  • Page - 462

    function, continued purity, 54 scope, 43, 44, 125, 202 as value, 45, 48, 83–84, 306, 418 wrapping, 86 Function constructor, 181, 184, 198, 200, 327, 421 function keyword, 42, 45, 179 Function prototype, 102, 104 future of JavaScript, 6, 26, 171, 185, 308 G game acceleration of character in, 240 drawing display for, 290–294 platform, 253–273 running, 270 game of life (exercise), 328, read more..

  • Page - 463

    helper function, 218 herbivore, 133–136, 413 hexadecimal number, 162, 301 hidden element, 227, 251, 380 higher-order function, 84–86, 87, 89, 90, 125 highlightCode function, 223 history, 6, 99, 378 Hoare, C.A.R., 80 Hooke’s law, 393 hooligan, 371 Host header, 301, 304 hot code, 390 hover effect, 243, 244 href attribute, 210, 219, 222, 337 HTML, 209, 215, 217, 276, 332 html (HTML read more..

  • Page - 464

    isEven (exercise), 56, 408 isInside function, 243 isNaN function, 30 isolation, 99, 176–178,180, 212 iteration, 117 J Jacques, the weresquirrel, 60 Java, 6 JavaScript absence of, 387 availability of, 2 flexibility of, 6 history of, 6, 207 in HTML, 211 syntax, 23 uses of, 6 versions of, 6 weaknesses of, 6 JavaScript console, 7, 15, 27, 143, 147, 327, 349 JavaScript Object Notation, see read more..

  • Page - 465

    load event, 246, 284, 293, 304, 324, 339, 420 loading,183 local scope, 176, 200 local variable, 43, 48, 84, 85, 202, 409, 418 localhost, 354 localStorage object, 325–326, 384 locked box (exercise), 151, 413 logging, 143 logical operators, 17 long polling,368–370, 376–377, 386 loop body, 32, 34 defined, 31 for,33, 83 nested, 84, 92 over matches, 168 termination of, 33 while,5 lycanthropy, read more..

  • Page - 466

    module object, 182 modulo operator, 14 Mongolian vowel separator, 171 month name (exercise), 187, 414 Mosaic, 213 motion, 254 MOUNTAINS data set, 108, 111, 232 mouse, 26, 332, 334, 342, 421 button, 237, 238, 241 cursor, 241 mouse trail (exercise), 250, 417 mousedown event, 238, 241, 332, 334, 421 mousemove event, 242–243, 248, 334–335, 417 mouseout event, 243 mouseover event, 243, 338 read more..

  • Page - 467

    immutable, 65 instanceof operator, 115 looping over, 70 as map, 105, 124, 257, 411 Math,75 OOP history, 99 overview, 59, 102 property, 61 Object prototype, 102, 106, 107 object shape, 403 Object.create function, 102, 107, 200 Object.keys function, 112, 123, 232 object-oriented programming, 99–100, 107–108, 115 obstacle, 130, 264–265 obstacleAt method, 265 offsetHeight property, 225 offsetWidth read more..

  • Page - 468

    percent sign, 301 performance canvas, 295, 344 compilation and, 200 games and, 255 JavaScript engine, 389 regular expressions and, 162 single thread and, 247 synchronous functions, 354 period character, 27, 61, 155, 165, 173, 424 persistence, 325, 368,384, 386, 425 phase, 258–259, 268 phi coefficient, 67–68 phi function, 68 photosynthesis, 130–131, 133 physics, 264, 268, 391, 417 physics read more..

  • Page - 469

    promise, 308–310, 313, 324, 362–363, 421 Promise constructor, 308, 313, 421 prompt function, 28, 340 promptDirection function, 148–149 promptInteger function, 144 propagation, see event propagation property adding, 104 assignment, 64 brace notation, 63 console.log,27 deletion, 64 DOM objects and, 222 global scope and, 77 interfaces and, 113 methods and, 100 model of, 64 naming, 127 Object.keys read more..

  • Page - 470

    rectangle tool (exercise), 342, 422 recursion, 50, 196, 219, 408, 417, 425, 426 reduce method, 89–90, 92, 95, 108–109 reduceAncestors function, 93 ReferenceError type, 202 RegExp constructor, 153–154, 166 regexp golf (exercise), 172 registerChange function, 374–375, 378, 425 regular expressions alternatives, 160 backtracking, 162 boundary, 160 character categories, 171 character sets, 154 creation, read more..

  • Page - 471

    runLevel function, 271, 273 running code, 7 run-time error, 139, 141, 142, 144, 150, 416 S Safari, 213 sandbox, 59, 212, 215, 305, 338 save link, 337 save method, 288–289 saving, 332 scalar replacement of aggregates, 396, 399 scale method, 286, 288 scaling, 260, 285–286, 293, 420 scheduling,348 scientific notation, 13, 173 scope, 43, 44, 77, 125, 176, 177, 181, 416 script (HTML tag), read more..

  • Page - 472

    sprite, 285, 292–293 square, 29, 42 square brackets, 61, 69, 155, 409 square example, 45 square root, 68, 75, 411 src attribute, 210, 211 stability, 135, 136, 177, 413 stack, see call stack stack overflow, 47, 50, 56, 409 stack trace, 145, 149, 361 staged compilation, 390 standard, 6, 26, 46, 170, 207, 336 standard environment, 26 standard output, 349, 357 standards, 213 star, read more..

  • Page - 473

    table example, 108–111, 114, 232, 416 tableFor function, 68 tag, 209–210, 215, 228. See also names of specific tags tagName property, 232 tainting,338 talk, 367–368, 374–376, 382 talksAbout function, 219 tampering, 311 tangent, 76 target property, 238, 243, 321, 421 task management example, 72 taste, 175, 188 TCP, 208, 299, 369 td (HTML tag), 232 template, 380, 382, 387, 426 read more..

  • Page - 474

    U unary operator, 15 uncaught exception, 147, 308, 361 undefined,18–19, 26, 42, 47, 63, 140, 144 underline, 226 underscore character, 25, 36, 109, 127, 166 Unicode, 16, 155, 170–171, 240, 351 unicycling, 367 uniformity, 192, 341 uniqueness, 228 unit (CSS), 231, 245 Universal Resource Locator, see URL Unix, 359, 361 Unix time, 159, 371 unlink function, 354 unshift method, 72 UnterlinedCell read more..

  • Page - 475

    Why’s Poignant Guide to Ruby,22 width (CSS), 342 window, 236, 237, 243, 246, 350 window variable, 77 Windows, 364 with statement, 141 withContext function, 146–147 word boundary, 160 word character, 155, 160, 170 work list, 423 workbench (exercise), 327, 421 world, 119, 120, 253 World type, 12–124, 126–127, 130 World Wide Web, 6, 87, 183, 207, 209, 212–213, 299 writable stream, read more..

  • Page - 476

    UPDATES Visit http://nostarch.com/ejs2/ for updates, errata, and other information. PHONE : 800.420.7240 OR 415.863.9900 EMAIL : SALES @NOSTARCH.COM WEB : WWW .NOSTARCH.COM THE BOOK OF CSS3, 2ND EDITION A Developer’s Guide to the Future of Web Design by PETER GASSTON NOVEMBER 2014, 304 PP ., $34.95 ISBN 978-1-59327-580-8 PYTHON FOR KIDS A Playful Introduction to read more..

  • Page - 477

    read more..

  • Page - 478

    JavaScript lies at the heart of almost every modern web application, from social apps to the newest browser-based games. Though simple for beginners to pick up and play with, you can use to build full-scale applications. Eloquent JavaScript, 2nd Edition dives deep into the JavaScript language to show you how to write beautiful, effective code. Author read more..

Write Your Review