├── .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 ├── external-logos ├── doppler_logo-light.svg ├── doppler_logo.svg ├── fem_logo-light.svg └── fem_logo.svg ├── fixed-it-for-you.png ├── get-started ├── README.md ├── apA.md ├── apB.md ├── ch1.md ├── ch2.md ├── ch3.md ├── ch4.md ├── foreword.md ├── images │ ├── cover.png │ ├── fig1.png │ ├── fig1.svg │ ├── fig2.png │ ├── fig2.svg │ ├── fig3.png │ ├── fig3.svg │ ├── fig4.png │ ├── fig4.svg │ ├── fig5.png │ ├── fig5.svg │ ├── fig6.png │ └── fig6.svg └── 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 ├── images │ ├── cover.png │ ├── fig1.png │ ├── fig2.png │ ├── fig3.png │ ├── fig4.png │ └── fig5.png └── 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 └── unbooks-cover.png /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | indent_style = tab 8 | indent_size = 4 9 | 10 | [*.md] 11 | indent_style = space 12 | indent_size = 4 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/content-question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Content Question 3 | about: Ask a question about something you read in the books? 4 | labels: 5 | 6 | --- 7 | 8 | **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). 9 | 10 | ---- 11 | 12 | **Please type "I already searched for this issue":** 13 | 14 | **Edition:** (1st or 2nd) 15 | 16 | **Book Title:** 17 | 18 | **Chapter:** 19 | 20 | **Section Title:** 21 | 22 | **Question:** 23 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/foreign-translation-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Foreign Translation Request 3 | about: Want to request a translation into a foreign language? 4 | labels: 5 | 6 | --- 7 | 8 | Foreign translations are appreciated, but only for the 3 second edition books. 9 | 10 | **I will not be accepting any new foreign translations for previous editions.** 11 | 12 | ---- 13 | 14 | Please check these issues first: 15 | 16 | * https://github.com/getify/You-Dont-Know-JS/issues?utf8=%E2%9C%93&q=label%3A%22foreign+language+translations%22+ 17 | * https://github.com/getify/You-Dont-Know-JS/issues/9 18 | * https://github.com/getify/You-Dont-Know-JS/issues/900 19 | * https://github.com/getify/You-Dont-Know-JS/issues/1378 20 | 21 | To summarize, the steps for a foreign language translation are: 22 | 23 | 1. Fork this repo 24 | 2. Make your own translation entirely in your fork, preferably of all six books, but at a minimum of one whole book 25 | 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) 26 | 4. Once the branch is created, you can PR to merge your translated work in 27 | 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 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/report-technical-mistake.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Report Technical Mistake 3 | about: Help us fix a mistake in the code. 4 | labels: 5 | 6 | --- 7 | 8 | **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.** 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/textual-grammar-typo.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Textual/Grammar Typo 3 | about: Help us correct a spelling or grammar error in the text. 4 | labels: 5 | 6 | --- 7 | 8 | **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.** 9 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | This book series is now complete, **so in general, we're no longer open to contributions.** 4 | 5 | ## Translations 6 | 7 | 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.** 8 | 9 | Foreign translations are appreciated, but only for the 3 second edition books. 10 | 11 | **I will not be accepting any new foreign translations for previous editions.** 12 | 13 | ---- 14 | 15 | Please check these issues first: 16 | 17 | * https://github.com/getify/You-Dont-Know-JS/issues?utf8=%E2%9C%93&q=label%3A%22foreign+language+translations%22+ 18 | * https://github.com/getify/You-Dont-Know-JS/issues/9 19 | * https://github.com/getify/You-Dont-Know-JS/issues/900 20 | * https://github.com/getify/You-Dont-Know-JS/issues/1378 21 | 22 | To summarize, the steps for a foreign language translation are: 23 | 24 | 1. Fork this repo 25 | 2. Make your own translation entirely in your fork, preferably of all six books, but at a minimum of one whole book 26 | 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) 27 | 4. Once the branch is created, you can PR to merge your translated work in 28 | 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 29 | 30 | ## Reading Experience (Chapter/Section links, etc) 31 | 32 | 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. 33 | 34 | This topic has been brought up many times, and I've considered it. For now, I **do not** accept these kinds of changes into the repo. 35 | 36 | 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. 37 | 38 | As such, this repo **is not optimized for your reading experience.** 39 | 40 | The intended **best reading experience** are the published books (either ebook or print), so I encourage you to purchase them for that purpose. 41 | 42 | ## Editions 43 | 44 | The current (and final) edition of the books is the 2nd edition. 45 | 46 | I **am not accepting any contributions** for 1st edition books, no exceptions. 47 | 48 | ## Typos? 49 | 50 | We're not worried about typo fixes anymore. The books are done and published. 51 | 52 | ## Search First! 53 | 54 | Seriously, no more need for contributions. 55 | 56 | But, if you're going to attempt a contribution, please make sure to search the issues (both open and closed!) first. 57 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Attribution-NonCommercial-NoDerivatives 4.0 International 2 | 3 | ======================================================================= 4 | 5 | Creative Commons Corporation ("Creative Commons") is not a law firm and 6 | does not provide legal services or legal advice. Distribution of 7 | Creative Commons public licenses does not create a lawyer-client or 8 | other relationship. Creative Commons makes its licenses and related 9 | information available on an "as-is" basis. Creative Commons gives no 10 | warranties regarding its licenses, any material licensed under their 11 | terms and conditions, or any related information. Creative Commons 12 | disclaims all liability for damages resulting from their use to the 13 | fullest extent possible. 14 | 15 | Using Creative Commons Public Licenses 16 | 17 | Creative Commons public licenses provide a standard set of terms and 18 | conditions that creators and other rights holders may use to share 19 | original works of authorship and other material subject to copyright 20 | and certain other rights specified in the public license below. The 21 | following considerations are for informational purposes only, are not 22 | exhaustive, and do not form part of our licenses. 23 | 24 | Considerations for licensors: Our public licenses are 25 | intended for use by those authorized to give the public 26 | permission to use material in ways otherwise restricted by 27 | copyright and certain other rights. Our licenses are 28 | irrevocable. Licensors should read and understand the terms 29 | and conditions of the license they choose before applying it. 30 | Licensors should also secure all rights necessary before 31 | applying our licenses so that the public can reuse the 32 | material as expected. Licensors should clearly mark any 33 | material not subject to the license. This includes other CC- 34 | licensed material, or material used under an exception or 35 | limitation to copyright. More considerations for licensors: 36 | wiki.creativecommons.org/Considerations_for_licensors 37 | 38 | Considerations for the public: By using one of our public 39 | licenses, a licensor grants the public permission to use the 40 | licensed material under specified terms and conditions. If 41 | the licensor's permission is not necessary for any reason--for 42 | example, because of any applicable exception or limitation to 43 | copyright--then that use is not regulated by the license. Our 44 | licenses grant only permissions under copyright and certain 45 | other rights that a licensor has authority to grant. Use of 46 | the licensed material may still be restricted for other 47 | reasons, including because others have copyright or other 48 | rights in the material. A licensor may make special requests, 49 | such as asking that all changes be marked or described. 50 | Although not required by our licenses, you are encouraged to 51 | respect those requests where reasonable. More_considerations 52 | for the public: 53 | wiki.creativecommons.org/Considerations_for_licensees 54 | 55 | ======================================================================= 56 | 57 | Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 58 | International Public License 59 | 60 | By exercising the Licensed Rights (defined below), You accept and agree 61 | to be bound by the terms and conditions of this Creative Commons 62 | Attribution-NonCommercial-NoDerivatives 4.0 International Public 63 | License ("Public License"). To the extent this Public License may be 64 | interpreted as a contract, You are granted the Licensed Rights in 65 | consideration of Your acceptance of these terms and conditions, and the 66 | Licensor grants You such rights in consideration of benefits the 67 | Licensor receives from making the Licensed Material available under 68 | these terms and conditions. 69 | 70 | 71 | Section 1 -- Definitions. 72 | 73 | a. Adapted Material means material subject to Copyright and Similar 74 | Rights that is derived from or based upon the Licensed Material 75 | and in which the Licensed Material is translated, altered, 76 | arranged, transformed, or otherwise modified in a manner requiring 77 | permission under the Copyright and Similar Rights held by the 78 | Licensor. For purposes of this Public License, where the Licensed 79 | Material is a musical work, performance, or sound recording, 80 | Adapted Material is always produced where the Licensed Material is 81 | synched in timed relation with a moving image. 82 | 83 | b. Copyright and Similar Rights means copyright and/or similar rights 84 | closely related to copyright including, without limitation, 85 | performance, broadcast, sound recording, and Sui Generis Database 86 | Rights, without regard to how the rights are labeled or 87 | categorized. For purposes of this Public License, the rights 88 | specified in Section 2(b)(1)-(2) are not Copyright and Similar 89 | Rights. 90 | 91 | c. Effective Technological Measures means those measures that, in the 92 | absence of proper authority, may not be circumvented under laws 93 | fulfilling obligations under Article 11 of the WIPO Copyright 94 | Treaty adopted on December 20, 1996, and/or similar international 95 | agreements. 96 | 97 | d. Exceptions and Limitations means fair use, fair dealing, and/or 98 | any other exception or limitation to Copyright and Similar Rights 99 | that applies to Your use of the Licensed Material. 100 | 101 | e. Licensed Material means the artistic or literary work, database, 102 | or other material to which the Licensor applied this Public 103 | License. 104 | 105 | f. Licensed Rights means the rights granted to You subject to the 106 | terms and conditions of this Public License, which are limited to 107 | all Copyright and Similar Rights that apply to Your use of the 108 | Licensed Material and that the Licensor has authority to license. 109 | 110 | g. Licensor means the individual(s) or entity(ies) granting rights 111 | under this Public License. 112 | 113 | h. NonCommercial means not primarily intended for or directed towards 114 | commercial advantage or monetary compensation. For purposes of 115 | this Public License, the exchange of the Licensed Material for 116 | other material subject to Copyright and Similar Rights by digital 117 | file-sharing or similar means is NonCommercial provided there is 118 | no payment of monetary compensation in connection with the 119 | exchange. 120 | 121 | i. Share means to provide material to the public by any means or 122 | process that requires permission under the Licensed Rights, such 123 | as reproduction, public display, public performance, distribution, 124 | dissemination, communication, or importation, and to make material 125 | available to the public including in ways that members of the 126 | public may access the material from a place and at a time 127 | individually chosen by them. 128 | 129 | j. Sui Generis Database Rights means rights other than copyright 130 | resulting from Directive 96/9/EC of the European Parliament and of 131 | the Council of 11 March 1996 on the legal protection of databases, 132 | as amended and/or succeeded, as well as other essentially 133 | equivalent rights anywhere in the world. 134 | 135 | k. You means the individual or entity exercising the Licensed Rights 136 | under this Public License. Your has a corresponding meaning. 137 | 138 | 139 | Section 2 -- Scope. 140 | 141 | a. License grant. 142 | 143 | 1. Subject to the terms and conditions of this Public License, 144 | the Licensor hereby grants You a worldwide, royalty-free, 145 | non-sublicensable, non-exclusive, irrevocable license to 146 | exercise the Licensed Rights in the Licensed Material to: 147 | 148 | a. reproduce and Share the Licensed Material, in whole or 149 | in part, for NonCommercial purposes only; and 150 | 151 | b. produce and reproduce, but not Share, Adapted Material 152 | for NonCommercial purposes only. 153 | 154 | 2. Exceptions and Limitations. For the avoidance of doubt, where 155 | Exceptions and Limitations apply to Your use, this Public 156 | License does not apply, and You do not need to comply with 157 | its terms and conditions. 158 | 159 | 3. Term. The term of this Public License is specified in Section 160 | 6(a). 161 | 162 | 4. Media and formats; technical modifications allowed. The 163 | Licensor authorizes You to exercise the Licensed Rights in 164 | all media and formats whether now known or hereafter created, 165 | and to make technical modifications necessary to do so. The 166 | Licensor waives and/or agrees not to assert any right or 167 | authority to forbid You from making technical modifications 168 | necessary to exercise the Licensed Rights, including 169 | technical modifications necessary to circumvent Effective 170 | Technological Measures. For purposes of this Public License, 171 | simply making modifications authorized by this Section 2(a) 172 | (4) never produces Adapted Material. 173 | 174 | 5. Downstream recipients. 175 | 176 | a. Offer from the Licensor -- Licensed Material. Every 177 | recipient of the Licensed Material automatically 178 | receives an offer from the Licensor to exercise the 179 | Licensed Rights under the terms and conditions of this 180 | Public License. 181 | 182 | b. No downstream restrictions. You may not offer or impose 183 | any additional or different terms or conditions on, or 184 | apply any Effective Technological Measures to, the 185 | Licensed Material if doing so restricts exercise of the 186 | Licensed Rights by any recipient of the Licensed 187 | Material. 188 | 189 | 6. No endorsement. Nothing in this Public License constitutes or 190 | may be construed as permission to assert or imply that You 191 | are, or that Your use of the Licensed Material is, connected 192 | with, or sponsored, endorsed, or granted official status by, 193 | the Licensor or others designated to receive attribution as 194 | provided in Section 3(a)(1)(A)(i). 195 | 196 | b. Other rights. 197 | 198 | 1. Moral rights, such as the right of integrity, are not 199 | licensed under this Public License, nor are publicity, 200 | privacy, and/or other similar personality rights; however, to 201 | the extent possible, the Licensor waives and/or agrees not to 202 | assert any such rights held by the Licensor to the limited 203 | extent necessary to allow You to exercise the Licensed 204 | Rights, but not otherwise. 205 | 206 | 2. Patent and trademark rights are not licensed under this 207 | Public License. 208 | 209 | 3. To the extent possible, the Licensor waives any right to 210 | collect royalties from You for the exercise of the Licensed 211 | Rights, whether directly or through a collecting society 212 | under any voluntary or waivable statutory or compulsory 213 | licensing scheme. In all other cases the Licensor expressly 214 | reserves any right to collect such royalties, including when 215 | the Licensed Material is used other than for NonCommercial 216 | purposes. 217 | 218 | 219 | Section 3 -- License Conditions. 220 | 221 | Your exercise of the Licensed Rights is expressly made subject to the 222 | following conditions. 223 | 224 | a. Attribution. 225 | 226 | 1. If You Share the Licensed Material, You must: 227 | 228 | a. retain the following if it is supplied by the Licensor 229 | with the Licensed Material: 230 | 231 | i. identification of the creator(s) of the Licensed 232 | Material and any others designated to receive 233 | attribution, in any reasonable manner requested by 234 | the Licensor (including by pseudonym if 235 | designated); 236 | 237 | ii. a copyright notice; 238 | 239 | iii. a notice that refers to this Public License; 240 | 241 | iv. a notice that refers to the disclaimer of 242 | warranties; 243 | 244 | v. a URI or hyperlink to the Licensed Material to the 245 | extent reasonably practicable; 246 | 247 | b. indicate if You modified the Licensed Material and 248 | retain an indication of any previous modifications; and 249 | 250 | c. indicate the Licensed Material is licensed under this 251 | Public License, and include the text of, or the URI or 252 | hyperlink to, this Public License. 253 | 254 | For the avoidance of doubt, You do not have permission under 255 | this Public License to Share Adapted Material. 256 | 257 | 2. You may satisfy the conditions in Section 3(a)(1) in any 258 | reasonable manner based on the medium, means, and context in 259 | which You Share the Licensed Material. For example, it may be 260 | reasonable to satisfy the conditions by providing a URI or 261 | hyperlink to a resource that includes the required 262 | information. 263 | 264 | 3. If requested by the Licensor, You must remove any of the 265 | information required by Section 3(a)(1)(A) to the extent 266 | reasonably practicable. 267 | 268 | 269 | Section 4 -- Sui Generis Database Rights. 270 | 271 | Where the Licensed Rights include Sui Generis Database Rights that 272 | apply to Your use of the Licensed Material: 273 | 274 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right 275 | to extract, reuse, reproduce, and Share all or a substantial 276 | portion of the contents of the database for NonCommercial purposes 277 | only and provided You do not Share Adapted Material; 278 | 279 | b. if You include all or a substantial portion of the database 280 | contents in a database in which You have Sui Generis Database 281 | Rights, then the database in which You have Sui Generis Database 282 | Rights (but not its individual contents) is Adapted Material; and 283 | 284 | c. You must comply with the conditions in Section 3(a) if You Share 285 | all or a substantial portion of the contents of the database. 286 | 287 | For the avoidance of doubt, this Section 4 supplements and does not 288 | replace Your obligations under this Public License where the Licensed 289 | Rights include other Copyright and Similar Rights. 290 | 291 | 292 | Section 5 -- Disclaimer of Warranties and Limitation of Liability. 293 | 294 | a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE 295 | EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS 296 | AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF 297 | ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, 298 | IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, 299 | WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR 300 | PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, 301 | ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT 302 | KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT 303 | ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. 304 | 305 | b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE 306 | TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, 307 | NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, 308 | INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, 309 | COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR 310 | USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN 311 | ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR 312 | DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR 313 | IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. 314 | 315 | c. The disclaimer of warranties and limitation of liability provided 316 | above shall be interpreted in a manner that, to the extent 317 | possible, most closely approximates an absolute disclaimer and 318 | waiver of all liability. 319 | 320 | 321 | Section 6 -- Term and Termination. 322 | 323 | a. This Public License applies for the term of the Copyright and 324 | Similar Rights licensed here. However, if You fail to comply with 325 | this Public License, then Your rights under this Public License 326 | terminate automatically. 327 | 328 | b. Where Your right to use the Licensed Material has terminated under 329 | Section 6(a), it reinstates: 330 | 331 | 1. automatically as of the date the violation is cured, provided 332 | it is cured within 30 days of Your discovery of the 333 | violation; or 334 | 335 | 2. upon express reinstatement by the Licensor. 336 | 337 | For the avoidance of doubt, this Section 6(b) does not affect any 338 | right the Licensor may have to seek remedies for Your violations 339 | of this Public License. 340 | 341 | c. For the avoidance of doubt, the Licensor may also offer the 342 | Licensed Material under separate terms or conditions or stop 343 | distributing the Licensed Material at any time; however, doing so 344 | will not terminate this Public License. 345 | 346 | d. Sections 1, 5, 6, 7, and 8 survive termination of this Public 347 | License. 348 | 349 | 350 | Section 7 -- Other Terms and Conditions. 351 | 352 | a. The Licensor shall not be bound by any additional or different 353 | terms or conditions communicated by You unless expressly agreed. 354 | 355 | b. Any arrangements, understandings, or agreements regarding the 356 | Licensed Material not stated herein are separate from and 357 | independent of the terms and conditions of this Public License. 358 | 359 | 360 | Section 8 -- Interpretation. 361 | 362 | a. For the avoidance of doubt, this Public License does not, and 363 | shall not be interpreted to, reduce, limit, restrict, or impose 364 | conditions on any use of the Licensed Material that could lawfully 365 | be made without permission under this Public License. 366 | 367 | b. To the extent possible, if any provision of this Public License is 368 | deemed unenforceable, it shall be automatically reformed to the 369 | minimum extent necessary to make it enforceable. If the provision 370 | cannot be reformed, it shall be severed from this Public License 371 | without affecting the enforceability of the remaining terms and 372 | conditions. 373 | 374 | c. No term or condition of this Public License will be waived and no 375 | failure to comply consented to unless expressly agreed to by the 376 | Licensor. 377 | 378 | d. Nothing in this Public License constitutes or may be interpreted 379 | as a limitation upon, or waiver of, any privileges and immunities 380 | that apply to the Licensor or You, including from the legal 381 | processes of any jurisdiction or authority. 382 | 383 | ======================================================================= 384 | 385 | Creative Commons is not a party to its public 386 | licenses. Notwithstanding, Creative Commons may elect to apply one of 387 | its public licenses to material it publishes and in those instances 388 | will be considered the “Licensor.” The text of the Creative Commons 389 | public licenses is dedicated to the public domain under the CC0 Public 390 | Domain Dedication. Except for the limited purpose of indicating that 391 | material is shared under a Creative Commons public license or as 392 | otherwise permitted by the Creative Commons policies published at 393 | creativecommons.org/policies, Creative Commons does not authorize the 394 | use of the trademark "Creative Commons" or any other trademark or logo 395 | of Creative Commons without its prior written consent including, 396 | without limitation, in connection with any unauthorized modifications 397 | to any of its public licenses or any other arrangements, 398 | understandings, or agreements concerning use of licensed material. For 399 | the avoidance of doubt, this paragraph does not form part of the 400 | public licenses. 401 | 402 | Creative Commons may be contacted at creativecommons.org. 403 | -------------------------------------------------------------------------------- /PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | **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). 2 | 3 | Specifically quoting these guidelines regarding typos: 4 | 5 | > Typos? 6 | > 7 | > Please don't worry about minor text typos. These will almost certainly be caught during the editing process. 8 | > 9 | > 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. 10 | 11 | ---- 12 | 13 | **Please type "I already searched for this issue":** 14 | 15 | **Edition:** (pull requests not accepted for previous editions) 16 | 17 | **Book Title:** 18 | 19 | **Chapter:** 20 | 21 | **Section Title:** 22 | 23 | **Topic:** 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # You Don't Know JS Yet (book series) - 2nd Edition 2 | 3 | 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: 4 | 5 |    6 |    7 | 8 | 9 | **To read more about the motivations and perspective behind this book series, check out the [Preface](preface.md).** 10 | 11 | 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). 12 | 13 | ## Titles 14 | 15 | I recommend reading the **second edition** books in this order: 16 | 17 | * [Get Started](get-started/README.md) | [Buy on Leanpub](https://leanpub.com/ydkjsy-get-started) | [Buy on Amazon](https://www.amazon.com/dp/B084BNMN7T) 18 | * [Scope & Closures](scope-closures/README.md) | [Buy on Leanpub](https://leanpub.com/ydkjsy-scope-closures) | [Buy on Amazon](https://www.amazon.com/dp/B08634PZ3N) 19 | * "The Unbooks" (ebook) | [Buy on Leanpub](https://leanpub.com/ydkjsy-unbooks) | [Buy on Amazon](https://www.amazon.com/dp/B0F7H1DN5S) 20 | - [Objects & Classes](objects-classes/README.md) (draft stable) 21 | - [Types & Grammar](types-grammar/README.md) (rough draft) 22 | - ~~Sync & Async (canceled)~~ 23 | - ~~ES.Next & Beyond (canceled)~~ 24 | 25 | 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). 26 | 27 | ## Publishing 28 | 29 | As always, you'll be able to read these books online here entirely for free. 30 | 31 | 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. 32 | 33 | 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: 34 | 35 | * [Github Sponsorship](https://github.com/users/getify/sponsorship) 36 | * [Patreon](https://www.patreon.com/getify) 37 | * [Paypal](https://www.paypal.me/getify) 38 | 39 | ## Contributions 40 | 41 | This book series is now complete, and is **not open to further contributions**. 42 | 43 | Thank you to those who've been part of the 11 years journey of this book series. 44 | 45 | ## Thank You To These Wonderful Sponsors 46 | 47 | [![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) 48 | 49 | [![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) 50 | 51 | **The first two books of the second edition** are exclusively sponsored by **[Frontend Masters](https://frontendmasters.com/?code=simpson)**. 52 | 53 | 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. 54 | 55 | **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. 56 | 57 | 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! 58 | 59 | ---- 60 | 61 | ## License & Copyright 62 | 63 | The materials herein are all © 2019-2025 Kyle Simpson. 64 | 65 | Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 4.0 Unported License. 66 | -------------------------------------------------------------------------------- /es-next-beyond/README.md: -------------------------------------------------------------------------------- 1 | # You Don't Know JS Yet: ES.Next & Beyond - 2nd Edition 2 | 3 | | NOTE: | 4 | | :--- | 5 | | Work in progress | 6 | 7 | [Table of Contents](toc.md) 8 | 9 | * [Foreword](foreword.md) (by TBA) 10 | * [Preface](../preface.md) 11 | * [Chapter 1: TODO](ch1.md) 12 | -------------------------------------------------------------------------------- /es-next-beyond/ch1.md: -------------------------------------------------------------------------------- 1 | # You Don't Know JS Yet: ES.Next & Beyond - 2nd Edition 2 | # Chapter 1: TODO 3 | 4 | | NOTE: | 5 | | :--- | 6 | | Work in progress | 7 | 8 | -------------------------------------------------------------------------------- /es-next-beyond/foreword.md: -------------------------------------------------------------------------------- 1 | # You Don't Know JS Yet: ES.Next & Beyond - 2nd Edition 2 | # Foreword 3 | 4 | | NOTE: | 5 | | :--- | 6 | | Work in progress | 7 | -------------------------------------------------------------------------------- /es-next-beyond/toc.md: -------------------------------------------------------------------------------- 1 | # You Don't Know JS Yet: ES.Next & Beyond - 2nd Edition 2 | 3 | | NOTE: | 4 | | :--- | 5 | | Work in progress | 6 | 7 | ## Table of Contents 8 | 9 | * Foreword 10 | * Preface 11 | * Chapter 1: TODO 12 | * TODO 13 | -------------------------------------------------------------------------------- /external-logos/doppler_logo-light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /external-logos/doppler_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /external-logos/fem_logo-light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /external-logos/fem_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /fixed-it-for-you.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getify/You-Dont-Know-JS/e3f784bcb18ba47a9e6ced0866bc361393fb299f/fixed-it-for-you.png -------------------------------------------------------------------------------- /get-started/README.md: -------------------------------------------------------------------------------- 1 | # You Don't Know JS Yet: Get Started - 2nd Edition 2 | 3 | 4 | 5 | ----- 6 | 7 | **[Purchase ebook/PDF from Leanpub](https://leanpub.com/ydkjsy-get-started)** 8 | 9 | ----- 10 | 11 | [Table of Contents](toc.md) 12 | 13 | * [Foreword](foreword.md) (by [Brian Holt](https://twitter.com/holtbt)) 14 | * [Preface](../preface.md) 15 | * [Chapter 1: What Is JavaScript?](ch1.md) 16 | * [Chapter 2: Surveying JS](ch2.md) 17 | * [Chapter 3: Digging to the Roots of JS](ch3.md) 18 | * [Chapter 4: The Bigger Picture](ch4.md) 19 | * [Appendix A: Exploring Further](apA.md) 20 | * [Appendix B: Practice, Practice, Practice!](apB.md) 21 | -------------------------------------------------------------------------------- /get-started/apA.md: -------------------------------------------------------------------------------- 1 | # You Don't Know JS Yet: Get Started - 2nd Edition 2 | # Appendix A: Exploring Further 3 | 4 | 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. 5 | 6 | ## Values vs. References 7 | 8 | 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. 9 | 10 | 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. 11 | 12 | If you assign/pass a value itself, the value is copied. For example: 13 | 14 | ```js 15 | var myName = "Kyle"; 16 | 17 | var yourName = myName; 18 | ``` 19 | 20 | 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**. 21 | 22 | Here's how you can prove there's two separate values involved: 23 | 24 | ```js 25 | var myName = "Kyle"; 26 | 27 | var yourName = myName; 28 | 29 | myName = "Frank"; 30 | 31 | console.log(myName); 32 | // Frank 33 | 34 | console.log(yourName); 35 | // Kyle 36 | ``` 37 | 38 | 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. 39 | 40 | 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. 41 | 42 | Consider: 43 | 44 | ```js 45 | var myAddress = { 46 | street: "123 JS Blvd", 47 | city: "Austin", 48 | state: "TX" 49 | }; 50 | 51 | var yourAddress = myAddress; 52 | 53 | // I've got to move to a new house! 54 | myAddress.street = "456 TS Ave"; 55 | 56 | console.log(yourAddress.street); 57 | // 456 TS Ave 58 | ``` 59 | 60 | 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. 61 | 62 | 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. 63 | 64 | ## So Many Function Forms 65 | 66 | Recall this snippet from the "Functions" section in Chapter 2: 67 | 68 | ```js 69 | var awesomeFunction = function(coolThings) { 70 | // .. 71 | return amazingStuff; 72 | }; 73 | ``` 74 | 75 | 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: 76 | 77 | ```js 78 | awesomeFunction.name; 79 | // "awesomeFunction" 80 | ``` 81 | 82 | 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. 83 | 84 | 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)". 85 | 86 | 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. 87 | 88 | Compare the anonymous function expression form to: 89 | 90 | ```js 91 | // let awesomeFunction = .. 92 | // const awesomeFunction = .. 93 | var awesomeFunction = function someName(coolThings) { 94 | // .. 95 | return amazingStuff; 96 | }; 97 | 98 | awesomeFunction.name; 99 | // "someName" 100 | ``` 101 | 102 | 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. 103 | 104 | Notice also that the explicit function name, the identifier `someName`, takes precedence when assigning a *name* for the `name` property. 105 | 106 | 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. 107 | 108 | 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. 109 | 110 | 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. 111 | 112 | There are, regrettably in some respects, many other function definition forms in JS as of early 2020 (maybe more in the future!). 113 | 114 | Here are some more declaration forms: 115 | 116 | ```js 117 | // generator function declaration 118 | function *two() { .. } 119 | 120 | // async function declaration 121 | async function three() { .. } 122 | 123 | // async generator function declaration 124 | async function *four() { .. } 125 | 126 | // named function export declaration (ES6 modules) 127 | export function five() { .. } 128 | ``` 129 | 130 | And here are some more of the (many!) function expression forms: 131 | 132 | ```js 133 | // IIFE 134 | (function(){ .. })(); 135 | (function namedIIFE(){ .. })(); 136 | 137 | // asynchronous IIFE 138 | (async function(){ .. })(); 139 | (async function namedAIIFE(){ .. })(); 140 | 141 | // arrow function expressions 142 | var f; 143 | f = () => 42; 144 | f = x => x * 2; 145 | f = (x) => x * 2; 146 | f = (x,y) => x * y; 147 | f = x => ({ x: x * 2 }); 148 | f = x => { return x * 2; }; 149 | f = async x => { 150 | var y = await doSomethingAsync(x); 151 | return y * 2; 152 | }; 153 | someOperation( x => x * 2 ); 154 | // .. 155 | ``` 156 | 157 | 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). 158 | 159 | 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. 160 | 161 | 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": 162 | 163 | ```js 164 | class SomethingKindaGreat { 165 | // class methods 166 | coolMethod() { .. } // no commas! 167 | boringMethod() { .. } 168 | } 169 | 170 | var EntirelyDifferent = { 171 | // object methods 172 | coolMethod() { .. }, // commas! 173 | boringMethod() { .. }, 174 | 175 | // (anonymous) function expression property 176 | oldSchool: function() { .. } 177 | }; 178 | ``` 179 | 180 | Phew! That's a lot of different ways to define functions. 181 | 182 | 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! 183 | 184 | ## Coercive Conditional Comparison 185 | 186 | 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. 187 | 188 | `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. 189 | 190 | Consider: 191 | 192 | ```js 193 | var x = 1; 194 | 195 | if (x) { 196 | // will run! 197 | } 198 | 199 | while (x) { 200 | // will run, once! 201 | x = false; 202 | } 203 | ``` 204 | 205 | You might think of these `(x)` conditional expressions like this: 206 | 207 | ```js 208 | var x = 1; 209 | 210 | if (x == true) { 211 | // will run! 212 | } 213 | 214 | while (x == true) { 215 | // will run, once! 216 | x = false; 217 | } 218 | ``` 219 | 220 | In this specific case -- the value of `x` being `1` -- that mental model works, but it's not accurate more broadly. Consider: 221 | 222 | ```js 223 | var x = "hello"; 224 | 225 | if (x) { 226 | // will run! 227 | } 228 | 229 | if (x == true) { 230 | // won't run :( 231 | } 232 | ``` 233 | 234 | Oops. So what is the `if` statement actually doing? This is the more accurate mental model: 235 | 236 | ```js 237 | var x = "hello"; 238 | 239 | if (Boolean(x) == true) { 240 | // will run 241 | } 242 | 243 | // which is the same as: 244 | 245 | if (Boolean(x) === true) { 246 | // will run 247 | } 248 | ``` 249 | 250 | 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. 251 | 252 | You just can't get away from coercions in JS comparisons. Buckle down and learn them. 253 | 254 | ## Prototypal "Classes" 255 | 256 | In Chapter 3, we introduced prototypes and showed how we can link objects through a prototype chain. 257 | 258 | 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. 259 | 260 | | TIP: | 261 | | :--- | 262 | | 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! | 263 | 264 | Let's first recall the `Object.create(..)` style of coding: 265 | 266 | ```js 267 | var Classroom = { 268 | welcome() { 269 | console.log("Welcome, students!"); 270 | } 271 | }; 272 | 273 | var mathClass = Object.create(Classroom); 274 | 275 | mathClass.welcome(); 276 | // Welcome, students! 277 | ``` 278 | 279 | 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`. 280 | 281 | The prototypal class pattern would have labeled this delegation behavior "inheritance," and alternatively have defined it (with the same behavior) as: 282 | 283 | ```js 284 | function Classroom() { 285 | // .. 286 | } 287 | 288 | Classroom.prototype.welcome = function hello() { 289 | console.log("Welcome, students!"); 290 | }; 291 | 292 | var mathClass = new Classroom(); 293 | 294 | mathClass.welcome(); 295 | // Welcome, students! 296 | ``` 297 | 298 | 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`. 299 | 300 | We add a `welcome` property on that empty object (called `Classroom.prototype`), pointing at the `hello()` function. 301 | 302 | Then `new Classroom()` creates a new object (assigned to `mathClass`), and prototype links it to the existing `Classroom.prototype` object. 303 | 304 | Though `mathClass` does not have a `welcome()` property/function, it successfully delegates to the function `Classroom.prototype.welcome()`. 305 | 306 | This "prototypal class" pattern is now strongly discouraged, in favor of using ES6's `class` mechanism: 307 | 308 | ```js 309 | class Classroom { 310 | constructor() { 311 | // .. 312 | } 313 | 314 | welcome() { 315 | console.log("Welcome, students!"); 316 | } 317 | } 318 | 319 | var mathClass = new Classroom(); 320 | 321 | mathClass.welcome(); 322 | // Welcome, students! 323 | ``` 324 | 325 | 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". 326 | -------------------------------------------------------------------------------- /get-started/apB.md: -------------------------------------------------------------------------------- 1 | # You Don't Know JS Yet: Get Started - 2nd Edition 2 | # Appendix B: Practice, Practice, Practice! 3 | 4 | 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. 5 | 6 | ## Practicing Comparisons 7 | 8 | Let's practice working with value types and comparisons (Chapter 4, Pillar 3) where coercion will need to be involved. 9 | 10 | `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. 11 | 12 | ```js 13 | const dayStart = "07:30"; 14 | const dayEnd = "17:45"; 15 | 16 | function scheduleMeeting(startTime,durationMinutes) { 17 | // ..TODO.. 18 | } 19 | 20 | scheduleMeeting("7:00",15); // false 21 | scheduleMeeting("07:15",30); // false 22 | scheduleMeeting("7:30",30); // true 23 | scheduleMeeting("11:30",60); // true 24 | scheduleMeeting("17:00",45); // true 25 | scheduleMeeting("17:30",30); // false 26 | scheduleMeeting("18:00",15); // false 27 | ``` 28 | 29 | 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. 30 | 31 | ## Practicing Closure 32 | 33 | Now let's practice with closure (Chapter 4, Pillar 1). 34 | 35 | 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. 36 | 37 | ```js 38 | function range(start,end) { 39 | // ..TODO.. 40 | } 41 | 42 | range(3,3); // [3] 43 | range(3,8); // [3,4,5,6,7,8] 44 | range(3,0); // [] 45 | 46 | var start3 = range(3); 47 | var start4 = range(4); 48 | 49 | start3(3); // [3] 50 | start3(8); // [3,4,5,6,7,8] 51 | start3(0); // [] 52 | 53 | start4(6); // [4,5,6] 54 | ``` 55 | 56 | Try to solve this yourself first. 57 | 58 | Once you have code that works, *compare* your solution(s) to the code in "Suggested Solutions" at the end of this appendix. 59 | 60 | ## Practicing Prototypes 61 | 62 | Finally, let's work on `this` and objects linked via prototype (Chapter 4, Pillar 2). 63 | 64 | Define a slot machine with three reels that can individually `spin()`, and then `display()` the current contents of all the reels. 65 | 66 | 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. 67 | 68 | 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. 69 | 70 | ```js 71 | function randMax(max) { 72 | return Math.trunc(1E9 * Math.random()) % max; 73 | } 74 | 75 | var reel = { 76 | symbols: [ 77 | "♠", "♥", "♦", "♣", "☺", "★", "☾", "☀" 78 | ], 79 | spin() { 80 | if (this.position == null) { 81 | this.position = randMax( 82 | this.symbols.length - 1 83 | ); 84 | } 85 | this.position = ( 86 | this.position + 100 + randMax(100) 87 | ) % this.symbols.length; 88 | }, 89 | display() { 90 | if (this.position == null) { 91 | this.position = randMax( 92 | this.symbols.length - 1 93 | ); 94 | } 95 | return this.symbols[this.position]; 96 | } 97 | }; 98 | 99 | var slotMachine = { 100 | reels: [ 101 | // this slot machine needs 3 separate reels 102 | // hint: Object.create(..) 103 | ], 104 | spin() { 105 | this.reels.forEach(function spinReel(reel){ 106 | reel.spin(); 107 | }); 108 | }, 109 | display() { 110 | // TODO 111 | } 112 | }; 113 | 114 | slotMachine.spin(); 115 | slotMachine.display(); 116 | // ☾ | ☀ | ★ 117 | // ☀ | ♠ | ☾ 118 | // ♠ | ♥ | ☀ 119 | 120 | slotMachine.spin(); 121 | slotMachine.display(); 122 | // ♦ | ♠ | ♣ 123 | // ♣ | ♥ | ☺ 124 | // ☺ | ♦ | ★ 125 | ``` 126 | 127 | Try to solve this yourself first. 128 | 129 | Hints: 130 | 131 | * Use the `%` modulo operator for wrapping `position` as you access symbols circularly around a reel. 132 | 133 | * 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. 134 | 135 | * 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. 136 | 137 | Once you have code that works, *compare* your solution(s) to the code in "Suggested Solutions" at the end of this appendix. 138 | 139 | ## Suggested Solutions 140 | 141 | 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. 142 | 143 | Suggested solution for "Comparisons" (Pillar 3) practice: 144 | 145 | ```js 146 | const dayStart = "07:30"; 147 | const dayEnd = "17:45"; 148 | 149 | function scheduleMeeting(startTime,durationMinutes) { 150 | var [ , meetingStartHour, meetingStartMinutes ] = 151 | startTime.match(/^(\d{1,2}):(\d{2})$/) || []; 152 | 153 | durationMinutes = Number(durationMinutes); 154 | 155 | if ( 156 | typeof meetingStartHour == "string" && 157 | typeof meetingStartMinutes == "string" 158 | ) { 159 | let durationHours = 160 | Math.floor(durationMinutes / 60); 161 | durationMinutes = 162 | durationMinutes - (durationHours * 60); 163 | let meetingEndHour = 164 | Number(meetingStartHour) + durationHours; 165 | let meetingEndMinutes = 166 | Number(meetingStartMinutes) + 167 | durationMinutes; 168 | 169 | if (meetingEndMinutes >= 60) { 170 | meetingEndHour = meetingEndHour + 1; 171 | meetingEndMinutes = 172 | meetingEndMinutes - 60; 173 | } 174 | 175 | // re-compose fully-qualified time strings 176 | // (to make comparison easier) 177 | let meetingStart = `${ 178 | meetingStartHour.padStart(2,"0") 179 | }:${ 180 | meetingStartMinutes.padStart(2,"0") 181 | }`; 182 | let meetingEnd = `${ 183 | String(meetingEndHour).padStart(2,"0") 184 | }:${ 185 | String(meetingEndMinutes).padStart(2,"0") 186 | }`; 187 | 188 | // NOTE: since expressions are all strings, 189 | // comparisons here are alphabetic, but it's 190 | // safe here since they're fully qualified 191 | // time strings (ie, "07:15" < "07:30") 192 | return ( 193 | meetingStart >= dayStart && 194 | meetingEnd <= dayEnd 195 | ); 196 | } 197 | 198 | return false; 199 | } 200 | 201 | scheduleMeeting("7:00",15); // false 202 | scheduleMeeting("07:15",30); // false 203 | scheduleMeeting("7:30",30); // true 204 | scheduleMeeting("11:30",60); // true 205 | scheduleMeeting("17:00",45); // true 206 | scheduleMeeting("17:30",30); // false 207 | scheduleMeeting("18:00",15); // false 208 | ``` 209 | 210 | ---- 211 | 212 | Suggested solution for "Closure" (Pillar 1) practice: 213 | 214 | ```js 215 | function range(start,end) { 216 | start = Number(start) || 0; 217 | 218 | if (end === undefined) { 219 | return function getEnd(end) { 220 | return getRange(start,end); 221 | }; 222 | } 223 | else { 224 | end = Number(end) || 0; 225 | return getRange(start,end); 226 | } 227 | 228 | 229 | // ********************** 230 | 231 | function getRange(start,end) { 232 | var ret = []; 233 | for (let i = start; i <= end; i++) { 234 | ret.push(i); 235 | } 236 | return ret; 237 | } 238 | } 239 | 240 | range(3,3); // [3] 241 | range(3,8); // [3,4,5,6,7,8] 242 | range(3,0); // [] 243 | 244 | var start3 = range(3); 245 | var start4 = range(4); 246 | 247 | start3(3); // [3] 248 | start3(8); // [3,4,5,6,7,8] 249 | start3(0); // [] 250 | 251 | start4(6); // [4,5,6] 252 | ``` 253 | 254 | ---- 255 | 256 | Suggested solution for "Prototypes" (Pillar 2) practice: 257 | 258 | ```js 259 | function randMax(max) { 260 | return Math.trunc(1E9 * Math.random()) % max; 261 | } 262 | 263 | var reel = { 264 | symbols: [ 265 | "♠", "♥", "♦", "♣", "☺", "★", "☾", "☀" 266 | ], 267 | spin() { 268 | if (this.position == null) { 269 | this.position = randMax( 270 | this.symbols.length - 1 271 | ); 272 | } 273 | this.position = ( 274 | this.position + 100 + randMax(100) 275 | ) % this.symbols.length; 276 | }, 277 | display() { 278 | if (this.position == null) { 279 | this.position = randMax( 280 | this.symbols.length - 1 281 | ); 282 | } 283 | return this.symbols[this.position]; 284 | } 285 | }; 286 | 287 | var slotMachine = { 288 | reels: [ 289 | Object.create(reel), 290 | Object.create(reel), 291 | Object.create(reel) 292 | ], 293 | spin() { 294 | this.reels.forEach(function spinReel(reel){ 295 | reel.spin(); 296 | }); 297 | }, 298 | display() { 299 | var lines = []; 300 | 301 | // display all 3 lines on the slot machine 302 | for ( 303 | let linePos = -1; linePos <= 1; linePos++ 304 | ) { 305 | let line = this.reels.map( 306 | function getSlot(reel){ 307 | var slot = Object.create(reel); 308 | slot.position = ( 309 | reel.symbols.length + 310 | reel.position + 311 | linePos 312 | ) % reel.symbols.length; 313 | return slot.display(); 314 | } 315 | ); 316 | lines.push(line.join(" | ")); 317 | } 318 | 319 | return lines.join("\n"); 320 | } 321 | }; 322 | 323 | slotMachine.spin(); 324 | slotMachine.display(); 325 | // ☾ | ☀ | ★ 326 | // ☀ | ♠ | ☾ 327 | // ♠ | ♥ | ☀ 328 | 329 | slotMachine.spin(); 330 | slotMachine.display(); 331 | // ♦ | ♠ | ♣ 332 | // ♣ | ♥ | ☺ 333 | // ☺ | ♦ | ★ 334 | ``` 335 | 336 | 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! 337 | -------------------------------------------------------------------------------- /get-started/ch4.md: -------------------------------------------------------------------------------- 1 | # You Don't Know JS Yet: Get Started - 2nd Edition 2 | # Chapter 4: The Bigger Picture 3 | 4 | This book surveys what you need to be aware of as you *get started* with JS. The goal is to fill in gaps that readers newer to JS might have tripped over in their early encounters with the language. I also hope that we've hinted at enough deeper detail throughout to pique your curiosity to want to dig more into the language. 5 | 6 | The rest of the books in this series are where we will unpack all of the rest of the language, in far greater detail than we could have done in a few brief chapters here. 7 | 8 | Remember to take your time, though. Rather than rushing onto the next book in an attempt to churn through all the books expediently, spend some time going back over the material in this book. Spend some more time looking through code in your current projects, and comparing what you see to what's been discussed so far. 9 | 10 | When you're ready, this final chapter divides the organization of the JS language into three main pillars, then offers a brief roadmap of what to expect from the rest of the book series, and how I suggest you proceed. Also, don't skip the appendices, especially Appendix B, "Practice, Practice, Practice!". 11 | 12 | ## Pillar 1: Scope and Closure 13 | 14 | The organization of variables into units of scope (functions, blocks) is one of the most foundational characteristics of any language; perhaps no other characteristic has a greater impact on how programs behave. 15 | 16 | Scopes are like buckets, and variables are like marbles you put into those buckets. The scope model of a language is like the rules that help you determine which color marbles go in which matching-color buckets. 17 | 18 | Scopes nest inside each other, and for any given expression or statement, only variables at that level of scope nesting, or in higher/outer scopes, are accessible; variables from lower/inner scopes are hidden and inaccessible. 19 | 20 | This is how scopes behave in most languages, which is called lexical scope. The scope unit boundaries, and how variables are organized in them, is determined at the time the program is parsed (compiled). In other words, it's an author-time decision: where you locate a function/scope in the program determines what the scope structure of that part of the program will be. 21 | 22 | JS is lexically scoped, though many claim it isn't, because of two particular characteristics of its model that are not present in other lexically scoped languages. 23 | 24 | The first is commonly called *hoisting*: when all variables declared anywhere in a scope are treated as if they're declared at the beginning of the scope. The other is that `var`-declared variables are function scoped, even if they appear inside a block. 25 | 26 | Neither hoisting nor function-scoped `var` are sufficient to back the claim that JS is not lexically scoped. `let`/`const` declarations have a peculiar error behavior called the "Temporal Dead Zone" (TDZ) which results in observable but unusable variables. Though TDZ can be strange to encounter, it's *also* not an invalidation of lexical scoping. All of these are just unique parts of the language that should be learned and understood by all JS developers. 27 | 28 | Closure is a natural result of lexical scope when the language has functions as first-class values, as JS does. When a function makes reference to variables from an outer scope, and that function is passed around as a value and executed in other scopes, it maintains access to its original scope variables; this is closure. 29 | 30 | Across all of programming, but especially in JS, closure drives many of the most important programming patterns, including modules. As I see it, modules are as *with the grain* as you can get, when it comes to code organization in JS. 31 | 32 | To dig further into scope, closures, and how modules work, read Book 2, *Scope & Closures*. 33 | 34 | ## Pillar 2: Prototypes 35 | 36 | The second pillar of the language is the prototypes system. We covered this topic in-depth in Chapter 3 ("Prototypes"), but I just want to make a few more comments about its importance. 37 | 38 | JS is one of very few languages where you have the option to create objects directly and explicitly, without first defining their structure in a class. 39 | 40 | For many years, people implemented the class design pattern on top of prototypes—so-called "prototypal inheritance" (see Appendix A, "Prototypal 'Classes'")—and then with the advent of ES6's `class` keyword, the language doubled-down on its inclination toward OO/class-style programming. 41 | 42 | But I think that focus has obscured the beauty and power of the prototype system: the ability for two objects to simply connect with each other and cooperate dynamically (during function/method execution) through sharing a `this` context. 43 | 44 | Classes are just one pattern you can build on top of such power. But another approach, in a very different direction, is to simply embrace objects as objects, forget classes altogether, and let objects cooperate through the prototype chain. This is called *behavior delegation*. I think delegation is more powerful than class inheritance, as a means for organizing behavior and data in our programs. 45 | 46 | But class inheritance gets almost all the attention. And the rest goes to functional programming (FP), as the sort of "anti-class" way of designing programs. This saddens me, because it snuffs out any chance for exploration of delegation as a viable alternative. 47 | 48 | I encourage you to spend plenty of time deep in Book 3, *Objects & Classes*, to see how object delegation holds far more potential than we've perhaps realized. This isn't an anti-`class` message, but it is intentionally a "classes aren't the only way to use objects" message that I want more JS developers to consider. 49 | 50 | Object delegation is, I would argue, far more *with the grain* of JS, than classes (more on *grains* in a bit). 51 | 52 | ## Pillar 3: Types and Coercion 53 | 54 | The third pillar of JS is by far the most overlooked part of JS's nature. 55 | 56 | The vast majority of developers have strong misconceptions about how *types* work in programming languages, and especially how they work in JS. A tidal wave of interest in the broader JS community has begun to shift to "static typing" approaches, using type-aware tooling like TypeScript or Flow. 57 | 58 | I agree that JS developers should learn more about types, and should learn more about how JS manages type conversions. I also agree that type-aware tooling can help developers, assuming they have gained and used this knowledge in the first place! 59 | 60 | But I don't agree at all that the inevitable conclusion of this is to decide JS's type mechanism is bad and that we need to cover up JS's types with solutions outside the language. We don't have to follow the "static typing" way to be smart and solid with types in our programs. There are other options, if you're just willing to go *against the grain* of the crowd, and *with the grain* of JS (again, more on that to come). 61 | 62 | Arguably, this pillar is more important than the other two, in the sense that no JS program will do anything useful if it doesn't properly leverage JS's value types, as well as the conversion (coercion) of values between types. 63 | 64 | Even if you love TypeScript/Flow, you are not going to get the most out of those tools or coding approaches if you aren't deeply familiar with how the language itself manages value types. 65 | 66 | To learn more about JS types and coercion, check out Book 4, *Types & Grammar*. But please don't skip over this topic just because you've always heard that we should use `===` and forget about the rest. 67 | 68 | Without learning this pillar, your foundation in JS is shaky and incomplete at best. 69 | 70 | ## With the Grain 71 | 72 | I have some advice to share on continuing your learning journey with JS, and your path through the rest of this book series: be aware of the *grain* (recall various references to *grain* earlier in this chapter). 73 | 74 | First, consider the *grain* (as in, wood) of how most people approach and use JS. You've probably already noticed that these books cut against that *grain* in many respects. In YDKJSY, I respect you the reader enough to explain all the parts of JS, not only some select popular parts. I believe you're both capable and deserving of that knowledge. 75 | 76 | But that is not what you'll find from a lot of other material out there. It also means that the more you follow and adhere to the guidance from these books—that you think carefully and analyze for yourself what's best in your code—the more you will stand out. That can be a good and bad thing. If you ever want to break out from the crowd, you're going to have to break from how the crowd does it! 77 | 78 | But I've also had many people tell me that they quoted some topic/explanation from these books during a job interview, and the interviewer told the candidate they were wrong; indeed, people have reportedly lost out on job offers as a result. 79 | 80 | As much as possible, I endeavor in these books to provide completely accurate information about JS, informed generally from the specification itself. But I also dose out quite a bit of my opinions on how you can interpret and use JS to the best benefit in your programs. I don't present opinion as fact, or vice versa. You'll always know which is which in these books. 81 | 82 | Facts about JS are not really up for debate. Either the specification says something, or it doesn't. If you don't like what the specification says, or my relaying of it, take that up with TC39! If you're in an interview and they claim you're wrong on the facts, ask them right then and there if you can look it up in the specification. If the interviewer won't re-consider, then you shouldn't want to work there anyway. 83 | 84 | But if you choose to align with my opinions, you have to be prepared to back up those choices with *why* you feel that way. Don't just parrot what I say. Own your opinions. Defend them. And if someone you were hoping to work with disagrees, walk away with your head still held high. It's a big JS, and there's plenty of room for lots of different ways. 85 | 86 | In other words, don't be afraid to go against the *grain*, as I have done with these books and all my teachings. Nobody can tell you how you will best make use of JS; that's for you to decide. I'm merely trying to empower you in coming to your own conclusions, no matter what they are. 87 | 88 | On the other hand, there's a *grain* you really should pay attention to and follow: the *grain* of how JS works, at the language level. There are things that work well and naturally in JS, given the right practice and approach, and there are things you really shouldn't try to do in the language. 89 | 90 | Can you make your JS program look like a Java, C#, or Perl program? What about Python or Ruby, or even PHP? To varying degrees, sure you can. But should you? 91 | 92 | No, I don't think you should. I think you should learn and embrace the JS way, and make your JS programs as JS'y as is practical. Some will think that means sloppy and informal programming, but I don't mean that at all. I just mean that JS has a lot of patterns and idioms that are recognizably "JS," and going with that *grain* is the general path to the best success. 93 | 94 | Finally, maybe the most important *grain* to recognize is how the existing program(s) you're working on, and developers you're working with, do stuff. Don't read these books and then try to change *all that grain* in your existing projects over night. That approach will always fail. 95 | 96 | You'll have to shift these things little by little, over time. Work on building consensus with your fellow developers on why it's important to re-visit and re-consider an approach. But do so with just one small topic at a time, and let before-and-after code comparisons do most of the talking. Bring everyone on the team together to discuss, and push for decisions that are based on analysis and evidence from the code rather than the inertia of "our senior devs have always done it this way." 97 | 98 | That's the most important advice I can impart to help you learn JS. Always keep looking for better ways to use what JS gives us to author more readable code. Everyone who works on your code, including your future self, will thank you! 99 | 100 | ## In Order 101 | 102 | So now you've got a broader perspective on what's left to explore in JS, and the right attitude to approach the rest of your journey. 103 | 104 | But one of the most common practical questions I get at this point is, "What order should I read the books?" There is a straightforward answer... but it also depends. 105 | 106 | My suggestion for most readers is to proceed through this series in this order: 107 | 108 | 1. Get started with a solid foundation of JS from *Get Started* (Book 1) -- good news, you've already almost finished this book! 109 | 110 | 2. In *Scope & Closures* (Book 2), dig into the first pillar of JS: lexical scope, how that supports closure, and how the module pattern organizes code. 111 | 112 | 3. In *Objects & Classes* (Book 3), focus on the second pillar of JS: how JS's `this` works, how object prototypes support delegation, and how prototypes enable the `class` mechanism for OO-style code organization. 113 | 114 | 4. In *Types & Grammar* (Book 4), tackle the third and final pillar of JS: types and type coercion, as well as how JS's syntax and grammar define how we write our code. 115 | 116 | 5. With the **three pillars** solidly in place, *Sync & Async* (Book 5) then explores how we use flow control to model state change in our programs, both synchronously (right away) and asynchronously (over time). 117 | 118 | 6. The series concludes with *ES.Next & Beyond* (Book 6), a forward look at the near- and mid-term future of JS, including a variety of features likely coming to your JS programs before too long. 119 | 120 | That's the intended order to read this book series. 121 | 122 | However, Books 2, 3, and 4 can generally be read in any order, depending on which topic you feel most curious about and comfortable exploring first. But I don't recommend you skip any of these three books—not even *Types & Grammar*, as some of you will be tempted to do!—even if you think you already have that topic down. 123 | 124 | Book 5 (*Sync & Async*) is crucial for deeply understanding JS, but if you start digging in and find it's too intimidating, this book can be deferred until you're more experienced with the language. The more JS you've written (and struggled with!), the more you'll come to appreciate this book. So don't be afraid to come back to it at a later time. 125 | 126 | The final book in the series, *ES.Next & Beyond*, in some respects stands alone. It can be read at the end, as I suggest, or right after *Getting Started* if you're looking for a shortcut to broaden your radar of what JS is all about. This book will also be more likely to receive updates in the future, so you'll probably want to re-visit it occasionally. 127 | 128 | However you choose to proceed with YDKJSY, check out the appendices of this book first, especially practicing the snippets in Appendix B, "Practice, Practice, Practice!" Did I mention you should go practice!? There's no better way to learn code than to write it. 129 | -------------------------------------------------------------------------------- /get-started/foreword.md: -------------------------------------------------------------------------------- 1 | # You Don't Know JS Yet: Get Started - 2nd Edition 2 | # Foreword 3 | 4 | The first time I saw a tweet advertising the crowdfunding campaign for the original book series *You Don't Know JS*, I thought to myself that whoever the hell this Kyle Simpson is can get bent. Of course I know JavaScript! At the time I had been working in JavaScript for many years with some of tech's biggest names, so I felt justified in looking down my nose at this sweeping claim. 5 | 6 | Once the funding for the book completed, I observed that a lot of people were really excited to read this book series and I decided to go ahead and give it a shot—you know, just to show everyone that I *do know* JavaScript. Once I dug in and poured over the texts, I experienced a profound mix of learning, surprise, and even a little anger. Kyle has a knack for saying something that challenges my world view and making me think about it until I realize what he said was actually true (I'll never admit this to him though!). 7 | 8 | So it turned out I didn't know JavaScript. I didn't know why I had adopted certain patterns; I didn't know why JavaScript behaves the way it does in certain situations, and I didn't know much of the nuance of the languages that I assumed I did. Many were things I didn't know I didn't know, and I was worse off as a developer for it. 9 | 10 | This is what this book series is great for. It's not just for someone picking up the language for the first time (though it's for them, too); it's for all software craftspeople who want to master their tools, who want to understand the ins and outs of their trade, and who want to select the proper methods for solving problems. 11 | 12 | The thing I appreciate about Kyle and his work is that he is delightfully uninfluenced by the zeitgeist of the programming world around him. That isn't to say he isn't aware of what's happening in the community but rather that it doesn't sway his pursuit of the best answers to the correct questions. This often has put him at odds with the latest "best practices," but in reality this is exactly what you need: a perspective removed from temporal influence and simply speaking to the underlying truth. That's why this series is so good. The first edition of *You Don't Know JS* is still accurate, years later! Not many things stand this test of time given the shifting sands of the JavaScript landscape. 13 | 14 | Let's talk a moment about this first book itself, *Get Started*. You may be tempted to skip it as you may think that you already have "gotten started," but it's worth reading this one! You'd be surprised how much depth, nuance, and oddity there is in the underlying building blocks of JavaScript, and it's quite essential for you to grapple with these underpinnings before venturing forward into the constructs of the language. It's exactly the sort of foundation you need, to really know JavaScript. 15 | 16 | So, do your future self a favor and dig into this book and unlock the knowledge within. These solid foundations will serve you better than any framework ever will; those come and go but we'll still be writing JavaScript itself for decades to come. Keep an open mind and challenge your preconceived notions. 17 | 18 | Because, as I found out myself, you probably don't know JavaScript (yet). 19 | 20 | Brian Holt
21 | Senior Program Manager
22 | Visual Studio Code and Node.js on Azure
23 | Microsoft 24 | -------------------------------------------------------------------------------- /get-started/images/cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getify/You-Dont-Know-JS/e3f784bcb18ba47a9e6ced0866bc361393fb299f/get-started/images/cover.png -------------------------------------------------------------------------------- /get-started/images/fig1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getify/You-Dont-Know-JS/e3f784bcb18ba47a9e6ced0866bc361393fb299f/get-started/images/fig1.png -------------------------------------------------------------------------------- /get-started/images/fig1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /get-started/images/fig2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getify/You-Dont-Know-JS/e3f784bcb18ba47a9e6ced0866bc361393fb299f/get-started/images/fig2.png -------------------------------------------------------------------------------- /get-started/images/fig3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getify/You-Dont-Know-JS/e3f784bcb18ba47a9e6ced0866bc361393fb299f/get-started/images/fig3.png -------------------------------------------------------------------------------- /get-started/images/fig4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getify/You-Dont-Know-JS/e3f784bcb18ba47a9e6ced0866bc361393fb299f/get-started/images/fig4.png -------------------------------------------------------------------------------- /get-started/images/fig5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getify/You-Dont-Know-JS/e3f784bcb18ba47a9e6ced0866bc361393fb299f/get-started/images/fig5.png -------------------------------------------------------------------------------- /get-started/images/fig6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getify/You-Dont-Know-JS/e3f784bcb18ba47a9e6ced0866bc361393fb299f/get-started/images/fig6.png -------------------------------------------------------------------------------- /get-started/toc.md: -------------------------------------------------------------------------------- 1 | # You Don't Know JS Yet: Get Started - 2nd Edition 2 | 3 | ## Table of Contents 4 | 5 | * Foreword 6 | * Preface 7 | * Chapter 1: What Is JavaScript? 8 | * About This Book 9 | * What's With That Name? 10 | * Language Specification 11 | * Many Faces 12 | * Backwards & Forwards 13 | * What's in an Interpretation? 14 | * Strictly Speaking 15 | * Defined 16 | * Chapter 2: Surveying JS 17 | * Each File is a Program 18 | * Values 19 | * Declaring and Using Variables 20 | * Functions 21 | * Comparisons 22 | * How We Organize in JS 23 | * The Rabbit Hole Deepens 24 | * Chapter 3: Digging To The Roots Of JS 25 | * Iteration 26 | * Closure 27 | * `this` Keyword 28 | * Prototypes 29 | * Asking "Why?" 30 | * Chapter 4: The Bigger Picture 31 | * Pillar 1: Scope and Closure 32 | * Pillar 2: Prototypes 33 | * Pillar 3: Types and Coercion 34 | * With the Grain 35 | * In Order 36 | * Appendix A: Exploring Further 37 | * Values vs. References 38 | * So Many Function Forms 39 | * Coercive Conditional Comparison 40 | * Prototypal "Classes" 41 | * Appendix B: Practice, Practice, Practice! 42 | * Practicing Comparisons 43 | * Practicing Closure 44 | * Practicing Prototypes 45 | * Suggested Solutions 46 | -------------------------------------------------------------------------------- /objects-classes/README.md: -------------------------------------------------------------------------------- 1 | # You Don't Know JS Yet: Objects & Classes - 2nd Edition 2 | 3 | | NOTE: | 4 | | :--- | 5 | | Work in progress | 6 | 7 | [Table of Contents](toc.md) 8 | 9 | * [Foreword](foreword.md) (by [Rick Waldron](https://twitter.com/rwaldron)) 10 | * [Preface](../preface.md) 11 | * [Chapter 1: Object Foundations](ch1.md) 12 | * [Chapter 2: How Objects Work](ch2.md) 13 | * [Chapter 3: Classy Objects](ch3.md) 14 | * [Chapter 4: This Works](ch4.md) 15 | * [Chapter 5: Delegation](ch5.md) 16 | * [Thank You!](thanks.md) 17 | -------------------------------------------------------------------------------- /objects-classes/foreword.md: -------------------------------------------------------------------------------- 1 | # You Don't Know JS Yet: Objects & Classes - 2nd Edition 2 | # Foreword 3 | 4 | Kyle Simpson has an unmatched brilliance in the art of explanation. 5 | 6 | In April of 2015 I was honored to author the foreword for Kyle's book [You Don't Know JS: ES6 & Beyond](https://www.oreilly.com/library/view/you-dont-know/9781491905241/), an exciting and detailed deep-dive into new JavaScript language features that hadn't even yet been ratified by Ecma (that wouldn't happen until June 2015), but had already made their way out into the world. At the time, there was gap in meaningful documentation and educational resources, and I declared that no better person had stepped up to fill it. I stand by everything I wrote in 2015, and I'm here in 2022 to double down for [You Don't Know JS Yet: Objects & Classes](). 7 | 8 | We are all better off for the time, effort and resources that Kyle pours into forming a better understanding of the JavaScript programming language for himself, and for the betterment of his peers: learning, honing and distilling complex semantics into easily digestable concepts that can be built upon in infinite, myriad ways. And that's exactly what we witness here: Kyle becomes an expert in programming subject matter by consuming it at every level. By probing the semantics of new language features, luring them out from the shadows, releasing them from arcane origins and freeing them for our consumption and growth. 9 | 10 | Even as a successful professional software engineer, I keep Kyle's works close at hand. At times these tomes are helpful in explaining deeply complex concepts to teammates and peers, while other times they serve as refreshers for myself, because there's always some interesting take-away or new perspective to gain. 11 | 12 | Rick Waldron (@rwaldron)
13 | Lead Software Engineer
14 | Lightning Web Security
15 | Salesforce 16 | -------------------------------------------------------------------------------- /objects-classes/thanks.md: -------------------------------------------------------------------------------- 1 | # You Don't Know JS Yet: Objects & Classes - 2nd Edition 2 | # Thank You! 3 | 4 | The following 371 Kickstarter backers generously backed the campaign to write/publish the four remaining books of the second edition. Without their faithful and patient support, these books would not have happened. 5 | 6 | I am deeply grateful to each of you! 7 | 8 | > Marc at Frontend Masters, Bassim, Tasos Tsournos, Lauren Clark, Simon, Appgrader, Marcos S., Noah Rodenbeek, Lichtjaeger, Jon Miller, Anil, Greg Gerard, Frank Deberle, Davide Bonifacio, Brandon Leichty, Rowdy Rabouw, Gaspar Radu, Sukumar Vaddi, Gordon, jakecodes, Leo Furze-Waddock, Nick de Jong, D. Vinci, Brian Vogel, Gareth loot, Simon Taylor, Chris O’Brien, Nayana Davis, Mark Kramer, Sunil Samuel, @nestor.j.g, Ryan McDaniel, Mert Even, Haim Yulzari, Josh Marks, Chiril Sarajiu, Barnabas Jovanovics, LynchyC, Yahya Jideh, Chris Weber, Dan Cortes, Johnny Tordgeman, Ky Lee, Brian Wisti, Steven Marrocco, Thomas Randolph, Petri Lindholm, John Cole, github, @denysmarkov, Jacob Scherber, Pierre-Yves Lebrun, mcekiera, Matthew Wasbrough, Génicot Jean-Baptiste, Adam Zając, Lenny Erlesand, Samuel Gustafsson, Hunter Jansen, Theo Armour, Nate Hargitt, Anon, Github repo, cawel, mpelikan, @farisaziz12, Ojars, Camilo Segura, Sean Seagren, Michael Vendivel, Evan, Eric Schwertfeger, Gene Garbutt, Elena Rogleva, Fiona Cheung, Anton Levholm, Lorenzo Bersano, Ando NARY, Ruben Krbashyan, Anonymous please, @jcubic, Bhavin Dave, A. Hitchcock, H0rn0chse, Yaniv Wainer, Zach, Raúl Pineda, Rohan Gupta, Karthik, Kapil, Ricardo Trejos, InvisibleLuis, BruceRobertson, Neil Lupton, Chris Schweda, Luca Mezzalira, antonio molinari, David Pinezich, Jon Barson, Nick Kaufmann, Just Andrew, Rock Kayode Winner, @omar12, Page Han, Aurélien Bottazini, Michael, Petr Siegl, Ilya Sarantsev, Alfredo Delgado, aharvard, Jannaee, Aaron McBride, Toma, epmatsw, Igor "kibertoad" Savin, Christian Rackerseder, NC Patro, Kevin, Brian Holt, Brian Ashenfelter, Selina Chang, cwavedave, Alex Grant, Craig Robertson, Eduardo Sanz Martin, oieduardorabelo, Esteban Massuh, tedhexaflow, Gershon Gerchikov, Harika Yedidi, Brad Dougherty, Nitin, Leo Balter, Syed Ahmad, Kaz de Groot, Pinnemouche Studio, Jerome Amos, Dan Poynor, John Liu, @thedavefulton, Madeline Bernard, Ikigai42, Antonio Chillaron, Sachin, Prakasam Venkatachalam, jmarti705, Mihailo23, Mihailo Pantovic, Magloire, samrudh, Mykenzie Rogers, Len, Lyza Danger Gardner, Ryan, Roman, Radojica Radivojevic, Gabrien Symons, Ryan Parker, Andrés, Merlin, rushabh_badani, notacouch, Anna Borja, Steve Albers, Marc at Frontend Masters, Bala Vemula, @chrismcdonald84, stern9, Janne Hellsten, Alexandre Madurell, Tanner Hodges, Joe Chellman, Joachim Kliemann, Stefano Frasson Pianizzola, Sergey Kochergan, Spiridonov Dmitriy, IonutBihari, Alexandru Olteanu, Javi, Marlee Peters, @vadocondes1, Gerardo Leal, Albert Sebastian, Atish Raina, Andreas Gebhardt, David Deren, Maksym Gerashchenko, Alexandru, Matt Peck, William Lacroix, Pavlo, Jon, Brett Walker, Iosif Psychas, Ferran Buireu, crs1138, Emiliano anichini, Max Koretskyi, Sander Elias, Michael Romanov, Barkóczi Dávid, Daw-Chih Liou, Dale Caffull, Amanda Dillon, Mike, Justin Hefko, Muhammad Ali Shah, Ketan Srivastav, redeemefy, Stefan Trivunčić, Manuel Juan Fosela Águila, Dragan Majstorović, Harsha C G, Himanshu, Luke, Sai Ponnada, Mark Franco, David Whittaker, Dr. Teresa Vasquez, Ian Wright, Lora Rusinouskaya, Petar, Harish, Mairead, shimon simo moyal, Sunny Puri, Максим Кочанов, Alex Georoceanu, Nicolas Carreras, damijanc, zach.dev, Coati, Brian Whitton, Denis Ciccale, Piotr Seefeld, Chase Hagwood, Amritha K, Κώστας Μηναϊδης, Trey Aughenbaugh, J David Eisenberg, Paul Thaden, Corina S, Chris Dhanaraj, Nahid Hossain, Justin McCullough, Arseny, Mark Trostler, Lucy Barker, Maaz Syed Adeeb, mcginkel, Derick Rodriguez, Helen Tsui, Rus Ustyugov, Vassilis Mastorostergios, Ryan Ewing, Rob Huelga, jinujj, ultimateoverload, Chaos, Andy Howell (spacebeers), Archana, AG Grid, theblang, Coyotiv School of Software Engineering, Ayush Rajniwal, Manish Bhatt, Shea Leslein, Jordan Chipman, jg0x42, Arvind Kumar, Eduardo Grigolo, Peter Svegrup, Jakub Kotula, William Richardson, Jonah and Ali, nicciwill, Lauren Hodges, Travis Sauer, Alexandros, Abhas, Kirankumar Ambati, Gopalakrishnan, Mika Rehman, Sreeram Sama, Shubhamsatyam Verma, Heejae Chang, Andrico karoulla, Niek Heezemans, Stanislav Horáček, Luis Ibanhi, Jasmine Wang, Yunier, Brian Barrow, Matteo Hertel, Aleksandar Milicevic, achung89, kushavi, Ahmed Fouad, Venkat Kaluva, Ian Wotkun, Andreas Näsman, ivan-siachoque, Paul Gain, Santhosh R, Gustavo Morales, ScottAwseome, Fredrik Thorkildsen, Manvel, holleB, James Sullivan, Adam Kaźmierczak, carlottosson, Alvee, Alex Reardon, Olie Chan, Fredrik S, Brett.Buskirk, Rui Sereno, Nathan Strong, lostdesign, ppseprus, James, anthonybsd, Alena Charnova, Kevin K, @codingthirty, Tim Davis, Jonathan Yee, Christa, Fabian Merchan, Nathanael McDaniel, Dave N, Brian Chirgwin, Abdulrahman (Abdu) Assabri, rmeja, Jan Václavek, Phillip Hogan, Adhithya Rajagopalan (xadhix), Jason Humphrey, Antoinette Smith, Elliot Redhead, zokocx, John Sims, Michalis Garganourakis, Adarsh Konchady, Anton Oleg Dobrovolskyy, George Tharakan, syd, Ryan D., Iris Nathan, Srishti Gupta, Miguel Rivero, @saileshraghavan, Yojan, @bgollum, Junyts, Like Ezugworie, Vsh13, LocalPCGuy, DMGabriel, Juan Tincho, William Greenlaw, atisbacsi, cris ryan tan, Jonathan Clifron, Daniel Dolich, Praj, Caisman, Michał, Mark C, 3xpedia 9 | 10 | A special thanks to: 11 | 12 | * A. Hitchcock 13 | * Alexandru 14 | * Appgrader 15 | * Coyotiv School of Software Engineering 16 | * Gaspar Radu 17 | * IonutBihari 18 | * jmarti705 19 | * John Liu 20 | * Syed Ahmad 21 | * Travis Sauer 22 | * William Greenlaw 23 | 24 | All of you are fantastic! 25 | -------------------------------------------------------------------------------- /objects-classes/toc.md: -------------------------------------------------------------------------------- 1 | # You Don't Know JS Yet: Objects & Classes - 2nd Edition 2 | 3 | | NOTE: | 4 | | :--- | 5 | | Work in progress | 6 | 7 | ## Table of Contents 8 | 9 | * Foreword 10 | * Preface 11 | * Chapter 1: Object Foundations 12 | * About This Book 13 | * Objects As Containers 14 | * Defining Properties 15 | * Accessing Properties 16 | * Assigning Properties 17 | * Deleting Properties 18 | * Determining Container Contents 19 | * Temporary Containers 20 | * Containers Are Collections Of Properties 21 | * Chapter 2: How Objects Work 22 | * Property Descriptors 23 | * Object Sub-Types 24 | * Object Characteristics 25 | * Extending the MOP 26 | * `[[Prototype]]` Chain 27 | * Objects Behavior 28 | * Chapter 3: Classy Objects 29 | * When Should I Class-Orient My Code? 30 | * Keep It `class`y 31 | * Class Instance `this` 32 | * Class Extension 33 | * Static Class Behavior 34 | * Private Class Behavior 35 | * Class Example 36 | * Chapter 4: This Works 37 | * This Aware 38 | * This Is It! 39 | * An Arrow Points Somewhere 40 | * Variations 41 | * Stay Aware 42 | * Chapter 5: Delegation 43 | * Preamble 44 | * What's A Constructor, Anyway? 45 | * Ditching Class Thinking 46 | * Delegation Illustrated 47 | * Composing Peer Objects 48 | * Why *This*? 49 | * Thank You! 50 | * TODO: 51 | * object wrappers (String, Boolean, etc) 52 | * object coercions (valueof, tostring, boxing) 53 | * well-known symbols extension points on objects 54 | * proxies 55 | * old "prototypal class" style 56 | * "inheritance" objections 57 | * protected visibility 58 | -------------------------------------------------------------------------------- /preface.md: -------------------------------------------------------------------------------- 1 | # You Don't Know JS Yet - 2nd Edition 2 | # Preface 3 | 4 | Welcome to the 2nd edition of the widely acclaimed *You Don't Know JS* (**YDKJS**) book series: *You Don't Know JS **Yet*** (**YDKJSY**). 5 | 6 | If you've read any of the 1st edition books, you can expect a refreshed approach in these new ones, with plenty of updated coverage of what's changed in JS over the last five years. But what I hope and believe you'll still *get* is the same commitment to respecting JS and digging into what really makes it tick. 7 | 8 | If this is your first time reading these books, I'm glad you're here. Prepare for a deep and extensive journey into all the corners of JavaScript. 9 | 10 | If you are new to programming or JS, be aware that these books are not intended as a gentle "intro to JavaScript." This material is, at times, complex and challenging, and goes much deeper than is typical for a first-time learner. You're welcome here no matter what your background is, but these books are written assuming you're already comfortable with JS and have at least 6–9 months experience with it. 11 | 12 | ## The Parts 13 | 14 | These books approach JavaScript intentionally opposite of how *The Good Parts* treats the language. No, that doesn't mean we're looking at *the bad parts*, but rather, exploring **all the parts**. 15 | 16 | You may have been told, or felt yourself, that JS is a deeply flawed language that was poorly designed and inconsistently implemented. Many have asserted that it's the worst most popular language in the world; that nobody writes JS because they want to, only because they have to given its place at the center of the web. That's a ridiculous, unhealthy, and wholly condescending claim. 17 | 18 | Millions of developers write JavaScript every day, and many of them appreciate and respect the language. 19 | 20 | Like any great language, it has its brilliant parts as well as its scars. Even the creator of JavaScript himself, Brendan Eich, laments some of those parts as mistakes. But he's wrong: they weren't mistakes at all. JS is what it is today—the world's most ubiquitous and thus most influential programming language—precisely because of *all those parts*. 21 | 22 | Don't buy the lie that you should only learn and use a small collection of *good parts* while avoiding all the bad stuff. Don't buy the "X is the new Y" snake oil, that some new feature of the language instantly relegates all usage of a previous feature as obsolete and ignorant. Don't listen when someone says your code isn't "modern" because it isn't yet using a stage-0 feature that was only proposed a few weeks ago! 23 | 24 | Every part of JS is useful. Some parts are more useful than others. Some parts require you to be more careful and intentional. 25 | 26 | I find it absurd to try to be a truly effective JavaScript developer while only using a small sliver of what the language has to offer. Can you imagine a construction worker with a toolbox full of tools, who only uses their hammer and scoffs at the screwdriver or tape measure as inferior? That's just silly. 27 | 28 | My unreserved claim is that you should go about learning all parts of JavaScript, and where appropriate, use them! And if I may be so bold as to suggest: it's time to discard any JS books that tell you otherwise. 29 | 30 | ## The Title? 31 | 32 | So what's the title of the series all about? 33 | 34 | I'm not trying to insult you with criticism about your current lack of knowledge or understanding of JavaScript. I'm not suggesting you can't or won't be able to learn JavaScript. I'm not boasting about secret advanced insider wisdom that I and only a select few possess. 35 | 36 | Seriously, all those were real reactions to the original series title before folks even read the books. And they're baseless. 37 | 38 | The primary point of the title "You Don't Know JS Yet" is to point out that most JS developers don't take the time to really understand how the code that they write works. They know *that* it works—that it produces a desired outcome. But they either don't understand exactly *how*, or worse, they have an inaccurate mental model for the *how* that falters on closer scrutiny. 39 | 40 | I'm presenting a gentle but earnest challenge to you the reader, to set aside the assumptions you have about JS, and approach it with fresh eyes and an invigorated curiosity that leads you to ask *why* for every line of code you write. Why does it do what it does? Why is one way better or more appropriate than the other half-dozen ways you could have accomplished it? Why do all the "popular kids" say to do X with your code, but it turns out that Y might be a better choice? 41 | 42 | I added "Yet" to the title, not only because it's the second edition, but because ultimately I want these books to challenge you in a hopeful rather than discouraging way. 43 | 44 | But let me be clear: I don't think it's possible to ever fully *know* JS. That's not an achievement to be obtained, but a goal to strive after. You don't finish knowing everything about JS, you just keep learning more and more as you spend more time with the language. And the deeper you go, the more you revisit what you *knew* before, and you re-learn it from that more experienced perspective. 45 | 46 | I encourage you to adopt a mindset around JavaScript, and indeed all of software development, that you will never fully have mastered it, but that you can and should keep working to get closer to that end, a journey that will stretch for the entirety of your software development career, and beyond. 47 | 48 | You can always know JS better than you currently do. That's what I hope these YDKJSY books represent. 49 | 50 | ## The Mission 51 | 52 | The case doesn't really need to be made for why developers should take JS seriously—I think it's already more than proven worthy of first-class status among the world's programming languages. 53 | 54 | But a different, more important case still needs to be made, and these books rise to that challenge. 55 | 56 | I've taught more than 5,000 developers from teams and companies all over the world, in more than 25 countries on six continents. And what I've seen is that far too often, what *counts* is generally just the result of the program, not how the program is written or how/why it works. 57 | 58 | My experience not only as a developer but in teaching many other developers tells me: you will always be more effective in your development work if you more completely understand how your code works than you are solely *just* getting it to produce a desired outcome. 59 | 60 | In other words, *good enough to work* is not, and should not be, *good enough*. 61 | 62 | All developers regularly struggle with some piece of code not working correctly, and they can't figure out why. But far too often, JS developers will blame this on the language rather than admitting it's their own understanding that is falling short. These books serve as both the question and answer: why did it do *this*, and here's how to get it to do *that* instead. 63 | 64 | My mission with YDKJSY is to empower every single JS developer to fully own the code they write, to understand it and to write with intention and clarity. 65 | 66 | ## The Path 67 | 68 | Some of you have started reading this book with the goal of completing all six books, back to back. 69 | 70 | I would like to caution you to consider changing that plan. 71 | 72 | It is not my intention that YDKJSY be read straight through. The material in these books is dense, because JavaScript is powerful, sophisticated, and in parts rather complex. Nobody can really hope to *download* all this information to their brains in a single pass and retain any significant amount of it. That's unreasonable, and it's foolish to try. 73 | 74 | My suggestion is you take your time going through YDKJSY. Take one chapter, read it completely through start to finish, and then go back and re-read it section by section. Stop in between each section, and practice the code or ideas from that section. For larger concepts, it probably is a good idea to expect to spend several days digesting, re-reading, practicing, then digesting some more. 75 | 76 | You could spend a week or two on each chapter, and a month or two on each book, and a year or more on the whole series, and you would still not be squeezing every ounce of YDKJSY out. 77 | 78 | Don't binge these books; be patient and spread out your reading. Interleave reading with lots of practice on real code in your job or on projects you participate in. Wrestle with the opinions I've presented along the way, debate with others, and most of all, disagree with me! Run a study group or book club. Teach mini-workshops at your office. Write blog posts on what you've learned. Speak about these topics at local JS meetups. 79 | 80 | It's never my goal to convince you to agree with my opinion, but to encourage you to own and be able to defend your opinions. You can't get *there* with an expedient read-through of these books. That's something that takes a long while to emerge, little by little, as you study and ponder and re-visit. 81 | 82 | These books are meant to be a field-guide on your wanderings through JavaScript, from wherever you currently are with the language, to a place of deeper understanding. And the deeper you understand JS, the more questions you will ask and the more you will have to explore! That's what I find so exciting! 83 | 84 | I'm so glad you're embarking on this journey, and I am so honored you would consider and consult these books along the way. It's time to start *getting to know JS*. 85 | -------------------------------------------------------------------------------- /scope-closures/README.md: -------------------------------------------------------------------------------- 1 | # You Don't Know JS Yet: Scope & Closures - 2nd Edition 2 | 3 | 4 | 5 | ----- 6 | 7 | **[Purchase ebook/PDF from Leanpub](https://leanpub.com/ydkjsy-scope-closures)** 8 | 9 | ----- 10 | 11 | [Table of Contents](toc.md) 12 | 13 | * [Foreword](foreword.md) (by [Sarah Drasner](https://sarah.dev/)) 14 | * [Preface](../preface.md) 15 | * [Chapter 1: What's the Scope?](ch1.md) 16 | * [Chapter 2: Illustrating Lexical Scope](ch2.md) 17 | * [Chapter 3: The Scope Chain](ch3.md) 18 | * [Chapter 4: Around the Global Scope](ch4.md) 19 | * [Chapter 5: The (Not So) Secret Lifecycle of Variables](ch5.md) 20 | * [Chapter 6: Limiting Scope Exposure](ch6.md) 21 | * [Chapter 7: Using Closures](ch7.md) 22 | * [Chapter 8: The Module Pattern](ch8.md) 23 | * [Appendix A: Exploring Further](apA.md) 24 | * [Appendix B: Practice](apB.md) 25 | -------------------------------------------------------------------------------- /scope-closures/ch8.md: -------------------------------------------------------------------------------- 1 | # You Don't Know JS Yet: Scope & Closures - 2nd Edition 2 | # Chapter 8: The Module Pattern 3 | 4 | In this chapter, we wrap up the main text of the book by exploring one of the most important code organization patterns in all of programming: the module. As we'll see, modules are inherently built from what we've already covered: the payoff for your efforts in learning lexical scope and closure. 5 | 6 | We've examined every angle of lexical scope, from the breadth of the global scope down through nested block scopes, into the intricacies of the variable lifecycle. Then we leveraged lexical scope to understand the full power of closure. 7 | 8 | Take a moment to reflect on how far you've come in this journey so far; you've taken big steps in getting to know JS more deeply! 9 | 10 | The central theme of this book has been that understanding and mastering scope and closure is key in properly structuring and organizing our code, especially the decisions on where to store information in variables. 11 | 12 | Our goal in this final chapter is to appreciate how modules embody the importance of these topics, elevating them from abstract concepts to concrete, practical improvements in building programs. 13 | 14 | ## Encapsulation and Least Exposure (POLE) 15 | 16 | Encapsulation is often cited as a principle of object-oriented (OO) programming, but it's more fundamental and broadly applicable than that. The goal of encapsulation is the bundling or co-location of information (data) and behavior (functions) that together serve a common purpose. 17 | 18 | Independent of any syntax or code mechanisms, the spirit of encapsulation can be realized in something as simple as using separate files to hold bits of the overall program with common purpose. If we bundle everything that powers a list of search results into a single file called "search-list.js", we're encapsulating that part of the program. 19 | 20 | The recent trend in modern front-end programming to organize applications around Component architecture pushes encapsulation even further. For many, it feels natural to consolidate everything that constitutes the search results list—even beyond code, including presentational markup and styling—into a single unit of program logic, something tangible we can interact with. And then we label that collection the "SearchList" component. 21 | 22 | Another key goal is the control of visibility of certain aspects of the encapsulated data and functionality. Recall from Chapter 6 the *least exposure* principle (POLE), which seeks to defensively guard against various *dangers* of scope over-exposure; these affect both variables and functions. In JS, we most often implement visibility control through the mechanics of lexical scope. 23 | 24 | The idea is to group alike program bits together, and selectively limit programmatic access to the parts we consider *private* details. What's not considered *private* is then marked as *public*, accessible to the whole program. 25 | 26 | The natural effect of this effort is better code organization. It's easier to build and maintain software when we know where things are, with clear and obvious boundaries and connection points. It's also easier to maintain quality if we avoid the pitfalls of over-exposed data and functionality. 27 | 28 | These are some of the main benefits of organizing JS programs into modules. 29 | 30 | ## What Is a Module? 31 | 32 | A module is a collection of related data and functions (often referred to as methods in this context), characterized by a division between hidden *private* details and *public* accessible details, usually called the "public API." 33 | 34 | A module is also stateful: it maintains some information over time, along with functionality to access and update that information. 35 | 36 | | NOTE: | 37 | | :--- | 38 | | A broader concern of the module pattern is fully embracing system-level modularization through loose-coupling and other program architecture techniques. That's a complex topic well beyond the bounds of our discussion, but is worth further study beyond this book. | 39 | 40 | To get a better sense of what a module is, let's compare some module characteristics to useful code patterns that aren't quite modules. 41 | 42 | ### Namespaces (Stateless Grouping) 43 | 44 | If you group a set of related functions together, without data, then you don't really have the expected encapsulation a module implies. The better term for this grouping of *stateless* functions is a namespace: 45 | 46 | ```js 47 | // namespace, not module 48 | var Utils = { 49 | cancelEvt(evt) { 50 | evt.preventDefault(); 51 | evt.stopPropagation(); 52 | evt.stopImmediatePropagation(); 53 | }, 54 | wait(ms) { 55 | return new Promise(function c(res){ 56 | setTimeout(res,ms); 57 | }); 58 | }, 59 | isValidEmail(email) { 60 | return /[^@]+@[^@.]+\.[^@.]+/.test(email); 61 | } 62 | }; 63 | ``` 64 | 65 | `Utils` here is a useful collection of utilities, yet they're all state-independent functions. Gathering functionality together is generally good practice, but that doesn't make this a module. Rather, we've defined a `Utils` namespace and organized the functions under it. 66 | 67 | ### Data Structures (Stateful Grouping) 68 | 69 | Even if you bundle data and stateful functions together, if you're not limiting the visibility of any of it, then you're stopping short of the POLE aspect of encapsulation; it's not particularly helpful to label that a module. 70 | 71 | Consider: 72 | 73 | ```js 74 | // data structure, not module 75 | var Student = { 76 | records: [ 77 | { id: 14, name: "Kyle", grade: 86 }, 78 | { id: 73, name: "Suzy", grade: 87 }, 79 | { id: 112, name: "Frank", grade: 75 }, 80 | { id: 6, name: "Sarah", grade: 91 } 81 | ], 82 | getName(studentID) { 83 | var student = this.records.find( 84 | student => student.id == studentID 85 | ); 86 | return student.name; 87 | } 88 | }; 89 | 90 | Student.getName(73); 91 | // Suzy 92 | ``` 93 | 94 | Since `records` is publicly accessible data, not hidden behind a public API, `Student` here isn't really a module. 95 | 96 | `Student` does have the data-and-functionality aspect of encapsulation, but not the visibility-control aspect. It's best to label this an instance of a data structure. 97 | 98 | ### Modules (Stateful Access Control) 99 | 100 | To embody the full spirit of the module pattern, we not only need grouping and state, but also access control through visibility (private vs. public). 101 | 102 | Let's turn `Student` from the previous section into a module. We'll start with a form I call the "classic module," which was originally referred to as the "revealing module" when it first emerged in the early 2000s. Consider: 103 | 104 | ```js 105 | var Student = (function defineStudent(){ 106 | var records = [ 107 | { id: 14, name: "Kyle", grade: 86 }, 108 | { id: 73, name: "Suzy", grade: 87 }, 109 | { id: 112, name: "Frank", grade: 75 }, 110 | { id: 6, name: "Sarah", grade: 91 } 111 | ]; 112 | 113 | var publicAPI = { 114 | getName 115 | }; 116 | 117 | return publicAPI; 118 | 119 | // ************************ 120 | 121 | function getName(studentID) { 122 | var student = records.find( 123 | student => student.id == studentID 124 | ); 125 | return student.name; 126 | } 127 | })(); 128 | 129 | Student.getName(73); // Suzy 130 | ``` 131 | 132 | `Student` is now an instance of a module. It features a public API with a single method: `getName(..)`. This method is able to access the private hidden `records` data. 133 | 134 | | WARNING: | 135 | | :--- | 136 | | I should point out that the explicit student data being hard-coded into this module definition is just for our illustration purposes. A typical module in your program will receive this data from an outside source, typically loaded from databases, JSON data files, Ajax calls, etc. The data is then injected into the module instance typically through method(s) on the module's public API. | 137 | 138 | How does the classic module format work? 139 | 140 | Notice that the instance of the module is created by the `defineStudent()` IIFE being executed. This IIFE returns an object (named `publicAPI`) that has a property on it referencing the inner `getName(..)` function. 141 | 142 | Naming the object `publicAPI` is stylistic preference on my part. The object can be named whatever you like (JS doesn't care), or you can just return an object directly without assigning it to any internal named variable. More on this choice in Appendix A. 143 | 144 | From the outside, `Student.getName(..)` invokes this exposed inner function, which maintains access to the inner `records` variable via closure. 145 | 146 | You don't *have* to return an object with a function as one of its properties. You could just return a function directly, in place of the object. That still satisfies all the core bits of a classic module. 147 | 148 | By virtue of how lexical scope works, defining variables and functions inside your outer module definition function makes everything *by default* private. Only properties added to the public API object returned from the function will be exported for external public use. 149 | 150 | The use of an IIFE implies that our program only ever needs a single central instance of the module, commonly referred to as a "singleton." Indeed, this specific example is simple enough that there's no obvious reason we'd need anything more than just one instance of the `Student` module. 151 | 152 | #### Module Factory (Multiple Instances) 153 | 154 | But if we did want to define a module that supported multiple instances in our program, we can slightly tweak the code: 155 | 156 | ```js 157 | // factory function, not singleton IIFE 158 | function defineStudent() { 159 | var records = [ 160 | { id: 14, name: "Kyle", grade: 86 }, 161 | { id: 73, name: "Suzy", grade: 87 }, 162 | { id: 112, name: "Frank", grade: 75 }, 163 | { id: 6, name: "Sarah", grade: 91 } 164 | ]; 165 | 166 | var publicAPI = { 167 | getName 168 | }; 169 | 170 | return publicAPI; 171 | 172 | // ************************ 173 | 174 | function getName(studentID) { 175 | var student = records.find( 176 | student => student.id == studentID 177 | ); 178 | return student.name; 179 | } 180 | } 181 | 182 | var fullTime = defineStudent(); 183 | fullTime.getName(73); // Suzy 184 | ``` 185 | 186 | Rather than specifying `defineStudent()` as an IIFE, we just define it as a normal standalone function, which is commonly referred to in this context as a "module factory" function. 187 | 188 | We then call the module factory, producing an instance of the module that we label `fullTime`. This module instance implies a new instance of the inner scope, and thus a new closure that `getName(..)` holds over `records`. `fullTime.getName(..)` now invokes the method on that specific instance. 189 | 190 | #### Classic Module Definition 191 | 192 | So to clarify what makes something a classic module: 193 | 194 | * There must be an outer scope, typically from a module factory function running at least once. 195 | 196 | * The module's inner scope must have at least one piece of hidden information that represents state for the module. 197 | 198 | * The module must return on its public API a reference to at least one function that has closure over the hidden module state (so that this state is actually preserved). 199 | 200 | You'll likely run across other variations on this classic module approach, which we'll look at in more detail in Appendix A. 201 | 202 | ## Node CommonJS Modules 203 | 204 | In Chapter 4, we introduced the CommonJS module format used by Node. Unlike the classic module format described earlier, where you could bundle the module factory or IIFE alongside any other code including other modules, CommonJS modules are file-based; one module per file. 205 | 206 | Let's tweak our module example to adhere to that format: 207 | 208 | ```js 209 | module.exports.getName = getName; 210 | 211 | // ************************ 212 | 213 | var records = [ 214 | { id: 14, name: "Kyle", grade: 86 }, 215 | { id: 73, name: "Suzy", grade: 87 }, 216 | { id: 112, name: "Frank", grade: 75 }, 217 | { id: 6, name: "Sarah", grade: 91 } 218 | ]; 219 | 220 | function getName(studentID) { 221 | var student = records.find( 222 | student => student.id == studentID 223 | ); 224 | return student.name; 225 | } 226 | ``` 227 | 228 | The `records` and `getName` identifiers are in the top-level scope of this module, but that's not the global scope (as explained in Chapter 4). As such, everything here is *by default* private to the module. 229 | 230 | To expose something on the public API of a CommonJS module, you add a property to the empty object provided as `module.exports`. In some older legacy code, you may run across references to just a bare `exports`, but for code clarity you should always fully qualify that reference with the `module.` prefix. 231 | 232 | For style purposes, I like to put my "exports" at the top and my module implementation at the bottom. But these exports can be placed anywhere. I strongly recommend collecting them all together, either at the top or bottom of your file. 233 | 234 | Some developers have the habit of replacing the default exports object, like this: 235 | 236 | ```js 237 | // defining a new object for the API 238 | module.exports = { 239 | // ..exports.. 240 | }; 241 | ``` 242 | 243 | There are some quirks with this approach, including unexpected behavior if multiple such modules circularly depend on each other. As such, I recommend against replacing the object. If you want to assign multiple exports at once, using object literal style definition, you can do this instead: 244 | 245 | ```js 246 | Object.assign(module.exports,{ 247 | // .. exports .. 248 | }); 249 | ``` 250 | 251 | What's happening here is defining the `{ .. }` object literal with your module's public API specified, and then `Object.assign(..)` is performing a shallow copy of all those properties onto the existing `module.exports` object, instead of replacing it This is a nice balance of convenience and safer module behavior. 252 | 253 | To include another module instance into your module/program, use Node's `require(..)` method. Assuming this module is located at "/path/to/student.js", this is how we can access it: 254 | 255 | ```js 256 | var Student = require("/path/to/student.js"); 257 | 258 | Student.getName(73); 259 | // Suzy 260 | ``` 261 | 262 | `Student` now references the public API of our example module. 263 | 264 | CommonJS modules behave as singleton instances, similar to the IIFE module definition style presented before. No matter how many times you `require(..)` the same module, you just get additional references to the single shared module instance. 265 | 266 | `require(..)` is an all-or-nothing mechanism; it includes a reference of the entire exposed public API of the module. To effectively access only part of the API, the typical approach looks like this: 267 | 268 | ```js 269 | var getName = require("/path/to/student.js").getName; 270 | 271 | // or alternately: 272 | 273 | var { getName } = require("/path/to/student.js"); 274 | ``` 275 | 276 | Similar to the classic module format, the publicly exported methods of a CommonJS module's API hold closures over the internal module details. That's how the module singleton state is maintained across the lifetime of your program. 277 | 278 | | NOTE: | 279 | | :--- | 280 | | In Node `require("student")` statements, non-absolute paths (`"student"`) assume a ".js" file extension and search "node_modules". | 281 | 282 | ## Modern ES Modules (ESM) 283 | 284 | The ESM format shares several similarities with the CommonJS format. ESM is file-based, and module instances are singletons, with everything private *by default*. One notable difference is that ESM files are assumed to be strict-mode, without needing a `"use strict"` pragma at the top. There's no way to define an ESM as non-strict-mode. 285 | 286 | Instead of `module.exports` in CommonJS, ESM uses an `export` keyword to expose something on the public API of the module. The `import` keyword replaces the `require(..)` statement. Let's adjust "students.js" to use the ESM format: 287 | 288 | ```js 289 | export { getName }; 290 | 291 | // ************************ 292 | 293 | var records = [ 294 | { id: 14, name: "Kyle", grade: 86 }, 295 | { id: 73, name: "Suzy", grade: 87 }, 296 | { id: 112, name: "Frank", grade: 75 }, 297 | { id: 6, name: "Sarah", grade: 91 } 298 | ]; 299 | 300 | function getName(studentID) { 301 | var student = records.find( 302 | student => student.id == studentID 303 | ); 304 | return student.name; 305 | } 306 | ``` 307 | 308 | The only change here is the `export { getName }` statement. As before, `export` statements can appear anywhere throughout the file, though `export` must be at the top-level scope; it cannot be inside any other block or function. 309 | 310 | ESM offers a fair bit of variation on how the `export` statements can be specified. For example: 311 | 312 | ```js 313 | export function getName(studentID) { 314 | // .. 315 | } 316 | ``` 317 | 318 | Even though `export` appears before the `function` keyword here, this form is still a `function` declaration that also happens to be exported. That is, the `getName` identifier is *function hoisted* (see Chapter 5), so it's available throughout the whole scope of the module. 319 | 320 | Another allowed variation: 321 | 322 | ```js 323 | export default function getName(studentID) { 324 | // .. 325 | } 326 | ``` 327 | 328 | This is a so-called "default export," which has different semantics from other exports. In essence, a "default export" is a shorthand for consumers of the module when they `import`, giving them a terser syntax when they only need this single default API member. 329 | 330 | Non-`default` exports are referred to as "named exports." 331 | 332 | The `import` keyword—like `export`, it must be used only at the top level of an ESM outside of any blocks or functions—also has a number of variations in syntax. The first is referred to as "named import": 333 | 334 | ```js 335 | import { getName } from "/path/to/students.js"; 336 | 337 | getName(73); // Suzy 338 | ``` 339 | 340 | As you can see, this form imports only the specifically named public API members from a module (skipping anything not named explicitly), and it adds those identifiers to the top-level scope of the current module. This type of import is a familiar style to those used to package imports in languages like Java. 341 | 342 | Multiple API members can be listed inside the `{ .. }` set, separated with commas. A named import can also be *renamed* with the `as` keyword: 343 | 344 | ```js 345 | import { getName as getStudentName } 346 | from "/path/to/students.js"; 347 | 348 | getStudentName(73); 349 | // Suzy 350 | ``` 351 | 352 | If `getName` is a "default export" of the module, we can import it like this: 353 | 354 | ```js 355 | import getName from "/path/to/students.js"; 356 | 357 | getName(73); // Suzy 358 | ``` 359 | 360 | The only difference here is dropping the `{ }` around the import binding. If you want to mix a default import with other named imports: 361 | 362 | ```js 363 | import { default as getName, /* .. others .. */ } 364 | from "/path/to/students.js"; 365 | 366 | getName(73); // Suzy 367 | ``` 368 | 369 | By contrast, the other major variation on `import` is called "namespace import": 370 | 371 | ```js 372 | import * as Student from "/path/to/students.js"; 373 | 374 | Student.getName(73); // Suzy 375 | ``` 376 | 377 | As is likely obvious, the `*` imports everything exported to the API, default and named, and stores it all under the single namespace identifier as specified. This approach most closely matches the form of classic modules for most of JS's history. 378 | 379 | | NOTE: | 380 | | :--- | 381 | | As of the time of this writing, modern browsers have supported ESM for a few years now, but Node's stable'ish support for ESM is fairly recent, and has been evolving for quite a while. The evolution is likely to continue for another year or more; the introduction of ESM to JS back in ES6 created a number of challenging compatibility concerns for Node's interop with CommonJS modules. Consult Node's ESM documentation for all the latest details: https://nodejs.org/api/esm.html | 382 | 383 | ## Exit Scope 384 | 385 | Whether you use the classic module format (browser or Node), CommonJS format (in Node), or ESM format (browser or Node), modules are one of the most effective ways to structure and organize your program's functionality and data. 386 | 387 | The module pattern is the conclusion of our journey in this book of learning how we can use the rules of lexical scope to place variables and functions in proper locations. POLE is the defensive *private by default* posture we always take, making sure we avoid over-exposure and interact only with the minimal public API surface area necessary. 388 | 389 | And underneath modules, the *magic* of how all our module state is maintained is closures leveraging the lexical scope system. 390 | 391 | That's it for the main text. Congratulations on quite a journey so far! As I've said numerous times throughout, it's a really good idea to pause, reflect, and practice what we've just discussed. 392 | 393 | When you're comfortable and ready, check out the appendices, which dig deeper into some of the corners of these topics, and also challenge you with some practice exercises to solidify what you've learned. 394 | -------------------------------------------------------------------------------- /scope-closures/foreword.md: -------------------------------------------------------------------------------- 1 | # You Don't Know JS Yet: Scope & Closures - 2nd Edition 2 | # Foreword 3 | 4 | If I look over the books on my bookshelf, I can clearly see which of these titles are well loved. Well loved in this sense meaning they are a little worn. Their binding is broken, their pages are tattered, there might even be a spilled drink smear or two. What’s ironic to me is that the most loved of my books often _**look**_ the least cared for, though honestly the opposite is true. 5 | 6 | *Scope and Closures* (1st ed.) is one of my most loved books. It’s small, but the binding is coming undone. The pages are worn and dog-eared. It’s a bit rumpled. It’s not a book I’ve read once. I’ve picked it up again and again in the many years since it was originally published. 7 | 8 | For me, it’s also been a benchmark for my own personal progression through JavaScript. When I first read it in 2014, I was familiar with the concepts but the depth of my understanding was admittedly not as deep as the thin volume. 9 | 10 | Over the years, even though I wasn’t necessarily feeling my own improvement on a day-to-day basis, each one of the concepts became more approachable. I’d smile to myself, realizing how far I’d come with the help of these guides. It became apparent there was an inverse correlation between how well I treated the book and how much I loved it. 11 | 12 | When Kyle asked me to write the Foreword for the 2nd edition, I was floored. It’s not often you’re asked to write about a book that’s been so formative for your own understanding and career, *Scope and Closures* in particular. I remember the day I first understood closures, the first time I used one well. The satisfaction was great, in part because the symmetry of the idea was compelling to me. Before I even picked this book up, I was already enamoured with closures. And yet, there’s a difference between being able to execute code successfully and fully explore the concepts with any depth. This book took my base understanding and drew it out, helped me master it. 13 | 14 | This book is deceptively short. It’s helpful that it’s small because it’s dense with useful knowledge. Since it is compact, I’d suggest you give yourself time to absorb each page. Take your time with it. Treat the book with care, and by that I mean, wear it down. 15 | 16 | Sarah Drasner
17 | Head of Developer Experience
18 | Netlify 19 | -------------------------------------------------------------------------------- /scope-closures/images/cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getify/You-Dont-Know-JS/e3f784bcb18ba47a9e6ced0866bc361393fb299f/scope-closures/images/cover.png -------------------------------------------------------------------------------- /scope-closures/images/fig1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getify/You-Dont-Know-JS/e3f784bcb18ba47a9e6ced0866bc361393fb299f/scope-closures/images/fig1.png -------------------------------------------------------------------------------- /scope-closures/images/fig2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getify/You-Dont-Know-JS/e3f784bcb18ba47a9e6ced0866bc361393fb299f/scope-closures/images/fig2.png -------------------------------------------------------------------------------- /scope-closures/images/fig3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getify/You-Dont-Know-JS/e3f784bcb18ba47a9e6ced0866bc361393fb299f/scope-closures/images/fig3.png -------------------------------------------------------------------------------- /scope-closures/images/fig4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getify/You-Dont-Know-JS/e3f784bcb18ba47a9e6ced0866bc361393fb299f/scope-closures/images/fig4.png -------------------------------------------------------------------------------- /scope-closures/images/fig5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getify/You-Dont-Know-JS/e3f784bcb18ba47a9e6ced0866bc361393fb299f/scope-closures/images/fig5.png -------------------------------------------------------------------------------- /scope-closures/toc.md: -------------------------------------------------------------------------------- 1 | # You Don't Know JS Yet: Scope & Closures - 2nd Edition 2 | 3 | ## Table of Contents 4 | 5 | * Foreword 6 | * Preface 7 | * Chapter 1: What's the Scope? 8 | * About This Book 9 | * Compiled vs. Interpreted 10 | * Compiling Code 11 | * Compiler Speak 12 | * Cheating: Run-Time Scope Modifications 13 | * Lexical Scope 14 | * Chapter 2: Illustrating Lexical Scope 15 | * Marbles, and Buckets, and Bubbles... Oh My! 16 | * A Conversation Among Friends 17 | * Nested Scope 18 | * Continue the Conversation 19 | * Chapter 3: The Scope Chain 20 | * "Lookup" Is (Mostly) Conceptual 21 | * Shadowing 22 | * Function Name Scope 23 | * Arrow Functions 24 | * Backing Out 25 | * Chapter 4: Around the Global Scope 26 | * Why Global Scope? 27 | * Where Exactly is this Global Scope? 28 | * Global This 29 | * Globally Aware 30 | * Chapter 5: The (Not So) Secret Lifecycle of Variables 31 | * When Can I Use a Variable? 32 | * Hoisting: Yet Another Metaphor 33 | * Re-declaration? 34 | * Uninitialized Variables (aka, TDZ) 35 | * Finally Initialized 36 | * Chapter 6: Limiting Scope Exposure 37 | * Least Exposure 38 | * Hiding in Plain (Function) Scope 39 | * Scoping with Blocks 40 | * Function Declarations in Blocks 41 | * Blocked Over 42 | * Chapter 7: Using Closures 43 | * See the Closure 44 | * The Closure Lifecycle and Garbage Collection (GC) 45 | * An Alternative Perspective 46 | * Why Closure? 47 | * Closer to Closure 48 | * Chapter 8: The Module Pattern 49 | * Encapsulation and Least Exposure (POLE) 50 | * What is a Module? 51 | * Node CommonJS Modules 52 | * Modern ES Modules (ESM) 53 | * Exit Scope 54 | * Appendix A: Exploring Further 55 | * Implied Scopes 56 | * Anonymous vs. Named Functions 57 | * Hoisting: Functions and Variables 58 | * The Case for `var` 59 | * What's the Deal with TDZ? 60 | * Are Synchronous Callbacks Still Closures? 61 | * Classic Module Variations 62 | * Appendix B: Practice 63 | * Buckets of Marbles 64 | * Closure (PART 1) 65 | * Closure (PART 2) 66 | * Closure (PART 3) 67 | * Modules 68 | * Suggested Solutions 69 | -------------------------------------------------------------------------------- /sync-async/README.md: -------------------------------------------------------------------------------- 1 | # You Don't Know JS Yet: Async & Performance - 2nd Edition 2 | 3 | | NOTE: | 4 | | :--- | 5 | | Work in progress | 6 | 7 | [Table of Contents](toc.md) 8 | 9 | * [Foreword](foreword.md) (by TBA) 10 | * [Preface](../preface.md) 11 | * [Chapter 1: TODO](ch1.md) 12 | -------------------------------------------------------------------------------- /sync-async/ch1.md: -------------------------------------------------------------------------------- 1 | # You Don't Know JS Yet: Sync & Async - 2nd Edition 2 | # Chapter 1: TODO 3 | 4 | | NOTE: | 5 | | :--- | 6 | | Work in progress | 7 | 8 | -------------------------------------------------------------------------------- /sync-async/foreword.md: -------------------------------------------------------------------------------- 1 | # You Don't Know JS Yet: Async & Performance - 2nd Edition 2 | # Foreword 3 | 4 | | NOTE: | 5 | | :--- | 6 | | Work in progress | 7 | -------------------------------------------------------------------------------- /sync-async/toc.md: -------------------------------------------------------------------------------- 1 | # You Don't Know JS Yet: Sync & Async - 2nd Edition 2 | 3 | | NOTE: | 4 | | :--- | 5 | | Work in progress | 6 | 7 | ## Table of Contents 8 | 9 | * Foreword 10 | * Preface 11 | * Chapter 1: TODO 12 | * TODO 13 | -------------------------------------------------------------------------------- /types-grammar/README.md: -------------------------------------------------------------------------------- 1 | # You Don't Know JS Yet: Types & Grammar - 2nd Edition 2 | 3 | | NOTE: | 4 | | :--- | 5 | | Work in progress | 6 | 7 | [Table of Contents](toc.md) 8 | 9 | * [Foreword](foreword.md) (by TBA) 10 | * [Preface](../preface.md) 11 | * [Chapter 1: Primitive Values](ch1.md) 12 | * [Chapter 2: Primitive Behaviors](ch2.md) 13 | * [Chapter 3: Object Values](ch3.md) 14 | * [Chapter 4: Coercing Values](ch4.md) 15 | * Chapter 5: TODO 16 | * [Thank You!](thanks.md) 17 | -------------------------------------------------------------------------------- /types-grammar/ch3.md: -------------------------------------------------------------------------------- 1 | # You Don't Know JS Yet: Types & Grammar - 2nd Edition 2 | # Chapter 3: Object Values 3 | 4 | | NOTE: | 5 | | :--- | 6 | | Work in progress | 7 | 8 | Now that we're comfortable with the built-in primitive types, we turn our attention to the `object` types in JS. 9 | 10 | I could write a whole book talking about objects in-depth; in fact, I already did! The "Objects & Classes" title of this series covers objects in-depth already, so make sure you've read that before continuing with this chapter. 11 | 12 | Rather than repeat that book's content, here we'll focus our attention on how the `object` value-type behaves and interacts with other values in JS. 13 | 14 | ## Types of Objects 15 | 16 | The `object` value-type comprises several sub-types, each with specialized behaviors, including: 17 | 18 | * plain objects 19 | * fundamental objects (boxed primitives) 20 | * built-in objects 21 | * arrays 22 | * regular expressions 23 | * functions (aka, "callable objects") 24 | 25 | Beyond the specialized behaviors, one shared characteristic is that all objects can act as collections (of properties) holding values (including functions/methods). 26 | 27 | ## Plain Objects 28 | 29 | The general object value-type is sometimes referred to as *plain ol' javascript objects* (POJOs). 30 | 31 | Plain objects have a literal form: 32 | 33 | ```js 34 | address = { 35 | street: "12345 Market St", 36 | city: "San Francisco", 37 | state: "CA", 38 | zip: "94114" 39 | }; 40 | ``` 41 | 42 | This plain object (POJO), as defined with the `{ .. }` curly braces, is a collection of named properties (`street`, `city`, `state`, and `zip`). Properties can hold any values, primitives or other objects (including arrays, functions, etc). 43 | 44 | The same object could also have been defined imperatively using the `new Object()` constructor: 45 | 46 | ```js 47 | address = new Object(); 48 | address.street = "12345 Market St"; 49 | address.city = "San Francisco"; 50 | address.state = "CA"; 51 | address.zip = "94114"; 52 | ``` 53 | 54 | Plain objects are by default `[[Prototype]]` linked to `Object.prototype`, giving them delegated access to several general object methods, such as: 55 | 56 | * `toString()` / `toLocaleString()` 57 | * `valueOf()` 58 | * `isPrototypeOf(..)` 59 | * `hasOwnProperty(..)` (recently deprecated -- alternative: static `Object.hasOwn(..)` utility) 60 | * `propertyIsEnumerable(..)` 61 | * `__proto__` (getter function) 62 | 63 | ```js 64 | address.isPrototypeOf(Object.prototype); // true 65 | address.isPrototypeOf({}); // false 66 | ``` 67 | 68 | ## Fundamental Objects 69 | 70 | JS defines several *fundamental* object types, which are instances of various built-in constructors, including: 71 | 72 | * `new String()` 73 | * `new Number()` 74 | * `new Boolean()` 75 | 76 | Note that these constructors must be used with the `new` keyword to construct instances of the fundamental objects. Otherwise, these functions actually perform type coercion (see Chapter 4). 77 | 78 | These fundamental object constructors create object value-types instead of a primitives: 79 | 80 | ```js 81 | myName = "Kyle"; 82 | typeof myName; // "string" 83 | 84 | myNickname = new String("getify"); 85 | typeof myNickname; // "object" 86 | ``` 87 | 88 | In other words, an instance of a fundamental object constructor can actually be seen as a wrapper around the corresponding underlying primitive value. 89 | 90 | | WARNING: | 91 | | :--- | 92 | | It's nearly universally regarded as *bad practice* to ever directly instantiate these fundamental objects. The primitive counterparts are generally more predictable, more performant, and offer *auto-boxing* (see "Automatic Objects" section below) whenever the underlying object-wrapper form is needed for property/method access. | 93 | 94 | The `Symbol(..)` and `BigInt(..)` functions are referred to in the specification as "constructors", though they're not used with the `new` keyword, and the values they produce in a JS program are indeed primitives. 95 | 96 | How, there are internal *fundamental objects* for these two types, used for prototype delegation and *auto-boxing*. 97 | 98 | By contrast, for `null` and `undefined` primitive values, there aren't `Null()` or `Undefined()` "constructors", nor corresponding fundamental objects or prototypes. 99 | 100 | ### Prototypes 101 | 102 | Instances of the fundamental object constructors are `[[Prototype]]` linked to their constructors' `prototype` objects: 103 | 104 | * `String.prototype`: defines `length` property, as well as string-specific methods, like `toUpperCase()`, etc. 105 | 106 | * `Number.prototype`: defines number-specific methods, like `toPrecision(..)`, `toFixed(..)`, etc. 107 | 108 | * `Boolean.prototype`: defines default `toString()` and `valueOf()` methods. 109 | 110 | * `Symbol.prototype`: defines `description` (getter), as well as default `toString()` and `valueOf()` methods. 111 | 112 | * `BigInt.prototype`: defines default `toString()`, `toLocaleString()`, and `valueOf()` methods. 113 | 114 | Any direct instance of the built-in constructors have `[[Prototype]]` delegated access to its respective `prototype` properties/methods. Moreover, corresponding primitive values also have such delegated access, by way of *auto-boxing*. 115 | 116 | ### Automatic Objects 117 | 118 | I've mentioned *auto-boxing* several times (including Chapters 1 and 2, and a few times so far in this chapter). It's finally time for us to explain that concept. 119 | 120 | Accessing a property or method on a value requires that the value be an object. As we've already seen in Chapter 1, primitives *are not* objects, so JS needs to then temporarily convert/wrap such a primitive to its fundamental object counterpart[^AutoBoxing] to perform that access. 121 | 122 | For example: 123 | 124 | ```js 125 | myName = "Kyle"; 126 | 127 | myName.length; // 4 128 | 129 | myName.toUpperCase(); // "KYLE" 130 | ``` 131 | 132 | Accessing the `length` property or the `toUpperCase()` method, is only allowed on a primitive string value because JS *auto-boxes* the primitive `string` into a wrapper fundamental object, an instance of `new String(..)`. Otherwise, all such accesses would have to fail, since primitives do not have any properties. 133 | 134 | More importantly, when the primitive value is *auto-boxed* to its fundamental object counterpart, those internally created objects have access to predefined properties/methods (like `length` and `toUpperCase()`) via a `[[Prototype]]` link to their respective fundamental object's prototype. 135 | 136 | So an *auto-boxed* `string` is an instance of `new String()`, and is thus linked to `String.prototype`. Further, the same is true of `number` (wrapped as an instance of `new Number()`) and `boolean` (wrapped as an instance of `new Boolean()`). 137 | 138 | Even though the `Symbol(..)` and `BigInt(..)` "constructors" (used without `new`produce primitive values, these primitive values can also be *auto-boxed* to their internal fundamental object wrapper forms, for the purposes of delegated access to properties/methods. 139 | 140 | | NOTE: | 141 | | :--- | 142 | | See the "Objects & Classes" book of this series for more on `[[Prototype]]` linkages and delegated/inherited access to the fundamental object constructors' prototype objects. | 143 | 144 | Since `null` and `undefined` have no corresponding fundamental objects, there is no *auto-boxing* of these values. 145 | 146 | A subjective question to consider: is *auto-boxing* a form of coercion? I say it is, though some disagree. Internally, a primitive is converted to an object, meaning a change in value-type has occurred. Yes, it's temporary, but plenty of coercions are temporary. Moreover, the conversion is rather *implicit* (implied by the property/method access, but only happens internally). We'll revisit the nature of coercion in Chapter 4. 147 | 148 | ## Other Built-in Objects 149 | 150 | In addition to fundamental object constructors, JS defines a number of other built-in constructors that create further specialized object sub-types: 151 | 152 | * `new Date(..)` 153 | * `new Error(..)` 154 | * `new Map(..)`, `new Set(..)`, `new WeakMap(..)`, `new WeakSet(..)` -- keyed collections 155 | * `new Int8Array(..)`, `new Uint32Array(..)`, etc -- indexed, typed-array collections 156 | * `new ArrayBuffer(..)`, `new SharedArrayBuffer(..)`, etc -- structured data collections 157 | 158 | ## Arrays 159 | 160 | Arrays are objects that are specialized to behave as numerically indexed collections of values, as opposed to holding values at named properties like plain objects do. 161 | 162 | Arrays have a literal form: 163 | 164 | ```js 165 | favoriteNumbers = [ 3, 12, 42 ]; 166 | 167 | favoriteNumbers[2]; // 42 168 | ``` 169 | 170 | The same array could also have been defined imperatively using the `new Array()` constructor: 171 | 172 | ```js 173 | favoriteNumbers = new Array(); 174 | favoriteNumbers[0] = 3; 175 | favoriteNumbers[1] = 12; 176 | favoriteNumbers[2] = 42; 177 | ``` 178 | 179 | Arrays are `[[Prototype]]` linked to `Array.prototype`, giving them delegated access to a variety of array-oriented methods, such as `map(..)`, `includes(..)`, etc: 180 | 181 | ```js 182 | favoriteNumbers.map(v => v * 2); 183 | // [ 6, 24, 84 ] 184 | 185 | favoriteNumbers.includes(42); // true 186 | ``` 187 | 188 | Some of the methods defined on `Array.prototype` -- for example, `push(..)`, `pop(..)`, `sort(..)`, etc -- behave by modifying the array value in place. Other methods -- for example, `concat(..)`, `map(..)`, `slice(..)` -- behave by creating a new array to return, leaving the original array intact. A third category of array functions -- for example, `indexOf(..)`, `includes(..)`, etc -- merely computes and returns a (non-array) result. 189 | 190 | ## Regular Expressions 191 | 192 | // TODO 193 | 194 | ## Functions 195 | 196 | // TODO 197 | 198 | ## Proposed: Records/Tuples 199 | 200 | At the time of this writing, a (stage-2) proposal[^RecordsTuplesProposal] exists to add a new set of features to JS, which correspond closely to plain objects and arrays, but with some notable differences. 201 | 202 | Records are similar to plain objects, but are immutable (sealed, read-only), and (unlike objects) are treated as primitive values, for the purposes of value assignment and equality comparison. The syntax difference is a `#` before the `{ }` delimiter. Records can only contain primitive values (including records and tuples). 203 | 204 | Tuples have exactly the same relationship, but to arrays, including the `#` before the `[ ]` delimiters. 205 | 206 | It's important to note that while these look and seem like objects/arrays, they are indeed primitive (non-object) values. 207 | 208 | [^FundamentalObjects]: "20 Fundamental Objects", EcamScript 2022 Language Specification; https://262.ecma-international.org/13.0/#sec-fundamental-objects ; Accessed August 2022 209 | 210 | [^AutoBoxing]: "6.2.4.6 PutValue(V,W)", Step 5.a, ECMAScript 2022 Language Specification; https://262.ecma-international.org/13.0/#sec-putvalue ; Accessed August 2022 211 | 212 | [^RecordsTuplesProposal]: "JavaScript Records & Tuples Proposal"; Robin Ricard, Rick Button, Nicolò Ribaudo; 213 | https://github.com/tc39/proposal-record-tuple ; Accessed August 2022 214 | -------------------------------------------------------------------------------- /types-grammar/foreword.md: -------------------------------------------------------------------------------- 1 | # You Don't Know JS Yet: Types & Grammar - 2nd Edition 2 | # Foreword 3 | 4 | | NOTE: | 5 | | :--- | 6 | | Work in progress | 7 | -------------------------------------------------------------------------------- /types-grammar/thanks.md: -------------------------------------------------------------------------------- 1 | # You Don't Know JS Yet: Types & Grammar - 2nd Edition 2 | # Thank You! 3 | 4 | The following 371 Kickstarter backers generously backed the campaign to write/publish the four remaining books of the second edition. Without their faithful and patient support, these books would not have happened. 5 | 6 | I am deeply grateful to each of you! 7 | 8 | > Marc at Frontend Masters, Bassim, Tasos Tsournos, Lauren Clark, Simon, Appgrader, Marcos S., Noah Rodenbeek, Lichtjaeger, Jon Miller, Anil, Greg Gerard, Frank Deberle, Davide Bonifacio, Brandon Leichty, Rowdy Rabouw, Gaspar Radu, Sukumar Vaddi, Gordon, jakecodes, Leo Furze-Waddock, Nick de Jong, D. Vinci, Brian Vogel, Gareth loot, Simon Taylor, Chris O’Brien, Nayana Davis, Mark Kramer, Sunil Samuel, @nestor.j.g, Ryan McDaniel, Mert Even, Haim Yulzari, Josh Marks, Chiril Sarajiu, Barnabas Jovanovics, LynchyC, Yahya Jideh, Chris Weber, Dan Cortes, Johnny Tordgeman, Ky Lee, Brian Wisti, Steven Marrocco, Thomas Randolph, Petri Lindholm, John Cole, github, @denysmarkov, Jacob Scherber, Pierre-Yves Lebrun, mcekiera, Matthew Wasbrough, Génicot Jean-Baptiste, Adam Zając, Lenny Erlesand, Samuel Gustafsson, Hunter Jansen, Theo Armour, Nate Hargitt, Anon, Github repo, cawel, mpelikan, @farisaziz12, Ojars, Camilo Segura, Sean Seagren, Michael Vendivel, Evan, Eric Schwertfeger, Gene Garbutt, Elena Rogleva, Fiona Cheung, Anton Levholm, Lorenzo Bersano, Ando NARY, Ruben Krbashyan, Anonymous please, @jcubic, Bhavin Dave, A. Hitchcock, H0rn0chse, Yaniv Wainer, Zach, Raúl Pineda, Rohan Gupta, Karthik, Kapil, Ricardo Trejos, InvisibleLuis, BruceRobertson, Neil Lupton, Chris Schweda, Luca Mezzalira, antonio molinari, David Pinezich, Jon Barson, Nick Kaufmann, Just Andrew, Rock Kayode Winner, @omar12, Page Han, Aurélien Bottazini, Michael, Petr Siegl, Ilya Sarantsev, Alfredo Delgado, aharvard, Jannaee, Aaron McBride, Toma, epmatsw, Igor "kibertoad" Savin, Christian Rackerseder, NC Patro, Kevin, Brian Holt, Brian Ashenfelter, Selina Chang, cwavedave, Alex Grant, Craig Robertson, Eduardo Sanz Martin, oieduardorabelo, Esteban Massuh, tedhexaflow, Gershon Gerchikov, Harika Yedidi, Brad Dougherty, Nitin, Leo Balter, Syed Ahmad, Kaz de Groot, Pinnemouche Studio, Jerome Amos, Dan Poynor, John Liu, @thedavefulton, Madeline Bernard, Ikigai42, Antonio Chillaron, Sachin, Prakasam Venkatachalam, jmarti705, Mihailo23, Mihailo Pantovic, Magloire, samrudh, Mykenzie Rogers, Len, Lyza Danger Gardner, Ryan, Roman, Radojica Radivojevic, Gabrien Symons, Ryan Parker, Andrés, Merlin, rushabh_badani, notacouch, Anna Borja, Steve Albers, Marc at Frontend Masters, Bala Vemula, @chrismcdonald84, stern9, Janne Hellsten, Alexandre Madurell, Tanner Hodges, Joe Chellman, Joachim Kliemann, Stefano Frasson Pianizzola, Sergey Kochergan, Spiridonov Dmitriy, IonutBihari, Alexandru Olteanu, Javi, Marlee Peters, @vadocondes1, Gerardo Leal, Albert Sebastian, Atish Raina, Andreas Gebhardt, David Deren, Maksym Gerashchenko, Alexandru, Matt Peck, William Lacroix, Pavlo, Jon, Brett Walker, Iosif Psychas, Ferran Buireu, crs1138, Emiliano anichini, Max Koretskyi, Sander Elias, Michael Romanov, Barkóczi Dávid, Daw-Chih Liou, Dale Caffull, Amanda Dillon, Mike, Justin Hefko, Muhammad Ali Shah, Ketan Srivastav, redeemefy, Stefan Trivunčić, Manuel Juan Fosela Águila, Dragan Majstorović, Harsha C G, Himanshu, Luke, Sai Ponnada, Mark Franco, David Whittaker, Dr. Teresa Vasquez, Ian Wright, Lora Rusinouskaya, Petar, Harish, Mairead, shimon simo moyal, Sunny Puri, Максим Кочанов, Alex Georoceanu, Nicolas Carreras, damijanc, zach.dev, Coati, Brian Whitton, Denis Ciccale, Piotr Seefeld, Chase Hagwood, Amritha K, Κώστας Μηναϊδης, Trey Aughenbaugh, J David Eisenberg, Paul Thaden, Corina S, Chris Dhanaraj, Nahid Hossain, Justin McCullough, Arseny, Mark Trostler, Lucy Barker, Maaz Syed Adeeb, mcginkel, Derick Rodriguez, Helen Tsui, Rus Ustyugov, Vassilis Mastorostergios, Ryan Ewing, Rob Huelga, jinujj, ultimateoverload, Chaos, Andy Howell (spacebeers), Archana, AG Grid, theblang, Coyotiv School of Software Engineering, Ayush Rajniwal, Manish Bhatt, Shea Leslein, Jordan Chipman, jg0x42, Arvind Kumar, Eduardo Grigolo, Peter Svegrup, Jakub Kotula, William Richardson, Jonah and Ali, nicciwill, Lauren Hodges, Travis Sauer, Alexandros, Abhas, Kirankumar Ambati, Gopalakrishnan, Mika Rehman, Sreeram Sama, Shubhamsatyam Verma, Heejae Chang, Andrico karoulla, Niek Heezemans, Stanislav Horáček, Luis Ibanhi, Jasmine Wang, Yunier, Brian Barrow, Matteo Hertel, Aleksandar Milicevic, achung89, kushavi, Ahmed Fouad, Venkat Kaluva, Ian Wotkun, Andreas Näsman, ivan-siachoque, Paul Gain, Santhosh R, Gustavo Morales, ScottAwseome, Fredrik Thorkildsen, Manvel, holleB, James Sullivan, Adam Kaźmierczak, carlottosson, Alvee, Alex Reardon, Olie Chan, Fredrik S, Brett.Buskirk, Rui Sereno, Nathan Strong, lostdesign, ppseprus, James, anthonybsd, Alena Charnova, Kevin K, @codingthirty, Tim Davis, Jonathan Yee, Christa, Fabian Merchan, Nathanael McDaniel, Dave N, Brian Chirgwin, Abdulrahman (Abdu) Assabri, rmeja, Jan Václavek, Phillip Hogan, Adhithya Rajagopalan (xadhix), Jason Humphrey, Antoinette Smith, Elliot Redhead, zokocx, John Sims, Michalis Garganourakis, Adarsh Konchady, Anton Oleg Dobrovolskyy, George Tharakan, syd, Ryan D., Iris Nathan, Srishti Gupta, Miguel Rivero, @saileshraghavan, Yojan, @bgollum, Junyts, Like Ezugworie, Vsh13, LocalPCGuy, DMGabriel, Juan Tincho, William Greenlaw, atisbacsi, cris ryan tan, Jonathan Clifron, Daniel Dolich, Praj, Caisman, Michał, Mark C, 3xpedia 9 | 10 | A special thanks to: 11 | 12 | * A. Hitchcock 13 | * Alexandru 14 | * Appgrader 15 | * Coyotiv School of Software Engineering 16 | * Gaspar Radu 17 | * IonutBihari 18 | * jmarti705 19 | * John Liu 20 | * Syed Ahmad 21 | * Travis Sauer 22 | * William Greenlaw 23 | 24 | All of you are fantastic! 25 | -------------------------------------------------------------------------------- /types-grammar/toc.md: -------------------------------------------------------------------------------- 1 | # You Don't Know JS Yet: Types & Grammar - 2nd Edition 2 | 3 | | NOTE: | 4 | | :--- | 5 | | Work in progress | 6 | 7 | ## Table of Contents 8 | 9 | * Foreword 10 | * Preface 11 | * Chapter 1: Primitive Values 12 | * Value Types 13 | * Empty Values 14 | * Boolean Values 15 | * String Values 16 | * Number Values 17 | * BigInteger Values 18 | * Symbol Values 19 | * Primitives Are Built-In Types 20 | * Chapter 2: Primitive Behaviors 21 | * Primitive Immutability 22 | * Primitive Assignments 23 | * String Behaviors 24 | * Number Behaviors 25 | * Primitives Are Foundational 26 | * Chapter 3: Object Values 27 | * Types of Objects 28 | * Plain Objects 29 | * Fundamental Objects 30 | * Other Built-in Objects 31 | * Arrays 32 | * Regular Expressions 33 | * Functions 34 | * Proposed: Records/Tuples 35 | * TODO 36 | * Chapter 4: Coercing Values 37 | * Coercion: Explicit vs Implicit 38 | * Abstracts 39 | * Concrete Coercions 40 | * Coercion Corner Cases 41 | * Type Awareness 42 | * What's Left? 43 | * Thank You! 44 | -------------------------------------------------------------------------------- /unbooks-cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getify/You-Dont-Know-JS/e3f784bcb18ba47a9e6ced0866bc361393fb299f/unbooks-cover.png --------------------------------------------------------------------------------