JavaScript: The Definitive Guide PDF
Document Details
David Flanagan
Tags
Summary
This book, "JavaScript: The Definitive Guide", 6th edition, by David Flanagan, is a comprehensive guide to JavaScript programming. It covers the core concepts, syntax, and features of the language. Suitable for professional developers.
Full Transcript
JavaScript: The Definitive Guide SIXTH EDITION JavaScript: The Definitive Guide David Flanagan Beijing Cambridge Farnham Köln Sebastopol Tokyo JavaScript: The Definitive Guide, Sixth...
JavaScript: The Definitive Guide SIXTH EDITION JavaScript: The Definitive Guide David Flanagan Beijing Cambridge Farnham Köln Sebastopol Tokyo JavaScript: The Definitive Guide, Sixth Edition by David Flanagan Copyright © 2011 David Flanagan. All rights reserved. Printed in the United States of America. Published by O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472. O’Reilly books may be purchased for educational, business, or sales promotional use. Online editions are also available for most titles (http://my.safaribooksonline.com). For more information, contact our corporate/institutional sales department: (800) 998-9938 or [email protected]. Editor: Mike Loukides Indexer: Ellen Troutman Zaig Production Editor: Teresa Elsey Cover Designer: Karen Montgomery Proofreader: Teresa Elsey Interior Designer: David Futato Illustrator: Robert Romano Printing History: August 1996: Beta Edition. January 1997: Second Edition. June 1998: Third Edition. January 2002: Fourth Edition. August 2006: Fifth Edition. March 2011: Sixth Edition. Nutshell Handbook, the Nutshell Handbook logo, and the O’Reilly logo are registered trademarks of O’Reilly Media, Inc. JavaScript: The Definitive Guide, the image of a Javan rhinoceros, and related trade dress are trademarks of O’Reilly Media, Inc. Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks. Where those designations appear in this book, and O’Reilly Media, Inc., was aware of a trademark claim, the designations have been printed in caps or initial caps. While every precaution has been taken in the preparation of this book, the publisher and authors assume no responsibility for errors or omissions, or for damages resulting from the use of the information con- tained herein. ISBN: 978-0-596-80552-4 [LSI] 1302719886 This book is dedicated to all who teach peace and resist violence. Table of Contents Preface.................................................................... xiii 1. Introduction to JavaScript................................................ 1 1.1 Core JavaScript 4 1.2 Client-Side JavaScript 8 Part I. Core JavaScript 2. Lexical Structure....................................................... 21 2.1 Character Set 21 2.2 Comments 23 2.3 Literals 23 2.4 Identifiers and Reserved Words 23 2.5 Optional Semicolons 25 3. Types, Values, and Variables............................................. 29 3.1 Numbers 31 3.2 Text 36 3.3 Boolean Values 40 3.4 null and undefined 41 3.5 The Global Object 42 3.6 Wrapper Objects 43 3.7 Immutable Primitive Values and Mutable Object References 44 3.8 Type Conversions 45 3.9 Variable Declaration 52 3.10 Variable Scope 53 4. Expressions and Operators............................................... 57 4.1 Primary Expressions 57 4.2 Object and Array Initializers 58 4.3 Function Definition Expressions 59 vii 4.4 Property Access Expressions 60 4.5 Invocation Expressions 61 4.6 Object Creation Expressions 61 4.7 Operator Overview 62 4.8 Arithmetic Expressions 66 4.9 Relational Expressions 71 4.10 Logical Expressions 75 4.11 Assignment Expressions 77 4.12 Evaluation Expressions 79 4.13 Miscellaneous Operators 82 5. Statements........................................................... 87 5.1 Expression Statements 88 5.2 Compound and Empty Statements 88 5.3 Declaration Statements 89 5.4 Conditionals 92 5.5 Loops 97 5.6 Jumps 102 5.7 Miscellaneous Statements 108 5.8 Summary of JavaScript Statements 112 6. Objects.............................................................. 115 6.1 Creating Objects 116 6.2 Querying and Setting Properties 120 6.3 Deleting Properties 124 6.4 Testing Properties 125 6.5 Enumerating Properties 126 6.6 Property Getters and Setters 128 6.7 Property Attributes 131 6.8 Object Attributes 135 6.9 Serializing Objects 138 6.10 Object Methods 138 7. Arrays............................................................... 141 7.1 Creating Arrays 141 7.2 Reading and Writing Array Elements 142 7.3 Sparse Arrays 144 7.4 Array Length 144 7.5 Adding and Deleting Array Elements 145 7.6 Iterating Arrays 146 7.7 Multidimensional Arrays 148 7.8 Array Methods 148 7.9 ECMAScript 5 Array Methods 153 7.10 Array Type 157 viii | Table of Contents 7.11 Array-Like Objects 158 7.12 Strings As Arrays 160 8. Functions............................................................ 163 8.1 Defining Functions 164 8.2 Invoking Functions 166 8.3 Function Arguments and Parameters 171 8.4 Functions As Values 176 8.5 Functions As Namespaces 178 8.6 Closures 180 8.7 Function Properties, Methods, and Constructor 186 8.8 Functional Programming 191 9. Classes and Modules................................................... 199 9.1 Classes and Prototypes 200 9.2 Classes and Constructors 201 9.3 Java-Style Classes in JavaScript 205 9.4 Augmenting Classes 208 9.5 Classes and Types 209 9.6 Object-Oriented Techniques in JavaScript 215 9.7 Subclasses 228 9.8 Classes in ECMAScript 5 238 9.9 Modules 246 10. Pattern Matching with Regular Expressions............................... 251 10.1 Defining Regular Expressions 251 10.2 String Methods for Pattern Matching 259 10.3 The RegExp Object 261 11. JavaScript Subsets and Extensions....................................... 265 11.1 JavaScript Subsets 266 11.2 Constants and Scoped Variables 269 11.3 Destructuring Assignment 271 11.4 Iteration 274 11.5 Shorthand Functions 282 11.6 Multiple Catch Clauses 283 11.7 E4X: ECMAScript for XML 283 12. Server-Side JavaScript................................................. 289 12.1 Scripting Java with Rhino 289 12.2 Asynchronous I/O with Node 296 Table of Contents | ix Part II. Client-Side JavaScript 13. JavaScript in Web Browsers............................................. 307 13.1 Client-Side JavaScript 307 13.2 Embedding JavaScript in HTML 311 13.3 Execution of JavaScript Programs 317 13.4 Compatibility and Interoperability 325 13.5 Accessibility 332 13.6 Security 332 13.7 Client-Side Frameworks 338 14. The Window Object................................................... 341 14.1 Timers 341 14.2 Browser Location and Navigation 343 14.3 Browsing History 345 14.4 Browser and Screen Information 346 14.5 Dialog Boxes 348 14.6 Error Handling 351 14.7 Document Elements As Window Properties 351 14.8 Multiple Windows and Frames 353 15. Scripting Documents.................................................. 361 15.1 Overview of the DOM 361 15.2 Selecting Document Elements 364 15.3 Document Structure and Traversal 371 15.4 Attributes 375 15.5 Element Content 378 15.6 Creating, Inserting, and Deleting Nodes 382 15.7 Example: Generating a Table of Contents 387 15.8 Document and Element Geometry and Scrolling 389 15.9 HTML Forms 396 15.10 Other Document Features 405 16. Scripting CSS......................................................... 413 16.1 Overview of CSS 414 16.2 Important CSS Properties 419 16.3 Scripting Inline Styles 431 16.4 Querying Computed Styles 435 16.5 Scripting CSS Classes 437 16.6 Scripting Stylesheets 440 17. Handling Events...................................................... 445 17.1 Types of Events 447 x | Table of Contents 17.2 Registering Event Handlers 456 17.3 Event Handler Invocation 460 17.4 Document Load Events 465 17.5 Mouse Events 467 17.6 Mousewheel Events 471 17.7 Drag and Drop Events 474 17.8 Text Events 481 17.9 Keyboard Events 484 18. Scripted HTTP........................................................ 491 18.1 Using XMLHttpRequest 494 18.2 HTTP by : JSONP 513 18.3 Comet with Server-Sent Events 515 19. The jQuery Library.................................................... 523 19.1 jQuery Basics 524 19.2 jQuery Getters and Setters 531 19.3 Altering Document Structure 537 19.4 Handling Events with jQuery 540 19.5 Animated Effects 551 19.6 Ajax with jQuery 558 19.7 Utility Functions 571 19.8 jQuery Selectors and Selection Methods 574 19.9 Extending jQuery with Plug-ins 582 19.10 The jQuery UI Library 585 20. Client-Side Storage.................................................... 587 20.1 localStorage and sessionStorage 589 20.2 Cookies 593 20.3 IE userData Persistence 599 20.4 Application Storage and Offline Webapps 601 21. Scripted Media and Graphics............................................ 613 21.1 Scripting Images 613 21.2 Scripting Audio and Video 615 21.3 SVG: Scalable Vector Graphics 622 21.4 Graphics in a 630 22. HTML5 APIs.......................................................... 667 22.1 Geolocation 668 22.2 History Management 671 22.3 Cross-Origin Messaging 676 22.4 Web Workers 680 Table of Contents | xi 22.5 Typed Arrays and ArrayBuffers 687 22.6 Blobs 691 22.7 The Filesystem API 700 22.8 Client-Side Databases 705 22.9 Web Sockets 712 Part III. Core JavaScript Reference Core JavaScript Reference.................................................... 719 Part IV. Client-Side JavaScript Reference Client-Side JavaScript Reference.............................................. 859 Index.................................................................... 1019 xii | Table of Contents Preface This book covers the JavaScript language and the JavaScript APIs implemented by web browsers. I wrote it for readers with at least some prior programming experience who want to learn JavaScript and also for programmers who already use JavaScript but want to take their understanding to a new level and really master the language and the web platform. My goal with this book is to document the JavaScript language and platform comprehensively and definitively. As a result, this is a large and detailed book. My hope, however, is that it will reward careful study, and that the time you spend reading it will be easily recouped in the form of higher programming productivity. This book is divided into four parts. Part I covers the JavaScript language itself. Part II covers client-side JavaScript: the JavaScript APIs defined by HTML5 and related standards and implemented by web browsers. Part III is the reference section for the core language, and Part IV is the reference for client-side JavaScript. Chapter 1 includes an outline of the chapters in Parts I and II (see §1.1). This sixth edition of the book covers both ECMAScript 5 (the latest version of the core language) and HTML5 (the latest version of the web platform). You’ll find ECMAScript 5 material throughout Part I. The new material on HTML5 is mostly in the chapters at the end of Part II, but there is also some in other chapters as well. Completely new chapters in this edition include Chapter 11, JavaScript Subsets and Extensions; Chapter 12, Server-Side JavaScript; Chapter 19, The jQuery Library; and Chapter 22, HTML5 APIs. Readers of previous editions may notice that I have completely rewritten many of the chapters in this book for the sixth edition. The core of Part I—the chapters covering objects, arrays, functions, and classes—is all new and brings the book in line with current programming styles and best practices. Similarly, key chapters of Part II, such as those covering documents and events, have been completely rewritten to bring them up-to-date. xiii A Note About Piracy If you are reading a digital version of this book that you (or your employer) did not pay for (or borrow from someone who did) then you probably have an illegally pirated copy. Writing the sixth edition of this book was a full-time job, and it took more than a year. The only way I get paid for that time is when readers actually buy the book. And the only way I can afford to work on a seventh edition is if I get paid for the sixth. I do not condone piracy, but if you have a pirated copy, go ahead and read a couple of chapters. I think that you’ll find that this is a valuable source of information about JavaScript, better organized and of higher quality than what you can find freely (and legally) available on the Web. If you agree that this is a valuable source of information, then please pay for that value by purchasing a legal copy (either digital or print) of the book. On the other hand, if you find that this book is no more valuable than the free information on the web, then please discard your pirated copy and use those free information sources. Conventions Used in This Book I use the following typographical conventions in this book: Italic Is used for emphasis and to indicate the first use of a term. Italic is also used for email addresses, URLs and file names. Constant width Is used in all JavaScript code and CSS and HTML listings, and generally for any- thing that you would type literally when programming. Constant width italic Is used for the names of function parameters, and generally as a placeholder to indicate an item that should be replaced with an actual value in your program. Example Code The examples in this book are available online. You can find them linked from the book’s catalog page at the publisher’s website: http://oreilly.com/catalog/9780596805531/ This book is here to help you get your job done. In general, you may use the code in this book in your programs and documentation. You do not need to contact O’Reilly for permission unless you’re reproducing a significant portion of the code. For example, writing a program that uses several chunks of code from this book does not require permission. Selling or distributing a CD-ROM of examples from O’Reilly books does require permission. Answering a question by citing this book and quoting example xiv | Preface code does not require permission. Incorporating a significant amount of example code from this book into your product’s documentation does require permission. If you use the code from this book, I appreciate, but do not require, attribution. An attribution usually includes the title, author, publisher, and ISBN. For example: “Java- Script: The Definitive Guide, by David Flanagan (O’Reilly). Copyright 2011 David Fla- nagan, 978-0-596-80552-4.” For more details on the O’Reilly code reuse policy, see http://oreilly.com/pub/a/oreilly/ ask_tim/2001/codepolicy.html. If you feel your use of the examples falls outside of the permission given above, feel free to contact O’Reilly at [email protected]. Errata and How to Contact Us The publisher maintains a public list of errors found in this book. You can view the list, and submit the errors you find, by visiting the book’s web page: http://oreilly.com/catalog/9780596805531 To comment or ask technical questions about this book, send email to: [email protected] For more information about our books, conferences, Resource Centers, and the O’Reilly Network, see our website at: http://www.oreilly.com Find us on Facebook: http://facebook.com/oreilly Follow us on Twitter: http://twitter.com/oreillymedia Watch us on YouTube: http://www.youtube.com/oreillymedia Acknowledgments Many people have helped me with the creation of this book. I’d like to thank my editor, Mike Loukides, for trying to keep me on schedule and for his insightful comments. Thanks also to my technical reviewers: Zachary Kessin, who reviewed many of the chapters in Part I, and Raffaele Cecco, who reviewed Chapter 19 and the material in Chapter 21. The production team at O’Reilly has done their usual fine job: Dan Fauxsmith managed the production process, Teresa Elsey was the production editor, Rob Romano drew the figures, and Ellen Troutman Zaig created the index. In this era of effortless electronic communication, it is impossible to keep track of all those who influence and inform us. I’d like to thank everyone who has answered my questions on the es5, w3c, and whatwg mailing lists, and everyone who has shared their insightful ideas about JavaScript programming online. I’m sorry I can’t list you all by Preface | xv name, but it is a pleasure to work within such a vibrant community of JavaScript programmers. Editors, reviewers, and contributors to previous editions of this book have included: Andrew Schulman, Angelo Sirigos, Aristotle Pagaltzis, Brendan Eich, Christian Heilmann, Dan Shafer, Dave C. Mitchell, Deb Cameron, Douglas Crockford, Dr. Tankred Hirschmann, Dylan Schiemann, Frank Willison, Geoff Stearns, Herman Ven- ter, Jay Hodges, Jeff Yates, Joseph Kesselman, Ken Cooper, Larry Sullivan, Lynn Roll- ins, Neil Berkman, Nick Thompson, Norris Boyd, Paula Ferguson, Peter-Paul Koch, Philippe Le Hegaret, Richard Yaker, Sanders Kleinfeld, Scott Furman, Scott Issacs, Shon Katzenberger, Terry Allen, Todd Ditchendorf, Vidur Apparao, and Waldemar Horwat. This edition of the book is substantially rewritten and kept me away from my family for many late nights. My love to them and my thanks for putting up with my absences. — David Flanagan (davidflanagan.com), March 2011 xvi | Preface CHAPTER 1 Introduction to JavaScript JavaScript is the programming language of the Web. The overwhelming majority of modern websites use JavaScript, and all modern web browsers—on desktops, game consoles, tablets, and smart phones—include JavaScript interpreters, making Java- Script the most ubiquitous programming language in history. JavaScript is part of the triad of technologies that all Web developers must learn: HTML to specify the content of web pages, CSS to specify the presentation of web pages, and JavaScript to specify the behavior of web pages. This book will help you master the language. If you are already familiar with other programming languages, it may help you to know that JavaScript is a high-level, dynamic, untyped interpreted programming language that is well-suited to object-oriented and functional programming styles. JavaScript derives its syntax from Java, its first-class functions from Scheme, and its prototype- based inheritance from Self. But you do not need to know any of those languages, or be familiar with those terms, to use this book and learn JavaScript. The name “JavaScript” is actually somewhat misleading. Except for a superficial syn- tactic resemblance, JavaScript is completely different from the Java programming lan- guage. And JavaScript has long since outgrown its scripting-language roots to become a robust and efficient general-purpose language. The latest version of the language (see the sidebar) defines new features for serious large-scale software development. 1 JavaScript: Names and Versions JavaScript was created at Netscape in the early days of the Web, and technically, “Java- Script” is a trademark licensed from Sun Microsystems (now Oracle) used to describe Netscape’s (now Mozilla’s) implementation of the language. Netscape submitted the language for standardization to ECMA—the European Computer Manufacturer’s As- sociation—and because of trademark issues, the standardized version of the language was stuck with the awkward name “ECMAScript.” For the same trademark reasons, Microsoft’s version of the language is formally known as “JScript.” In practice, just about everyone calls the language JavaScript. This book uses the name “ECMAScript” only to refer to the language standard. For the last decade, all web browsers have implemented version 3 of the ECMAScript standard and there has really been no need to think about version numbers: the lan- guage standard was stable and browser implementations of the language were, for the most part, interoperable. Recently, an important new version of the language has been defined as ECMAScript version 5 and, at the time of this writing, browsers are beginning to implement it. This book covers all the new features of ECMAScript 5 as well as all the long-standing features of ECMAScript 3. You’ll sometimes see these language ver- sions abbreviated as ES3 and ES5, just as you’ll sometimes see the name JavaScript abbreviated as JS. When we’re speaking of the language itself, the only version numbers that are relevant are ECMAScript versions 3 or 5. (Version 4 of ECMAScript was under development for years, but proved to be too ambitious and was never released.) Sometimes, however, you’ll also see a JavaScript version number, such as JavaScript 1.5 or JavaScript 1.8. These are Mozilla’s version numbers: version 1.5 is basically ECMAScript 3, and later versions include nonstandard language extensions (see Chapter 11). Finally, there are also version numbers attached to particular JavaScript interpreters or “engines.” Goo- gle calls its JavaScript interpreter V8, for example, and at the time of this writing the current version of the V8 engine is 3.0. To be useful, every language must have a platform or standard library or API of func- tions for performing things like basic input and output. The core JavaScript language defines a minimal API for working with text, arrays, dates, and regular expressions but does not include any input or output functionality. Input and output (as well as more sophisticated features, such as networking, storage, and graphics) are the responsibility of the “host environment” within which JavaScript is embedded. Usually that host environment is a web browser (though we’ll see two uses of JavaScript without a web browser in Chapter 12). Part I of this book covers the language itself and its minimal built-in API. Part II explains how JavaScript is used in web browsers and covers the sprawling browser-based APIs loosely known as “client-side JavaScript.” Part III is the reference section for the core API. You can read about the JavaScript array manipulation API by looking up “Array” in this part of the book, for example. Part IV is the reference section for client-side JavaScript. You might look up “Canvas” 2 | Chapter 1: Introduction to JavaScript in this part of the book to read about the graphics API defined by the HTML5 element, for example. This book covers low-level fundamentals first, and then builds on those to more advanced and higher-level abstractions. The chapters are intended to be read more or less in order. But learning a new programming language is never a linear process, and describing a language is not linear either: each language feature is related to other fea- tures and this book is full of cross-references—sometimes backward and sometimes forward to material you have not yet read. This chapter makes a quick first pass through the core language and the client-side API, introducing key features that will make it easier to understand the in-depth treatment in the chapters that follow. Exploring JavaScript When learning a new programming language, it’s important to try the examples in the book, and then modify them and try them again to test your understanding of the language. To do that, you need a JavaScript interpreter. Fortunately, every web browser includes a JavaScript interpreter, and if you’re reading this book, you probably already have more than one web browser installed on your computer. We’ll see later on in this chapter that you can embed JavaScript code within tags in HTML files, and when the browser loads the file, it will execute the code. For- tunately, however, you don’t have to do that every time you want to try out simple snippets of JavaScript code. Spurred on by the powerful and innovative Firebug exten- sion for Firefox (pictured in Figure 1-1 and available for download from http://getfirebug.com/), today’s web browsers all include web developer tools that are indispensable for debugging, experimenting, and learning. You can usually find these tools in the Tools menu of the browser under names like “Developer Tools” or “Web Console.” (Firefox 4 includes a built-in “Web Console,” but at the time of this writing, the Firebug extension is better.) Often, you can call up a console with a keystroke like F12 or Ctrl- Shift-J. These console tools often appear as panes at the top or bottom of the browser window, but some allow you to open them as separate windows (as pictured in Fig- ure 1-1), which is often quite convenient. A typical “developer tools” pane or window includes multiple tabs that allow you to inspect things like HTML document structure, CSS styles, network requests, and so on. One of the tabs is a “JavaScript console” that allows you to type in lines of JavaScript code and try them out. This is a particularly easy way to play around with JavaScript, and I recommend that you use it as you read this book. There is a simple console API that is portably implemented by modern browsers. You can use the function console.log() to display text on the console. This is often sur- prisingly helpful while debugging, and some of the examples in this book (even in the core language section) use console.log() to perform simple output. A similar but more intrusive way to display output or debugging messages is by passing a string of text to the alert() function, which displays it in a modal dialog box. Introduction to JavaScript | 3 Figure 1-1. The Firebug debugging console for Firefox 1.1 Core JavaScript This section is a tour of the JavaScript language, and also a tour of Part I of this book. After this introductory chapter, we dive into JavaScript at the lowest level: Chapter 2, Lexical Structure, explains things like JavaScript comments, semicolons, and the Uni- code character set. Chapter 3, Types, Values, and Variables, starts to get more inter- esting: it explains JavaScript variables and the values you can assign to those variables. Here’s some sample code to illustrate the highlights of those two chapters: // Anything following double slashes is an English-language comment. // Read the comments carefully: they explain the JavaScript code. // variable is a symbolic name for a value. // Variables are declared with the var keyword: var x; // Declare a variable named x. // Values can be assigned to variables with an = sign x = 0; // Now the variable x has the value 0 x // => 0: A variable evaluates to its value. // JavaScript supports several types of values x = 1; // Numbers. x = 0.01; // Just one Number type for integers and reals. x = "hello world"; // Strings of text in quotation marks. x = 'JavaScript'; // Single quote marks also delimit strings. x = true; // Boolean values. x = false; // The other Boolean value. 4 | Chapter 1: Introduction to JavaScript x = null; // Null is a special value that means "no value". x = undefined; // Undefined is like null. Two other very important types that JavaScript programs can manipulate are objects and arrays. These are the subject of Chapter 6, Objects, and Chapter 7, Arrays, but they are so important that you’ll see them many times before you reach those chapters. // JavaScript's most important data type is the object. // An object is a collection of name/value pairs, or a string to value map. var book = { // Objects are enclosed in curly braces. topic: "JavaScript", // The property "topic" has value "JavaScript". fat: true // The property "fat" has value true. }; // The curly brace marks the end of the object. // Access the properties of an object with. or []: book.topic // => "JavaScript" book["fat"] // => true: another way to access property values. book.author = "Flanagan"; // Create new properties by assignment. book.contents = {}; // {} is an empty object with no properties. // JavaScript also supports arrays (numerically indexed lists) of values: var primes = [2, 3, 5, 7]; // An array of 4 values, delimited with [ and ]. primes // => 2: the first element (index 0) of the array. primes.length // => 4: how many elements in the array. primes[primes.length-1] // => 7: the last element of the array. primes = 9; // Add a new element by assignment. primes = 11; // Or alter an existing element by assignment. var empty = []; // [] is an empty array with no elements. empty.length // => 0 // Arrays and objects can hold other arrays and objects: var points = [ // An array with 2 elements. {x:0, y:0}, // Each element is an object. {x:1, y:1} ]; var data = { // An object with 2 properties trial1: [[1,2], [3,4]], // The value of each property is an array. trial2: [[2,3], [4,5]] // The elements of the arrays are arrays. }; The syntax illustrated above for listing array elements within square braces or mapping object property names to property values inside curly braces is known as an initializer expression, and it is just one of the topics of Chapter 4, Expressions and Operators. An expression is a phrase of JavaScript that can be evaluated to produce a value. The use of. and [] to refer to the value of an object property or array element is an expression, for example. You may have noticed in the code above that when an expression stands alone on a line, the comment that follows it begins with an arrow (=>) and the value of the expression. This is a convention that you’ll see throughout this book. One of the most common ways to form expressions in JavaScript is to use operators like these: // Operators act on values (the operands) to produce a new value. // Arithmetic operators are the most common: 3 + 2 // => 5: addition 1.1 Core JavaScript | 5 3 - 2 // => 1: subtraction 3 * 2 // => 6: multiplication 3 / 2 // => 1.5: division points.x - points.x // => 1: more complicated operands work, too "3" + "2" // => "32": + adds numbers, concatenates strings // JavaScript defines some shorthand arithmetic operators var count = 0; // Define a variable count++; // Increment the variable count--; // Decrement the variable count += 2; // Add 2: same as count = count + 2; count *= 3; // Multiply by 3: same as count = count * 3; count // => 6: variable names are expressions, too. // Equality and relational operators test whether two values are equal, // unequal, less than, greater than, and so on. They evaluate to true or false. var x = 2, y = 3; // These = signs are assignment, not equality tests x == y // => false: equality x != y // => true: inequality x < y // => true: less-than x true: less-than or equal x > y // => false: greater-than x >= y // => false: greater-than or equal "two" == "three" // => false: the two strings are different "two" > "three" // => true: "tw" is alphabetically greater than "th" false == (x > y) // => true: false is equal to false // Logical operators combine or invert boolean values (x == 2) && (y == 3) // => true: both comparisons are true. && is AND (x > 3) || (y < 3) // => false: neither comparison is true. || is OR !(x == y) // => true: ! inverts a boolean value If the phrases of JavaScript are expressions, then the full sentences are statements, which are the topic of Chapter 5, Statements. In the code above, the lines that end with semicolons are statements. (In the code below, you’ll see multiline statements that do not end with semicolons.) There is actually a lot of overlap between statements and expressions. Roughly, an expression is something that computes a value but doesn’t do anything: it doesn’t alter the program state in any way. Statements, on the other hand, don’t have a value (or don’t have a value that we care about), but they do alter the state. You’ve seen variable declarations and assignment statements above. The other broad category of statement is control structures, such as conditionals and loops. Examples are below, after we cover functions. A function is a named and parametrized block of JavaScript code that you define once, and can then invoke over and over again. Functions aren’t covered formally until Chapter 8, Functions, but like objects and arrays, you’ll see them many times before you get to that chapter. Here are some simple examples: // Functions are parameterized blocks of JavaScript code that we can invoke. function plus1(x) { // Define a function named "plus1" with parameter "x" return x+1; // Return a value one larger than the value passed in } // Functions are enclosed in curly braces 6 | Chapter 1: Introduction to JavaScript plus1(y) // => 4: y is 3, so this invocation returns 3+1 var square = function(x) { // Functions are values and can be assigned to vars return x*x; // Compute the function's value }; // Semicolon marks the end of the assignment. square(plus1(y)) // => 16: invoke two functions in one expression When we combine functions with objects, we get methods: // When functions are assigned to the properties of an object, we call // them "methods". All JavaScript objects have methods: var a = []; // Create an empty array a.push(1,2,3); // The push() method adds elements to an array a.reverse(); // Another method: reverse the order of elements // We can define our own methods, too. The "this" keyword refers to the object // on which the method is defined: in this case, the points array from above. points.dist = function() { // Define a method to compute distance between points var p1 = this; // First element of array we're invoked on var p2 = this; // Second element of the "this" object var a = p2.x-p1.x; // Difference in X coordinates var b = p2.y-p1.y; // Difference in Y coordinates return Math.sqrt(a*a + // The Pythagorean theorem b*b); // Math.sqrt() computes the square root }; points.dist() // => 1.414: distance between our 2 points Now, as promised, here are some functions whose bodies demonstrate common Java- Script control structure statements: // JavaScript statements include conditionals and loops using the syntax // of C, C++, Java, and other languages. function abs(x) { // A function to compute the absolute value if (x >= 0) { // The if statement... return x; // executes this code if the comparison is true. } // This is the end of the if clause. else { // The optional else clause executes its code if return -x; // the comparison is false. } // Curly braces optional when 1 statement per clause. } // Note return statements nested inside if/else. function factorial(n) { // A function to compute factorials var product = 1; // Start with a product of 1 while(n > 1) { // Repeat statements in {} while expr in () is true product *= n; // Shortcut for product = product * n; n--; // Shortcut for n = n - 1 } // End of loop return product; // Return the product } factorial(4) // => 24: 1*4*3*2 function factorial2(n) { // Another version using a different loop var i, product = 1; // Start with 1 for(i=2; i 120: 1*2*3*4*5 JavaScript is an object-oriented language, but it is quite different than most. Chapter 9, Classes and Modules, covers object-oriented programming in JavaScript in detail, with lots of examples, and is one of the longest chapters in the book. Here is a very simple example that demonstrates how to define a JavaScript class to represent 2D geometric points. Objects that are instances of this class have a single method named r() that computes the distance of the point from the origin: // Define a constructor function to initialize a new Point object function Point(x,y) { // By convention, constructors start with capitals this.x = x; // this keyword is the new object being initialized this.y = y; // Store function arguments as object properties } // No return is necessary // Use a constructor function with the keyword "new" to create instances var p = new Point(1, 1); // The geometric point (1,1) // Define methods for Point objects by assigning them to the prototype // object associated with the constructor function. Point.prototype.r = function() { return Math.sqrt( // Return the square root of x² + y² this.x * this.x + // This is the Point object on which the method... this.y * this.y //...is invoked. ); }; // Now the Point object p (and all future Point objects) inherits the method r() p.r() // => 1.414... Chapter 9 is really the climax of Part I, and the chapters that follow wrap up some loose ends and bring our exploration of the core language to a close. Chapter 10, Pattern Matching with Regular Expressions, explains the regular expression grammar and dem- onstrates how to use these “regexps” for textual pattern matching. Chapter 11, Java- Script Subsets and Extensions, covers subsets and extensions of core JavaScript. Finally, before we plunge into client-side JavaScript in web browsers, Chapter 12, Server-Side JavaScript, introduces two ways to use JavaScript outside of web browsers. 1.2 Client-Side JavaScript Client-side JavaScript does not exhibit the nonlinear cross-reference problem nearly to the extent that the core language does, and it is possible to learn how to use JavaScript in web browsers in a fairly linear sequence. But you’re probably reading this book to learn client-side JavaScript, and Part II is a long way off, so this section is a quick sketch of basic client-side programming techniques, followed by an in-depth example. Chapter 13, JavaScript in Web Browsers, is the first chapter of Part II and it explains in detail how to put JavaScript to work in web browsers. The most important thing you’ll 8 | Chapter 1: Introduction to JavaScript learn in that chapter is that JavaScript code can be embedded within HTML files using the tag: This is a paragraph of HTML // And this is some client-side JavaScript code // literally embedded within the HTML file Here is more HTML. Chapter 14, The Window Object, explains techniques for scripting the web browser and covers some important global functions of client-side JavaScript. For example: function moveon() { // Display a modal dialog to ask the user a question var answer = confirm("Ready to move on?"); // If they clicked the "OK" button, make the browser load a new page if (answer) window.location = "http://google.com"; } // Run the function defined above 1 minute (60,000 milliseconds) from now. setTimeout(moveon, 60000); Note that the client-side example code shown in this section comes in longer snippets than the core language examples earlier in the chapter. These examples are not designed to be typed into a Firebug (or similar) console window. Instead you can embed them in an HTML file and try them out by loading them in your web browser. The code above, for instance, works as a stand-alone HTML file. Chapter 15, Scripting Documents, gets down to the real business of client-side Java- Script, scripting HTML document content. It shows you how to select particular HTML elements from within a document, how to set HTML attributes of those elements, how to alter the content of those elements, and how to add new elements to the document. This function demonstrates a number of these basic document searching and modifi- cation techniques: // Display a message in a special debugging output section of the document. // If the document does not contain such a section, create one. function debug(msg) { // Find the debugging section of the document, looking at HTML id attributes var log = document.getElementById("debuglog"); // If no element with the id "debuglog" exists, create one. if (!log) { log = document.createElement("div"); // Create a new element log.id = "debuglog"; // Set the HTML id attribute on it 1.2 Client-Side JavaScript | 9 log.innerHTML = "Debug Log"; // Define initial content document.body.appendChild(log); // Add it at end of document } // Now wrap the message in its own and append it to the log var pre = document.createElement("pre"); // Create a tag var text = document.createTextNode(msg); // Wrap msg in a text node pre.appendChild(text); // Add text to the log.appendChild(pre); // Add to the log } Chapter 15 shows how JavaScript can script the HTML elements that define web con- tent. Chapter 16, Scripting CSS, shows how you can use JavaScript with the CSS styles that define the presentation of that content. This is often done with the style or class attribute of HTML elements: function hide(e, reflow) { // Hide the element e by scripting its style if (reflow) { // If 2nd argument is true e.style.display = "none" // hide element and use its space } else { // Otherwise e.style.visibility = "hidden"; // make e invisible, but leave its space } } function highlight(e) { // Highlight e by setting a CSS class // Simply define or append to the HTML class attribute. // This assumes that a CSS stylesheet already defines the "hilite" class if (!e.className) e.className = "hilite"; else e.className += " hilite"; } JavaScript allows us to script the HTML content and CSS presentation of documents in web browsers, but it also allows us to define behavior for those documents with event handlers. An event handler is a JavaScript function that we register with the browser and the browser invokes when some specified type of event occurs. The event of interest might be a mouse click or a key press (or on a smart phone, it might be a two-finger gesture of some sort). Or an event handler might be triggered when the browser finishes loading a document, when the user resizes the browser window, or when the user enters data into an HTML form element. Chapter 17, Handling Events, explains how you can define and register event handlers and how the browser invokes them when events occur. The simplest way to define event handlers is with HTML attributes that begin with “on”. The “onclick” handler is a particularly useful one when you’re writing simple test programs. Suppose that you had typed in the debug() and hide() functions from above and saved them in files named debug.js and hide.js. You could write a simple HTML test file using elements with onclick event handler attributes: Hello Hide1 10 | Chapter 1: Introduction to JavaScript Hide2 World Here is some more client-side JavaScript code that uses events. It registers an event handler for the very important “load” event, and it also demonstrates a more sophis- ticated way of registering event handler functions for “click” events: // The "load" event occurs when a document is fully loaded. Usually we // need to wait for this event before we start running our JavaScript code. window.onload = function() { // Run this function when the document loads // Find all tags in the document var images = document.getElementsByTagName("img"); // Loop through them, adding an event handler for "click" events to each // so that clicking on the image hides it. for(var i = 0; i < images.length; i++) { var image = images[i]; if (image.addEventListener) // Another way to register a handler image.addEventListener("click", hide, false); else // For compatibility with IE8 and before image.attachEvent("onclick", hide); } // This is the event handler function registered above function hide(event) { event.target.style.visibility = "hidden"; } }; Chapters 15, 16, and 17 explain how you can use JavaScript to script the content (HTML), presentation (CSS), and behavior (event handling) of web pages. The APIs described in those chapters are somewhat complex and, until recently, riddled with browser incompatibilities. For these reasons, many or most client-side JavaScript pro- grammers choose to use a client-side library or framework to simplify their basic pro- gramming tasks. The most popular such library is jQuery, the subject of Chapter 19, The jQuery Library. jQuery defines a clever and easy-to-use API for scripting document content, presentation, and behavior. It has been thoroughly tested and works in all major browsers, including old ones like IE6. jQuery code is easy to identify because it makes frequent use of a function named $(). Here is what the debug() function used previously looks like when rewritten to use jQuery: function debug(msg) { var log = $("#debuglog"); // Find the element to display msg in. if (log.length == 0) { // If it doesn't exist yet, create it... log = $("Debug Log"); log.appendTo(document.body); // and insert it at the end of the body. } log.append($("").text(msg)); // Wrap msg in and append to log. } The four chapters of Part II described so far have all really been about web pages. Four more chapters shift gears to focus on web applications. These chapters are not about using web browsers to display documents with scriptable content, presentation, and 1.2 Client-Side JavaScript | 11 behavior. Instead, they’re about using web browsers as application platforms, and they describe the APIs that modern browsers provide to support sophisticated client-side web apps. Chapter 18, Scripted HTTP, explains how to make scripted HTTP requests with JavaScript—a kind of networking API. Chapter 20, Client-Side Storage, describes mechanisms for storing data—and even entire applications—on the client side for use in future browsing sessions. Chapter 21, Scripted Media and Graphics, covers a client- side API for drawing arbitrary graphics in an HTML tag. And, finally, Chap- ter 22, HTML5 APIs, covers an assortment of new web app APIs specified by or affiliated with HTML5. Networking, storage, graphics: these are OS-type services being provided by the web browser, defining a new cross-platform application environment. If you are targeting browsers that support these new APIs, it is an exciting time to be a client-side JavaScript programmer. There are no code samples from these final four chapters here, but the extended example below uses some of these new APIs. 1.2.1 Example: A JavaScript Loan Calculator This chapter ends with an extended example that puts many of these techniques to- gether and shows what real-world client-side JavaScript (plus HTML and CSS) pro- grams look like. Example 1-1 lists the code for the simple loan payment calculator application pictured in Figure 1-2. Figure 1-2. A loan calculator web application It is worth reading through Example 1-1 carefully. You shouldn’t expect to understand everything, but the code is heavily commented and you should be able to at least get 12 | Chapter 1: Introduction to JavaScript the big-picture view of how it works. The example demonstrates a number of core JavaScript language features, and also demonstrates important client-side JavaScript techniques: How to find elements in a document. How to get user input from form input elements. How to set the HTML content of document elements. How to store data in the browser. How to make scripted HTTP requests. How to draw graphics with the element. Example 1-1. A loan calculator in JavaScript JavaScript Loan Calculator.output { font-weight: bold; } #payment { text-decoration: underline; } #graph { border: solid black 1px; } th, td { vertical-align: top; } Enter Loan Data: Loan Balance, Cumulative Equity, and Interest Payments Amount of the loan ($): Annual interest (%): Repayment period (years): Zipcode (to find lenders): Approximate Payments: Calculate Monthly payment: $ Total payment: $ 1.2 Client-Side JavaScript | 13 Total interest: $ Sponsors: Apply for your loan with one of these fine lenders: "use strict"; // Use ECMAScript 5 strict mode in browsers that support it function calculate() { // Look up the input and output elements in the document var amount = document.getElementById("amount"); var apr = document.getElementById("apr"); var years = document.getElementById("years"); var zipcode = document.getElementById("zipcode"); var payment = document.getElementById("payment"); var total = document.getElementById("total"); var totalinterest = document.getElementById("totalinterest"); // Get the user's input from the input elements. Assume it is all valid. // Convert interest from a percentage to a decimal, and convert from // an annual rate to a monthly rate. Convert payment period in years // to the number of monthly payments. var principal = parseFloat(amount.value); var interest = parseFloat(apr.value) / 100 / 12; var payments = parseFloat(years.value) * 12; // Now compute the monthly payment figure. var x = Math.pow(1 + interest, payments); // Math.pow() computes powers var monthly = (principal*x*interest)/(x-1); // If the result is a finite number, the user's input was good and // we have meaningful results to display if (isFinite(monthly)) { // Fill in the output fields, rounding to 2 decimal places payment.innerHTML = monthly.toFixed(2); total.innerHTML = (monthly * payments).toFixed(2); totalinterest.innerHTML = ((monthly*payments)-principal).toFixed(2); // Save the user's input so we can restore it the next time they visit save(amount.value, apr.value, years.value, zipcode.value); // Advertise: find and display local lenders, but ignore network errors try { // Catch any errors that occur within these curly braces getLenders(amount.value, apr.value, years.value, zipcode.value); } 14 | Chapter 1: Introduction to JavaScript catch(e) { } // Finally, chart loan balance, and interest and equity payments chart(principal, interest, monthly, payments); } else { // Result was Not-a-Number or infinite, which means the input was // incomplete or invalid. Clear any previously displayed output. payment.innerHTML = ""; // Erase the content of these elements total.innerHTML = "" totalinterest.innerHTML = ""; chart(); // With no arguments, clears the chart } } // Save the user's input as properties of the localStorage object. Those // properties will still be there when the user visits in the future // This storage feature will not work in some browsers (Firefox, e.g.) if you // run the example from a local file:// URL. It does work over HTTP, however. function save(amount, apr, years, zipcode) { if (window.localStorage) { // Only do this if the browser supports it localStorage.loan_amount = amount; localStorage.loan_apr = apr; localStorage.loan_years = years; localStorage.loan_zipcode = zipcode; } } // Automatically attempt to restore input fields when the document first loads. window.onload = function() { // If the browser supports localStorage and we have some stored data if (window.localStorage && localStorage.loan_amount) { document.getElementById("amount").value = localStorage.loan_amount; document.getElementById("apr").value = localStorage.loan_apr; document.getElementById("years").value = localStorage.loan_years; document.getElementById("zipcode").value = localStorage.loan_zipcode; } }; // Pass the user's input to a server-side script which can (in theory) return // a list of links to local lenders interested in making loans. This example // does not actually include a working implementation of such a lender-finding // service. But if the service existed, this function would work with it. function getLenders(amount, apr, years, zipcode) { // If the browser does not support the XMLHttpRequest object, do nothing if (!window.XMLHttpRequest) return; // Find the element to display the list of lenders in var ad = document.getElementById("lenders"); if (!ad) return; // Quit if no spot for output 1.2 Client-Side JavaScript | 15 // Encode the user's input as query parameters in a URL var url = "getLenders.php" + // Service url plus "?amt=" + encodeURIComponent(amount) + // user data in query string "&apr=" + encodeURIComponent(apr) + "&yrs=" + encodeURIComponent(years) + "&zip=" + encodeURIComponent(zipcode); // Fetch the contents of that URL using the XMLHttpRequest object var req = new XMLHttpRequest(); // Begin a new request req.open("GET", url); // An HTTP GET request for the url req.send(null); // Send the request with no body // Before returning, register an event handler function that will be called // at some later time when the HTTP server's response arrives. This kind of // asynchronous programming is very common in client-side JavaScript. req.onreadystatechange = function() { if (req.readyState == 4 && req.status == 200) { // If we get here, we got a complete valid HTTP response var response = req.responseText; // HTTP response as a string var lenders = JSON.parse(response); // Parse it to a JS array // Convert the array of lender objects to a string of HTML var list = ""; for(var i = 0; i < lenders.length; i++) { list += "" + lenders[i].name + ""; } // Display the HTML in the element from above. ad.innerHTML = "" + list + ""; } } } // Chart monthly loan balance, interest and equity in an HTML element. // If called with no arguments then just erase any previously drawn chart. function chart(principal, interest, monthly, payments) { var graph = document.getElementById("graph"); // Get the tag graph.width = graph.width; // Magic to clear and reset the canvas element // If we're called with no arguments, or if this browser does not support // graphics in a element, then just return now. if (arguments.length == 0 || !graph.getContext) return; // Get the "context" object for the that defines the drawing API var g = graph.getContext("2d"); // All drawing is done with this object var width = graph.width, height = graph.height; // Get canvas size // These functions convert payment numbers and dollar amounts to pixels function paymentToX(n) { return n * width/payments; } function amountToY(a) { return height-(a * height/(monthly*payments*1.05));} // Payments are a straight line from (0,0) to (payments, monthly*payments) g.moveTo(paymentToX(0), amountToY(0)); // Start at lower left g.lineTo(paymentToX(payments), // Draw to upper right amountToY(monthly*payments)); 16 | Chapter 1: Introduction to JavaScript g.lineTo(paymentToX(payments), amountToY(0)); // Down to lower right g.closePath(); // And back to start g.fillStyle = "#f88"; // Light red g.fill(); // Fill the triangle g.font = "bold 12px sans-serif"; // Define a font g.fillText("Total Interest Payments", 20,20); // Draw text in legend // Cumulative equity is non-linear and trickier to chart var equity = 0; g.beginPath(); // Begin a new shape g.moveTo(paymentToX(0), amountToY(0)); // starting at lower-left for(var p = 1; p "hello": the original string has not changed Primitives are also compared by value: two values are the same only if they have the same value. This sounds circular for numbers, booleans, null, and undefined: there is no other way that they could be compared. Again, however, it is not so obvious for strings. If two distinct string values are compared, JavaScript treats them as equal if, and only if, they have the same length and if the character at each index is the same. Objects are different than primitives. First, they are mutable—their values can change: var o = { x:1 }; // Start with an object o.x = 2; // Mutate it by changing the value of a property o.y = 3; // Mutate it again by adding a new property var a = [1,2,3] // Arrays are also mutable a = 0; // Change the value of an array element a = 4; // Add a new array element 44 | Chapter 3: Types, Values, and Variables Objects are not compared by value: two objects are not equal even if they have the same Core JavaScript properties and values. And two arrays are not equal even if they have the same elements in the same order: var o = {x:1}, p = {x:1}; // Two objects with the same properties o === p // => false: distinct objects are never equal var a = [], b = []; // Two distinct, empty arrays a === b // => false: distinct arrays are never equal Objects are sometimes called reference types to distinguish them from JavaScript’s primitive types. Using this terminology, object values are references, and we say that objects are compared by reference: two object values are the same if and only if they refer to the same underlying object. var a = []; // The variable a refers to an empty array. var b = a; // Now b refers to the same array. b = 1; // Mutate the array referred to by variable b. a // => 1: the change is also visible through variable a. a === b // => true: a and b refer to the same object, so they are equal. As you can see from the code above, assigning an object (or array) to a variable simply assigns the reference: it does not create a new copy of the object. If you want to make a new copy of an object or array, you must explicitly copy the properties of the object or the elements of the array. This example demonstrates using a for loop (§5.5.3): var a = ['a','b','c']; // An array we want to copy var b = []; // A distinct array we'll copy into for(var i = 0; i < a.length; i++) { // For each index of a[] b[i] = a[i]; // Copy an element of a into b } Similarly, if we want to compare two distinct objects or arrays, we must compare their properties or elements. This code defines a function to compare two arrays: function equalArrays(a,b) { if (a.length != b.length) return false; // Different-size arrays not equal for(var i = 0; i < a.length; i++) // Loop through all elements if (a[i] !== b[i]) return false; // If any differ, arrays not equal return true; // Otherwise they are equal } 3.8 Type Conversions JavaScript is very flexible about the types of values it requires. We’ve seen this for booleans: when JavaScript expects a boolean value, you may supply a value of any type, and JavaScript will convert it as needed. Some values (“truthy” values) convert to true and others (“falsy” values) convert to false. The same is true for other types: if JavaScript wants a string, it will convert whatever value you give it to a string. If Java- Script wants a number, it will try to convert the value you give it to a number (or to NaN if it cannot perform a meaningful conversion). Some examples: 10 + " objects" // => "10 objects". Number 10 converts to a string "7" * "4" // => 28: both strings convert to numbers 3.8 Type Conversions | 45 var n = 1 - "x"; // => NaN: string "x" can't convert to a number n + " objects" // => "NaN objects": NaN converts to string "NaN" Table 3-2 summarizes how values convert from one type to another in JavaScript. Bold entries in the table highlight conversions that you may find surprising. Empty cells indicate that no conversion is necessary and none is performed. Table 3-2. JavaScript type conversions Value Converted to: String Number Boolean Object undefined "undefined" NaN false throws TypeError null "null" 0 false throws TypeError true "true" 1 new Boolean(true) false "false" 0 new Boolean(false) "" (empty string) 0 false new String("") "1.2" (nonempty, numeric) 1.2 true new String("1.2") "one" (nonempty, non-numeric) NaN true new String("one") 0 "0" false new Number(0) -0 "0" false new Number(-0) NaN "NaN" false new Number(NaN) Infinity "Infinity" true new Number(Infinity) -Infinity "-Infinity" true new Number(-Infinity) 1 (finite, non-zero) "1" true new Number(1) {} (any object) see §3.8.3 see §3.8.3 true [] (empty array) "" 0 true (1 numeric elt) "9" 9 true ['a'] (any other array) use join() method NaN true function(){} (any function) see §3.8.3 NaN true The primitive-to-primitive conversions shown in the table are relatively straightforward. Conversion to boolean was already discussed in §3.3. Conversion to strings is well-defined for all primitive values. Conversion to numbers is just a little trickier. Strings that can be parsed as numbers convert to those numbers. Leading and trailing spaces are allowed, but any leading or trailing nonspace characters that are not part of a numeric literal cause the string-to-number conversion to produce NaN. Some numeric conversions may seem surprising: true converts to 1, and false and the empty string "" convert to 0. Primitive-to-object conversions are straightforward: primitive values convert to their wrapper object (§3.6) as if by calling the String(), Number(), or Boolean() constructor. 46 | Chapter 3: Types, Values, and Variables The exceptions are null and undefined: any attempt to use these values where an object Core JavaScript is expected raises a TypeError exception rather than performing a conversion. Object-to-primitive conversion is somewhat more complicated, and it is the subject of §3.8.3. 3.8.1 Conversions and Equality Because JavaScript can convert values flexibly, its == equality operator is also flexible with its notion of equality. All of the following comparisons are true, for example: null == undefined // These two values are treated as equal. "0" == 0 // String converts to a number before comparing. 0 == false // Boolean converts to number before comparing. "0" == false // Both operands convert to numbers before comparing. §4.9.1 explains exactly what conversions are performed by the == operator in order to determine whether two values should be considered equal, and it also describes the strict equality operator === that does not perform conversions when testing for equality. Keep in mind that convertibility of one value to another does not imply equality of those two values. If undefined is used where a boolean value is expected, for example, it will convert to false. But this does not mean that undefined == false. JavaScript operators and statements expect values of various types, and perform conversions to those types. The if statement converts undefined to false, but the == operator never attempts to convert its operands to booleans. 3.8.2 Explicit Conversions Although JavaScript performs many type conversions automatically, you may some- times need to perform an explicit conversion, or you may prefer to make the conversions explicit to keep your code clearer. The simplest way to perform an explicit type conversion is to use the Boolean(), Number(), String(), or Object() functions. We’ve already seen these functions as con- structors for wrapper objects (in §3.6). When invoked without the new operator, how- ever, they work as conversion functions and perform the conversions summarized in Table 3-2: Number("3") // => 3 String(false) // => "false" Or use false.toString() Boolean([]) // => true Object(3) // => new Number(3) Note that any value other than null or undefined has a toString() method and the result of this method is usually the same as that returned by the String() function. Also note that Table 3-2 shows a TypeError if you attempt to convert null or undefined to an object. The Object() function does not throw an exception in this case: instead it simply returns a newly created empty object. 3.8 Type Conversions | 47 Certain JavaScript operators perform implicit type conversions, and are sometimes used for the purposes of type conversion. If one operand of the + operator is a string, it converts the other one to a string. The unary + operator converts its operand to a number. And the unary ! operator converts its operand to a boolean and negates it. These facts lead to the following type conversion idioms that you may see in some code: x + "" // Same as String(x) +x // Same as Number(x). You may also see x-0 !!x // Same as Boolean(x). Note double ! Formatting and parsing numbers are common tasks in computer programs and Java- Script has specialized functions and methods that provide more precise control over number-to-string and string-to-number conversions. The toString() method defined by the Number class accepts an optional argument that specifies a radix, or base, for the conversion. If you do not specify the argument, the conversion is done in base 10. However, you can also convert numbers in other bases (between 2 and 36). For example: var n = 17; binary_string = n.toString(2); // Evaluates to "10001" octal_string = "0" + n.toString(8); // Evaluates to "021" hex_string = "0x" + n.toString(16); // Evaluates to "0x11" When working with financial or scientific data, you may want to convert numbers to strings in ways that give you control over the number of decimal places or the number of significant digits in the output, or you may want to control whether exponential notation is used. The Number class defines three methods for these kinds of number- to-string conversions. toFixed() converts a number to a string with a specified number of digits after the decimal point. It never uses exponential notation. toExponential() converts a number to a string using exponential notation, with one digit before the decimal point and a specified number of digits after the decimal point (which means that the number of significant digits is one larger than the value you specify). toPreci sion() converts a number to a string with the number of significant digits you specify. It uses exponential notation if the number of significant digits is not large enough to display the entire integer portion of the number. Note that all three methods round the trailing digits or pad with zeros as appropriate. Consider the following examples: var n = 123456.789; n.toFixed(0); // "123457" n.toFixed(2); // "123456.79" n.toFixed(5); // "123456.78900" n.toExponential(1); // "1.2e+5" n.toExponential(3); // "1.235e+5" n.toPrecision(4); // "1.235e+5" n.toPrecision(7); // "123456.8" n.toPrecision(10); // "123456.7890" If you pass a string to the Number() conversion function, it attempts to parse that string as an integer or floating-point literal. That function only works for base-10 integers, and does not allow trailing characters that are not part of the literal. The parseInt() 48 | Chapter 3: Types, Values, and Variables and parseFloat() functions (these are global functions, not methods of any class) are Core JavaScript more flexible. parseInt() parses only integers, while parseFloat() parses both integers and floating-point numbers. If a string begins with “0x” or “0X”, parseInt() interprets it as a hexadecimal number.2 Both parseInt() and parseFloat() skip leading white- space, parse as many numeric characters as they can, and ignore anything that follows. If the first nonspace character is not part of a valid numeric literal, they return NaN: parseInt("3 blind mice") // => 3 parseFloat(" 3.14 meters") // => 3.14 parseInt("-12.34") // => -12 parseInt("0xFF") // => 255 parseInt("0xff") // => 255 parseInt("-0XFF") // => -255 parseFloat(".1") // => 0.1 parseInt("0.1") // => 0 parseInt(".1") // => NaN: integers can't start with "." parseFloat("$72.47"); // => NaN: numbers can't start with "$" parseInt() accepts an optional second argument specifying the radix (base) of the number to be parsed. Legal values are between 2 and 36. For example: parseInt("11", 2); // => 3 (1*2 + 1) parseInt("ff", 16); // => 255 (15*16 + 15) parseInt("zz", 36); // => 1295 (35*36 + 35) parseInt("077", 8); // => 63 (7*8 + 7) parseInt("077", 10); // => 77 (7*10 + 7) 3.8.3 Object to Primitive Conversions Object-to-boolean conversions are trivial: all objects (including arrays and functions) convert to true. This is so even for wrapper objects: new Boolean(false) is an object rather than a primitive value, and so it converts to true. Object-to-string and object-to-number conversions are performed by invoking a meth- od of the object to be converted. This is complicated by the fact that JavaScript objects have two different methods that perform conversions, and it is also complicated by some special cases described below. Note that the string and number conversion rules described here apply only to native objects. Host objects (defined by web browsers, for example) can convert to numbers and strings according to their own algorithms. All objects inherit two conversion methods. The first is called toString(), and its job is to return a string representation of the object. The default toString() method does not return a very interesting value (though we’ll find it useful in Example 6-4): ({x:1, y:2}).toString() // => "[object Object]" 2. In ECMAScript 3, parseInt() may parse a string that begins with “0” (but not “0x” or “0X”) as an octal number or as a decimal number. Because the behavior is unspecified, you should never use parseInt() to parse numbers with leading zeros, unless you explicitly specify the radix to be used! In ECMAScript 5, parseInt() only parses octal numbers if you explicitly pass 8 as the second argument. 3.8 Type Conversions | 49 Many classes define more specific versions of the toString() method. The toString() method of the Array class, for example, converts each array element to a string and joins the resulting strings together with commas in between. The toString() method of the Function class returns an implementation-defined representation of a function. In practice, implementations usually convert user-defined functions to strings of Java- Script source code. The Date class defines a toString() method that returns a human- readable (and JavaScript-parsable) date and time string. The RegExp class defines a toString() method that converts RegExp objects to a string that looks like a RegExp literal: [1,2,3].toString() // => "1,2,3" (function(x) { f(x); }).toString() // => "function(x) {\n f(x);\n}" /\d+/g.toString() // => "/\\d+/g" new Date(2010,0,1).toString() // => "Fri Jan 01 2010 00:00:00 GMT-0800 (PST)" The other object conversion function is called valueOf(). The job of this method is less well-defined: it is supposed to convert an object to a primitive value that represents the object, if any such primitive value exists. Objects are compound values, and most ob- jects cannot really be represented by a single primitive value, so the default valueOf() method simply returns the object itself rather than returning a primitive. Wrapper classes define valueOf() methods that return the wrapped primitive value. Arrays, functions, and regular expressions simply inherit the default method. Calling valueOf() for instances of these types simply returns the object itself. The Date class defines a valueOf() method that returns the date in its internal representation: the number of milliseconds since January 1, 1970: var d = new Date(2010, 0, 1); // January 1st, 2010, (Pacific time) d.valueOf() // => 1262332800000 With the toString() and valueOf() methods explained, we can now cover object-to- string and object-to-number conversions. Do note, however, that there are some special cases in which JavaScript performs a different object-to-primitive conversion. These special cases are covered at the end of this section. To convert an object to a string, JavaScript takes these steps: If the object has a toString() method, JavaScript calls it. If it returns a primitive value, JavaScript converts that value to a string (if it is not already a string) and returns the result of that conversion. Note that primitive-to-string conversions are all well-defined in Table 3-2. If the object has no toString() method, or if that method does not return a primitive value, then JavaScript looks for a valueOf() method. If the method exists, Java- Script calls it. If the return value is a primitive, JavaScript converts that value to a string (if it is not already) and returns the converted value. Otherwise, JavaScript cannot obtain a primitive value from either toString() or valueOf(), so it throws a TypeError. 50 | Chapter 3: Types, Values, and Variables To convert an object to a number, JavaScript does the same thing, but it tries the Core JavaScript valueOf() method first: If the object has a valueOf() method that returns a primitive value, JavaScript con- verts (if necessary) that primitive value to a number and returns the result. Otherwise, if the object has a toString() method that returns a primitive value, JavaScript converts and returns the value. Otherwise, JavaScript throws a TypeError. The details of this object-to-number conversion explain why an empty array converts to the number 0 and why an array with a single element may also convert to a number. Arrays inherit the default valueOf() method that returns an object rather than a prim- itive value, so array-to-number conversion relies on the toString() method. Empty arrays convert to the empty string. And the empty string converts to the number 0. An array with a single element converts to the same string that that one element does. If an array contains a single number, that number is converted to a string, and then back to a number. The + operator in JavaScript performs numeric addition and string concatenation. If either of its operands is an object, JavaScript converts the object using a special object- to-primitive conversion rather than the object-to-number conversion used by the other arithmetic operators. The == equality operator is similar. If asked to compare an object with a primitive value, it converts the object using the object-to-primitive conversion. The object-to-primitive conversion used by + and == includes a special case for Date objects. The Date class is the only predefined core JavaScript type that defines mean- ingful conversions to both strings and numbers. The object-to-primitive conversion is basically an object-to-number conversion (valueof() first) for all objects that are not dates, and an object-to-string conversion (toString() first) for Date objects. The con- version is not exactly the same as those explained above, however: the primitive value returned by valueOf() or toString() is used directly without being forced to a number or string. The < operator and the other relational operators perform object-to-primitive conver- sions like == does, but without the special case for Date objects: any object is converted by trying valueOf() first and then toString(). Whatever primitive value is obtained is used directly, without being further converted to a number or string. +, ==, != and the relational operators are the only ones that perform this special kind of string-to-primitive conversions. Other operators convert more explicitly to a specified type and do not have any special case for Date objects. The - operator, for example, converts its operands to numbers. The following code demonstrates the behavior of +, -, ==, and > with Date objects: var now = new Date(); // Create a Date object typeof (now + 1) // => "string": + converts dates to strings typeof (now - 1) // => "number": - uses object-to-number conversion 3.8 Type Conversions | 51 now == now.toString() // => true: implicit and explicit string conversions now > (now -1) // => t