text:
- Programming
- Engineering
- Economics & Finance
- Health & Medicine
- Others
Besides explaining JavaScript, this book also will introduce the basic principles of programming.
Marijn Haverbeke
478 Pages
44573 Reads
95 Downloads
PDF Format
A Modern Introduction to Programming Marijn Haverbeke SECOND EDITION read more..
ELOQUENT JAVASCRIPT read more..
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..
ELOQUENT JAVASCRIPT A Modern Introduction to Programming by Marijn Haverbeke San Francisco read more..
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..
For Lotte and Jan read more..
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..
PART I LANGUAGE read more..
"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..
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..
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..
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..
(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..
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..
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..
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..
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..
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..
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..
"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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
"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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
"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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
"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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
"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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
}; 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..
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..
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..
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..
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..
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..
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..
"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..
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..
var plan = ["############################", "# # # o ##", "# #", "# ##### #", "## # # ## #", "### ## # #", "# ### # #", "# #### #", "# ## o #", "# o # o ### #", "# # #", "############################"]; The # characters in this plan represent walls and rocks, and the o char- acters represent read more..
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..
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..
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..
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..
//### 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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
############################ ############################ #####O O ###### ##### O ###### ## ## ## ## # ##O ## # ## O ## #O O *## # # ## # # OOO **## O # # ## # # **## O # # O ## * # ## *** * ## #O # ## O***** O# # O # O # ###****** # # ## O O # ## ###****** ### ## ### O ### ############################ ############################ ############################ ############################ ##### read more..
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..
"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..
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..
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..
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..
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..
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..
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..
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..
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..
} 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..
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..
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..
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..
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..
"Some people, when confronted with a problem, think 'I know, I'll use regular expressions.' Now they have two problems." — Jamie Zawinski read more..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
"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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
PART II BROWSER read more..
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..
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..
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..
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 &. Inside an attribute, which is wrapped in double read more..
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..
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..
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..
</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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
<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..
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..
<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..
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..
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..
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..
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..
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..
"You have power over your mind— not outside events. Realize this, and you will find strength." — Marcus Aurelius, Meditations read more..
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..
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..
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..
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..
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..
<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..
<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..
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..
}); </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..
<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..
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..
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..
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..
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..
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..
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..
"All reality is a game." — Iain Banks, The Player of Games read more..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
"Drawing is deception." — M.C. Escher, cited by Bruno Ernst in The Magic Mirror of M.C. Escher read more..
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..
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..
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..
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..
<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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
"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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
}); 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..
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..
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..
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..
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..
"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..
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..
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..
<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..
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..
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..
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..
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..
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..
</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..
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..
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..
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..
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..
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..
"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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
PART III BEYOND read more..
"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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
npm http 304 https://registry.npmjs.org/mime firstname.lastname@example.com 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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
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..
Write Your Review