Repository: getify/You-Dont-Know-JS Branch: 2nd-ed Commit: 044120ef5556 Files: 57 Total size: 921.9 KB Directory structure: gitextract_n5rrk2u_/ ├── .editorconfig ├── .github/ │ └── ISSUE_TEMPLATE/ │ ├── content-question.md │ ├── foreign-translation-request.md │ ├── report-technical-mistake.md │ └── textual-grammar-typo.md ├── CONTRIBUTING.md ├── LICENSE.txt ├── PULL_REQUEST_TEMPLATE.md ├── README.md ├── es-next-beyond/ │ ├── README.md │ ├── ch1.md │ ├── foreword.md │ └── toc.md ├── get-started/ │ ├── README.md │ ├── apA.md │ ├── apB.md │ ├── ch1.md │ ├── ch2.md │ ├── ch3.md │ ├── ch4.md │ ├── foreword.md │ └── toc.md ├── objects-classes/ │ ├── README.md │ ├── ch1.md │ ├── ch2.md │ ├── ch3.md │ ├── ch4.md │ ├── ch5.md │ ├── foreword.md │ ├── thanks.md │ └── toc.md ├── preface.md ├── scope-closures/ │ ├── README.md │ ├── apA.md │ ├── apB.md │ ├── ch1.md │ ├── ch2.md │ ├── ch3.md │ ├── ch4.md │ ├── ch5.md │ ├── ch6.md │ ├── ch7.md │ ├── ch8.md │ ├── foreword.md │ └── toc.md ├── sync-async/ │ ├── README.md │ ├── ch1.md │ ├── foreword.md │ └── toc.md └── types-grammar/ ├── README.md ├── ch1.md ├── ch2.md ├── ch3.md ├── ch4.md ├── foreword.md ├── thanks.md └── toc.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: .editorconfig ================================================ root = true [*] charset = utf-8 end_of_line = lf insert_final_newline = true indent_style = tab indent_size = 4 [*.md] indent_style = space indent_size = 4 ================================================ FILE: .github/ISSUE_TEMPLATE/content-question.md ================================================ --- name: Content Question about: Ask a question about something you read in the books? labels: --- **We are not currently accepting any more corrections to the book content. The 2nd edition books have all been published and finalized. Thank you for your interest and support.** ================================================ FILE: .github/ISSUE_TEMPLATE/foreign-translation-request.md ================================================ --- name: Foreign Translation Request about: Want to request a translation into a foreign language? labels: --- Foreign translations are appreciated, but only for the 3 second edition books. **I will not be accepting any new foreign translations for previous editions.** ---- Please check these issues first: * https://github.com/getify/You-Dont-Know-JS/issues?utf8=%E2%9C%93&q=label%3A%22foreign+language+translations%22+ * https://github.com/getify/You-Dont-Know-JS/issues/9 * https://github.com/getify/You-Dont-Know-JS/issues/900 * https://github.com/getify/You-Dont-Know-JS/issues/1378 To summarize, the steps for a foreign language translation are: 1. Fork this repo 2. Make your own translation entirely in your fork, preferably of all six books, but at a minimum of one whole book 3. File an issue asking for a branch to be made on our main repo, named for that [language's ISO code](http://www.lingoes.net/en/translator/langcode.htm) 4. Once the branch is created, you can PR to merge your translated work in 5. Once the merge is complete, I will promote you to a repository maintainer so you can manage any further translation maintenance work on your own branch of this repo ================================================ FILE: .github/ISSUE_TEMPLATE/report-technical-mistake.md ================================================ --- name: Report Technical Mistake about: Help us fix a mistake in the code. labels: --- **We are not currently accepting any more corrections to the book content. The 2nd edition books have all been published and finalized. Thank you for your interest and support.** ================================================ FILE: .github/ISSUE_TEMPLATE/textual-grammar-typo.md ================================================ --- name: Textual/Grammar Typo about: Help us correct a spelling or grammar error in the text. labels: --- **We are not currently accepting any more corrections to the book content. The 2nd edition books have all been published and finalized. Thank you for your interest and support.** ================================================ FILE: CONTRIBUTING.md ================================================ # Contributing This book series is now complete, **so we are no longer open to contributions.** ## Translations If you're wanting to translate these books, please keep in mind that any such translations **must be posted to this github repository, free and open, and not monetized.** Foreign translations are appreciated, but only for the 3 second edition books. **We will not be accepting any new foreign translations for previous editions.** ---- Please check these issues first: * https://github.com/getify/You-Dont-Know-JS/issues?utf8=%E2%9C%93&q=label%3A%22foreign+language+translations%22+ * https://github.com/getify/You-Dont-Know-JS/issues/9 * https://github.com/getify/You-Dont-Know-JS/issues/900 * https://github.com/getify/You-Dont-Know-JS/issues/1378 To summarize, the steps for a foreign language translation are: 1. Fork this repo 2. Make your own translation entirely in your fork, preferably of all six books, but at a minimum of one whole book 3. File an issue asking for a branch to be made on our main repo, named for that [language's ISO code](http://www.lingoes.net/en/translator/langcode.htm) 4. Once the branch is created, you can PR to merge your translated work in 5. Once the merge is complete, I will promote you to a repository maintainer so you can manage any further translation maintenance work on your own branch of this repo ## Reading Experience (Chapter/Section links, etc) I understand that reading one long .md file, with no relative cross links to other sections/etc, is not the preferred reading experience for most of you. As such, it's totally reasonable to want to file an issue/PR to add those kinds of features. This topic has been brought up many times, and I've considered it. But we are not accepting such changes. The main purpose of my book repos is to track and manage the content for the purposes of publication (paid-for ebooks and print books). I do this in the open because I also care about providing free and early access to the content, to make sure there is no paywall barrier to learning. As such, this repo **is not optimized for your reading experience.** The intended **best reading experience** are the published books (either ebook or print), so I encourage you to purchase them for that purpose. ## Editions The current (and final) edition of the books is the 2nd edition. We **are not accepting any contributions** for these books, no exceptions. ## Typos? We're not worried about typo fixes anymore. The books are done and published. ## Search First! Seriously, no more need for contributions. If you have a question, please search first before asking. It's probably already been asked and answered before, as these books have been around for 12 years now. ================================================ FILE: LICENSE.txt ================================================ Attribution-NonCommercial-NoDerivatives 4.0 International ======================================================================= Creative Commons Corporation ("Creative Commons") is not a law firm and does not provide legal services or legal advice. Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. Creative Commons makes its licenses and related information available on an "as-is" basis. Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or any related information. Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible. Using Creative Commons Public Licenses Creative Commons public licenses provide a standard set of terms and conditions that creators and other rights holders may use to share original works of authorship and other material subject to copyright and certain other rights specified in the public license below. The following considerations are for informational purposes only, are not exhaustive, and do not form part of our licenses. Considerations for licensors: Our public licenses are intended for use by those authorized to give the public permission to use material in ways otherwise restricted by copyright and certain other rights. Our licenses are irrevocable. Licensors should read and understand the terms and conditions of the license they choose before applying it. Licensors should also secure all rights necessary before applying our licenses so that the public can reuse the material as expected. Licensors should clearly mark any material not subject to the license. This includes other CC- licensed material, or material used under an exception or limitation to copyright. More considerations for licensors: wiki.creativecommons.org/Considerations_for_licensors Considerations for the public: By using one of our public licenses, a licensor grants the public permission to use the licensed material under specified terms and conditions. If the licensor's permission is not necessary for any reason--for example, because of any applicable exception or limitation to copyright--then that use is not regulated by the license. Our licenses grant only permissions under copyright and certain other rights that a licensor has authority to grant. Use of the licensed material may still be restricted for other reasons, including because others have copyright or other rights in the material. A licensor may make special requests, such as asking that all changes be marked or described. Although not required by our licenses, you are encouraged to respect those requests where reasonable. More_considerations for the public: wiki.creativecommons.org/Considerations_for_licensees ======================================================================= Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International Public License By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. Section 1 -- Definitions. a. Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. b. Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. c. Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. d. Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. e. Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License. f. Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. g. Licensor means the individual(s) or entity(ies) granting rights under this Public License. h. NonCommercial means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this Public License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange. i. Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. j. Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. k. You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. Section 2 -- Scope. a. License grant. 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: a. reproduce and Share the Licensed Material, in whole or in part, for NonCommercial purposes only; and b. produce and reproduce, but not Share, Adapted Material for NonCommercial purposes only. 2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. 3. Term. The term of this Public License is specified in Section 6(a). 4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a) (4) never produces Adapted Material. 5. Downstream recipients. a. Offer from the Licensor -- Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. b. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. 6. No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). b. Other rights. 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. 2. Patent and trademark rights are not licensed under this Public License. 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties, including when the Licensed Material is used other than for NonCommercial purposes. Section 3 -- License Conditions. Your exercise of the Licensed Rights is expressly made subject to the following conditions. a. Attribution. 1. If You Share the Licensed Material, You must: a. retain the following if it is supplied by the Licensor with the Licensed Material: i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); ii. a copyright notice; iii. a notice that refers to this Public License; iv. a notice that refers to the disclaimer of warranties; v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; b. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and c. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. For the avoidance of doubt, You do not have permission under this Public License to Share Adapted Material. 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. Section 4 -- Sui Generis Database Rights. Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database for NonCommercial purposes only and provided You do not Share Adapted Material; b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material; and c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights. Section 5 -- Disclaimer of Warranties and Limitation of Liability. a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. Section 6 -- Term and Termination. a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or 2. upon express reinstatement by the Licensor. For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. Section 7 -- Other Terms and Conditions. a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. Section 8 -- Interpretation. a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. ======================================================================= Creative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the “Licensor.” The text of the Creative Commons public licenses is dedicated to the public domain under the CC0 Public Domain Dedication. Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at creativecommons.org/policies, Creative Commons does not authorize the use of the trademark "Creative Commons" or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses. Creative Commons may be contacted at creativecommons.org. ================================================ FILE: PULL_REQUEST_TEMPLATE.md ================================================ **Yes, I promise I've read the [Contributions Guidelines](https://github.com/getify/You-Dont-Know-JS/blob/master/CONTRIBUTING.md)** (please feel free to remove this line). Specifically quoting these guidelines regarding typos: > Typos? > > Please don't worry about minor text typos. These will almost certainly be caught during the editing process. > > If you're going to submit a PR for typo fixes, please be measured in doing so by collecting several small changes into a single PR (in separate commits). Or, **just don't even worry about them for now,** because we'll get to them later. I promise. ---- **Please type "I already searched for this issue":** **Edition:** (pull requests not accepted for previous editions) **Book Title:** **Chapter:** **Section Title:** **Topic:** ================================================ FILE: README.md ================================================ # You Don't Know JS Yet (book series) - 2nd Edition This is a series of books diving deep into the core mechanisms of the JavaScript language. This is the **second edition** of the book series:       **To read more about the motivations and perspective behind this book series, check out the [Preface](preface.md).** If you're looking for the previous **first edition** books, [they can be found here](https://github.com/getify/You-Dont-Know-JS/blob/1st-ed/README.md). ## Titles I recommend reading the **second edition** books in this order: * [Get Started](get-started/README.md) | [Buy on Leanpub](https://leanpub.com/ydkjsy-get-started) | [Buy on Amazon](https://www.amazon.com/dp/B084BNMN7T) * [Scope & Closures](scope-closures/README.md) | [Buy on Leanpub](https://leanpub.com/ydkjsy-scope-closures) | [Buy on Amazon](https://www.amazon.com/dp/B08634PZ3N) * "The Unbooks" (ebook) | [Buy on Leanpub](https://leanpub.com/ydkjsy-unbooks) | [Buy on Amazon](https://www.amazon.com/dp/B0F7H1DN5S) - [Objects & Classes](objects-classes/README.md) (draft stable) - [Types & Grammar](types-grammar/README.md) (rough draft) - ~~Sync & Async (canceled)~~ - ~~ES.Next & Beyond (canceled)~~ If you're looking for the previous **first edition** books, [they can be found here](https://github.com/getify/You-Dont-Know-JS/blob/1st-ed/README.md). ## Publishing As always, you'll be able to read these books online here entirely for free. This edition of the books is being self-published through [GetiPub](https://geti.pub) publishing. The published books will be made available for sale through normal book retail sources. If you'd like to contribute financially towards the effort (or any of my other OSS efforts) aside from purchasing the published books, please consider these options: * [Github Sponsorship](https://github.com/users/getify/sponsorship) * [Patreon](https://www.patreon.com/getify) * [Paypal](https://www.paypal.me/getify) ## Contributions This book series is now complete, and is **not open to further contributions**. Thank you to those who've been part of the 11 years journey of this book series. ## Thank You To These Wonderful Sponsors [![Frontend Masters Logo (dark)](https://github.com/getify/You-Dont-Know-JS/blob/2nd-ed/external-logos/fem_logo-light.svg)](https://frontendmasters.com#gh-light-mode-only) [![Frontend Masters Logo (light)](https://github.com/getify/You-Dont-Know-JS/blob/2nd-ed/external-logos/fem_logo.svg)](https://frontendmasters.com#gh-dark-mode-only) **The first two books of the second edition** are exclusively sponsored by **[Frontend Masters](https://frontendmasters.com/?code=simpson)**. Frontend Masters is the gold standard for top-of-the-line expert training material in frontend-oriented software development. With over 150 courses on all things frontend, this should be your first and only stop for quality video training on HTML, CSS, JS, and related technologies. **Note:** I teach [all my workshops](https://frontendmasters.com/teachers/kyle-simpson?code=simpson) exclusively through Frontend Masters. If you like this book content, please check out my video training courses. I want to extend a warm and deep thanks to Marc Grabanski and the entire Frontend Masters team, not only for their excellent work with the video training platform, but for their unwavering support of me and of the "You Don't Know JS" books! ---- ## License & Copyright The materials herein are all © 2019-2025 Kyle Simpson. Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 4.0 Unported License. ================================================ FILE: es-next-beyond/README.md ================================================ # You Don't Know JS Yet: ES.Next & Beyond - 2nd Edition | NOTE: | | :--- | | Work in progress | [Table of Contents](toc.md) * [Foreword](foreword.md) (by TBA) * [Preface](../preface.md) * [Chapter 1: TODO](ch1.md) ================================================ FILE: es-next-beyond/ch1.md ================================================ # You Don't Know JS Yet: ES.Next & Beyond - 2nd Edition # Chapter 1: TODO | NOTE: | | :--- | | Work in progress | ================================================ FILE: es-next-beyond/foreword.md ================================================ # You Don't Know JS Yet: ES.Next & Beyond - 2nd Edition # Foreword | NOTE: | | :--- | | Work in progress | ================================================ FILE: es-next-beyond/toc.md ================================================ # You Don't Know JS Yet: ES.Next & Beyond - 2nd Edition | NOTE: | | :--- | | Work in progress | ## Table of Contents * Foreword * Preface * Chapter 1: TODO * TODO ================================================ FILE: get-started/README.md ================================================ # You Don't Know JS Yet: Get Started - 2nd Edition ----- **[Purchase ebook/PDF from Leanpub](https://leanpub.com/ydkjsy-get-started)** ----- [Table of Contents](toc.md) * [Foreword](foreword.md) (by [Brian Holt](https://twitter.com/holtbt)) * [Preface](../preface.md) * [Chapter 1: What Is JavaScript?](ch1.md) * [Chapter 2: Surveying JS](ch2.md) * [Chapter 3: Digging to the Roots of JS](ch3.md) * [Chapter 4: The Bigger Picture](ch4.md) * [Appendix A: Exploring Further](apA.md) * [Appendix B: Practice, Practice, Practice!](apB.md) ================================================ FILE: get-started/apA.md ================================================ # You Don't Know JS Yet: Get Started - 2nd Edition # Appendix A: Exploring Further In this appendix, we're going to explore some topics from the main chapter text in a bit more detail. Think of this content as an optional preview of some of the more nuanced details covered throughout the rest of the book series. ## Values vs. References In Chapter 2, we introduced the two main types of values: primitives and objects. But we didn't discuss yet one key difference between the two: how these values are assigned and passed around. In many languages, the developer can choose between assigning/passing a value as the value itself, or as a reference to the value. In JS, however, this decision is entirely determined by the kind of value. That surprises a lot of developers from other languages when they start using JS. If you assign/pass a value itself, the value is copied. For example: ```js var myName = "Kyle"; var yourName = myName; ``` Here, the `yourName` variable has a separate copy of the `"Kyle"` string from the value that's stored in `myName`. That's because the value is a primitive, and primitive values are always assigned/passed as **value copies**. Here's how you can prove there's two separate values involved: ```js var myName = "Kyle"; var yourName = myName; myName = "Frank"; console.log(myName); // Frank console.log(yourName); // Kyle ``` See how `yourName` wasn't affected by the re-assignment of `myName` to `"Frank"`? That's because each variable holds its own copy of the value. By contrast, references are the idea that two or more variables are pointing at the same value, such that modifying this shared value would be reflected by access via any of those references. In JS, only object values (arrays, objects, functions, etc.) are treated as references. Consider: ```js var myAddress = { street: "123 JS Blvd", city: "Austin", state: "TX" }; var yourAddress = myAddress; // I've got to move to a new house! myAddress.street = "456 TS Ave"; console.log(yourAddress.street); // 456 TS Ave ``` Because the value assigned to `myAddress` is an object, it's held/assigned by reference, and thus the assignment to the `yourAddress` variable is a copy of the reference, not the object value itself. That's why the updated value assigned to the `myAddress.street` is reflected when we access `yourAddress.street`. `myAddress` and `yourAddress` have copies of the reference to the single shared object, so an update to one is an update to both. Again, JS chooses the value-copy vs. reference-copy behavior based on the value type. Primitives are held by value, objects are held by reference. There's no way to override this in JS, in either direction. ## So Many Function Forms Recall this snippet from the "Functions" section in Chapter 2: ```js var awesomeFunction = function(coolThings) { // .. return amazingStuff; }; ``` The function expression here is referred to as an *anonymous function expression*, since it has no name identifier between the `function` keyword and the `(..)` parameter list. This point confuses many JS developers because as of ES6, JS performs a "name inference" on an anonymous function: ```js awesomeFunction.name; // "awesomeFunction" ``` The `name` property of a function will reveal either its directly given name (in the case of a declaration) or its inferred name in the case of an anonymous function expression. That value is generally used by developer tools when inspecting a function value or when reporting an error stack trace. So even an anonymous function expression *might* get a name. However, name inference only happens in limited cases such as when the function expression is assigned (with `=`). If you pass a function expression as an argument to a function call, for example, no name inference occurs; the `name` property will be an empty string, and the developer console will usually report "(anonymous function)". Even if a name is inferred, **it's still an anonymous function.** Why? Because the inferred name is a metadata string value, not an available identifier to refer to the function. An anonymous function doesn't have an identifier to use to refer to itself from inside itself—for recursion, event unbinding, etc. Compare the anonymous function expression form to: ```js // let awesomeFunction = .. // const awesomeFunction = .. var awesomeFunction = function someName(coolThings) { // .. return amazingStuff; }; awesomeFunction.name; // "someName" ``` This function expression is a *named function expression*, since the identifier `someName` is directly associated with the function expression at compile time; the association with the identifier `awesomeFunction` still doesn't happen until runtime at the time of that statement. Those two identifiers don't have to match; sometimes it makes sense to have them be different, other times it's better to have them be the same. Notice also that the explicit function name, the identifier `someName`, takes precedence when assigning a *name* for the `name` property. Should function expressions be named or anonymous? Opinions vary widely on this. Most developers tend to be unconcerned with using anonymous functions. They're shorter, and unquestionably more common in the broad sphere of JS code out there. In my opinion, if a function exists in your program, it has a purpose; otherwise, take it out! And if it has a purpose, it has a natural name that describes that purpose. If a function has a name, you the code author should include that name in the code, so that the reader does not have to infer that name from reading and mentally executing that function's source code. Even a trivial function body like `x * 2` has to be read to infer a name like "double" or "multBy2"; that brief extra mental work is unnecessary when you could just take a second to name the function "double" or "multBy2" *once*, saving the reader that repeated mental work every time it's read in the future. There are, regrettably in some respects, many other function definition forms in JS as of early 2020 (maybe more in the future!). Here are some more declaration forms: ```js // generator function declaration function *two() { .. } // async function declaration async function three() { .. } // async generator function declaration async function *four() { .. } // named function export declaration (ES6 modules) export function five() { .. } ``` And here are some more of the (many!) function expression forms: ```js // IIFE (function(){ .. })(); (function namedIIFE(){ .. })(); // asynchronous IIFE (async function(){ .. })(); (async function namedAIIFE(){ .. })(); // arrow function expressions var f; f = () => 42; f = x => x * 2; f = (x) => x * 2; f = (x,y) => x * y; f = x => ({ x: x * 2 }); f = x => { return x * 2; }; f = async x => { var y = await doSomethingAsync(x); return y * 2; }; someOperation( x => x * 2 ); // .. ``` Keep in mind that arrow function expressions are **syntactically anonymous**, meaning the syntax doesn't provide a way to provide a direct name identifier for the function. The function expression may get an inferred name, but only if it's one of the assignment forms, not in the (more common!) form of being passed as a function call argument (as in the last line of the snippet). Since I don't think anonymous functions are a good idea to use frequently in your programs, I'm not a fan of using the `=>` arrow function form. This kind of function actually has a specific purpose (i.e., handling the `this` keyword lexically), but that doesn't mean we should use it for every function we write. Use the most appropriate tool for each job. Functions can also be specified in class definitions and object literal definitions. They're typically referred to as "methods" when in these forms, though in JS this term doesn't have much observable difference over "function": ```js class SomethingKindaGreat { // class methods coolMethod() { .. } // no commas! boringMethod() { .. } } var EntirelyDifferent = { // object methods coolMethod() { .. }, // commas! boringMethod() { .. }, // (anonymous) function expression property oldSchool: function() { .. } }; ``` Phew! That's a lot of different ways to define functions. There's no simple shortcut path here; you just have to build familiarity with all the function forms so you can recognize them in existing code and use them appropriately in the code you write. Study them closely and practice! ## Coercive Conditional Comparison Yes, that section name is quite a mouthful. But what are we talking about? We're talking about conditional expressions needing to perform coercion-oriented comparisons to make their decisions. `if` and `? :`-ternary statements, as well as the test clauses in `while` and `for` loops, all perform an implicit value comparison. But what sort? Is it "strict" or "coercive"? Both, actually. Consider: ```js var x = 1; if (x) { // will run! } while (x) { // will run, once! x = false; } ``` You might think of these `(x)` conditional expressions like this: ```js var x = 1; if (x == true) { // will run! } while (x == true) { // will run, once! x = false; } ``` In this specific case -- the value of `x` being `1` -- that mental model works, but it's not accurate more broadly. Consider: ```js var x = "hello"; if (x) { // will run! } if (x == true) { // won't run :( } ``` Oops. So what is the `if` statement actually doing? This is the more accurate mental model: ```js var x = "hello"; if (Boolean(x) == true) { // will run } // which is the same as: if (Boolean(x) === true) { // will run } ``` Since the `Boolean(..)` function always returns a value of type boolean, the `==` vs `===` in this snippet is irrelevant; they'll both do the same thing. But the important part is to see that before the comparison, a coercion occurs, from whatever type `x` currently is, to boolean. You just can't get away from coercions in JS comparisons. Buckle down and learn them. ## Prototypal "Classes" In Chapter 3, we introduced prototypes and showed how we can link objects through a prototype chain. Another way of wiring up such prototype linkages served as the (honestly, ugly) predecessor to the elegance of the ES6 `class` system (see Chapter 2, "Classes"), and is referred to as prototypal classes. | TIP: | | :--- | | While this style of code is quite uncommon in JS these days, it's still perplexingly rather common to be asked about it in job interviews! | Let's first recall the `Object.create(..)` style of coding: ```js var Classroom = { welcome() { console.log("Welcome, students!"); } }; var mathClass = Object.create(Classroom); mathClass.welcome(); // Welcome, students! ``` Here, a `mathClass` object is linked via its prototype to a `Classroom` object. Through this linkage, the function call `mathClass.welcome()` is delegated to the method defined on `Classroom`. The prototypal class pattern would have labeled this delegation behavior "inheritance," and alternatively have defined it (with the same behavior) as: ```js function Classroom() { // .. } Classroom.prototype.welcome = function hello() { console.log("Welcome, students!"); }; var mathClass = new Classroom(); mathClass.welcome(); // Welcome, students! ``` All functions by default reference an empty object at a property named `prototype`. Despite the confusing naming, this is **not** the function's *prototype* (where the function is prototype linked to), but rather the prototype object to *link to* when other objects are created by calling the function with `new`. We add a `welcome` property on that empty object (called `Classroom.prototype`), pointing at the `hello()` function. Then `new Classroom()` creates a new object (assigned to `mathClass`), and prototype links it to the existing `Classroom.prototype` object. Though `mathClass` does not have a `welcome()` property/function, it successfully delegates to the function `Classroom.prototype.welcome()`. This "prototypal class" pattern is now strongly discouraged, in favor of using ES6's `class` mechanism: ```js class Classroom { constructor() { // .. } welcome() { console.log("Welcome, students!"); } } var mathClass = new Classroom(); mathClass.welcome(); // Welcome, students! ``` Under the covers, the same prototype linkage is wired up, but this `class` syntax fits the class-oriented design pattern much more cleanly than "prototypal classes". ================================================ FILE: get-started/apB.md ================================================ # You Don't Know JS Yet: Get Started - 2nd Edition # Appendix B: Practice, Practice, Practice! In this appendix, we'll explore some exercises and their suggested solutions. These are just to *get you started* with practice over the concepts from the book. ## Practicing Comparisons Let's practice working with value types and comparisons (Chapter 4, Pillar 3) where coercion will need to be involved. `scheduleMeeting(..)` should take a start time (in 24-hour format as a string "hh:mm") and a meeting duration (number of minutes). It should return `true` if the meeting falls entirely within the work day (according to the times specified in `dayStart` and `dayEnd`); return `false` if the meeting violates the work day bounds. ```js const dayStart = "07:30"; const dayEnd = "17:45"; function scheduleMeeting(startTime,durationMinutes) { // ..TODO.. } scheduleMeeting("7:00",15); // false scheduleMeeting("07:15",30); // false scheduleMeeting("7:30",30); // true scheduleMeeting("11:30",60); // true scheduleMeeting("17:00",45); // true scheduleMeeting("17:30",30); // false scheduleMeeting("18:00",15); // false ``` Try to solve this yourself first. Consider the usage of equality and relational comparison operators, and how coercion impacts this code. Once you have code that works, *compare* your solution(s) to the code in "Suggested Solutions" at the end of this appendix. ## Practicing Closure Now let's practice with closure (Chapter 4, Pillar 1). The `range(..)` function takes a number as its first argument, representing the first number in a desired range of numbers. The second argument is also a number representing the end of the desired range (inclusive). If the second argument is omitted, then another function should be returned that expects that argument. ```js function range(start,end) { // ..TODO.. } range(3,3); // [3] range(3,8); // [3,4,5,6,7,8] range(3,0); // [] var start3 = range(3); var start4 = range(4); start3(3); // [3] start3(8); // [3,4,5,6,7,8] start3(0); // [] start4(6); // [4,5,6] ``` Try to solve this yourself first. Once you have code that works, *compare* your solution(s) to the code in "Suggested Solutions" at the end of this appendix. ## Practicing Prototypes Finally, let's work on `this` and objects linked via prototype (Chapter 4, Pillar 2). Define a slot machine with three reels that can individually `spin()`, and then `display()` the current contents of all the reels. The basic behavior of a single reel is defined in the `reel` object below. But the slot machine needs individual reels—objects that delegate to `reel`, and which each have a `position` property. A reel only *knows how* to `display()` its current slot symbol, but a slot machine typically shows three symbols per reel: the current slot (`position`), one slot above (`position - 1`), and one slot below (`position + 1`). So displaying the slot machine should end up displaying a 3 x 3 grid of slot symbols. ```js function randMax(max) { return Math.trunc(1E9 * Math.random()) % max; } var reel = { symbols: [ "♠", "♥", "♦", "♣", "☺", "★", "☾", "☀" ], spin() { if (this.position == null) { this.position = randMax( this.symbols.length - 1 ); } this.position = ( this.position + 100 + randMax(100) ) % this.symbols.length; }, display() { if (this.position == null) { this.position = randMax( this.symbols.length - 1 ); } return this.symbols[this.position]; } }; var slotMachine = { reels: [ // this slot machine needs 3 separate reels // hint: Object.create(..) ], spin() { this.reels.forEach(function spinReel(reel){ reel.spin(); }); }, display() { // TODO } }; slotMachine.spin(); slotMachine.display(); // ☾ | ☀ | ★ // ☀ | ♠ | ☾ // ♠ | ♥ | ☀ slotMachine.spin(); slotMachine.display(); // ♦ | ♠ | ♣ // ♣ | ♥ | ☺ // ☺ | ♦ | ★ ``` Try to solve this yourself first. Hints: * Use the `%` modulo operator for wrapping `position` as you access symbols circularly around a reel. * Use `Object.create(..)` to create an object and prototype-link it to another object. Once linked, delegation allows the objects to share `this` context during method invocation. * Instead of modifying the reel object directly to show each of the three positions, you can use another temporary object (`Object.create(..)` again) with its own `position`, to delegate from. Once you have code that works, *compare* your solution(s) to the code in "Suggested Solutions" at the end of this appendix. ## Suggested Solutions Keep in mind that these suggested solutions are just that: suggestions. There are many different ways to solve these practice exercises. Compare your approach to what you see here, and consider the pros and cons of each. Suggested solution for "Comparisons" (Pillar 3) practice: ```js const dayStart = "07:30"; const dayEnd = "17:45"; function scheduleMeeting(startTime,durationMinutes) { var [ , meetingStartHour, meetingStartMinutes ] = startTime.match(/^(\d{1,2}):(\d{2})$/) || []; durationMinutes = Number(durationMinutes); if ( typeof meetingStartHour == "string" && typeof meetingStartMinutes == "string" ) { let durationHours = Math.floor(durationMinutes / 60); durationMinutes = durationMinutes - (durationHours * 60); let meetingEndHour = Number(meetingStartHour) + durationHours; let meetingEndMinutes = Number(meetingStartMinutes) + durationMinutes; if (meetingEndMinutes >= 60) { meetingEndHour = meetingEndHour + 1; meetingEndMinutes = meetingEndMinutes - 60; } // re-compose fully-qualified time strings // (to make comparison easier) let meetingStart = `${ meetingStartHour.padStart(2,"0") }:${ meetingStartMinutes.padStart(2,"0") }`; let meetingEnd = `${ String(meetingEndHour).padStart(2,"0") }:${ String(meetingEndMinutes).padStart(2,"0") }`; // NOTE: since expressions are all strings, // comparisons here are alphabetic, but it's // safe here since they're fully qualified // time strings (ie, "07:15" < "07:30") return ( meetingStart >= dayStart && meetingEnd <= dayEnd ); } return false; } scheduleMeeting("7:00",15); // false scheduleMeeting("07:15",30); // false scheduleMeeting("7:30",30); // true scheduleMeeting("11:30",60); // true scheduleMeeting("17:00",45); // true scheduleMeeting("17:30",30); // false scheduleMeeting("18:00",15); // false ``` ---- Suggested solution for "Closure" (Pillar 1) practice: ```js function range(start,end) { start = Number(start) || 0; if (end === undefined) { return function getEnd(end) { return getRange(start,end); }; } else { end = Number(end) || 0; return getRange(start,end); } // ********************** function getRange(start,end) { var ret = []; for (let i = start; i <= end; i++) { ret.push(i); } return ret; } } range(3,3); // [3] range(3,8); // [3,4,5,6,7,8] range(3,0); // [] var start3 = range(3); var start4 = range(4); start3(3); // [3] start3(8); // [3,4,5,6,7,8] start3(0); // [] start4(6); // [4,5,6] ``` ---- Suggested solution for "Prototypes" (Pillar 2) practice: ```js function randMax(max) { return Math.trunc(1E9 * Math.random()) % max; } var reel = { symbols: [ "♠", "♥", "♦", "♣", "☺", "★", "☾", "☀" ], spin() { if (this.position == null) { this.position = randMax( this.symbols.length - 1 ); } this.position = ( this.position + 100 + randMax(100) ) % this.symbols.length; }, display() { if (this.position == null) { this.position = randMax( this.symbols.length - 1 ); } return this.symbols[this.position]; } }; var slotMachine = { reels: [ Object.create(reel), Object.create(reel), Object.create(reel) ], spin() { this.reels.forEach(function spinReel(reel){ reel.spin(); }); }, display() { var lines = []; // display all 3 lines on the slot machine for ( let linePos = -1; linePos <= 1; linePos++ ) { let line = this.reels.map( function getSlot(reel){ var slot = Object.create(reel); slot.position = ( reel.symbols.length + reel.position + linePos ) % reel.symbols.length; return slot.display(); } ); lines.push(line.join(" | ")); } return lines.join("\n"); } }; slotMachine.spin(); slotMachine.display(); // ☾ | ☀ | ★ // ☀ | ♠ | ☾ // ♠ | ♥ | ☀ slotMachine.spin(); slotMachine.display(); // ♦ | ♠ | ♣ // ♣ | ♥ | ☺ // ☺ | ♦ | ★ ``` That's it for this book. But now it's time to look for real projects to practice these ideas on. Just keep coding, because that's the best way to learn! ================================================ FILE: get-started/ch1.md ================================================ # You Don't Know JS Yet: Get Started - 2nd Edition # Chapter 1: What *Is* JavaScript? You don't know JS, yet. Neither do I, not fully anyway. None of us do. But we can all start getting to know JS better. In this first chapter of the first book of the *You Don't Know JS Yet* (YDKJSY) series, we will take some time to build a foundation to move forward on. We need to start by covering a variety of important background housekeeping details, clearing up some myths and misconceptions about what the language really is (and isn't!). This is valuable insight into the identity and process of how JS is organized and maintained; all JS developers should understand it. If you want to get to know JS, this is how to *get started* taking the first steps in that journey. ## About This Book I emphasize the word journey because *knowing JS* is not a destination, it's a direction. No matter how much time you spend with the language, you will always be able to find something else to learn and understand a little better. So don't look at this book as something to rush through for a quick achievement. Instead, patience and persistence are best as you take these first few steps. Following this background chapter, the rest of the book lays out a high-level map of what you will find as you dig into and study JS with the YDKJSY books. In particular, Chapter 4 identifies three main pillars around which the JS language is organized: scope/closures, prototypes/objects, and types/coercion. JS is a broad and sophisticated language, with many features and capabilities. But all of JS is founded on these three foundational pillars. Keep in mind that even though this book is titled "Get Started," it's **not intended as a beginner/intro book**. This book's main job is to get you ready for studying JS deeply throughout the rest of the series; it's written assuming you already have familiarity with JS over at least several months experience before moving on in YDKJSY. So to get the most out of *Get Started*, make sure you spend plenty of time writing JS code to build up your experience. Even if you've already written a lot of JS before, this book should not be skimmed over or skipped; take your time to fully process the material here. **A good start always depends on a solid first step.** ## What's With That Name? The name JavaScript is probably the most mistaken and misunderstood programming language name. Is this language related to Java? Is it only the script form for Java? Is it only for writing scripts and not real programs? The truth is, the name JavaScript is an artifact of marketing shenanigans. When Brendan Eich first conceived of the language, he code-named it Mocha. Internally at Netscape, the brand LiveScript was used. But when it came time to publicly name the language, "JavaScript" won the vote. Why? Because this language was originally designed to appeal to an audience of mostly Java programmers, and because the word "script" was popular at the time to refer to lightweight programs. These lightweight "scripts" would be the first ones to embed inside of pages on this new thing called the web! In other words, JavaScript was a marketing ploy to try to position this language as a palatable alternative to writing the heavier and more well-known Java of the day. It could just as easily have been called "WebJava," for that matter. There are some superficial resemblances between JavaScript's code and Java code. Those similarities don't particularly come from shared development, but from both languages targeting developers with assumed syntax expectations from C (and to an extent, C++). For example, we use the `{` to begin a block of code and the `}` to end that block of code, just like C/C++ and Java. We also use the `;` to punctuate the end of a statement. In some ways, legal relationships run even deeper than the syntax. Oracle (via Sun), the company that still owns and runs Java, also owns the official trademark for the name "JavaScript" (via Netscape). This trademark is almost never enforced, and likely couldn't be at this point. For these reasons, some have suggested we use JS instead of JavaScript. That is a very common shorthand, if not a good candidate for an official language branding itself. Indeed, these books use JS almost exclusively to refer to the language. Further distancing the language from the Oracle-owned trademark, the official name of the language specified by TC39 and formalized by the ECMA standards body is **ECMAScript**. And indeed, since 2016, the official language name has also been suffixed by the revision year; as of this writing, that's ECMAScript 2019, or otherwise abbreviated ES2019. In other words, the JavaScript/JS that runs in your browser or in Node.js, is *an* implementation of the ES2019 standard. | NOTE: | | :--- | | Don't use terms like "JS6" or "ES8" to refer to the language. Some do, but those terms only serve to perpetuate confusion. "ES20xx" or just "JS" are what you should stick to. | Whether you call it JavaScript, JS, ECMAScript, or ES2019, it's most definitely not a variant of the Java language! > "Java is to JavaScript as ham is to hamster." --Jeremy Keith, 2009 ## Language Specification I mentioned TC39, the technical steering committee that manages JS. Their primary task is managing the official specification for the language. They meet regularly to vote on any agreed changes, which they then submit to ECMA, the standards organization. JS's syntax and behavior are defined in the ES specification. ES2019 happens to be the 10th major numbered specification/revision since JS's inception in 1995, so in the specification's official URL as hosted by ECMA, you'll find "10.0": https://www.ecma-international.org/ecma-262/10.0/ The TC39 committee is comprised of between 50 and about 100 different people from a broad section of web-invested companies, such as browser makers (Mozilla, Google, Apple) and device makers (Samsung, etc). All members of the committee are volunteers, though many of them are employees of these companies and so may receive compensation in part for their duties on the committee. TC39 meets generally about every other month, usually for about three days, to review work done by members since the last meeting, discuss issues, and vote on proposals. Meeting locations rotate among member companies willing to host. All TC39 proposals progress through a five-stage process—of course, since we're programmers, it's 0-based!—Stage 0 through Stage 4. You can read more about the Stage process here: https://tc39.es/process-document/ Stage 0 means roughly, someone on TC39 thinks it's a worthy idea and plans to champion and work on it. That means lots of ideas that non-TC39 members "propose," through informal means such as social media or blog posts, are really "pre-stage 0." You have to get a TC39 member to champion a proposal for it to be considered "Stage 0" officially. Once a proposal reaches "Stage 4" status, it is eligible to be included in the next yearly revision of the language. It can take anywhere from several months to a few years for a proposal to work its way through these stages. All proposals are managed in the open, on TC39's Github repository: https://github.com/tc39/proposals Anyone, whether on TC39 or not, is welcome to participate in these public discussions and the processes for working on the proposals. However, only TC39 members can attend meetings and vote on the proposals and changes. So in effect, the voice of a TC39 member carries a lot of weight in where JS will go. Contrary to some established and frustratingly perpetuated myth, there are *not* multiple versions of JavaScript in the wild. There's just **one JS**, the official standard as maintained by TC39 and ECMA. Back in the early 2000s, when Microsoft maintained a forked and reverse-engineered (and not entirely compatible) version of JS called "JScript," there were legitimately "multiple versions" of JS. But those days are long gone. It's outdated and inaccurate to make such claims about JS today. All major browsers and device makers have committed to keeping their JS implementations compliant with this one central specification. Of course, engines implement features at different times. But it should never be the case that the v8 engine (Chrome's JS engine) implements a specified feature differently or incompatibly as compared to the SpiderMonkey engine (Mozilla's JS engine). That means you can learn **one JS**, and rely on that same JS everywhere. ### The Web Rules Everything About (JS) While the array of environments that run JS is constantly expanding (from browsers, to servers (Node.js), to robots, to lightbulbs, to...), the one environment that rules JS is the web. In other words, how JS is implemented for web browsers is, in all practicality, the only reality that matters. For the most part, the JS defined in the specification and the JS that runs in browser-based JS engines is the same. But there are some differences that must be considered. Sometimes the JS specification will dictate some new or refined behavior, and yet that won't exactly match with how it works in browser-based JS engines. Such a mismatch is historical: JS engines have had 20+ years of observable behaviors around corner cases of features that have come to be relied on by web content. As such, sometimes the JS engines will refuse to conform to a specification-dictated change because it would break that web content. In these cases, often TC39 will backtrack and simply choose to conform the specification to the reality of the web. For example, TC39 planned to add a `contains(..)` method for Arrays, but it was found that this name conflicted with old JS frameworks still in use on some sites, so they changed the name to a non-conflicting `includes(..)`. The same happened with a comedic/tragic JS *community crisis* dubbed "smooshgate," where the planned `flatten(..)` method was eventually renamed `flat(..)`. But occasionally, TC39 will decide the specification should stick firm on some point even though it is unlikely that browser-based JS engines will ever conform. The solution? Appendix B, "Additional ECMAScript Features for Web Browsers".[^specApB] The JS specification includes this appendix to detail out any known mismatches between the official JS specification and the reality of JS on the web. In other words, these are exceptions that are allowed *only* for web JS; other JS environments must stick to the letter of the law. Section B.1 and B.2 cover *additions* to JS (syntax and APIs) that web JS includes, again for historical reasons, but which TC39 does not plan to formally specify in the core of JS. Examples include `0`-prefixed octal literals, the global `escape(..)` / `unescape(..)` utilities, String "helpers" like `anchor(..)` and `blink()`, and the RegExp `compile(..)` method. Section B.3 includes some conflicts where code may run in both web and non-web JS engines, but where the behavior *could* be observably different, resulting in different outcomes. Most of the listed changes involve situations that are labeled as early errors when code is running in strict mode. Appendix B *gotchas* aren't encountered very often, but it's still a good idea to avoid these constructs to be future safe. Wherever possible, adhere to the JS specification and don't rely on behavior that's only applicable in certain JS engine environments. ### Not All (Web) JS... Is this code a JS program? ```js alert("Hello, JS!"); ``` Depends on how you look at things. The `alert(..)` function shown here is not included in the JS specification, but it *is* in all web JS environments. Yet, you won't find it in Appendix B, so what gives? Various JS environments (like browser JS engines, Node.js, etc.) add APIs into the global scope of your JS programs that give you environment-specific capabilities, like being able to pop an alert-style box in the user's browser. In fact, a wide range of JS-looking APIs, like `fetch(..)`, `getCurrentLocation(..)`, and `getUserMedia(..)`, are all web APIs that look like JS. In Node.js, we can access hundreds of API methods from various built-in modules, like `fs.write(..)`. Another common example is `console.log(..)` (and all the other `console.*` methods!). These are not specified in JS, but because of their universal utility are defined by pretty much every JS environment, according to a roughly agreed consensus. So `alert(..)` and `console.log(..)` are not defined by JS. But they *look* like JS. They are functions and object methods and they obey JS syntax rules. The behaviors behind them are controlled by the environment running the JS engine, but on the surface they definitely have to abide by JS to be able to play in the JS playground. Most of the cross-browser differences people complain about with "JS is so inconsistent!" claims are actually due to differences in how those environment behaviors work, not in how the JS itself works. So an `alert(..)` call *is* JS, but `alert` itself is really just a guest, not part of the official JS specification. ### It's Not Always JS Using the console/REPL (Read-Evaluate-Print-Loop) in your browser's Developer Tools (or Node) feels like a pretty straightforward JS environment at first glance. But it's not, really. Developer Tools are... tools for developers. Their primary purpose is to make life easier for developers. They prioritize DX (Developer Experience). It is *not* a goal of such tools to accurately and purely reflect all nuances of strict-spec JS behavior. As such, there's many quirks that may act as "gotchas" if you're treating the console as a *pure* JS environment. This convenience is a good thing, by the way! I'm glad Developer Tools make developers' lives easier! I'm glad we have nice UX charms like auto-complete of variables/properties, etc. I'm just pointing out that we can't and shouldn't expect such tools to *always* adhere strictly to the way JS programs are handled, because that's not the purpose of these tools. Since such tools vary in behavior from browser to browser, and since they change (sometimes rather frequently), I'm not going to "hardcode" any of the specific details into this text, thereby ensuring this book text is outdated quickly. But I'll just hint at some examples of quirks that have been true at various points in different JS console environments, to reinforce my point about not assuming native JS behavior while using them: * Whether a `var` or `function` declaration in the top-level "global scope" of the console actually creates a real global variable (and mirrored `window` property, and vice versa!). * What happens with multiple `let` and `const` declarations in the top-level "global scope." * Whether `"use strict";` on one line-entry (pressing `` after) enables strict mode for the rest of that console session, the way it would on the first line of a .js file, as well as whether you can use `"use strict";` beyond the "first line" and still get strict mode turned on for that session. * How non-strict mode `this` default-binding works for function calls, and whether the "global object" used will contain expected global variables. * How hoisting (see Book 2, *Scope & Closures*) works across multiple line entries. * ...several others The developer console is not trying to pretend to be a JS compiler that handles your entered code exactly the same way the JS engine handles a .js file. It's trying to make it easy for you to quickly enter a few lines of code and see the results immediately. These are entirely different use cases, and as such, it's unreasonable to expect one tool to handle both equally. Don't trust what behavior you see in a developer console as representing *exact* to-the-letter JS semantics; for that, read the specification. Instead, think of the console as a "JS-friendly" environment. That's useful in its own right. ## Many Faces The term "paradigm" in programming language context refers to a broad (almost universal) mindset and approach to structuring code. Within a paradigm, there are myriad variations of style and form that distinguish programs, including countless different libraries and frameworks that leave their unique signature on any given code. But no matter what a program's individual style may be, the big picture divisions around paradigms are almost always evident at first glance of any program. Typical paradigm-level code categories include procedural, object-oriented (OO/classes), and functional (FP): * Procedural style organizes code in a top-down, linear progression through a pre-determined set of operations, usually collected together in related units called procedures. * OO style organizes code by collecting logic and data together into units called classes. * FP style organizes code into functions (pure computations as opposed to procedures), and the adaptations of those functions as values. Paradigms are neither right nor wrong. They're orientations that guide and mold how programmers approach problems and solutions, how they structure and maintain their code. Some languages are heavily slanted toward one paradigm—C is procedural, Java/C++ are almost entirely class oriented, and Haskell is FP through and through. But many languages also support code patterns that can come from, and even mix and match from, different paradigms. So called "multi-paradigm languages" offer ultimate flexibility. In some cases, a single program can even have two or more expressions of these paradigms sitting side by side. JavaScript is most definitely a multi-paradigm language. You can write procedural, class-oriented, or FP-style code, and you can make those decisions on a line-by-line basis instead of being forced into an all-or-nothing choice. ## Backwards & Forwards One of the most foundational principles that guides JavaScript is preservation of *backwards compatibility*. Many are confused by the implications of this term, and often confuse it with a related but different term: *forwards compatibility*. Let's set the record straight. Backwards compatibility means that once something is accepted as valid JS, there will not be a future change to the language that causes that code to become invalid JS. Code written in 1995—however primitive or limited it may have been!—should still work today. As TC39 members often proclaim, "we don't break the web!" The idea is that JS developers can write code with confidence that their code won't stop working unpredictably because a browser update is released. This makes the decision to choose JS for a program a more wise and safe investment, for years into the future. That "guarantee" is no small thing. Maintaining backwards compatibility, stretched out across almost 25 years of the language's history, creates an enormous burden and a whole slew of unique challenges. You'd be hard pressed to find many other examples in computing of such a commitment to backwards compatibility. The costs of sticking to this principle should not be casually dismissed. It necessarily creates a very high bar to including changing or extending the language; any decision becomes effectively permanent, mistakes and all. Once it's in JS, it can't be taken out because it might break programs, even if we'd really, really like to remove it! There are some small exceptions to this rule. JS has had some backwards-incompatible changes, but TC39 is extremely cautious in doing so. They study existing code on the web (via browser data gathering) to estimate the impact of such breakage, and browsers ultimately decide and vote on whether they're willing to take the heat from users for a very small-scale breakage weighed against the benefits of fixing or improving some aspect of the language for many more sites (and users). These kinds of changes are rare, and are almost always in corner cases of usage that are unlikely to be observably breaking in many sites. Compare *backwards compatibility* to its counterpart, *forwards compatibility*. Being forwards-compatible means that including a new addition to the language in a program would not cause that program to break if it were run in an older JS engine. **JS is not forwards-compatible**, despite many wishing such, and even incorrectly believing the myth that it is. HTML and CSS, by contrast, are forwards-compatible but not backwards-compatible. If you dug up some HTML or CSS written back in 1995, it's entirely possible it would not work (or work the same) today. But, if you use a new feature from 2019 in a browser from 2010, the page isn't "broken" -- the unrecognized CSS/HTML is skipped over, while the rest of the CSS/HTML would be processed accordingly. It may seem desirable for forwards-compatibility to be included in programming language design, but it's generally impractical to do so. Markup (HTML) or styling (CSS) are declarative in nature, so it's much easier to "skip over" unrecognized declarations with minimal impact to other recognized declarations. But chaos and non-determinism would ensue if a programming language engine selectively skipped statements (or even expressions!) that it didn't understand, as it's impossible to ensure that a subsequent part of the program wasn't expecting the skipped-over part to have been processed. Though JS isn't, and can't be, forwards-compatible, it's critical to recognize JS's backwards compatibility, including the enduring benefits to the web and the constraints and difficulties it places on JS as a result. ### Jumping the Gaps Since JS is not forwards-compatible, it means that there is always the potential for a gap between code that you can write that's valid JS, and the oldest engine that your site or application needs to support. If you run a program that uses an ES2019 feature in an engine from 2016, you're very likely to see the program break and crash. If the feature is a new syntax, the program will in general completely fail to compile and run, usually throwing a syntax error. If the feature is an API (such as ES6's `Object.is(..)`), the program may run up to a point but then throw a runtime exception and stop once it encounters the reference to the unknown API. Does this mean JS developers should always lag behind the pace of progress, using only code that is on the trailing edge of the oldest JS engine environments they need to support? No! But it does mean that JS developers need to take special care to address this gap. For new and incompatible syntax, the solution is transpiling. Transpiling is a contrived and community-invented term to describe using a tool to convert the source code of a program from one form to another (but still as textual source code). Typically, forwards-compatibility problems related to syntax are solved by using a transpiler (the most common one being Babel (https://babeljs.io)) to convert from that newer JS syntax version to an equivalent older syntax. For example, a developer may write a snippet of code like: ```js if (something) { let x = 3; console.log(x); } else { let x = 4; console.log(x); } ``` This is how the code would look in the source code tree for that application. But when producing the file(s) to deploy to the public website, the Babel transpiler might convert that code to look like this: ```js var x$0, x$1; if (something) { x$0 = 3; console.log(x$0); } else { x$1 = 4; console.log(x$1); } ``` The original snippet relied on `let` to create block-scoped `x` variables in both the `if` and `else` clauses which did not interfere with each other. An equivalent program (with minimal re-working) that Babel can produce just chooses to name two different variables with unique names, producing the same non-interference outcome. | NOTE: | | :--- | | The `let` keyword was added in ES6 (in 2015). The preceding example of transpiling would only need to apply if an application needed to run in a pre-ES6 supporting JS environment. The example here is just for simplicity of illustration. When ES6 was new, the need for such a transpilation was quite prevalent, but in 2020 it's much less common to need to support pre-ES6 environments. The "target" used for transpilation is thus a sliding window that shifts upward only as decisions are made for a site/application to stop supporting some old browser/engine. | You may wonder: why go to the trouble of using a tool to convert from a newer syntax version to an older one? Couldn't we just write the two variables and skip using the `let` keyword? The reason is, it's strongly recommended that developers use the latest version of JS so that their code is clean and communicates its ideas most effectively. Developers should focus on writing the clean, new syntax forms, and let the tools take care of producing a forwards-compatible version of that code that is suitable to deploy and run on the oldest-supported JS engine environments. ### Filling the Gaps If the forwards-compatibility issue is not related to new syntax, but rather to a missing API method that was only recently added, the most common solution is to provide a definition for that missing API method that stands in and acts as if the older environment had already had it natively defined. This pattern is called a polyfill (aka "shim"). Consider this code: ```js // getSomeRecords() returns us a promise for some // data it will fetch var pr = getSomeRecords(); // show the UI spinner while we get the data startSpinner(); pr .then(renderRecords) // render if successful .catch(showError) // show an error if not .finally(hideSpinner) // always hide the spinner ``` This code uses an ES2019 feature, the `finally(..)` method on the promise prototype. If this code were used in a pre-ES2019 environment, the `finally(..)` method would not exist, and an error would occur. A polyfill for `finally(..)` in pre-ES2019 environments could look like this: ```js if (!Promise.prototype.finally) { Promise.prototype.finally = function f(fn){ return this.then( function t(v){ return Promise.resolve( fn() ) .then(function t(){ return v; }); }, function c(e){ return Promise.resolve( fn() ) .then(function t(){ throw e; }); } ); }; } ``` | WARNING: | | :--- | | This is only a simple illustration of a basic (not entirely spec-compliant) polyfill for `finally(..)`. Don't use this polyfill in your code; always use a robust, official polyfill wherever possible, such as the collection of polyfills/shims in ES-Shim. | The `if` statement protects the polyfill definition by preventing it from running in any environment where the JS engine has already defined that method. In older environments, the polyfill is defined, but in newer environments the `if` statement is quietly skipped. Transpilers like Babel typically detect which polyfills your code needs and provide them automatically for you. But occasionally you may need to include/define them explicitly, which works similar to the snippet we just looked at. Always write code using the most appropriate features to communicate its ideas and intent effectively. In general, this means using the most recent stable JS version. Avoid negatively impacting the code's readability by trying to manually adjust for the syntax/API gaps. That's what tools are for! Transpilation and polyfilling are two highly effective techniques for addressing that gap between code that uses the latest stable features in the language and the old environments a site or application needs to still support. Since JS isn't going to stop improving, the gap will never go away. Both techniques should be embraced as a standard part of every JS project's production chain going forward. ## What's in an Interpretation? A long-debated question for code written in JS: is it an interpreted script or a compiled program? The majority opinion seems to be that JS is an interpreted (scripting) language. But the truth is more complicated than that. For much of the history of programming languages, "interpreted" languages and "scripting" languages have been looked down on as inferior compared to their compiled counterparts. The reasons for this acrimony are numerous, including the perception that there is a lack of performance optimization, as well as dislike of certain language characteristics, such as scripting languages generally using dynamic typing instead of the "more mature" statically typed languages. Languages regarded as "compiled" usually produce a portable (binary) representation of the program that is distributed for execution later. Since we don't really observe that kind of model with JS (we distribute the source code, not the binary form), many claim that disqualifies JS from the category. In reality, the distribution model for a program's "executable" form has become drastically more varied and also less relevant over the last few decades; to the question at hand, it doesn't really matter so much anymore what form of a program gets passed around. These misinformed claims and criticisms should be set aside. The real reason it matters to have a clear picture on whether JS is interpreted or compiled relates to the nature of how errors are handled. Historically, scripted or interpreted languages were executed in generally a top-down and line-by-line fashion; there's typically not an initial pass through the program to process it before execution begins (see Figure 1).
Interpreting a script to execute it
Fig. 1: Interpreted/Scripted Execution


In scripted or interpreted languages, an error on line 5 of a program won't be discovered until lines 1 through 4 have already executed. Notably, the error on line 5 might be due to a runtime condition, such as some variable or value having an unsuitable value for an operation, or it may be due to a malformed statement/command on that line. Depending on context, deferring error handling to the line the error occurs on may be a desirable or undesirable effect. Compare that to languages which do go through a processing step (typically, called parsing) before any execution occurs, as illustrated in Figure 2:
Parsing, compiling, and executing a program
Fig. 2: Parsing + Compilation + Execution


In this processing model, an invalid command (such as broken syntax) on line 5 would be caught during the parsing phase, before any execution has begun, and none of the program would run. For catching syntax (or otherwise "static") errors, generally it's preferred to know about them ahead of any doomed partial execution. So what do "parsed" languages have in common with "compiled" languages? First, all compiled languages are parsed. So a parsed language is quite a ways down the road toward being compiled already. In classic compilation theory, the last remaining step after parsing is code generation: producing an executable form. Once any source program has been fully parsed, it's very common that its subsequent execution will, in some form or fashion, include a translation from the parsed form of the program—usually called an Abstract Syntax Tree (AST)—to that executable form. In other words, parsed languages usually also perform code generation before execution, so it's not that much of a stretch to say that, in spirit, they're compiled languages. JS source code is parsed before it is executed. The specification requires as much, because it calls for "early errors"—statically determined errors in code, such as a duplicate parameter name—to be reported before the code starts executing. Those errors cannot be recognized without the code having been parsed. So **JS is a parsed language**, but is it *compiled*? The answer is closer to yes than no. The parsed JS is converted to an optimized (binary) form, and that "code" is subsequently executed (Figure 2); the engine does not commonly switch back into line-by-line execution (like Figure 1) mode after it has finished all the hard work of parsing—most languages/engines wouldn't, because that would be highly inefficient. To be specific, this "compilation" produces a binary byte code (of sorts), which is then handed to the "JS virtual machine" to execute. Some like to say this VM is "interpreting" the byte code. But then that means Java, and a dozen other JVM-driven languages, for that matter, are interpreted rather than compiled. Of course, that contradicts the typical assertion that Java/etc are compiled languages. Interestingly, while Java and JavaScript are very different languages, the question of interpreted/compiled is pretty closely related between them! Another wrinkle is that JS engines can employ multiple passes of JIT (Just-In-Time) processing/optimization on the generated code (post parsing), which again could reasonably be labeled either "compilation" or "interpretation" depending on perspective. It's actually a fantastically complex situation under the hood of a JS engine. So what do these nitty-gritty details boil down to? Step back and consider the entire flow of a JS source program: 1. After a program leaves a developer's editor, it gets transpiled by Babel, then packed by Webpack (and perhaps half a dozen other build processes), then it gets delivered in that very different form to a JS engine. 2. The JS engine parses the code to an AST. 3. Then the engine converts that AST to a kind-of byte code, a binary intermediate representation (IR), which is then refined/converted even further by the optimizing JIT compiler. 4. Finally, the JS VM executes the program. To visualize those steps, again:
Steps of JS compilation and execution
Fig. 3: Parsing, Compiling, and Executing JS


Is JS handled more like an interpreted, line-by-line script, as in Figure 1, or is it handled more like a compiled language that's processed in one-to-several passes first, before execution (as in Figures 2 and 3)? I think it's clear that in spirit, if not in practice, **JS is a compiled language**. And again, the reason that matters is, since JS is compiled, we are informed of static errors (such as malformed syntax) before our code is executed. That is a substantively different interaction model than we get with traditional "scripting" programs, and arguably more helpful! ### Web Assembly (WASM) One dominating concern that has driven a significant amount of JS's evolution is performance, both how quickly JS can be parsed/compiled and how quickly that compiled code can be executed. In 2013, engineers from Mozilla Firefox demonstrated a port of the Unreal 3 game engine from C to JS. The ability for this code to run in a browser JS engine at full 60fps performance was predicated on a set of optimizations that the JS engine could perform specifically because the JS version of the Unreal engine's code used a style of code that favored a subset of the JS language, named "ASM.js". This subset is valid JS written in ways that are somewhat uncommon in normal coding, but which signal certain important typing information to the engine that allow it to make key optimizations. ASM.js was introduced as one way of addressing the pressures on the runtime performance of JS. But it's important to note that ASM.js was never intended to be code that was authored by developers, but rather a representation of a program having been transpiled from another language (such as C), where these typing "annotations" were inserted automatically by the tooling. Several years after ASM.js demonstrated the validity of tooling-created versions of programs that can be processed more efficiently by the JS engine, another group of engineers (also, initially, from Mozilla) released Web Assembly (WASM). WASM is similar to ASM.js in that its original intent was to provide a path for non-JS programs (C, etc.) to be converted to a form that could run in the JS engine. Unlike ASM.js, WASM chose to additionally get around some of the inherent delays in JS parsing/compilation before a program can execute, by representing the program in a form that is entirely unlike JS. WASM is a representation format more akin to Assembly (hence, its name) that can be processed by a JS engine by skipping the parsing/compilation that the JS engine normally does. The parsing/compilation of a WASM-targeted program happen ahead of time (AOT); what's distributed is a binary-packed program ready for the JS engine to execute with very minimal processing. An initial motivation for WASM was clearly the potential performance improvements. While that continues to be a focus, WASM is additionally motivated by the desire to bring more parity for non-JS languages to the web platform. For example, if a language like Go supports threaded programming, but JS (the language) does not, WASM offers the potential for such a Go program to be converted to a form the JS engine can understand, without needing a threads feature in the JS language itself. In other words, WASM relieves the pressure to add features to JS that are mostly/exclusively intended to be used by transpiled programs from other languages. That means JS feature development can be judged (by TC39) without being skewed by interests/demands in other language ecosystems, while still letting those languages have a viable path onto the web. Another perspective on WASM that's emerging is, interestingly, not even directly related to the web (W). WASM is evolving to become a cross-platform virtual machine (VM) of sorts, where programs can be compiled once and run in a variety of different system environments. So, WASM isn't only for the web, and WASM also isn't JS. Ironically, even though WASM runs in the JS engine, the JS language is one of the least suitable languages to source WASM programs with, because WASM relies heavily on static typing information. Even TypeScript (TS)—ostensibly, JS + static types—is not quite suitable (as it stands) to transpile to WASM, though language variants like AssemblyScript are attempting to bridge the gap between JS/TS and WASM. This book isn't about WASM, so I won't spend much more time discussing it, except to make one final point. *Some* folks have suggested WASM points to a future where JS is excised from, or minimized in, the web. These folks often harbor ill feelings about JS, and want some other language—any other language!—to replace it. Since WASM lets other languages run in the JS engine, on its face this isn't an entirely fanciful fairytale. But let me just state simply: WASM will not replace JS. WASM significantly augments what the web (including JS) can accomplish. That's a great thing, entirely orthogonal to whether some people will use it as an escape hatch from having to write JS. ## *Strict*ly Speaking Back in 2009 with the release of ES5, JS added *strict mode* as an opt-in mechanism for encouraging better JS programs. The benefits of strict mode far outweigh the costs, but old habits die hard and the inertia of existing (aka "legacy") code bases is really hard to shift. So sadly, more than 10 years later, strict mode's *optionality* means that it's still not necessarily the default for JS programmers. Why strict mode? Strict mode shouldn't be thought of as a restriction on what you can't do, but rather as a guide to the best way to do things so that the JS engine has the best chance of optimizing and efficiently running the code. Most JS code is worked on by teams of developers, so the *strict*-ness of strict mode (along with tooling like linters!) often helps collaboration on code by avoiding some of the more problematic mistakes that slip by in non-strict mode. Most strict mode controls are in the form of *early errors*, meaning errors that aren't strictly syntax errors but are still thrown at compile time (before the code is run). For example, strict mode disallows naming two function parameters the same, and results in an early error. Some other strict mode controls are only observable at runtime, such as how `this` defaults to `undefined` instead of the global object. Rather than fighting and arguing with strict mode, like a kid who just wants to defy whatever their parents tell them not to do, the best mindset is that strict mode is like a linter reminding you how JS *should* be written to have the highest quality and best chance at performance. If you find yourself feeling handcuffed, trying to work around strict mode, that should be a blaring red warning flag that you need to back up and rethink the whole approach. Strict mode is switched on per file with a special pragma (nothing allowed before it except comments/whitespace): ```js // only whitespace and comments are allowed // before the use-strict pragma "use strict"; // the rest of the file runs in strict mode ``` | WARNING: | | :--- | | Something to be aware of is that even a stray `;` all by itself appearing before the strict mode pragma will render the pragma useless; no errors are thrown because it's valid JS to have a string literal expression in a statement position, but it also will silently *not* turn on strict mode! | Strict mode can alternatively be turned on per-function scope, with exactly the same rules about its surroundings: ```js function someOperations() { // whitespace and comments are fine here "use strict"; // all this code will run in strict mode } ``` Interestingly, if a file has strict mode turned on, the function-level strict mode pragmas are disallowed. So you have to pick one or the other. The **only** valid reason to use a per-function approach to strict mode is when you are converting an existing non-strict mode program file and need to make the changes little by little over time. Otherwise, it's vastly better to simply turn strict mode on for the entire file/program. Many have wondered if there would ever be a time when JS made strict mode the default? The answer is, almost certainly not. As we discussed earlier around backwards compatibility, if a JS engine update started assuming code was strict mode even if it's not marked as such, it's possible that this code would break as a result of strict mode's controls. However, there are a few factors that reduce the future impact of this non-default "obscurity" of strict mode. For one, virtually all transpiled code ends up in strict mode even if the original source code isn't written as such. Most JS code in production has been transpiled, so that means most JS is already adhering to strict mode. It's possible to undo that assumption, but you really have to go out of your way to do so, so it's highly unlikely. Moreover, a wide shift is happening toward more/most new JS code being written using the ES6 module format. ES6 modules assume strict mode, so all code in such files is automatically defaulted to strict mode. Taken together, strict mode is largely the de facto default even though technically it's not actually the default. ## Defined JS is an implementation of the ECMAScript standard (version ES2019 as of this writing), which is guided by the TC39 committee and hosted by ECMA. It runs in browsers and other JS environments such as Node.js. JS is a multi-paradigm language, meaning the syntax and capabilities allow a developer to mix and match (and bend and reshape!) concepts from various major paradigms, such as procedural, object-oriented (OO/classes), and functional (FP). JS is a compiled language, meaning the tools (including the JS engine) process and verify a program (reporting any errors!) before it executes. With our language now *defined*, let's start getting to know its ins and outs. [^specApB]: ECMAScript 2019 Language Specification, Appendix B: Additional ECMAScript Features for Web Browsers, https://www.ecma-international.org/ecma-262/10.0/#sec-additional-ecmascript-features-for-web-browsers (latest as of time of this writing in January 2020) ================================================ FILE: get-started/ch2.md ================================================ # You Don't Know JS Yet: Get Started - 2nd Edition # Chapter 2: Surveying JS The best way to learn JS is to start writing JS. To do that, you need to know how the language works, and that's what we'll focus on here. Even if you've programmed in other languages before, take your time getting comfortable with JS, and make sure to practice each piece. This chapter is not an exhaustive reference on every bit of syntax of the JS language. It's also not intended to be a complete "intro to JS" primer. Instead, we're just going to survey some of the major topic areas of the language. Our goal is to get a better *feel* for it, so that we can move forward writing our own programs with more confidence. We'll revisit many of these topics in successively more detail as you go through the rest of this book, and the rest of the series. Please don't expect this chapter to be a quick read. It's long and there's plenty of detail to chew on. Take your time. | TIP: | | :--- | | If you're still getting familiar with JS, I suggest you reserve plenty of extra time to work through this chapter. Take each section and ponder and explore the topic for awhile. Look through existing JS programs and compare what you see in them to the code and explanations (and opinions!) presented here. You will get a lot more out of the rest of the book and series with a solid foundation of JS's *nature*. | ## Each File is a Program Almost every website (web application) you use is comprised of many different JS files (typically with the .js file extension). It's tempting to think of the whole thing (the application) as one program. But JS sees it differently. In JS, each standalone file is its own separate program. The reason this matters is primarily around error handling. Since JS treats files as programs, one file may fail (during parse/compile or execution) and that will not necessarily prevent the next file from being processed. Obviously, if your application depends on five .js files, and one of them fails, the overall application will probably only partially operate, at best. It's important to ensure that each file works properly, and that to whatever extent possible, they handle failure in other files as gracefully as possible. It may surprise you to consider separate .js files as separate JS programs. From the perspective of your usage of an application, it sure seems like one big program. That's because the execution of the application allows these individual *programs* to cooperate and act as one program. | NOTE: | | :--- | | Many projects use build process tools that end up combining separate files from the project into a single file to be delivered to a web page. When this happens, JS treats this single combined file as the entire program. | The only way multiple standalone .js files act as a single program is by sharing their state (and access to their public functionality) via the "global scope." They mix together in this global scope namespace, so at runtime they act as a whole. Since ES6, JS has also supported a module format in addition to the typical standalone JS program format. Modules are also file-based. If a file is loaded via module-loading mechanism such as an `import` statement or a `