[
  {
    "path": ".gitignore",
    "content": ""
  },
  {
    "path": "LICENSE.txt",
    "content": "Creative Commons\nAttribution-NonCommercial-NoDerivs 3.0 Unported\n\n    CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN \"AS-IS\" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE. \n\nLicense\n\nTHE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE (\"CCPL\" OR \"LICENSE\"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.\n\nBY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.\n\n1. Definitions\n\n    \"Adaptation\" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image (\"synching\") will be considered an Adaptation for the purpose of this License.\n    \"Collection\" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(f) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined above) for the purposes of this License.\n    \"Distribute\" means to make available to the public the original and copies of the Work through sale or other transfer of ownership.\n    \"Licensor\" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License.\n    \"Original Author\" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast.\n    \"Work\" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work.\n    \"You\" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation.\n    \"Publicly Perform\" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images.\n    \"Reproduce\" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium.\n\n2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws.\n\n3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below:\n\n    to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections; and,\n    to Distribute and Publicly Perform the Work including as incorporated in Collections.\n\nThe above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats, but otherwise you have no rights to make Adaptations. Subject to 8(f), all rights not expressly granted by Licensor are hereby reserved, including but not limited to the rights set forth in Section 4(d).\n\n4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions:\n\n    You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(c), as requested.\n    You may not exercise any of the rights granted to You in Section 3 above in any manner that is primarily intended for or directed toward commercial advantage or private monetary compensation. The exchange of the Work for other copyrighted works by means of digital file-sharing or otherwise shall not be considered to be intended for or directed toward commercial advantage or private monetary compensation, provided there is no payment of any monetary compensation in connection with the exchange of copyrighted works.\n    If You Distribute, or Publicly Perform the Work or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution (\"Attribution Parties\") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work. The credit required by this Section 4(c) may be implemented in any reasonable manner; provided, however, that in the case of a Collection, at a minimum such credit will appear, if a credit for all contributing authors of Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties.\n\n    For the avoidance of doubt:\n        Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License;\n        Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License if Your exercise of such rights is for a purpose or use which is otherwise than noncommercial as permitted under Section 4(b) and otherwise waives the right to collect royalties through any statutory or compulsory licensing scheme; and,\n        Voluntary License Schemes. The Licensor reserves the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License that is for a purpose or use which is otherwise than noncommercial as permitted under Section 4(b).\n    Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation.\n\n5. Representations, Warranties and Disclaimer\n\nUNLESS OTHERWISE MUTUALLY AGREED BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.\n\n6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n\n7. Termination\n\n    This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License.\n    Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above.\n\n8. Miscellaneous\n\n    Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License.\n    If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.\n    No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent.\n    This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You.\n    The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law.\n\n    Creative Commons Notice\n\n    Creative Commons is not a party to this License, and makes no warranty whatsoever in connection with the Work. Creative Commons will not be liable to You or any party on any legal theory for any damages whatsoever, including without limitation any general, special, incidental or consequential damages arising in connection to this license. Notwithstanding the foregoing two (2) sentences, if Creative Commons has expressly identified itself as the Licensor hereunder, it shall have all rights and obligations of Licensor.\n\n    Except for the limited purpose of indicating to the public that the Work is licensed under the CCPL, Creative Commons does not authorize the use by either party of the trademark \"Creative Commons\" or any related trademark or logo of Creative Commons without the prior written consent of Creative Commons. Any permitted use will be in compliance with Creative Commons' then-current trademark usage guidelines, as may be published on its website or otherwise made available upon request from time to time. For the avoidance of doubt, this trademark restriction does not form part of this License.\n\n    Creative Commons may be contacted at http://creativecommons.org/."
  },
  {
    "path": "README.md",
    "content": "# Вы не знаете JS (серия книг)\n\nПредставляю вам серию книг, погружение в которую позволит вам окунуться в основные механизмы языка JavaScript. Первое издание серии книг в настоящий момент завершено.\n\n<a href=\"http://shop.oreilly.com/product/0636920039303.do\"><img src=\"up %26 going/cover.jpg\" width=\"75\"></a>&nbsp;\n<a href=\"http://shop.oreilly.com/product/0636920026327.do\"><img src=\"scope %26 closures/cover.jpg\" width=\"75\"></a>&nbsp;\n<a href=\"http://shop.oreilly.com/product/0636920033738.do\"><img src=\"this %26 object prototypes/cover.jpg\" width=\"75\"></a>&nbsp;\n<a href=\"http://shop.oreilly.com/product/0636920033745.do\"><img src=\"types %26 grammar/cover.jpg\" width=\"75\"></a>&nbsp;\n<a href=\"http://shop.oreilly.com/product/0636920033752.do\"><img src=\"async %26 performance/cover.jpg\" width=\"75\"></a>&nbsp;\n<a href=\"http://shop.oreilly.com/product/0636920033769.do\"><img src=\"es6 %26 beyond/cover.jpg\" width=\"75\"></a>\n\nНе стесняйтесь вносить свой вклад в улучшение качества материала данной серии книг, отправляйте свои PR для улучшения фрагментов кода, пояснений и т.д. Исправление опечаток также приветствуется.\n\n**О том, что послужило причиной для написания данной серии книг, вы можете узнать из [Предисловия](preface.md).**\n\n## Содержимое\n\n* Читать онлайн (бесплатно!): [«Начните и Совершенствуйтесь»](up%20%26%20going/README.md#Вы-не-знаете-js-Начните-и-Совершенствуйтесь), Опубликовано: [Купить сейчас](http://shop.oreilly.com/product/0636920039303.do) в бумажном варианте, электронная книга бесплатна!\n* Читать онлайн (бесплатно!): [«Область Видимости и Замыкания»](scope%20%26%20closures/README.md#Вы-не-знаете-js-Область-видимости-и-замыкания), Опубликовано: [Купить сейчас](http://shop.oreilly.com/product/0636920026327.do)\n* Читать онлайн (бесплатно!): [«This и Прототипы Объектов»](this%20%26%20object%20prototypes/README.md#you-dont-know-js-this--object-prototypes), Опубликовано: [Купить сейчас](http://shop.oreilly.com/product/0636920033738.do)\n* Читать онлайн (бесплатно!): [«Типы и Синтаксис»](types%20%26%20grammar/README.md#you-dont-know-js-types--grammar), Опубликовано: [Купить сейчас](http://shop.oreilly.com/product/0636920033745.do)\n* Читать онлайн (бесплатно!): [«Асинхронность и Производительность»](async%20%26%20performance/README.md#you-dont-know-js-async--performance), Опубликовано: [Купить сейчас](http://shop.oreilly.com/product/0636920033752.do)\n* Читать онлайн (бесплатно!): [«ES6 и не только»](es6%20%26%20beyond/README.md#you-dont-know-js-es6--beyond), Опубликовано: [Купить сейчас](https://www.ozon.ru/context/detail/id/137473815/)\n\n## Издательство\n\nСерия книг свободно распространяется для чтения, но редактируется, производится и публикуется в книжном издательстве O'Reilly.\n\nЕсли вам нравится содержание книг, и вы хотите поддержать развитие серии, пожалуйста, приобретите книги, как только они будут доступны для продажи, там, где вы обычно их покупаете. :)\n\nЕсли же вы хотите поддержать данную работу финансово, но не хотите покупать книги, вы можете это сделать через сервис [Patreon](https://www.patreon.com/getify); я буду глубоко признателен вам за вашу щедрость.\n\n<a href=\"https://www.patreon.com/getify\">[![patreon.png](https://c5.patreon.com/external/logo/become_a_patron_button.png)](https://www.patreon.com/getify)</a>\n\n## Очное обучение\n\nСодержание этих книг в значительной степени состоит из учебных материалов, которые я преподаю профессионально в формате следующих семинаров (как бесплатных, так и платных): \"Deep JavaScript Foundations\", \"Rethinking Async\" и \"ES6: The Right Parts\".\n\nЕсли вам нравятся мои книги, и вы бы хотели связаться со мной по поводу очного обучения в рамках вышеупомянутого учебного курса или других различных моих семинаров по JS / HTML5 / Node.JS, пожалуйста, обратитесь ко мне по электронной почте getify@gmail.com\n\n## Онлайн обучение\n\nКроме этого, я также преподаю некоторый учебный материал в формате видео. Я веду дистанционные курсы на сервисе [Frontend Masters](https://FrontendMasters.com), такие как [Глубокое понимание основ JavaScript](https://frontendmasters.com/courses/javascript-foundations/). Вы можете найти [все мои курсы здесь](https://frontendmasters.com/kyle-simpson/).\n\nНекоторые из этих курсов также доступны на других платформах, таких как Pluralsight, Lynda.com и O'Reilly Safari Online.\n\n## Вклад в развитие контента\n\nЛюбой вклад в развитие данного проекта **будет высоко оценён**.\n\nТем не менее, учитывайте то, что если вы желаете внести свой вклад в содержание книг (а не только исправить опечатки) в этом репозитории, вы соглашаетесь на то, что вы даёте мне абсолютные права на использование добавленного вами контента для серии книг таким образом, каким я (и O'Reilly) сочту это целесообразным.\n\nБла-бла-бла... :)\n\n## Лицензия и Авторские права\n\nАвтор материалов данной серии книг &copy; 2013-2015 Kyle Simpson.\n\n<a rel=\"license\" href=\"http://creativecommons.org/licenses/by-nc-nd/3.0/\"><img alt=\"Creative Commons License\" style=\"border-width:0\" src=\"https://i.creativecommons.org/l/by-nc-nd/3.0/88x31.png\" /></a><br />Лицензируется в соответствии с <a rel=\"license\" href=\"http://creativecommons.org/licenses/by-nc-nd/3.0/\">Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License</a>.\n"
  },
  {
    "path": "async & performance/README.md",
    "content": "# Вы не знаете JS: Асинхронность и Производительность\n\n<img src=\"cover.jpg\" width=\"300\">\n\n-----\n\n**[Купить цифровую или печатную книгу от издательства O'Reilly (англ.)](http://shop.oreilly.com/product/0636920033752.do)**\n\n-----\n\n[Оглавление](toc.md)\n\n* [Введение](foreword.md) (от [Jake Archibald](http://jakearchibald.com))\n* [Предисловие](../preface.md)\n* [Глава 1: Асинхронность: Сейчас и Тогда](ch1.md)\n* [Глава 2: Колбеки](ch2.md)\n* [Глава 3: Обещания](ch3.md)\n* [Глава 4: Генераторы](ch4.md)\n* [Глава 5: Производительность программы](ch5.md)\n* [Глава 6: Бенчмаркинг и настройка](ch6.md)\n* [Приложение A: Библиотека: asynquence](apA.md)\n* [Приложение B: Расширенные асинхронные шаблоны](apB.md)\n* [Приложение C: Благодарности!](apC.md)\n"
  },
  {
    "path": "async & performance/apA.md",
    "content": "# You Don't Know JS: Async & Performance\n# Appendix A: *asynquence* Library\n\nChapters 1 and 2 went into quite a bit of detail about typical asynchronous programming patterns and how they're commonly solved with callbacks. But we also saw why callbacks are fatally limited in capability, which led us to Chapters 3 and 4, with Promises and generators offering a much more solid, trustable, and reason-able base to build your asynchrony on.\n\nI referenced my own asynchronous library *asynquence* (http://github.com/getify/asynquence) -- \"async\" + \"sequence\" = \"asynquence\" -- several times in this book, and I want to now briefly explain how it works and why its unique design is important and helpful.\n\nIn the next appendix, we'll explore some advanced async patterns, but you'll probably want a library to make those palatable enough to be useful. We'll use *asynquence* to express those patterns, so you'll want to spend a little time here getting to know the library first.\n\n*asynquence* is obviously not the only option for good async coding; certainly there are many great libraries in this space. But *asynquence* provides a unique perspective by combining the best of all these patterns into a single library, and moreover is built on a single basic abstraction: the (async) sequence.\n\nMy premise is that sophisticated JS programs often need bits and pieces of various different asynchronous patterns woven together, and this is usually left entirely up to each developer to figure out. Instead of having to bring in two or more different async libraries that focus on different aspects of asynchrony, *asynquence* unifies them into variated sequence steps, with just one core library to learn and deploy.\n\nI believe the value is strong enough with *asynquence* to make async flow control programming with Promise-style semantics super easy to accomplish, so that's why we'll exclusively focus on that library here.\n\nTo begin, I'll explain the design principles behind *asynquence*, and then we'll illustrate how its API works with code examples.\n\n## Sequences, Abstraction Design\n\nUnderstanding *asynquence* begins with understanding a fundamental abstraction: any series of steps for a task, whether they separately are synchronous or asynchronous, can be collectively thought of as a \"sequence\". In other words, a sequence is a container that represents a task, and is comprised of individual (potentially async) steps to complete that task.\n\nEach step in the sequence is controlled under the covers by a Promise (see Chapter 3). That is, every step you add to a sequence implicitly creates a Promise that is wired to the previous end of the sequence. Because of the semantics of Promises, every single step advancement in a sequence is asynchronous, even if you synchronously complete the step.\n\nMoreover, a sequence will always proceed linearly from step to step, meaning that step 2 always comes after step 1 finishes, and so on.\n\nOf course, a new sequence can be forked off an existing sequence, meaning the fork only occurs once the main sequence reaches that point in the flow. Sequences can also be combined in various ways, including having one sequence subsumed by another sequence at a particular point in the flow.\n\nA sequence is kind of like a Promise chain. However, with Promise chains, there is no \"handle\" to grab that references the entire chain. Whichever Promise you have a reference to only represents the current step in the chain plus any other steps hanging off it. Essentially, you cannot hold a reference to a Promise chain unless you hold a reference to the first Promise in the chain.\n\nThere are many cases where it turns out to be quite useful to have a handle that references the entire sequence collectively. The most important of those cases is with sequence abort/cancel. As we covered extensively in Chapter 3, Promises themselves should never be able to be canceled, as this violates a fundamental design imperative: external immutability.\n\nBut sequences have no such immutability design principle, mostly because sequences are not passed around as future-value containers that need immutable value semantics. So sequences are the proper level of abstraction to handle abort/cancel behavior. *asynquence* sequences can be `abort()`ed at any time, and the sequence will stop at that point and not go for any reason.\n\nThere's plenty more reasons to prefer a sequence abstraction on top of Promise chains, for flow control purposes.\n\nFirst, Promise chaining is a rather manual process -- one that can get pretty tedious once you start creating and chaining Promises across a wide swath of your programs -- and this tedium can act counterproductively to dissuade the developer from using Promises in places where they are quite appropriate.\n\nAbstractions are meant to reduce boilerplate and tedium, so the sequence abstraction is a good solution to this problem. With Promises, your focus is on the individual step, and there's little assumption that you will keep the chain going. With sequences, the opposite approach is taken, assuming the sequence will keep having more steps added indefinitely.\n\nThis abstraction complexity reduction is especially powerful when you start thinking about higher-order Promise patterns (beyond `race([..])` and `all([..])`.\n\nFor example, in the middle of a sequence, you may want to express a step that is conceptually like a `try..catch` in that the step will always result in success, either the intended main success resolution or a positive nonerror signal for the caught error. Or, you might want to express a step that is like a retry/until loop, where it keeps trying the same step over and over until success occurs.\n\nThese sorts of abstractions are quite nontrivial to express using only Promise primitives, and doing so in the middle of an existing Promise chain is not pretty. But if you abstract your thinking to a sequence, and consider a step as a wrapper around a Promise, that step wrapper can hide such details, freeing you to think about the flow control in the most sensible way without being bothered by the details.\n\nSecond, and perhaps more importantly, thinking of async flow control in terms of steps in a sequence allows you to abstract out the details of what types of asynchronicity are involved with each individual step. Under the covers, a Promise will always control the step, but above the covers, that step can look either like a continuation callback (the simple default), or like a real Promise, or as a run-to-completion generator, or ... Hopefully, you get the picture.\n\nThird, sequences can more easily be twisted to adapt to different modes of thinking, such as event-, stream-, or reactive-based coding. *asynquence* provides a pattern I call \"reactive sequences\" (which we'll cover later) as a variation on the \"reactive observable\" ideas in RxJS (\"Reactive Extensions\"), that lets a repeatable event fire off a new sequence instance each time. Promises are one-shot-only, so it's quite awkward to express repetitious asynchrony with Promises alone.\n\nAnother alternate mode of thinking inverts the resolution/control capability in a pattern I call \"iterable sequences\". Instead of each individual step internally controlling its own completion (and thus advancement of the sequence), the sequence is inverted so the advancement control is through an external iterator, and each step in the *iterable sequence* just responds to the `next(..)` *iterator* control.\n\nWe'll explore all of these different variations as we go throughout the rest of this appendix, so don't worry if we ran over those bits far too quickly just now.\n\nThe takeaway is that sequences are a more powerful and sensible abstraction for complex asynchrony than just Promises (Promise chains) or just generators, and *asynquence* is designed to express that abstraction with just the right level of sugar to make async programming more understandable and more enjoyable.\n\n## *asynquence* API\n\nTo start off, the way you create a sequence (an *asynquence* instance) is with the `ASQ(..)` function. An `ASQ()` call with no parameters creates an empty initial sequence, whereas passing one or more values or functions to `ASQ(..)` sets up the sequence with each argument representing the initial steps of the sequence.\n\n**Note:** For the purposes of all code examples here, I will use the *asynquence* top-level identifier in global browser usage: `ASQ`. If you include and use *asynquence* through a module system (browser or server), you of course can define whichever symbol you prefer, and *asynquence* won't care!\n\nMany of the API methods discussed here are built into the core of *asynquence*, but others are provided through including the optional \"contrib\" plug-ins package. See the documentation for *asynquence* for whether a method is built in or defined via plug-in: http://github.com/getify/asynquence\n\n### Steps\n\nIf a function represents a normal step in the sequence, that function is invoked with the first parameter being the continuation callback, and any subsequent parameters being any messages passed on from the previous step. The step will not complete until the continuation callback is called. Once it's called, any arguments you pass to it will be sent along as messages to the next step in the sequence.\n\nTo add an additional normal step to the sequence, call `then(..)` (which has essentially the exact same semantics as the `ASQ(..)` call):\n\n```js\nASQ(\n\t// step 1\n\tfunction(done){\n\t\tsetTimeout( function(){\n\t\t\tdone( \"Hello\" );\n\t\t}, 100 );\n\t},\n\t// step 2\n\tfunction(done,greeting) {\n\t\tsetTimeout( function(){\n\t\t\tdone( greeting + \" World\" );\n\t\t}, 100 );\n\t}\n)\n// step 3\n.then( function(done,msg){\n\tsetTimeout( function(){\n\t\tdone( msg.toUpperCase() );\n\t}, 100 );\n} )\n// step 4\n.then( function(done,msg){\n\tconsole.log( msg );\t\t\t// HELLO WORLD\n} );\n```\n\n**Note:** Though the name `then(..)` is identical to the native Promises API, this `then(..)` is different. You can pass as few or as many functions or values to `then(..)` as you'd like, and each is taken as a separate step. There's no two-callback fulfilled/rejected semantics involved.\n\nUnlike with Promises, where to chain one Promise to the next you have to create and `return` that Promise from a `then(..)` fulfillment handler, with *asynquence*, all you need to do is call the continuation callback -- I always call it `done()` but you can name it whatever suits you -- and optionally pass it completion messages as arguments.\n\nEach step defined by `then(..)` is assumed to be asynchronous. If you have a step that's synchronous, you can either just call `done(..)` right away, or you can use the simpler `val(..)` step helper:\n\n```js\n// step 1 (sync)\nASQ( function(done){\n\tdone( \"Hello\" );\t// manually synchronous\n} )\n// step 2 (sync)\n.val( function(greeting){\n\treturn greeting + \" World\";\n} )\n// step 3 (async)\n.then( function(done,msg){\n\tsetTimeout( function(){\n\t\tdone( msg.toUpperCase() );\n\t}, 100 );\n} )\n// step 4 (sync)\n.val( function(msg){\n\tconsole.log( msg );\n} );\n```\n\nAs you can see, `val(..)`-invoked steps don't receive a continuation callback, as that part is assumed for you -- and the parameter list is less cluttered as a result! To send a message along to the next step, you simply use `return`.\n\nThink of `val(..)` as representing a synchronous \"value-only\" step, which is useful for synchronous value operations, logging, and the like.\n\n### Errors\n\nOne important difference with *asynquence* compared to Promises is with error handling.\n\nWith Promises, each individual Promise (step) in a chain can have its own independent error, and each subsequent step has the ability to handle the error or not. The main reason for this semantic comes (again) from the focus on individual Promises rather than on the chain (sequence) as a whole.\n\nI believe that most of the time, an error in one part of a sequence is generally not recoverable, so the subsequent steps in the sequence are moot and should be skipped. So, by default, an error at any step of a sequence throws the entire sequence into error mode, and the rest of the normal steps are ignored.\n\nIf you *do* need to have a step where its error is recoverable, there are several different API methods that can accommodate, such as `try(..)` -- previously mentioned as a kind of `try..catch` step -- or `until(..)` -- a retry loop that keeps attempting the step until it succeeds or you manually `break()` the loop. *asynquence* even has `pThen(..)` and `pCatch(..)` methods, which work identically to how normal Promise `then(..)` and `catch(..)` work (see Chapter 3), so you can do localized mid-sequence error handling if you so choose.\n\nThe point is, you have both options, but the more common one in my experience is the default. With Promises, to get a chain of steps to ignore all steps once an error occurs, you have to take care not to register a rejection handler at any step; otherwise, that error gets swallowed as handled, and the sequence may continue (perhaps unexpectedly). This kind of desired behavior is a bit awkward to properly and reliably handle.\n\nTo register a sequence error notification handler, *asynquence* provides an `or(..)` sequence method, which also has an alias of `onerror(..)`. You can call this method anywhere in the sequence, and you can register as many handlers as you'd like. That makes it easy for multiple different consumers to listen in on a sequence to know if it failed or not; it's kind of like an error event handler in that respect.\n\nJust like with Promises, all JS exceptions become sequence errors, or you can programmatically signal a sequence error:\n\n```js\nvar sq = ASQ( function(done){\n\tsetTimeout( function(){\n\t\t// signal an error for the sequence\n\t\tdone.fail( \"Oops\" );\n\t}, 100 );\n} )\n.then( function(done){\n\t// will never get here\n} )\n.or( function(err){\n\tconsole.log( err );\t\t\t// Oops\n} )\n.then( function(done){\n\t// won't get here either\n} );\n\n// later\n\nsq.or( function(err){\n\tconsole.log( err );\t\t\t// Oops\n} );\n```\n\nAnother really important difference with error handling in *asynquence* compared to native Promises is the default behavior of \"unhandled exceptions\". As we discussed at length in Chapter 3, a rejected Promise without a registered rejection handler will just silently hold (aka swallow) the error; you have to remember to always end a chain with a final `catch(..)`.\n\nIn *asynquence*, the assumption is reversed.\n\nIf an error occurs on a sequence, and it **at that moment** has no error handlers registered, the error is reported to the `console`. In other words, unhandled rejections are by default always reported so as not to be swallowed and missed.\n\nAs soon as you register an error handler against a sequence, it opts that sequence out of such reporting, to prevent duplicate noise.\n\nThere may, in fact, be cases where you want to create a sequence that may go into the error state before you have a chance to register the handler. This isn't common, but it can happen from time to time.\n\nIn those cases, you can also **opt a sequence instance out** of error reporting by calling `defer()` on the sequence. You should only opt out of error reporting if you are sure that you're going to eventually handle such errors:\n\n```js\nvar sq1 = ASQ( function(done){\n\tdoesnt.Exist();\t\t\t// will throw exception to console\n} );\n\nvar sq2 = ASQ( function(done){\n\tdoesnt.Exist();\t\t\t// will throw only a sequence error\n} )\n// opt-out of error reporting\n.defer();\n\nsetTimeout( function(){\n\tsq1.or( function(err){\n\t\tconsole.log( err );\t// ReferenceError\n\t} );\n\n\tsq2.or( function(err){\n\t\tconsole.log( err );\t// ReferenceError\n\t} );\n}, 100 );\n\n// ReferenceError (from sq1)\n```\n\nThis is better error handling behavior than Promises themselves have, because it's the Pit of Success, not the Pit of Failure (see Chapter 3).\n\n**Note:** If a sequence is piped into (aka subsumed by) another sequence -- see \"Combining Sequences\"  for a complete description -- then the source sequence is opted out of error reporting, but now the target sequence's error reporting or lack thereof must be considered.\n\n### Parallel Steps\n\nNot all steps in your sequences will have just a single (async) task to perform; some will need to perform multiple steps \"in parallel\" (concurrently). A step in a sequence in which multiple substeps are processing concurrently is called a `gate(..)` -- there's an `all(..)` alias if you prefer -- and is directly symmetric to native `Promise.all([..])`.\n\nIf all the steps in the `gate(..)` complete successfully, all success messages will be passed to the next sequence step. If any of them generate errors, the whole sequence immediately goes into an error state.\n\nConsider:\n\n```js\nASQ( function(done){\n\tsetTimeout( done, 100 );\n} )\n.gate(\n\tfunction(done){\n\t\tsetTimeout( function(){\n\t\t\tdone( \"Hello\" );\n\t\t}, 100 );\n\t},\n\tfunction(done){\n\t\tsetTimeout( function(){\n\t\t\tdone( \"World\", \"!\" );\n\t\t}, 100 );\n\t}\n)\n.val( function(msg1,msg2){\n\tconsole.log( msg1 );\t// Hello\n\tconsole.log( msg2 );\t// [ \"World\", \"!\" ]\n} );\n```\n\nFor illustration, let's compare that example to native Promises:\n\n```js\nnew Promise( function(resolve,reject){\n\tsetTimeout( resolve, 100 );\n} )\n.then( function(){\n\treturn Promise.all( [\n\t\tnew Promise( function(resolve,reject){\n\t\t\tsetTimeout( function(){\n\t\t\t\tresolve( \"Hello\" );\n\t\t\t}, 100 );\n\t\t} ),\n\t\tnew Promise( function(resolve,reject){\n\t\t\tsetTimeout( function(){\n\t\t\t\t// note: we need a [ ] array here\n\t\t\t\tresolve( [ \"World\", \"!\" ] );\n\t\t\t}, 100 );\n\t\t} )\n\t] );\n} )\n.then( function(msgs){\n\tconsole.log( msgs[0] );\t// Hello\n\tconsole.log( msgs[1] );\t// [ \"World\", \"!\" ]\n} );\n```\n\nYuck. Promises require a lot more boilerplate overhead to express the same asynchronous flow control. That's a great illustration of why the *asynquence* API and abstraction make dealing with Promise steps a lot nicer. The improvement only goes higher the more complex your asynchrony is.\n\n#### Step Variations\n\nThere are several variations in the contrib plug-ins on *asynquence*'s `gate(..)` step type that can be quite helpful:\n\n* `any(..)` is like `gate(..)`, except just one segment has to eventually succeed to proceed on the main sequence.\n* `first(..)` is like `any(..)`, except as soon as any segment succeeds, the main sequence proceeds (ignoring subsequent results from other segments).\n* `race(..)` (symmetric with `Promise.race([..])`) is like `first(..)`, except the main sequence proceeds as soon as any segment completes (either success or failure).\n* `last(..)` is like `any(..)`, except only the latest segment to complete successfully sends its message(s) along to the main sequence.\n* `none(..)` is the inverse of `gate(..)`: the main sequence proceeds only if all the segments fail (with all segment error message(s) transposed as success message(s) and vice versa).\n\nLet's first define some helpers to make illustration cleaner:\n\n```js\nfunction success1(done) {\n\tsetTimeout( function(){\n\t\tdone( 1 );\n\t}, 100 );\n}\n\nfunction success2(done) {\n\tsetTimeout( function(){\n\t\tdone( 2 );\n\t}, 100 );\n}\n\nfunction failure3(done) {\n\tsetTimeout( function(){\n\t\tdone.fail( 3 );\n\t}, 100 );\n}\n\nfunction output(msg) {\n\tconsole.log( msg );\n}\n```\n\nNow, let's demonstrate these `gate(..)` step variations:\n\n```js\nASQ().race(\n\tfailure3,\n\tsuccess1\n)\n.or( output );\t\t// 3\n\n\nASQ().any(\n\tsuccess1,\n\tfailure3,\n\tsuccess2\n)\n.val( function(){\n\tvar args = [].slice.call( arguments );\n\tconsole.log(\n\t\targs\t\t// [ 1, undefined, 2 ]\n\t);\n} );\n\n\nASQ().first(\n\tfailure3,\n\tsuccess1,\n\tsuccess2\n)\n.val( output );\t\t// 1\n\n\nASQ().last(\n\tfailure3,\n\tsuccess1,\n\tsuccess2\n)\n.val( output );\t\t// 2\n\nASQ().none(\n\tfailure3\n)\n.val( output )\t\t// 3\n.none(\n\tfailure3\n\tsuccess1\n)\n.or( output );\t\t// 1\n```\n\nAnother step variation is `map(..)`, which lets you asynchronously map elements of an array to different values, and the step doesn't proceed until all the mappings are complete. `map(..)` is very similar to `gate(..)`, except it gets the initial values from an array instead of from separately specified functions, and also because you define a single function callback to operate on each value:\n\n```js\nfunction double(x,done) {\n\tsetTimeout( function(){\n\t\tdone( x * 2 );\n\t}, 100 );\n}\n\nASQ().map( [1,2,3], double )\n.val( output );\t\t\t\t\t// [2,4,6]\n```\n\nAlso, `map(..)` can receive either of its parameters (the array or the callback) from messages passed from the previous step:\n\n```js\nfunction plusOne(x,done) {\n\tsetTimeout( function(){\n\t\tdone( x + 1 );\n\t}, 100 );\n}\n\nASQ( [1,2,3] )\n.map( double )\t\t\t// message `[1,2,3]` comes in\n.map( plusOne )\t\t\t// message `[2,4,6]` comes in\n.val( output );\t\t\t// [3,5,7]\n```\n\nAnother variation is `waterfall(..)`, which is kind of like a mixture between `gate(..)`'s message collection behavior but `then(..)`'s sequential processing.\n\nStep 1 is first executed, then the success message from step 1 is given to step 2, and then both success messages go to step 3, and then all three success messages go to step 4, and so on, such that the messages sort of collect and cascade down the \"waterfall\".\n\nConsider:\n\n```js\nfunction double(done) {\n\tvar args = [].slice.call( arguments, 1 );\n\tconsole.log( args );\n\n\tsetTimeout( function(){\n\t\tdone( args[args.length - 1] * 2 );\n\t}, 100 );\n}\n\nASQ( 3 )\n.waterfall(\n\tdouble,\t\t\t\t\t// [ 3 ]\n\tdouble,\t\t\t\t\t// [ 6 ]\n\tdouble,\t\t\t\t\t// [ 6, 12 ]\n\tdouble\t\t\t\t\t// [ 6, 12, 24 ]\n)\n.val( function(){\n\tvar args = [].slice.call( arguments );\n\tconsole.log( args );\t// [ 6, 12, 24, 48 ]\n} );\n```\n\nIf at any point in the \"waterfall\" an error occurs, the whole sequence immediately goes into an error state.\n\n#### Error Tolerance\n\nSometimes you want to manage errors at the step level and not let them necessarily send the whole sequence into the error state. *asynquence* offers two step variations for that purpose.\n\n`try(..)` attempts a step, and if it succeeds, the sequence proceeds as normal, but if the step fails, the failure is turned into a success message formated as `{ catch: .. }` with the error message(s) filled in:\n\n```js\nASQ()\n.try( success1 )\n.val( output )\t\t\t// 1\n.try( failure3 )\n.val( output )\t\t\t// { catch: 3 }\n.or( function(err){\n\t// never gets here\n} );\n```\n\nYou could instead set up a retry loop using `until(..)`, which tries the step and if it fails, retries the step again on the next event loop tick, and so on.\n\nThis retry loop can continue indefinitely, but if you want to break out of the loop, you can call the `break()` flag on the completion trigger, which sends the main sequence into an error state:\n\n```js\nvar count = 0;\n\nASQ( 3 )\n.until( double )\n.val( output )\t\t\t\t\t// 6\n.until( function(done){\n\tcount++;\n\n\tsetTimeout( function(){\n\t\tif (count < 5) {\n\t\t\tdone.fail();\n\t\t}\n\t\telse {\n\t\t\t// break out of the `until(..)` retry loop\n\t\t\tdone.break( \"Oops\" );\n\t\t}\n\t}, 100 );\n} )\n.or( output );\t\t\t\t\t// Oops\n```\n\n#### Promise-Style Steps\n\nIf you would prefer to have, inline in your sequence, Promise-style semantics like Promises' `then(..)` and `catch(..)` (see Chapter 3), you can use the `pThen` and `pCatch` plug-ins:\n\n```js\nASQ( 21 )\n.pThen( function(msg){\n\treturn msg * 2;\n} )\n.pThen( output )\t\t\t\t// 42\n.pThen( function(){\n\t// throw an exception\n\tdoesnt.Exist();\n} )\n.pCatch( function(err){\n\t// caught the exception (rejection)\n\tconsole.log( err );\t\t\t// ReferenceError\n} )\n.val( function(){\n\t// main sequence is back in a\n\t// success state because previous\n\t// exception was caught by\n\t// `pCatch(..)`\n} );\n```\n\n`pThen(..)` and `pCatch(..)` are designed to run in the sequence, but behave as if it was a normal Promise chain. As such, you can either resolve genuine Promises or *asynquence* sequences from the \"fulfillment\" handler passed to `pThen(..)` (see Chapter 3).\n\n### Forking Sequences\n\nOne feature that can be quite useful about Promises is that you can attach multiple `then(..)` handler registrations to the same promise, effectively \"forking\" the flow-control at that promise:\n\n```js\nvar p = Promise.resolve( 21 );\n\n// fork 1 (from `p`)\np.then( function(msg){\n\treturn msg * 2;\n} )\n.then( function(msg){\n\tconsole.log( msg );\t\t// 42\n} )\n\n// fork 2 (from `p`)\np.then( function(msg){\n\tconsole.log( msg );\t\t// 21\n} );\n```\n\nThe same \"forking\" is easy in *asynquence* with `fork()`:\n\n```js\nvar sq = ASQ(..).then(..).then(..);\n\nvar sq2 = sq.fork();\n\n// fork 1\nsq.then(..)..;\n\n// fork 2\nsq2.then(..)..;\n```\n\n### Combining Sequences\n\nThe reverse of `fork()`ing, you can combine two sequences by subsuming one into another, using the `seq(..)` instance method:\n\n```js\nvar sq = ASQ( function(done){\n\tsetTimeout( function(){\n\t\tdone( \"Hello World\" );\n\t}, 200 );\n} );\n\nASQ( function(done){\n\tsetTimeout( done, 100 );\n} )\n// subsume `sq` sequence into this sequence\n.seq( sq )\n.val( function(msg){\n\tconsole.log( msg );\t\t// Hello World\n} )\n```\n\n`seq(..)` can either accept a sequence itself, as shown here, or a function. If a function, it's expected that the function when called will return a sequence, so the preceding code could have been done with:\n\n```js\n// ..\n.seq( function(){\n\treturn sq;\n} )\n// ..\n```\n\nAlso, that step could instead have been accomplished with a `pipe(..)`:\n\n```js\n// ..\n.then( function(done){\n\t// pipe `sq` into the `done` continuation callback\n\tsq.pipe( done );\n} )\n// ..\n```\n\nWhen a sequence is subsumed, both its success message stream and its error stream are piped in.\n\n**Note:** As mentioned in an earlier note, piping (manually with `pipe(..)` or automatically with `seq(..)`) opts the source sequence out of error-reporting, but doesn't affect the error reporting status of the target sequence.\n\n## Value and Error Sequences\n\nIf any step of a sequence is just a normal value, that value is just mapped to that step's completion message:\n\n```js\nvar sq = ASQ( 42 );\n\nsq.val( function(msg){\n\tconsole.log( msg );\t\t// 42\n} );\n```\n\nIf you want to make a sequence that's automatically errored:\n\n```js\nvar sq = ASQ.failed( \"Oops\" );\n\nASQ()\n.seq( sq )\n.val( function(msg){\n\t// won't get here\n} )\n.or( function(err){\n\tconsole.log( err );\t\t// Oops\n} );\n```\n\nYou also may want to automatically create a delayed-value or a delayed-error sequence. Using the `after` and `failAfter` contrib plug-ins, this is easy:\n\n```js\nvar sq1 = ASQ.after( 100, \"Hello\", \"World\" );\nvar sq2 = ASQ.failAfter( 100, \"Oops\" );\n\nsq1.val( function(msg1,msg2){\n\tconsole.log( msg1, msg2 );\t\t// Hello World\n} );\n\nsq2.or( function(err){\n\tconsole.log( err );\t\t\t\t// Oops\n} );\n```\n\nYou can also insert a delay in the middle of a sequence using `after(..)`:\n\n```js\nASQ( 42 )\n// insert a delay into the sequence\n.after( 100 )\n.val( function(msg){\n\tconsole.log( msg );\t\t// 42\n} );\n```\n\n## Promises and Callbacks\n\nI think *asynquence* sequences provide a lot of value on top of native Promises, and for the most part you'll find it more pleasant and more powerful to work at that level of abstraction. However, integrating *asynquence* with other non-*asynquence* code will be a reality.\n\nYou can easily subsume a promise (e.g., thenable -- see Chapter 3) into a sequence using the `promise(..)` instance method:\n\n```js\nvar p = Promise.resolve( 42 );\n\nASQ()\n.promise( p )\t\t\t// could also: `function(){ return p; }`\n.val( function(msg){\n\tconsole.log( msg );\t// 42\n} );\n```\n\nAnd to go the opposite direction and fork/vend a promise from a sequence at a certain step, use the `toPromise` contrib plug-in:\n\n```js\nvar sq = ASQ.after( 100, \"Hello World\" );\n\nsq.toPromise()\n// this is a standard promise chain now\n.then( function(msg){\n\treturn msg.toUpperCase();\n} )\n.then( function(msg){\n\tconsole.log( msg );\t\t// HELLO WORLD\n} );\n```\n\nTo adapt *asynquence* to systems using callbacks, there are several helper facilities. To automatically generate an \"error-first style\" callback from your sequence to wire into a callback-oriented utility, use `errfcb`:\n\n```js\nvar sq = ASQ( function(done){\n\t// note: expecting \"error-first style\" callback\n\tsomeAsyncFuncWithCB( 1, 2, done.errfcb )\n} )\n.val( function(msg){\n\t// ..\n} )\n.or( function(err){\n\t// ..\n} );\n\n// note: expecting \"error-first style\" callback\nanotherAsyncFuncWithCB( 1, 2, sq.errfcb() );\n```\n\nYou also may want to create a sequence-wrapped version of a utility -- compare to \"promisory\" in Chapter 3 and \"thunkory\" in Chapter 4 -- and *asynquence* provides `ASQ.wrap(..)` for that purpose:\n\n```js\nvar coolUtility = ASQ.wrap( someAsyncFuncWithCB );\n\ncoolUtility( 1, 2 )\n.val( function(msg){\n\t// ..\n} )\n.or( function(err){\n\t// ..\n} );\n```\n\n**Note:** For the sake of clarity (and for fun!), let's coin yet another term, for a sequence-producing function that comes from `ASQ.wrap(..)`, like `coolUtility` here. I propose \"sequory\" (\"sequence\" + \"factory\").\n\n## Iterable Sequences\n\nThe normal paradigm for a sequence is that each step is responsible for completing itself, which is what advances the sequence. Promises work the same way.\n\nThe unfortunate part is that sometimes you need external control over a Promise/step, which leads to awkward \"capability extraction\".\n\nConsider this Promises example:\n\n```js\nvar domready = new Promise( function(resolve,reject){\n\t// don't want to put this here, because\n\t// it belongs logically in another part\n\t// of the code\n\tdocument.addEventListener( \"DOMContentLoaded\", resolve );\n} );\n\n// ..\n\ndomready.then( function(){\n\t// DOM is ready!\n} );\n```\n\nThe \"capability extraction\" anti-pattern with Promises looks like this:\n\n```js\nvar ready;\n\nvar domready = new Promise( function(resolve,reject){\n\t// extract the `resolve()` capability\n\tready = resolve;\n} );\n\n// ..\n\ndomready.then( function(){\n\t// DOM is ready!\n} );\n\n// ..\n\ndocument.addEventListener( \"DOMContentLoaded\", ready );\n```\n\n**Note:** This anti-pattern is an awkward code smell, in my opinion, but some developers like it, for reasons I can't grasp.\n\n*asynquence* offers an inverted sequence type I call \"iterable sequences\", which externalizes the control capability (it's quite useful in use cases like the `domready`):\n\n```js\n// note: `domready` here is an *iterator* that\n// controls the sequence\nvar domready = ASQ.iterable();\n\n// ..\n\ndomready.val( function(){\n\t// DOM is ready\n} );\n\n// ..\n\ndocument.addEventListener( \"DOMContentLoaded\", domready.next );\n```\n\nThere's more to iterable sequences than what we see in this scenario. We'll come back to them in Appendix B.\n\n## Running Generators\n\nIn Chapter 4, we derived a utility called `run(..)` which can run generators to completion, listening for `yield`ed Promises and using them to async resume the generator. *asynquence* has just such a utility built in, called `runner(..)`.\n\nLet's first set up some helpers for illustration:\n\n```js\nfunction doublePr(x) {\n\treturn new Promise( function(resolve,reject){\n\t\tsetTimeout( function(){\n\t\t\tresolve( x * 2 );\n\t\t}, 100 );\n\t} );\n}\n\nfunction doubleSeq(x) {\n\treturn ASQ( function(done){\n\t\tsetTimeout( function(){\n\t\t\tdone( x * 2)\n\t\t}, 100 );\n\t} );\n}\n```\n\nNow, we can use `runner(..)` as a step in the middle of a sequence:\n\n```js\nASQ( 10, 11 )\n.runner( function*(token){\n\tvar x = token.messages[0] + token.messages[1];\n\n\t// yield a real promise\n\tx = yield doublePr( x );\n\n\t// yield a sequence\n\tx = yield doubleSeq( x );\n\n\treturn x;\n} )\n.val( function(msg){\n\tconsole.log( msg );\t\t\t// 84\n} );\n```\n\n### Wrapped Generators\n\nYou can also create a self-packaged generator -- that is, a normal function that runs your specified generator and returns a sequence for its completion -- by `ASQ.wrap(..)`ing it:\n\n```js\nvar foo = ASQ.wrap( function*(token){\n\tvar x = token.messages[0] + token.messages[1];\n\n\t// yield a real promise\n\tx = yield doublePr( x );\n\n\t// yield a sequence\n\tx = yield doubleSeq( x );\n\n\treturn x;\n}, { gen: true } );\n\n// ..\n\nfoo( 8, 9 )\n.val( function(msg){\n\tconsole.log( msg );\t\t\t// 68\n} );\n```\n\nThere's a lot more awesome that `runner(..)` is capable of, but we'll come back to that in Appendix B.\n\n## Review\n\n*asynquence* is a simple abstraction -- a sequence is a series of (async) steps -- on top of Promises, aimed at making working with various asynchronous patterns much easier, without any compromise in capability.\n\nThere are other goodies in the *asynquence* core API and its contrib plug-ins beyond what we saw in this appendix, but we'll leave that as an exercise for the reader to go check the rest of the capabilities out.\n\nYou've now seen the essence and spirit of *asynquence*. The key take away is that a sequence is comprised of steps, and those steps can be any of dozens of different variations on Promises, or they can be a generator-run, or... The choice is up to you, you have all the freedom to weave together whatever async flow control logic is appropriate for your tasks. No more library switching to catch different async patterns.\n\nIf these *asynquence* snippets have made sense to you, you're now pretty well up to speed on the library; it doesn't take that much to learn, actually!\n\nIf you're still a little fuzzy on how it works (or why!), you'll want to spend a little more time examining the previous examples and playing around with *asynquence* yourself, before going on to the next appendix. Appendix B will push *asynquence* into several more advanced and powerful async patterns.\n"
  },
  {
    "path": "async & performance/apB.md",
    "content": "# You Don't Know JS: Async & Performance\n# Appendix B: Advanced Async Patterns\n\nAppendix A introduced the *asynquence* library for sequence-oriented async flow control, primarily based on Promises and generators.\n\nNow we'll explore other advanced asynchronous patterns built on top of that existing understanding and functionality, and see how *asynquence* makes those sophisticated async techniques easy to mix and match in our programs without needing lots of separate libraries.\n\n## Iterable Sequences\n\nWe introduced *asynquence*'s iterable sequences in the previous appendix, but we want to revisit them in more detail.\n\nTo refresh, recall:\n\n```js\nvar domready = ASQ.iterable();\n\n// ..\n\ndomready.val( function(){\n\t// DOM is ready\n} );\n\n// ..\n\ndocument.addEventListener( \"DOMContentLoaded\", domready.next );\n```\n\nNow, let's define a sequence of multiple steps as an iterable sequence:\n\n```js\nvar steps = ASQ.iterable();\n\nsteps\n.then( function STEP1(x){\n\treturn x * 2;\n} )\n.steps( function STEP2(x){\n\treturn x + 3;\n} )\n.steps( function STEP3(x){\n\treturn x * 4;\n} );\n\nsteps.next( 8 ).value;\t// 16\nsteps.next( 16 ).value;\t// 19\nsteps.next( 19 ).value;\t// 76\nsteps.next().done;\t\t// true\n```\n\nAs you can see, an iterable sequence is a standard-compliant *iterator* (see Chapter 4). So, it can be iterated with an ES6 `for..of` loop, just like a generator (or any other *iterable*) can:\n\n```js\nvar steps = ASQ.iterable();\n\nsteps\n.then( function STEP1(){ return 2; } )\n.then( function STEP2(){ return 4; } )\n.then( function STEP3(){ return 6; } )\n.then( function STEP4(){ return 8; } )\n.then( function STEP5(){ return 10; } );\n\nfor (var v of steps) {\n\tconsole.log( v );\n}\n// 2 4 6 8 10\n```\n\nBeyond the event triggering example shown in the previous appendix, iterable sequences are interesting because in essence they can be seen as a stand-in for generators or Promise chains, but with even more flexibility.\n\nConsider a multiple Ajax request example -- we've seen the same scenario in Chapters 3 and 4, both as a Promise chain and as a generator, respectively -- expressed as an iterable sequence:\n\n```js\n// sequence-aware ajax\nvar request = ASQ.wrap( ajax );\n\nASQ( \"http://some.url.1\" )\n.runner(\n\tASQ.iterable()\n\n\t.then( function STEP1(token){\n\t\tvar url = token.messages[0];\n\t\treturn request( url );\n\t} )\n\n\t.then( function STEP2(resp){\n\t\treturn ASQ().gate(\n\t\t\trequest( \"http://some.url.2/?v=\" + resp ),\n\t\t\trequest( \"http://some.url.3/?v=\" + resp )\n\t\t);\n\t} )\n\n\t.then( function STEP3(r1,r2){ return r1 + r2; } )\n)\n.val( function(msg){\n\tconsole.log( msg );\n} );\n```\n\nThe iterable sequence expresses a sequential series of (sync or async) steps that looks awfully similar to a Promise chain -- in other words, it's much cleaner looking than just plain nested callbacks, but not quite as nice as the `yield`-based sequential syntax of generators.\n\nBut we pass the iterable sequence into `ASQ#runner(..)`, which runs it to completion the same as if it was a generator. The fact that an iterable sequence behaves essentially the same as a generator is notable for a couple of reasons.\n\nFirst, iterable sequences are kind of a pre-ES6 equivalent to a certain subset of ES6 generators, which means you can either author them directly (to run anywhere), or you can author ES6 generators and transpile/convert them to iterable sequences (or Promise chains for that matter!).\n\nThinking of an async-run-to-completion generator as just syntactic sugar for a Promise chain is an important recognition of their isomorphic relationship.\n\nBefore we move on, we should note that the previous snippet could have been expressed in *asynquence* as:\n\n```js\nASQ( \"http://some.url.1\" )\n.seq( /*STEP 1*/ request )\n.seq( function STEP2(resp){\n\treturn ASQ().gate(\n\t\trequest( \"http://some.url.2/?v=\" + resp ),\n\t\trequest( \"http://some.url.3/?v=\" + resp )\n\t);\n} )\n.val( function STEP3(r1,r2){ return r1 + r2; } )\n.val( function(msg){\n\tconsole.log( msg );\n} );\n```\n\nMoreover, step 2 could have even been expressed as:\n\n```js\n.gate(\n\tfunction STEP2a(done,resp) {\n\t\trequest( \"http://some.url.2/?v=\" + resp )\n\t\t.pipe( done );\n\t},\n\tfunction STEP2b(done,resp) {\n\t\trequest( \"http://some.url.3/?v=\" + resp )\n\t\t.pipe( done );\n\t}\n)\n```\n\nSo, why would we go to the trouble of expressing our flow control as an iterable sequence in a `ASQ#runner(..)` step, when it seems like a simpler/flatter *asyquence* chain does the job well?\n\nBecause the iterable sequence form has an important trick up its sleeve that gives us more capability. Read on.\n\n### Extending Iterable Sequences\n\nGenerators, normal *asynquence* sequences, and Promise chains, are all **eagerly evaluated** -- whatever flow control is expressed initially *is* the fixed flow that will be followed.\n\nHowever, iterable sequences are **lazily evaluated**, which means that during execution of the iterable sequence, you can extend the sequence with more steps if desired.\n\n**Note:** You can only append to the end of an iterable sequence, not inject into the middle of the sequence.\n\nLet's first look at a simpler (synchronous) example of that capability to get familiar with it:\n\n```js\nfunction double(x) {\n\tx *= 2;\n\n\t// should we keep extending?\n\tif (x < 500) {\n\t\tisq.then( double );\n\t}\n\n\treturn x;\n}\n\n// setup single-step iterable sequence\nvar isq = ASQ.iterable().then( double );\n\nfor (var v = 10, ret;\n\t(ret = isq.next( v )) && !ret.done;\n) {\n\tv = ret.value;\n\tconsole.log( v );\n}\n```\n\nThe iterable sequence starts out with only one defined step (`isq.then(double)`), but the sequence keeps extending itself under certain conditions (`x < 500`). Both *asynquence* sequences and Promise chains technically *can* do something similar, but we'll see in a little bit why their capability is insufficient.\n\nThough this example is rather trivial and could otherwise be expressed with a `while` loop in a generator, we'll consider more sophisticated cases.\n\nFor instance, you could examine the response from an Ajax request and if it indicates that more data is needed, you conditionally insert more steps into the iterable sequence to make the additional request(s). Or you could conditionally add a value-formatting step to the end of your Ajax handling.\n\nConsider:\n\n```js\nvar steps = ASQ.iterable()\n\n.then( function STEP1(token){\n\tvar url = token.messages[0].url;\n\n\t// was an additional formatting step provided?\n\tif (token.messages[0].format) {\n\t\tsteps.then( token.messages[0].format );\n\t}\n\n\treturn request( url );\n} )\n\n.then( function STEP2(resp){\n\t// add another Ajax request to the sequence?\n\tif (/x1/.test( resp )) {\n\t\tsteps.then( function STEP5(text){\n\t\t\treturn request(\n\t\t\t\t\"http://some.url.4/?v=\" + text\n\t\t\t);\n\t\t} );\n\t}\n\n\treturn ASQ().gate(\n\t\trequest( \"http://some.url.2/?v=\" + resp ),\n\t\trequest( \"http://some.url.3/?v=\" + resp )\n\t);\n} )\n\n.then( function STEP3(r1,r2){ return r1 + r2; } );\n```\n\nYou can see in two different places where we conditionally extend `steps` with `steps.then(..)`. And to run this `steps` iterable sequence, we just wire it into our main program flow with an *asynquence* sequence (called `main` here) using `ASQ#runner(..)`:\n\n```js\nvar main = ASQ( {\n\turl: \"http://some.url.1\",\n\tformat: function STEP4(text){\n\t\treturn text.toUpperCase();\n\t}\n} )\n.runner( steps )\n.val( function(msg){\n\tconsole.log( msg );\n} );\n```\n\nCan the flexibility (conditional behavior) of the `steps` iterable sequence be expressed with a generator? Kind of, but we have to rearrange the logic in a slightly awkward way:\n\n```js\nfunction *steps(token) {\n\t// **STEP 1**\n\tvar resp = yield request( token.messages[0].url );\n\n\t// **STEP 2**\n\tvar rvals = yield ASQ().gate(\n\t\trequest( \"http://some.url.2/?v=\" + resp ),\n\t\trequest( \"http://some.url.3/?v=\" + resp )\n\t);\n\n\t// **STEP 3**\n\tvar text = rvals[0] + rvals[1];\n\n\t// **STEP 4**\n\t// was an additional formatting step provided?\n\tif (token.messages[0].format) {\n\t\ttext = yield token.messages[0].format( text );\n\t}\n\n\t// **STEP 5**\n\t// need another Ajax request added to the sequence?\n\tif (/foobar/.test( resp )) {\n\t\ttext = yield request(\n\t\t\t\"http://some.url.4/?v=\" + text\n\t\t);\n\t}\n\n\treturn text;\n}\n\n// note: `*steps()` can be run by the same `ASQ` sequence\n// as `steps` was previously\n```\n\nSetting aside the already identified benefits of the sequential, synchronous-looking syntax of generators (see Chapter 4), the `steps` logic had to be reordered in the `*steps()` generator form, to fake the dynamicism of the extendable iterable sequence `steps`.\n\nWhat about expressing the functionality with Promises or sequences, though? You *can* do something like this:\n\n```js\nvar steps = something( .. )\n.then( .. )\n.then( function(..){\n\t// ..\n\n\t// extending the chain, right?\n\tsteps = steps.then( .. );\n\n\t// ..\n})\n.then( .. );\n```\n\nThe problem is subtle but important to grasp. So, consider trying to wire up our `steps` Promise chain into our main program flow -- this time expressed with Promises instead of *asynquence*:\n\n```js\nvar main = Promise.resolve( {\n\turl: \"http://some.url.1\",\n\tformat: function STEP4(text){\n\t\treturn text.toUpperCase();\n\t}\n} )\n.then( function(..){\n\treturn steps;\t\t\t// hint!\n} )\n.val( function(msg){\n\tconsole.log( msg );\n} );\n```\n\nCan you spot the problem now? Look closely!\n\nThere's a race condition for sequence steps ordering. When you `return steps`, at that moment `steps` *might* be the originally defined promise chain, or it might now point to the extended promise chain via the `steps = steps.then(..)` call, depending on what order things happen.\n\nHere are the two possible outcomes:\n\n* If `steps` is still the original promise chain, once it's later \"extended\" by `steps = steps.then(..)`, that extended promise on the end of the chain is **not** considered by the `main` flow, as it's already tapped the `steps` chain. This is the unfortunately limiting **eager evaluation**.\n* If `steps` is already the extended promise chain, it works as we expect in that the extended promise is what `main` taps.\n\nOther than the obvious fact that a race condition is intolerable, the first case is the concern; it illustrates **eager evaluation** of the promise chain. By contrast, we easily extended the iterable sequence without such issues, because iterable sequences are **lazily evaluated**.\n\nThe more dynamic you need your flow control, the more iterable sequences will shine.\n\n**Tip:** Check out more information and examples of iterable sequences on the *asynquence* site (https://github.com/getify/asynquence/blob/master/README.md#iterable-sequences).\n\n## Event Reactive\n\nIt should be obvious from (at least!) Chapter 3 that Promises are a very powerful tool in your async toolbox. But one thing that's clearly lacking is in their capability to handle streams of events, as a Promise can only be resolved once. And frankly, this exact same weakness is true of plain *asynquence* sequences, as well.\n\nConsider a scenario where you want to fire off a series of steps every time a certain event is fired. A single Promise or sequence cannot represent all occurrences of that event. So, you have to create a whole new Promise chain (or sequence) for *each* event occurrence, such as:\n\n```js\nlistener.on( \"foobar\", function(data){\n\n\t// create a new event handling promise chain\n\tnew Promise( function(resolve,reject){\n\t\t// ..\n\t} )\n\t.then( .. )\n\t.then( .. );\n\n} );\n```\n\nThe base functionality we need is present in this approach, but it's far from a desirable way to express our intended logic. There are two separate capabilities conflated in this paradigm: the event listening, and responding to the event; separation of concerns would implore us to separate out these capabilities.\n\nThe carefully observant reader will see this problem as somewhat symmetrical to the problems we detailed with callbacks in Chapter 2; it's kind of an inversion of control problem.\n\nImagine uninverting this paradigm, like so:\n\n```js\nvar observable = listener.on( \"foobar\" );\n\n// later\nobservable\n.then( .. )\n.then( .. );\n\n// elsewhere\nobservable\n.then( .. )\n.then( .. );\n```\n\nThe `observable` value is not exactly a Promise, but you can *observe* it much like you can observe a Promise, so it's closely related. In fact, it can be observed many times, and it will send out notifications every time its event (`\"foobar\"`) occurs.\n\n**Tip:** This pattern I've just illustrated is a **massive simplification** of the concepts and motivations behind reactive programming (aka RP), which has been implemented/expounded upon by several great projects and languages. A variation on RP is functional reactive programming (FRP), which refers to applying functional programming techniques (immutability, referential integrity, etc.) to streams of data. \"Reactive\" refers to spreading this functionality out over time in response to events. The interested reader should consider studying \"Reactive Observables\" in the fantastic \"Reactive Extensions\" library (\"RxJS\" for JavaScript) by Microsoft (http://rxjs.codeplex.com/); it's much more sophisticated and powerful than I've just shown. Also, Andre Staltz has an excellent write-up (https://gist.github.com/staltz/868e7e9bc2a7b8c1f754) that pragmatically lays out RP in concrete examples.\n\n### ES7 Observables\n\nAt the time of this writing, there's an early ES7 proposal for a new data type called \"Observable\" (https://github.com/jhusain/asyncgenerator#introducing-observable), which in spirit is similar to what we've laid out here, but is definitely more sophisticated.\n\nThe notion of this kind of Observable is that the way you \"subscribe\" to the events from a stream is to pass in a generator -- actually the *iterator* is the interested party -- whose `next(..)` method will be called for each event.\n\nYou could imagine it sort of like this:\n\n```js\n// `someEventStream` is a stream of events, like from\n// mouse clicks, and the like.\n\nvar observer = new Observer( someEventStream, function*(){\n\twhile (var evt = yield) {\n\t\tconsole.log( evt );\n\t}\n} );\n```\n\nThe generator you pass in will `yield` pause the `while` loop waiting for the next event. The *iterator* attached to the generator instance will have its `next(..)` called each time `someEventStream` has a new event published, and so that event data will resume your generator/*iterator* with the `evt` data.\n\nIn the subscription to events functionality here, it's the *iterator* part that matters, not the generator. So conceptually you could pass in practically any iterable, including `ASQ.iterable()` iterable sequences.\n\nInterestingly, there are also proposed adapters to make it easy to construct Observables from certain types of streams, such as `fromEvent(..)` for DOM events. If you look at a suggested implementation of `fromEvent(..)` in the earlier linked ES7 proposal, it looks an awful lot like the `ASQ.react(..)` we'll see in the next section.\n\nOf course, these are all early proposals, so what shakes out may very well look/behave differently than shown here. But it's exciting to see the early alignments of concepts across different libraries and language proposals!\n\n### Reactive Sequences\n\nWith that crazy brief summary of Observables (and F/RP) as our inspiration and motivation, I will now illustrate an adaptation of a small subset of \"Reactive Observables,\" which I call \"Reactive Sequences.\"\n\nFirst, let's start with how to create an Observable, using an *asynquence* plug-in utility called `react(..)`:\n\n```js\nvar observable = ASQ.react( function setup(next){\n\tlistener.on( \"foobar\", next );\n} );\n```\n\nNow, let's see how to define a sequence that \"reacts\" -- in F/RP, this is typically called \"subscribing\" -- to that `observable`:\n\n```js\nobservable\n.seq( .. )\n.then( .. )\n.val( .. );\n```\n\nSo, you just define the sequence by chaining off the Observable. That's easy, huh?\n\nIn F/RP, the stream of events typically channels through a set of functional transforms, like `scan(..)`, `map(..)`, `reduce(..)`, and so on. With reactive sequences, each event channels through a new instance of the sequence. Let's look at a more concrete example:\n\n```js\nASQ.react( function setup(next){\n\tdocument.getElementById( \"mybtn\" )\n\t.addEventListener( \"click\", next, false );\n} )\n.seq( function(evt){\n\tvar btnID = evt.target.id;\n\treturn request(\n\t\t\"http://some.url.1/?id=\" + btnID\n\t);\n} )\n.val( function(text){\n\tconsole.log( text );\n} );\n```\n\nThe \"reactive\" portion of the reactive sequence comes from assigning one or more event handlers to invoke the event trigger (calling `next(..)`).\n\nThe \"sequence\" portion of the reactive sequence is exactly like the sequences we've already explored: each step can be whatever asynchronous technique makes sense, from continuation callback to Promise to generator.\n\nOnce you set up a reactive sequence, it will continue to initiate instances of the sequence as long as the events keep firing. If you want to stop a reactive sequence, you can call `stop()`.\n\nIf a reactive sequence is `stop()`'d, you likely want the event handler(s) to be unregistered as well; you can register a teardown handler for this purpose:\n\n```js\nvar sq = ASQ.react( function setup(next,registerTeardown){\n\tvar btn = document.getElementById( \"mybtn\" );\n\n\tbtn.addEventListener( \"click\", next, false );\n\n\t// will be called once `sq.stop()` is called\n\tregisterTeardown( function(){\n\t\tbtn.removeEventListener( \"click\", next, false );\n\t} );\n} )\n.seq( .. )\n.then( .. )\n.val( .. );\n\n// later\nsq.stop();\n```\n\n**Note:** The `this` binding reference inside the `setup(..)` handler is the same `sq` reactive sequence, so you can use the `this` reference to add to the reactive sequence definition, call methods like `stop()`, and so on.\n\nHere's an example from the Node.js world, using reactive sequences to handle incoming HTTP requests:\n\n```js\nvar server = http.createServer();\nserver.listen(8000);\n\n// reactive observer\nvar request = ASQ.react( function setup(next,registerTeardown){\n\tserver.addListener( \"request\", next );\n\tserver.addListener( \"close\", this.stop );\n\n\tregisterTeardown( function(){\n\t\tserver.removeListener( \"request\", next );\n\t\tserver.removeListener( \"close\", request.stop );\n\t} );\n});\n\n// respond to requests\nrequest\n.seq( pullFromDatabase )\n.val( function(data,res){\n\tres.end( data );\n} );\n\n// node teardown\nprocess.on( \"SIGINT\", request.stop );\n```\n\nThe `next(..)` trigger can also adapt to node streams easily, using `onStream(..)` and `unStream(..)`:\n\n```js\nASQ.react( function setup(next){\n\tvar fstream = fs.createReadStream( \"/some/file\" );\n\n\t// pipe the stream's \"data\" event to `next(..)`\n\tnext.onStream( fstream );\n\n\t// listen for the end of the stream\n\tfstream.on( \"end\", function(){\n\t\tnext.unStream( fstream );\n\t} );\n} )\n.seq( .. )\n.then( .. )\n.val( .. );\n```\n\nYou can also use sequence combinations to compose multiple reactive sequence streams:\n\n```js\nvar sq1 = ASQ.react( .. ).seq( .. ).then( .. );\nvar sq2 = ASQ.react( .. ).seq( .. ).then( .. );\n\nvar sq3 = ASQ.react(..)\n.gate(\n\tsq1,\n\tsq2\n)\n.then( .. );\n```\n\nThe main takeaway is that `ASQ.react(..)` is a lightweight adaptation of F/RP concepts, enabling the wiring of an event stream to a sequence, hence the term \"reactive sequence.\" Reactive sequences are generally capable enough for basic reactive uses.\n\n**Note:** Here's an example of using `ASQ.react(..)` in managing UI state (http://jsbin.com/rozipaki/6/edit?js,output), and another example of handling HTTP request/response streams with `ASQ.react(..)` (https://gist.github.com/getify/bba5ec0de9d6047b720e).\n\n## Generator Coroutine\n\nHopefully Chapter 4 helped you get pretty familiar with ES6 generators. In particular, we want to revisit the \"Generator Concurrency\" discussion, and push it even further.\n\nWe imagined a `runAll(..)` utility that could take two or more generators and run them concurrently, letting them cooperatively `yield` control from one to the next, with optional message passing.\n\nIn addition to being able to run a single generator to completion, the `ASQ#runner(..)` we discussed in Appendix A is a similar implementation of the concepts of `runAll(..)`, which can run multiple generators concurrently to completion.\n\nSo let's see how we can implement the concurrent Ajax scenario from Chapter 4:\n\n```js\nASQ(\n\t\"http://some.url.2\"\n)\n.runner(\n\tfunction*(token){\n\t\t// transfer control\n\t\tyield token;\n\n\t\tvar url1 = token.messages[0]; // \"http://some.url.1\"\n\n\t\t// clear out messages to start fresh\n\t\ttoken.messages = [];\n\n\t\tvar p1 = request( url1 );\n\n\t\t// transfer control\n\t\tyield token;\n\n\t\ttoken.messages.push( yield p1 );\n\t},\n\tfunction*(token){\n\t\tvar url2 = token.messages[0]; // \"http://some.url.2\"\n\n\t\t// message pass and transfer control\n\t\ttoken.messages[0] = \"http://some.url.1\";\n\t\tyield token;\n\n\t\tvar p2 = request( url2 );\n\n\t\t// transfer control\n\t\tyield token;\n\n\t\ttoken.messages.push( yield p2 );\n\n\t\t// pass along results to next sequence step\n\t\treturn token.messages;\n\t}\n)\n.val( function(res){\n\t// `res[0]` comes from \"http://some.url.1\"\n\t// `res[1]` comes from \"http://some.url.2\"\n} );\n```\n\nThe main differences between `ASQ#runner(..)` and `runAll(..)` are as follows:\n\n* Each generator (coroutine) is provided an argument we call `token`, which is the special value to `yield` when you want to explicitly transfer control to the next coroutine.\n* `token.messages` is an array that holds any messages passed in from the previous sequence step. It's also a data structure that you can use to share messages between coroutines.\n* `yield`ing a Promise (or sequence) value does not transfer control, but instead pauses the coroutine processing until that value is ready.\n* The last `return`ed or `yield`ed value from the coroutine processing run will be forward passed to the next step in the sequence.\n\nIt's also easy to layer helpers on top of the base `ASQ#runner(..)` functionality to suit different uses.\n\n### State Machines\n\nOne example that may be familiar to many programmers is state machines. You can, with the help of a simple cosmetic utility, create an easy-to-express state machine processor.\n\nLet's imagine such a utility. We'll call it `state(..)`, and will pass it two arguments: a state value and a generator that handles that state. `state(..)` will do the dirty work of creating and returning an adapter generator to pass to `ASQ#runner(..)`.\n\nConsider:\n\n```js\nfunction state(val,handler) {\n\t// make a coroutine handler for this state\n\treturn function*(token) {\n\t\t// state transition handler\n\t\tfunction transition(to) {\n\t\t\ttoken.messages[0] = to;\n\t\t}\n\n\t\t// set initial state (if none set yet)\n\t\tif (token.messages.length < 1) {\n\t\t\ttoken.messages[0] = val;\n\t\t}\n\n\t\t// keep going until final state (false) is reached\n\t\twhile (token.messages[0] !== false) {\n\t\t\t// current state matches this handler?\n\t\t\tif (token.messages[0] === val) {\n\t\t\t\t// delegate to state handler\n\t\t\t\tyield *handler( transition );\n\t\t\t}\n\n\t\t\t// transfer control to another state handler?\n\t\t\tif (token.messages[0] !== false) {\n\t\t\t\tyield token;\n\t\t\t}\n\t\t}\n\t};\n}\n```\n\nIf you look closely, you'll see that `state(..)` returns back a generator that accepts a `token`, and then it sets up a `while` loop that will run until the state machine reaches its final state (which we arbitrarily pick as the `false` value); that's exactly the kind of generator we want to pass to `ASQ#runner(..)`!\n\nWe also arbitrarily reserve the `token.messages[0]` slot as the place where the current state of our state machine will be tracked, which means we can even seed the initial state as the value passed in from the previous step in the sequence.\n\nHow do we use the `state(..)` helper along with `ASQ#runner(..)`?\n\n```js\nvar prevState;\n\nASQ(\n\t/* optional: initial state value */\n\t2\n)\n// run our state machine\n// transitions: 2 -> 3 -> 1 -> 3 -> false\n.runner(\n\t// state `1` handler\n\tstate( 1, function *stateOne(transition){\n\t\tconsole.log( \"in state 1\" );\n\n\t\tprevState = 1;\n\t\tyield transition( 3 );\t// goto state `3`\n\t} ),\n\n\t// state `2` handler\n\tstate( 2, function *stateTwo(transition){\n\t\tconsole.log( \"in state 2\" );\n\n\t\tprevState = 2;\n\t\tyield transition( 3 );\t// goto state `3`\n\t} ),\n\n\t// state `3` handler\n\tstate( 3, function *stateThree(transition){\n\t\tconsole.log( \"in state 3\" );\n\n\t\tif (prevState === 2) {\n\t\t\tprevState = 3;\n\t\t\tyield transition( 1 ); // goto state `1`\n\t\t}\n\t\t// all done!\n\t\telse {\n\t\t\tyield \"That's all folks!\";\n\n\t\t\tprevState = 3;\n\t\t\tyield transition( false ); // terminal state\n\t\t}\n\t} )\n)\n// state machine complete, so move on\n.val( function(msg){\n\tconsole.log( msg );\t// That's all folks!\n} );\n```\n\nIt's important to note that the `*stateOne(..)`, `*stateTwo(..)`, and `*stateThree(..)` generators themselves are reinvoked each time that state is entered, and they finish when you `transition(..)` to another value. While not shown here, of course these state generator handlers can be asynchronously paused by `yield`ing Promises/sequences/thunks.\n\nThe underneath hidden generators produced by the `state(..)` helper and actually passed to `ASQ#runner(..)` are the ones that continue to run concurrently for the length of the state machine, and each of them handles cooperatively `yield`ing control to the next, and so on.\n\n**Note:** See this \"ping pong\" example (http://jsbin.com/qutabu/1/edit?js,output) for more illustration of using cooperative concurrency with generators driven by `ASQ#runner(..)`.\n\n## Communicating Sequential Processes (CSP)\n\n\"Communicating Sequential Processes\" (CSP) was first described by C. A. R. Hoare in a 1978 academic paper (http://dl.acm.org/citation.cfm?doid=359576.359585), and later in a 1985 book (http://www.usingcsp.com/) of the same name. CSP describes a formal method for concurrent \"processes\" to interact (aka \"communicate\") during processing.\n\nYou may recall that we examined concurrent \"processes\" back in Chapter 1, so our exploration of CSP here will build upon that understanding.\n\nLike most great concepts in computer science, CSP is heavily steeped in academic formalism, expressed as a process algebra. However, I suspect symbolic algebra theorems won't make much practical difference to the reader, so we will want to find some other way of wrapping our brains around CSP.\n\nI will leave much of the formal description and proof of CSP to Hoare's writing, and to many other fantastic writings since. Instead, we will try to just briefly explain the idea of CSP in as un-academic and hopefully intuitively understandable a way as possible.\n\n### Message Passing\n\nThe core principle in CSP is that all communication/interaction between otherwise independent processes must be through formal message passing. Perhaps counter to your expectations, CSP message passing is described as a synchronous action, where the sender process and the receiver process have to mutually be ready for the message to be passed.\n\nHow could such synchronous messaging possibly be related to asynchronous programming in JavaScript?\n\nThe concreteness of relationship comes from the nature of how ES6 generators are used to produce synchronous-looking actions that under the covers can indeed either be synchronous or (more likely) asynchronous.\n\nIn other words, two or more concurrently running generators can appear to synchronously message each other while preserving the fundamental asynchrony of the system because each generator's code is paused (aka \"blocked\") waiting on resumption of an asynchronous action.\n\nHow does this work?\n\nImagine a generator (aka \"process\") called \"A\" that wants to send a message to generator \"B.\" First, \"A\" `yield`s the message (thus pausing \"A\") to be sent to \"B.\" When \"B\" is ready and takes the message, \"A\" is then resumed (unblocked).\n\nSymmetrically, imagine a generator \"A\" that wants a message **from** \"B.\" \"A\" `yield`s its request (thus pausing \"A\") for the message from \"B,\" and once \"B\" sends a message, \"A\" takes the message and is resumed.\n\nOne of the more popular expressions of this CSP message passing theory comes from ClojureScript's core.async library, and also from the *go* language. These takes on CSP embody the described communication semantics in a conduit that is opened between processes called a \"channel.\"\n\n**Note:** The term *channel* is used in part because there are modes in which more than one value can be sent at once into the \"buffer\" of the channel; this is similar to what you may think of as a stream. We won't go into depth about it here, but it can be a very powerful technique for managing streams of data.\n\nIn the simplest notion of CSP, a channel that we create between \"A\" and \"B\" would have a method called `take(..)` for blocking to receive a value, and a method called `put(..)` for blocking to send a value.\n\nThis might look like:\n\n```js\nvar ch = channel();\n\nfunction *foo() {\n\tvar msg = yield take( ch );\n\n\tconsole.log( msg );\n}\n\nfunction *bar() {\n\tyield put( ch, \"Hello World\" );\n\n\tconsole.log( \"message sent\" );\n}\n\nrun( foo );\nrun( bar );\n// Hello World\n// \"message sent\"\n```\n\nCompare this structured, synchronous(-looking) message passing interaction to the informal and unstructured message sharing that `ASQ#runner(..)` provides through the `token.messages` array and cooperative `yield`ing. In essence, `yield put(..)` is a single operation that both sends the value and pauses execution to transfer control, whereas in earlier examples we did those as separate steps.\n\nMoreover, CSP stresses that you don't really explicitly \"transfer control,\" but rather you design your concurrent routines to block expecting either a value received from the channel, or to block expecting to try to send a message on the channel. The blocking around receiving or sending messages is how you coordinate sequencing of behavior between the coroutines.\n\n**Note:** Fair warning: this pattern is very powerful but it's also a little mind twisting to get used to at first. You will want to practice this a bit to get used to this new way of thinking about coordinating your concurrency.\n\nThere are several great libraries that have implemented this flavor of CSP in JavaScript, most notably \"js-csp\" (https://github.com/ubolonton/js-csp), which James Long (http://twitter.com/jlongster) forked (https://github.com/jlongster/js-csp) and has written extensively about (http://jlongster.com/Taming-the-Asynchronous-Beast-with-CSP-in-JavaScript). Also, it cannot be stressed enough how amazing the many writings of David Nolen (http://twitter.com/swannodette) are on the topic of adapting ClojureScript's go-style core.async CSP into JS generators (http://swannodette.github.io/2013/08/24/es6-generators-and-csp/).\n\n### asynquence CSP emulation\n\nBecause we've been discussing async patterns here in the context of my *asynquence* library, you might be interested to see that we can fairly easily add an emulation layer on top of `ASQ#runner(..)` generator handling as a nearly perfect porting of the CSP API and behavior. This emulation layer ships as an optional part of the \"asynquence-contrib\" package alongside *asynquence*.\n\nVery similar to the `state(..)` helper from earlier, `ASQ.csp.go(..)` takes a generator -- in go/core.async terms, it's known as a goroutine -- and adapts it to use with `ASQ#runner(..)` by returning a new generator.\n\nInstead of being passed a `token`, your goroutine receives an initially created channel (`ch` below) that all goroutines in this run will share. You can create more channels (which is often quite helpful!) with `ASQ.csp.chan(..)`.\n\nIn CSP, we model all asynchrony in terms of blocking on channel messages, rather than blocking waiting for a Promise/sequence/thunk to complete.\n\nSo, instead of `yield`ing the Promise returned from `request(..)`, `request(..)` should return a channel that you `take(..)` a value from. In other words, a single-value channel is roughly equivalent in this context/usage to a Promise/sequence.\n\nLet's first make a channel-aware version of `request(..)`:\n\n```js\nfunction request(url) {\n\tvar ch = ASQ.csp.channel();\n\tajax( url ).then( function(content){\n\t\t// `putAsync(..)` is a version of `put(..)` that\n\t\t// can be used outside of a generator. It returns\n\t\t// a promise for the operation's completion. We\n\t\t// don't use that promise here, but we could if\n\t\t// we needed to be notified when the value had\n\t\t// been `take(..)`n.\n\t\tASQ.csp.putAsync( ch, content );\n\t} );\n\treturn ch;\n}\n```\n\nFrom Chapter 3, \"promisory\" is a Promise-producing utility, \"thunkory\" from Chapter 4 is a thunk-producing utility, and finally, in Appendix A we invented \"sequory\" for a sequence-producing utility.\n\nNaturally, we need to coin a symmetric term here for a channel-producing utility. So let's unsurprisingly call it a \"chanory\" (\"channel\" + \"factory\"). As an exercise for the reader, try your hand at defining a `channelify(..)` utility similar to `Promise.wrap(..)`/`promisify(..)` (Chapter 3), `thunkify(..)` (Chapter 4), and `ASQ.wrap(..)` (Appendix A).\n\nNow consider the concurrent Ajax example using *asyquence*-flavored CSP:\n\n```js\nASQ()\n.runner(\n\tASQ.csp.go( function*(ch){\n\t\tyield ASQ.csp.put( ch, \"http://some.url.2\" );\n\n\t\tvar url1 = yield ASQ.csp.take( ch );\n\t\t// \"http://some.url.1\"\n\n\t\tvar res1 = yield ASQ.csp.take( request( url1 ) );\n\n\t\tyield ASQ.csp.put( ch, res1 );\n\t} ),\n\tASQ.csp.go( function*(ch){\n\t\tvar url2 = yield ASQ.csp.take( ch );\n\t\t// \"http://some.url.2\"\n\n\t\tyield ASQ.csp.put( ch, \"http://some.url.1\" );\n\n\t\tvar res2 = yield ASQ.csp.take( request( url2 ) );\n\t\tvar res1 = yield ASQ.csp.take( ch );\n\n\t\t// pass along results to next sequence step\n\t\tch.buffer_size = 2;\n\t\tASQ.csp.put( ch, res1 );\n\t\tASQ.csp.put( ch, res2 );\n\t} )\n)\n.val( function(res1,res2){\n\t// `res1` comes from \"http://some.url.1\"\n\t// `res2` comes from \"http://some.url.2\"\n} );\n```\n\nThe message passing that trades the URL strings between the two goroutines is pretty straightforward. The first goroutine makes an Ajax request to the first URL, and that response is put onto the `ch` channel. The second goroutine makes an Ajax request to the second URL, then gets the first response `res1` off the `ch` channel. At that point, both responses `res1` and `res2` are completed and ready.\n\nIf there are any remaining values in the `ch` channel at the end of the goroutine run, they will be passed along to the next step in the sequence. So, to pass out message(s) from the final goroutine, `put(..)` them into `ch`. As shown, to avoid the blocking of those final `put(..)`s, we switch `ch` into buffering mode by setting its `buffer_size` to `2` (default: `0`).\n\n**Note:** See many more examples of using *asynquence*-flavored CSP here (https://gist.github.com/getify/e0d04f1f5aa24b1947ae).\n\n## Review\n\nPromises and generators provide the foundational building blocks upon which we can build much more sophisticated and capable asynchrony.\n\n*asynquence* has utilities for implementing *iterable sequences*, *reactive sequences* (aka \"Observables\"), *concurrent coroutines*, and even *CSP goroutines*.\n\nThose patterns, combined with the continuation-callback and Promise capabilities, gives *asynquence* a powerful mix of different asynchronous functionalities, all integrated in one clean async flow control abstraction: the sequence.\n"
  },
  {
    "path": "async & performance/apC.md",
    "content": "# Вы не знаете JS: Асинхронность и Производительность\n# Приложение C: Благодарности\n\nЕсть множество людей, которых нужно поблагодарить за то, что появилась на свет эта книга и вся серия.\n\nВо-первых, я должен поблагодарить мою жену Кристен Симпсон (Christen Simpson) и двух моих детей Итана (Ethan) и Эмили (Emily), за то, что мирились с тем, что их папу вечно надо было отрывать от компьютера. Даже когда я не писал книги, моя одержимость JavaScript приклеивала мой взгляд к экрану больше, чем следовало. То время, которое я занял у моей семьи, и есть причина, по которой эти книги могут так глубоко и полностью объяснить JavaScript для вас, читатель. Я в большом долгу перед своей семьей.\n\nХочу поблагодарить моих редакторов в O'Reilly, а именно Simon St.Laurent и Brian MacDonald, как и остальных в команде редакторов и маркетинга. Работать с ними — одно удовольствие, и хочется особенно поблагодарить их за создание подходящих условий во время этого эксперимента с написанием \"open source\"-книги, за редактирование и выпуск.\n\nСпасибо всем тем, кто участвовал в улучшении этой серии книг присылая предложения по редактированию и корректировке, включая Shelley Powers, Tim Ferro, Evan Borden, Forrest L. Norvell, Jennifer Davis, Jesse Harlin и многих других. Большое спасибо Shane Hudson за написание предисловия к этой серии книг.\n\nСпасибо бесчисленным участникам сообщества, включая членов комитета TC39, кто поделился столько многим с нами и особенно за терпеливое отношение к моим бесконечным вопросам и изысканиям. John-David Dalton, Juriy \"kangax\" Zaytsev, Mathias Bynens, Axel Rauschmayer, Nicholas Zakas, Angus Croll, Reginald Braithwaite, Dave Herman, Brendan Eich, Allen Wirfs-Brock, Bradley Meck, Domenic Denicola, David Walsh, Tim Disney, Peter van der Zee, Andrea Giammarchi, Kit Cambridge, Eric Elliott и многие другие, я упомянул лишь малую часть.\n\nСерия книг *Вы не знаете JS* родилась на Kickstarter, поэтому я также хочу поблагодарить всех моих (почти) 500 щедрых инвесторов, без которых эта серия книг не появилась бы:\n\n> Jan Szpila, nokiko, Murali Krishnamoorthy, Ryan Joy, Craig Patchett, pdqtrader, Dale Fukami, ray hatfield, R0drigo Perez [Mx], Dan Petitt, Jack Franklin, Andrew Berry, Brian Grinstead, Rob Sutherland, Sergi Meseguer, Phillip Gourley, Mark Watson, Jeff Carouth, Alfredo Sumaran, Martin Sachse, Marcio Barrios, Dan, AimelyneM, Matt Sullivan, Delnatte Pierre-Antoine, Jake Smith, Eugen Tudorancea, Iris, David Trinh, simonstl, Ray Daly, Uros Gruber, Justin Myers, Shai Zonis, Mom & Dad, Devin Clark, Dennis Palmer, Brian Panahi Johnson, Josh Marshall, Marshall, Dennis Kerr, Matt Steele, Erik Slagter, Sacah, Justin Rainbow, Christian Nilsson, Delapouite, D.Pereira, Nicolas Hoizey, George V. Reilly, Dan Reeves, Bruno Laturner, Chad Jennings, Shane King, Jeremiah Lee Cohick, od3n, Stan Yamane, Marko Vucinic, Jim B, Stephen Collins, Ægir Þorsteinsson, Eric Pederson, Owain, Nathan Smith, Jeanetteurphy, Alexandre ELISÉ, Chris Peterson, Rik Watson, Luke Matthews, Justin Lowery, Morten Nielsen, Vernon Kesner, Chetan Shenoy, Paul Tregoing, Marc Grabanski, Dion Almaer, Andrew Sullivan, Keith Elsass, Tom Burke, Brian Ashenfelter, David Stuart, Karl Swedberg, Graeme, Brandon Hays, John Christopher, Gior, manoj reddy, Chad Smith, Jared Harbour, Minoru TODA, Chris Wigley, Daniel Mee, Mike, Handyface, Alex Jahraus, Carl Furrow, Rob Foulkrod, Max Shishkin, Leigh Penny Jr., Robert Ferguson, Mike van Hoenselaar, Hasse Schougaard, rajan venkataguru, Jeff Adams, Trae Robbins, Rolf Langenhuijzen, Jorge Antunes, Alex Koloskov, Hugh Greenish, Tim Jones, Jose Ochoa, Michael Brennan-White, Naga Harish Muvva, Barkóczi Dávid, Kitt Hodsden, Paul McGraw, Sascha Goldhofer, Andrew Metcalf, Markus Krogh, Michael Mathews, Matt Jared, Juanfran, Georgie Kirschner, Kenny Lee, Ted Zhang, Amit Pahwa, Inbal Sinai, Dan Raine, Schabse Laks, Michael Tervoort, Alexandre Abreu, Alan Joseph Williams, NicolasD, Cindy Wong, Reg Braithwaite, LocalPCGuy, Jon Friskics, Chris Merriman, John Pena, Jacob Katz, Sue Lockwood, Magnus Johansson, Jeremy Crapsey, Grzegorz Pawłowski, nico nuzzaci, Christine Wilks, Hans Bergren, charles montgomery, Ariel בר-לבב Fogel, Ivan Kolev, Daniel Campos, Hugh Wood, Christian Bradford, Frédéric Harper, Ionuţ Dan Popa, Jeff Trimble, Rupert Wood, Trey Carrico, Pancho Lopez, Joël kuijten, Tom A Marra, Jeff Jewiss, Jacob Rios, Paolo Di Stefano, Soledad Penades, Chris Gerber, Andrey Dolganov, Wil Moore III, Thomas Martineau, Kareem, Ben Thouret, Udi Nir, Morgan Laupies, jory carson-burson, Nathan L Smith, Eric Damon Walters, Derry Lozano-Hoyland, Geoffrey Wiseman, mkeehner, KatieK, Scott MacFarlane, Brian LaShomb, Adrien Mas, christopher ross, Ian Littman, Dan Atkinson, Elliot Jobe, Nick Dozier, Peter Wooley, John Hoover, dan, Martin A. Jackson, Héctor Fernando Hurtado, andy ennamorato, Paul Seltmann, Melissa Gore, Dave Pollard, Jack Smith, Philip Da Silva, Guy Israeli, @megalithic, Damian Crawford, Felix Gliesche, April Carter Grant, Heidi, jim tierney, Andrea Giammarchi, Nico Vignola, Don Jones, Chris Hartjes, Alex Howes, john gibbon, David J. Groom, BBox, Yu 'Dilys' Sun, Nate Steiner, Brandon Satrom, Brian Wyant, Wesley Hales, Ian Pouncey, Timothy Kevin Oxley, George Terezakis, sanjay raj, Jordan Harband, Marko McLion, Wolfgang Kaufmann, Pascal Peuckert, Dave Nugent, Markus Liebelt, Welling Guzman, Nick Cooley, Daniel Mesquita, Robert Syvarth, Chris Coyier, Rémy Bach, Adam Dougal, Alistair Duggin, David Loidolt, Ed Richer, Brian Chenault, GoldFire Studios, Carles Andrés, Carlos Cabo, Yuya Saito, roberto ricardo, Barnett Klane, Mike Moore, Kevin Marx, Justin Love, Joe Taylor, Paul Dijou, Michael Kohler, Rob Cassie, Mike Tierney, Cody Leroy Lindley, tofuji, Shimon Schwartz, Raymond, Luc De Brouwer, David Hayes, Rhys Brett-Bowen, Dmitry, Aziz Khoury, Dean, Scott Tolinski - Level Up, Clement Boirie, Djordje Lukic, Anton Kotenko, Rafael Corral, Philip Hurwitz, Jonathan Pidgeon, Jason Campbell, Joseph C., SwiftOne, Jan Hohner, Derick Bailey, getify, Daniel Cousineau, Chris Charlton, Eric Turner, David Turner, Joël Galeran, Dharma Vagabond, adam, Dirk van Bergen, dave ♥♫★ furf, Vedran Zakanj, Ryan McAllen, Natalie Patrice Tucker, Eric J. Bivona, Adam Spooner, Aaron Cavano, Kelly Packer, Eric J, Martin Drenovac, Emilis, Michael Pelikan, Scott F. Walter, Josh Freeman, Brandon Hudgeons, vijay chennupati, Bill Glennon, Robin R., Troy Forster, otaku_coder, Brad, Scott, Frederick Ostrander, Adam Brill, Seb Flippence, Michael Anderson, Jacob, Adam Randlett, Standard, Joshua Clanton, Sebastian Kouba, Chris Deck, SwordFire, Hannes Papenberg, Richard Woeber, hnzz, Rob Crowther, Jedidiah Broadbent, Sergey Chernyshev, Jay-Ar Jamon, Ben Combee, luciano bonachela, Mark Tomlinson, Kit Cambridge, Michael Melgares, Jacob Adams, Adrian Bruinhout, Bev Wieber, Scott Puleo, Thomas Herzog, April Leone, Daniel Mizieliński, Kees van Ginkel, Jon Abrams, Erwin Heiser, Avi Laviad, David newell, Jean-Francois Turcot, Niko Roberts, Erik Dana, Charles Neill, Aaron Holmes, Grzegorz Ziółkowski, Nathan Youngman, Timothy, Jacob Mather, Michael Allan, Mohit Seth, Ryan Ewing, Benjamin Van Treese, Marcelo Santos, Denis Wolf, Phil Keys, Chris Yung, Timo Tijhof, Martin Lekvall, Agendine, Greg Whitworth, Helen Humphrey, Dougal Campbell, Johannes Harth, Bruno Girin, Brian Hough, Darren Newton, Craig McPheat, Olivier Tille, Dennis Roethig, Mathias Bynens, Brendan Stromberger, sundeep, John Meyer, Ron Male, John F Croston III, gigante, Carl Bergenhem, B.J. May, Rebekah Tyler, Ted Foxberry, Jordan Reese, Terry Suitor, afeliz, Tom Kiefer, Darragh Duffy, Kevin Vanderbeken, Andy Pearson, Simon Mac Donald, Abid Din, Chris Joel, Tomas Theunissen, David Dick, Paul Grock, Brandon Wood, John Weis, dgrebb, Nick Jenkins, Chuck Lane, Johnny Megahan, marzsman, Tatu Tamminen, Geoffrey Knauth, Alexander Tarmolov, Jeremy Tymes, Chad Auld, Sean Parmelee, Rob Staenke, Dan Bender, Yannick derwa, Joshua Jones, Geert Plaisier, Tom LeZotte, Christen Simpson, Stefan Bruvik, Justin Falcone, Carlos Santana, Michael Weiss, Pablo Villoslada, Peter deHaan, Dimitris Iliopoulos, seyDoggy, Adam Jordens, Noah Kantrowitz, Amol M, Matthew Winnard, Dirk Ginader, Phinam Bui, David Rapson, Andrew Baxter, Florian Bougel, Michael George, Alban Escalier, Daniel Sellers, Sasha Rudan, John Green, Robert Kowalski, David I. Teixeira (@ditma, Charles Carpenter, Justin Yost, Sam S, Denis Ciccale, Kevin Sheurs, Yannick Croissant, Pau Fracés, Stephen McGowan, Shawn Searcy, Chris Ruppel, Kevin Lamping, Jessica Campbell, Christopher Schmitt, Sablons, Jonathan Reisdorf, Bunni Gek, Teddy Huff, Michael Mullany, Michael Fürstenberg, Carl Henderson, Rick Yoesting, Scott Nichols, Hernán Ciudad, Andrew Maier, Mike Stapp, Jesse Shawl, Sérgio Lopes, jsulak, Shawn Price, Joel Clermont, Chris Ridmann, Sean Timm, Jason Finch, Aiden Montgomery, Elijah Manor, Derek Gathright, Jesse Harlin, Dillon Curry, Courtney Myers, Diego Cadenas, Arne de Bree, João Paulo Dubas, James Taylor, Philipp Kraeutli, Mihai Păun, Sam Gharegozlou, joshjs, Matt Murchison, Eric Windham, Timo Behrmann, Andrew Hall, joshua price, Théophile Villard\n\nЭта серия книг выпускается в стиле \"open source\", включая редактирование и выпуск. Мы отдаем дань благодарности GitHub за предоставление такой возможности для сообщества!\n\nЕще раз спасибо всех бесчисленным людям, которых я не перечислил по имени, но кого я тем не менее должен поблагодарить. Пусть эта серия книг будет \"принадлежать\" всем нам и служить вкладом в увеличение информированности и понимании языка JavaScript, на благо все нынешних и будущих вкладчиков в общее дело сообщества.\n"
  },
  {
    "path": "async & performance/ch1.md",
    "content": "# Вы не знаете JS: Асинхронность и Выполнение\n# Глава 1: Асинхронность: Сейчас и Потом\n\nУправление программой в течении её времени выполнения является глубокой и, в то же время, важной темой для понимания Javascript.\n\nИмеется ввиду не только то, что происходит от начала 'for' цикла и до его завершения, выполнение которого занимает, в основном, небольшой промежуток времени (от микро до миллисекунд), но и, то, что случается между запуском одной части программы *сейчас* и другой *позже* -- в этом промежутке, когда она не в активном исполнении.\n\nПрактически, все нетривиальные программы (особенно, написанные на Javascript) управляют выше упомянутым промежутком, будь то ожидание ввода данных пользователем, запрос информации с базы данных или файловой системы, отправка данных по сети и ожидание ответа, или выполнение повторяющихся действий в заданном интервале (анимация). Во всех этих случаях, ваша программа должна управлять своим состоянием во время этой \"паузы\" в ходе своего исполнения. Как говорят в Лондоне \"Mind the gap!\"(дословно -- \"Помни о разрыве\") -- надпись на платформе, предупреждающая о расстоянии между её краем и дверью поезда.\n\nНа самом деле, отношение *сейчас* и *потом* частей вашей программы является сердцем асинхронного программирования.\n\nАсинхронное программирование существовало в JS изначально. Но многие разработчики не вдавались в подробности как именно оно работает в их программах, или находили *другие* способы управления им. *Почти хорошим* подходом считалась скромная callback функция. Многие до сих пор считают, что callback'и являются эффективным решением.\n\nНо с ростом масштаба и сложности JS, для удовлетворения постоянно расширяющихся требований первоклассного языка программирования, работающего как в браузерах так и на серверах, и на любых мыслимых устройствах, между прочим, росла и боль с которой приходилось управлять асинхронностью.\n\nСейчас это все может показаться довольно абстрактным. Но я вас уверяю, что мы углубимся в детали и изучим множество новых методов для асинхронного программирования в JavaScript в следующих главах.\n\nДля этого нам надо разобраться во всех тонкостях асинхронности в JS.\n\n## Программа по кусочкам\n\nДаже, если вы пишете ваш код в одном *.js* файле, ваша программа почти наверняка состоит из нескольких *кусочков*, один из которых выполнится *сейчас*, а остальные *потом*. Наиболее распространенная единица *кусочка* - 'function'.\n\nБольшинство новоприбывших в JS разработчиков думают, что асинхронный код приостанавливается для выполнения, но это не так.\n\nДавайте посмотрим:\n\n```js\n// ajax(..) обычная ajax функция\nvar data = ajax( \"http://some.url.1\" );\n\nconsole.log( data );\n// Упс! `данные` не получены\n```\n\nВы вероятно знаете, что Ajax запросы не выполняются синхронно, а это значит, что `ajax(..)` функция ещё не получила данных для присвоения в переменную `data`. Если бы `ajax(..)` запрос мог бы приостановить код для получения данных, тогда бы `data` не была пуста. \n\nПростейшая (но далеко не самая лучшая) реализация Ajax -- это использование функции callback. \n\n```js\najax( \"http://some.url.1\", function myCallbackFunction(data){\n\n\tconsole.log( data ); // Ура, Я получил `data`!\n\n} );\n```\n\n**Предупреждение.** Возможно, вы слышали, что можно выполнять синхронные запросы Ajax. Хотя технически это верно, вы никогда не должны этого делать ни при каких обстоятельствах, потому что это блокирует пользовательский интерфейс браузера (кнопки, меню, прокрутку и т.д.) и предотвращает любое взаимодействие с пользователем. Это ужасная идея, и ее всегда следует избегать.\n\nПрежде чем возражать против несогласия, нет, ваше желание избежать путаницы с колбеками *не* является оправданием для блокировки синхронного Ajax.\n\nНапример, рассмотрим этот код:\n\n```js\nfunction now() {\n\treturn 21;\n}\n\nfunction later() {\n\tanswer = answer * 2;\n\tconsole.log( \"Meaning of life:\", answer );\n}\n\nvar answer = now();\n\nsetTimeout( later, 1000 ); // Meaning of life: 42\n```\n\nВ этой программе есть две части: то, что будет запущено *сейчас*, и то, что будет запущено *позже*. Должно быть довольно очевидно, что это за два фрагмента, но давайте будем очень явными:\n\nСейчас:\n```js\nfunction now() {\n\treturn 21;\n}\n\nfunction later() { .. }\n\nvar answer = now();\n\nsetTimeout( later, 1000 );\n```\n\nПозже:\n```js\nanswer = answer * 2;\nconsole.log( \"Meaning of life:\", answer );\n```\n\nБлок *now* запускается сразу же, как только вы запускаете свою программу. Но `setTimeout(..)` также устанавливает событие (тайм-аут), которое произойдет *позже*, поэтому содержимое функции `later()` будет выполнено позже (через 1000 миллисекунд).\n\nКаждый раз, когда вы заключаете часть кода в `функцию` и указываете, что она должна выполняться в ответ на какое-то событие (таймер, щелчок мышью, ответ Ajax и т.д.), вы создаете более позднюю* часть своего кода, и, таким образом, вводя асинхронность в вашу программу.\n\n### Асинхронная консоль\n\nНе существует спецификации или набора требований относительно того, как работают методы `console.*` — они официально не являются частью JavaScript, а вместо этого добавляются в JS *средой всплытия* (см. заголовок *Типы и грамматика* эту серию книг).\n\nТаким образом, разные браузеры и среды JS делают то, что им заблагорассудится, что иногда может привести к путанице.\n\nВ частности, есть некоторые браузеры и некоторые условия, при которых `console.log(..)` на самом деле не сразу выводит то, что ему дано. Основная причина, по которой это может произойти, заключается в том, что ввод-вывод является очень медленной и блокирующей частью многих программ (не только JS). Таким образом, браузер может лучше (с точки зрения страницы/интерфейса) обрабатывать «консольный» ввод-вывод асинхронно в фоновом режиме, и вы, возможно, даже не подозреваете об этом.\n\nНе очень распространенный, но возможный сценарий, в котором это может быть *наблюдаемо* (не из самого кода, а извне):\n\n```js\nvar a = {\n\tindex: 1\n};\n\n// позже\nconsole.log( a ); // ??\n\n// ещё позже\na.index++;\n```\n\nОбычно мы ожидаем, что снимок объекта `a` будет сделан точно в момент выполнения оператора `console.log(..)`, выводя что-то вроде `{ index: 1 }`, так что в следующем операторе, когда `a.index++`, он изменяет что-то отличное от вывода `a` или сразу после него.\n\nВ большинстве случаев приведенный выше код, вероятно, будет создавать представление объекта в консоли инструментов разработчика, которое вы ожидаете. Но возможно, что этот же код может работать в ситуации, когда браузер считает необходимым отложить консольный ввод-вывод в фоновом режиме, и в этом случае *возможно*, что к тому времени, когда объект будет представлен в консоли браузера, ` a.index++` уже произошло, и он показывает `{ index: 2 }`.\n\nЭто движущаяся цель, при каких условиях именно «консольный» ввод-вывод будет отложен, или даже будет ли он наблюдаться. Просто имейте в виду эту возможную асинхронность в вводе/выводе на тот случай, если вы когда-нибудь столкнетесь с проблемами при отладке, когда объекты были изменены *после* оператора `console.log(..)`, и тем не менее вы видите неожиданные изменения.\n\n**Примечание.** Если вы столкнулись с этим редким случаем, лучше всего использовать точки останова в отладчике JS вместо того, чтобы полагаться на вывод консоли. Следующим лучшим вариантом было бы принудительно сделать «моментальный снимок» рассматриваемого объекта, сериализовав его в «строку», например, с «JSON.stringify(..)».\n\n## Цикл событий (Event Loop)\n\nДавайте сделаем (возможно, шокирующее) утверждение: несмотря на явное разрешение асинхронного кода JS (например, тайм-аут, который мы только что рассмотрели), до недавнего времени (ES6) сам JavaScript на самом деле никогда не имел прямого встроенного понятия асинхронности.\n\n**Что!?** Это кажется безумием, верно? На самом деле, это правда. Сам JS-движок никогда не делал ничего, кроме как выполнял один фрагмент вашей программы в любой момент, когда его об этом попросят.\n\n\"Попросят\" Кто? Это важная часть!\n\nДвижок JS не работает изолированно. Он работает внутри *среды хостинга*, которая для большинства разработчиков является типичным веб-браузером. За последние несколько лет (но не исключительно) JS расширился за пределы браузера в другие среды, такие как серверы, с помощью таких вещей, как Node.js. Фактически, в наши дни JavaScript внедряется во все виды устройств, от роботов до лампочек.\n\nНо один общий «поток» (это не очень тонкая асинхронная шутка, чего бы это ни стоило) всех этих сред заключается в том, что в них есть механизм, который обрабатывает выполнение нескольких фрагментов вашей программы *с течением времени*, в каждый момент времени. момент вызова JS-движка, называемый «циклом событий».\n\nДругими словами, движок JS не имеет врожденного чувства *времени*, а вместо этого является средой выполнения по требованию для любого произвольного фрагмента JS. Это окружающая среда, которая всегда *планирует* «события» (выполнения кода JS).\n\nТак, например, когда ваша программа JS делает запрос Ajax для получения некоторых данных с сервера, вы настраиваете код «ответа» в функции (обычно называемой «обратным вызовом»), и механизм JS сообщает среде хостинга, «Эй, я собираюсь приостановить выполнение на данный момент, но когда вы закончите с этим сетевым запросом, и у вас есть какие-то данные, *вызовите* эту функцию *назад*».\n\nЗатем браузер настраивается на прослушивание ответа из сети, и когда ему есть что вам дать, он планирует выполнение функции обратного вызова, вставляя ее в *цикл событий*.\n\nТак что же такое *цикл событий*?\n\nДавайте сначала концептуализируем это с помощью некоторого фальшивого кода:\n\n```js\n// `eventLoop` - это массив, который действует как очередь (первым пришел, первым ушел)\nvar eventLoop = [ ];\nvar event;\n\n// будет работать \"всегда\"\nwhile (true) {\n\t// выполняем \"такт\"\n\tif (eventLoop.length > 0) {\n\t\t// получаем следующее событие из очереди\n\t\tevent = eventLoop.shift();\n\n\t\t// теперь выполняем следующее событие\n\t\ttry {\n\t\t\tevent();\n\t\t}\n\t\tcatch (err) {\n\t\t\treportError(err);\n\t\t}\n\t}\n}\n```\n\nЭто, конечно, сильно упрощенный псевдокод для иллюстрации концепций. Но этого должно быть достаточно, чтобы помочь лучше понять.\n\nКак видите, существует непрерывно работающий цикл, представленный циклом while, и каждая итерация этого цикла называется «тактом». Для каждого такта, если событие ожидает в очереди, оно снимается и выполняется. Эти события являются обратными вызовами ваших функций.\n\nВажно отметить, что `setTimeout(..)` не помещает ваш обратный вызов в очередь цикла событий. Что он делает, так это устанавливает таймер; когда таймер истекает, среда помещает ваш обратный вызов в цикл событий, так что какой-то будущий такт подберет его и выполнит.\n\nЧто делать, если в этот момент в цикле событий уже 20 элементов? Ваш обратный вызов ждет. Он становится в очередь позади других — обычно нет пути для опережения очереди и пропуска вперед в очереди. Это объясняет, почему таймеры `setTimeout(..)` могут не срабатывать с идеальной временной точностью. Вам гарантируется (грубо говоря), что ваш обратный вызов не сработает *до* указанного вами временного интервала, но это может произойти в это время или позже, в зависимости от состояния очереди событий.\n\nТаким образом, другими словами, ваша программа обычно разбивается на множество небольших фрагментов, которые выполняются один за другим в очереди цикла событий. И технически, другие события, не связанные напрямую с вашей программой, также могут чередоваться в очереди.\n\n**Примечание.** Мы упоминали «до недавнего времени» в связи с тем, что ES6 изменил характер управления очередью цикла событий. В основном это формальная техническая особенность, но теперь ES6 определяет, как работает цикл обработки событий, что означает, что технически это находится в компетенции JS-движка, а не только *среды хостинга*. Одной из основных причин этого изменения является введение промисов ES6, которые мы обсудим в главе 3, потому что они требуют возможности иметь прямой, детальный контроль над операциями планирования в очереди цикла событий (см. обсуждение `setTimeout (..0)` в разделе \"Cooperation\").\n\n## Параллельная обработка\n\nОчень часто смешивают термины «асинхронный» и «параллельный», но на самом деле они совершенно разные. Помните, что асинхронность — это разрыв между *сейчас* и *позже*. Но параллель означает, что вещи могут происходить одновременно.\n\nНаиболее распространенными инструментами для параллельных вычислений являются процессы и потоки. Процессы и потоки выполняются независимо и могут выполняться одновременно: на разных процессорах или даже на разных компьютерах, но несколько потоков могут совместно использовать память одного процесса.\n\nЦикл событий, напротив, разбивает свою работу на задачи и выполняет их последовательно, запрещая параллельный доступ и изменения в разделяемой памяти. Параллелизм и «сериализм» могут сосуществовать в виде взаимодействующих циклов событий в отдельных потоках.\n\nЧередование параллельных потоков выполнения и чередование асинхронных событий происходит на очень разных уровнях детализации.\n\nНапример:\n\n```js\nfunction later() {\n\tanswer = answer * 2;\n\tconsole.log( \"Meaning of life:\", answer );\n}\n```\n\nВ то время как все содержимое `later()` будет рассматриваться как одна запись в очереди цикла событий, если подумать о потоке, в котором будет выполняться этот код, на самом деле существует, возможно, дюжина различных низкоуровневых операций. Например, `answer = answer * 2` требует сначала загрузить текущее значение `answer`, затем куда-то поместить `2`, затем выполнить умножение, затем взять результат и сохранить его обратно в `answer`.\n\nВ однопоточной среде на самом деле не имеет значения, что элементы в очереди потоков являются низкоуровневыми операциями, потому что ничто не может прервать поток. Но если у вас есть параллельная система, в которой два разных потока работают в одной и той же программе, вы, скорее всего, получите непредсказуемое поведение.\n\nРассмотрим:\n\n```js\nvar a = 20;\n\nfunction foo() {\n\ta = a + 1;\n}\n\nfunction bar() {\n\ta = a * 2;\n}\n\n// ajax(..) — это произвольная функция Ajax, заданная библиотекой\najax( \"http://some.url.1\", foo );\najax( \"http://some.url.2\", bar );\n```\n\nВ однопоточном поведении JavaScript, если `foo()` запускается до `bar()`, результатом будет то, что `a` имеет `42`, но если `bar()` запускается до `foo()`, результатом будет `a` будет `41`.\n\nЕсли бы события JS, совместно использующие одни и те же данные, выполнялись параллельно, проблемы были бы гораздо более тонкими. Рассмотрим эти два списка задач псевдокода как потоки, которые могли бы соответственно запускать код в `foo()` и `bar()`, и подумайте, что произойдет, если они будут выполняться точно в одно и то же время:\n\nПоток 1 («X» и «Y» — временные ячейки памяти):\n```\nfoo():\n   а. загрузить значение `a` в `X`\n   б. сохранить `1` в `Y`\n   в. добавить `X` и `Y`, сохранить результат в `X`\n   д. сохранить значение `X` в `a`\n```\n\nПоток 2 («X» и «Y» — временные ячейки памяти):\n```\nbar():\n   а. загрузить значение `a` в `X`\n   б. сохранить `2` в `Y`\n   в. умножить `X` и `Y`, сохранить результат в `X`\n   д. сохранить значение `X` в `a`\n```\n\nТеперь предположим, что два потока действительно выполняются параллельно. Вы, вероятно, можете определить проблему, верно? Они используют разделяемые ячейки памяти `X` и `Y` для своих временных шагов.\n\nКаков конечный результат в `a`, если шаги происходят так?\n\n```\n1a (загрузить значение `a` в `X` ==> `20`)\n2a (загрузить значение `a` в `X` ==> `20`)\n1b (сохранить `1` в `Y` ==> `1`)\n2b (сохранить `2` в `Y` ==> `2`)\n1c (добавьте `X` и `Y`, сохраните результат в `X` ==> `22`)\n1d (сохранить значение `X` в `a` ==> `22`)\n2c (умножить `X` и `Y`, сохранить результат в `X` ==> `44`)\n2d (сохранить значение `X` в `a` ==> `44`)\n```\n\nРезультатом в «а» будет «44». Но как быть с этим заказом?\n\n```\n1a (загрузить значение `a` в `X` ==> `20`)\n2a (загрузить значение `a` в `X` ==> `20`)\n2b (сохранить `2` в `Y` ==> `2`)\n1b (сохранить `1` в `Y` ==> `1`)\n2c (умножить `X` и `Y`, сохранить результат в `X` ==> `20`)\n1c (добавьте `X` и `Y`, сохраните результат в `X` ==> `21`)\n1d (сохранить значение `X` в `a` ==> `21`)\n2d (сохранить значение `X` в `a` ==> `21`)\n```\n\nРезультатом в «а» будет «21».\n\nТаким образом, многопоточное программирование очень сложно, потому что, если вы не предпримете специальных шагов для предотвращения такого прерывания/перемежения, вы можете получить очень неожиданное, недетерминированное поведение, которое часто приводит к головной боли.\n\nJavaScript никогда не делится данными между потоками, а это означает, что *этот* уровень недетерминизма не имеет значения. Но это не значит, что JS всегда детерминирован. Помните ранее, где относительное упорядочение `foo()` и `bar()` дает два разных результата (`41` или `42`)?\n\n**Примечание.** Возможно, это еще не очевидно, но не всякий недетерминизм плох. Иногда это неуместно, а иногда намеренно. Мы увидим больше примеров этого в этой и следующих нескольких главах.\n\n### Выполнить до завершения\n\nИз-за однопоточности JavaScript код внутри `foo()` (и `bar()`) является атомарным, что означает, что как только `foo()` запускается, весь его код завершится до того, как любой из кода в `bar()` начнет работать, и наоборот. Это называется поведением «запуск до завершения».\n\nНа самом деле семантика выполнения до завершения более очевидна, когда `foo()` и `bar()` содержат больше кода, например:\n\n```js\nvar a = 1;\nvar b = 2;\n\nfunction foo() {\n\ta++;\n\tb = b * a;\n\ta = b + 3;\n}\n\nfunction bar() {\n\tb--;\n\ta = 8 + b;\n\tb = a * 2;\n}\n\n// ajax(..) — это произвольная функция Ajax, заданная библиотекой\najax( \"http://some.url.1\", foo );\najax( \"http://some.url.2\", bar );\n```\n\nПоскольку `foo()` не может быть прервана `bar()`, а `bar()` не может быть прервана `foo()`, эта программа имеет только два возможных результата в зависимости от того, какой из них запустится первым: - если бы существовала многопоточность и отдельные операторы в `foo()` и `bar()` могли чередоваться, количество возможных результатов было бы значительно увеличено!\n\nБлок 1 является синхронным (происходит *сейчас*), но фрагменты 2 и 3 асинхронны (происходят *позже*), что означает, что их выполнение будет разделено временным промежутком.\n\nБлок 1:\n```js\nvar a = 1;\nvar b = 2;\n```\n\nБлок 2 (`foo()`):\n```js\na++;\nb = b * a;\na = b + 3;\n```\n\nБлок 3 (`bar()`):\n```js\nb--;\na = 8 + b;\nb = a * 2;\n```\n\nБлоки 2 и 3 могут выполняться в любом порядке, поэтому для этой программы есть два возможных результата, как показано здесь:\n\nВывод 1:\n```js\nvar a = 1;\nvar b = 2;\n\n// foo()\na++;\nb = b * a;\na = b + 3;\n\n// bar()\nb--;\na = 8 + b;\nb = a * 2;\n\na; // 11\nb; // 22\n```\n\nВывод 2:\n```js\nvar a = 1;\nvar b = 2;\n\n// bar()\nb--;\na = 8 + b;\nb = a * 2;\n\n// foo()\na++;\nb = b * a;\na = b + 3;\n\na; // 183\nb; // 180\n```\n\nДва результата одного и того же кода означают, что у нас все еще есть недетерминизм! Но это на уровне упорядочения функций (событий), а не на уровне упорядочения операторов (или, фактически, на уровне упорядочения операций выражений), как в случае с потоками. Другими словами, это *более детерминировано*, чем потоки.\n\nПрименительно к поведению JavaScript этот недетерминизм упорядочения функций является общим термином «состояние гонки», поскольку `foo()` и `bar()` соревнуются друг с другом, чтобы увидеть, какой из них запустится первым. В частности, это «состояние гонки», потому что вы не можете надежно предсказать, как окажутся «a» и «b».\n\n**Примечание:** Если бы в JS была функция, которая каким-то образом не имела бы поведения выполнения до завершения, у нас могло бы быть гораздо больше возможных результатов, верно? Оказывается, ES6 представляет именно такую вещь (см. главу 4 «Генераторы»), но не волнуйтесь прямо сейчас, мы еще вернемся к этому!\n\n## Конкурентность\n\nДавайте представим себе сайт, на котором отображается список обновлений статуса (например, лента новостей в социальной сети), который постепенно загружается по мере того, как пользователь прокручивает список вниз. Чтобы такая функция работала правильно, (по крайней мере) два отдельных «процесса» должны выполняться *одновременно* (т.е. в течение одного и того же промежутка времени, но не обязательно в один и тот же момент).\n\n**Примечание.** Мы используем здесь слово «процесс» в кавычках, потому что это не настоящие процессы уровня операционной системы с точки зрения информатики. Это виртуальные процессы или задачи, которые представляют собой логически связанные последовательные серии операций. Мы просто предпочтем «процесс», а не «задачу», потому что с точки зрения терминологии это будет соответствовать определениям изучаемых нами понятий.\n\nПервый «процесс» будет реагировать на события «onscroll» (запросы Ajax для нового контента), поскольку они срабатывают, когда пользователь прокручивает страницу дальше вниз. Второй «процесс» будет получать ответы Ajax (для отображения содержимого на странице).\n\nОчевидно, что если пользователь прокручивает страницу достаточно быстро, вы можете увидеть два или более события onscroll, запускаемых в течение времени, необходимого для получения и обработки первого ответа, и, таким образом, у вас будут события onscroll и события ответа Ajax, которые будут **конкурировать** друг с другом.\n\nКонкурентность — это когда два или более «процессов» выполняются одновременно в течение одного и того же периода, независимо от того, происходят ли их отдельные составляющие операции *параллельно* (в один и тот же момент на разных процессорах или ядрах) или нет. Тогда вы можете думать о конкурентности как о параллелизме на уровне «процесса» (или на уровне задачи), в отличие от параллелизма на уровне операций (потоки, исполняемые на отдельных процессорах).\n\n**Примечание.** Конкурентность также вводит необязательное понятие этих «процессов», взаимодействующих друг с другом. Мы вернемся к этому позже.\n\nДля данного окна времени (несколько секунд пользовательской прокрутки) давайте визуализируем каждый независимый «процесс» как серию событий/операций:\n\n\"Процесс\" 1 (`onscroll` events):\n```\nonscroll, request 1\nonscroll, request 2\nonscroll, request 3\nonscroll, request 4\nonscroll, request 5\nonscroll, request 6\nonscroll, request 7\n```\n\n\"Процесс\" 2 (Ajax response events):\n```\nresponse 1\nresponse 2\nresponse 3\nresponse 4\nresponse 5\nresponse 6\nresponse 7\n```\n\nВполне возможно, что событие `onscroll` и событие ответа Ajax могут быть готовы к обработке в один и тот же *момент*. Например, давайте визуализируем эти события на временной шкале:\n\n```\nonscroll, request 1\nonscroll, request 2          response 1\nonscroll, request 3          response 2\nresponse 3\nonscroll, request 4\nonscroll, request 5\nonscroll, request 6          response 4\nonscroll, request 7\nresponse 6\nresponse 5\nresponse 7\n```\n\nНо, возвращаясь к нашему представлению о цикле событий из предыдущей главы, JS сможет обрабатывать только одно событие за раз, поэтому либо `onscroll, request 2` будет происходить первым, либо `response 1` должно произойти первым, но они не могут произойти буквально в один и тот же момент. Так же, как дети в школьной столовой, независимо от того, какую толпу они образуют за дверью, им придется выстроиться в одну очередь, чтобы получить свой обед!\n\nДавайте визуализируем чередование всех этих событий в очереди цикла событий.\n\nОчередь цикла событий:\n```\nonscroll, request 1   <--- Процесс 1 начинается\nonscroll, request 2\nresponse 1            <--- Процесс 2 начинается\nonscroll, request 3\nresponse 2\nresponse 3\nonscroll, request 4\nonscroll, request 5\nonscroll, request 6\nresponse 4\nonscroll, request 7   <--- Процесс 1 заканчивается\nresponse 6\nresponse 5\nresponse 7            <--- Процесс 2 заканчивается\n```\n\n«Процесс 1» и «Процесс 2» выполняются одновременно (параллельно на уровне задач), но их отдельные события выполняются последовательно в очереди цикла событий.\n\nКстати, обратите внимание, как «ответ 6» и «ответ 5» вернулись не в том порядке, в котором ожидалось?\n\nОднопоточный цикл событий — это одно из проявлений конкурентности (конечно, есть и другие, к которым мы вернемся позже).\n\n### Не взаимодействующий\n\nПоскольку два или более «процессов» одновременно чередуют свои шаги/события одновременно внутри одной программы, им не обязательно взаимодействовать друг с другом, если задачи не связаны между собой. **Если они не взаимодействуют, недетерминизм вполне приемлем.**\n\nНапример:\n\n```js\nvar res = {};\n\nfunction foo(results) {\n\tres.foo = results;\n}\n\nfunction bar(results) {\n\tres.bar = results;\n}\n\najax( \"http://some.url.1\", foo );\najax( \"http://some.url.2\", bar );\n```\n\n`foo()` и `bar()` - это два конкурирующих \"процесса\", и нельзя однозначно определить в каком порядке они будут вызваны. Однако мы построили программу таким образом, что порядок их вызова не имеет значения, так как они работают независимо и, следовательно, не нуждаются во взаимодействии.\n\nЭто не ошибка «состояния гонки», так как код всегда будет работать правильно, независимо от порядка.\n\n### Взаимодействие\n\nЧаще всего, конкурирующие «процессы» будут по необходимости взаимодействовать косвенно через область видимости и/или DOM. Когда такое взаимодействие произойдет, вам необходимо координировать эти взаимодействия, чтобы предотвратить «состояние гонки», как описано ранее.\n\nВот простой пример двух конкурирующих «процессов», которые взаимодействуют из-за подразумеваемого порядка, который только *иногда нарушается*:\n\n```js\nvar res = [];\n\nfunction response(data) {\n\tres.push( data );\n}\n\najax( \"http://some.url.1\", response );\najax( \"http://some.url.2\", response );\n```\n\nКонкурирующие «процессы» — это два вызова `response()`, которые будут выполняться для обработки ответов Ajax. Они могут происходить в любом порядке.\n\nПредположим, ожидаемое поведение состоит в том, что `res[0]` имеет результаты вызова `\"http://some.url.1\"`, а `res[1]` имеет результаты `\"http:/ /some.url.2\"` вызов. Иногда это будет иметь место, но иногда они будут перевернуты, в зависимости от того, какой вызов завершится первым. Существует довольно большая вероятность того, что этот недетерминизм является ошибкой «состояния гонки».\n\n**Примечание.** Будьте крайне осторожны с предположениями, которые вы можете делать в подобных ситуациях. Например, разработчик нередко замечает, что «http://some.url.2» «всегда» отвечает намного медленнее, чем «http://some.url.1», возможно, из-за в силу того, какие задачи они выполняют (например, одна выполняет задачу базы данных, а другая просто извлекает статический файл), поэтому наблюдаемый порядок всегда выглядит так, как ожидалось. Даже если оба запроса отправляются на один и тот же сервер, и *он* намеренно отвечает в определенном порядке, нет *реальной* гарантии того, в каком порядке ответы будут возвращены в браузер.\n\nТаким образом, для устранения такого состояния гонки вы можете координировать порядок взаимодействий:\n\n```js\nvar res = [];\n\nfunction response(data) {\n\tif (data.url == \"http://some.url.1\") {\n\t\tres[0] = data;\n\t}\n\telse if (data.url == \"http://some.url.2\") {\n\t\tres[1] = data;\n\t}\n}\n\najax( \"http://some.url.1\", response );\najax( \"http://some.url.2\", response );\n```\n\nНезависимо от того, какой ответ Ajax возвращается первым, мы проверяем `data.url` (предполагая, что он возвращен с сервера, конечно!), чтобы выяснить, какую позицию данные ответа должны занимать в массиве `res`. `res[0]` всегда будет содержать результаты `\"http://some.url.1\"`, а `res[1]` всегда будет содержать результаты `\"http://some.url.2\"`. Путем простой координации мы устранили недетерминизм «состояния гонки».\n\nТе же рассуждения из этого сценария применимы, если несколько конкурирующих вызовов функций взаимодействуют друг с другом через общую модель DOM, например, один обновляет содержимое `<div>`, а другой обновляет стиль или атрибуты `<div>` (например, чтобы сделать элемент DOM видимым после того, как у него есть содержимое). Вы, вероятно, не захотите показывать элемент DOM до того, как у него будет содержимое, поэтому координация должна обеспечивать правильное взаимодействие с упорядочением.\n\nНекоторые сценарии конкуренции *всегда ломаются* (а не просто *иногда*) без скоординированного взаимодействия. \n\nРассмотрим:\n\n```js\nvar a, b;\n\nfunction foo(x) {\n\ta = x * 2;\n\tbaz();\n}\n\nfunction bar(y) {\n\tb = y * 2;\n\tbaz();\n}\n\nfunction baz() {\n\tconsole.log(a + b);\n}\n\najax( \"http://some.url.1\", foo );\najax( \"http://some.url.2\", bar );\n```\n\nВ этом примере, независимо от того, срабатывает ли сначала `foo()` или `bar()`, `baz()` всегда будет запускаться слишком рано (либо `a`, либо `b` все еще будут `undefined`), но второй вызов `baz()` будет работать, так как будут доступны и `a`, и `b`.\n\nСуществуют разные способы справиться с таким состоянием. Вот один простой способ:\n\n```js\nvar a, b;\n\nfunction foo(x) {\n\ta = x * 2;\n\tif (a && b) {\n\t\tbaz();\n\t}\n}\n\nfunction bar(y) {\n\tb = y * 2;\n\tif (a && b) {\n\t\tbaz();\n\t}\n}\n\nfunction baz() {\n\tconsole.log( a + b );\n}\n\najax( \"http://some.url.1\", foo );\najax( \"http://some.url.2\", bar );\n```\n\nУсловие `if (a && b)` вокруг вызова `baz()` традиционно называется \"воротами\", потому что мы не уверены, какой порядок `a` и `b` прибудет, но мы ждем оба из них, чтобы попасть туда, прежде чем мы приступим к открытию ворот (вызов `baz()`).\n\nЕще одно условие конкурентного взаимодействия, с которым вы можете столкнуться, иногда называют «гонкой», но правильнее называть его «защелкой». Характеризуется поведением «побеждает только первый». Здесь приемлем недетерминизм, поскольку вы явно говорите, что в «гонке» до финиша может быть только один победитель.\n\nРассмотрим этот сломанный код:\n\n```js\nvar a;\n\nfunction foo(x) {\n\ta = x * 2;\n\tbaz();\n}\n\nfunction bar(x) {\n\ta = x / 2;\n\tbaz();\n}\n\nfunction baz() {\n\tconsole.log( a );\n}\n\najax( \"http://some.url.1\", foo );\najax( \"http://some.url.2\", bar );\n```\n\nКакой бы из них (`foo()` или `bar()`) не срабатывал последним, он не только перезапишет назначенное значение `a` из другого, но также будет дублировать вызов `baz()` (вероятно, нежелательный).\n\nИтак, мы можем согласовать взаимодействие с простой защелкой, чтобы пропускать только первую:\n\n```js\nvar a;\n\nfunction foo(x) {\n\tif (a == undefined) {\n\t\ta = x * 2;\n\t\tbaz();\n\t}\n}\n\nfunction bar(x) {\n\tif (a == undefined) {\n\t\ta = x / 2;\n\t\tbaz();\n\t}\n}\n\nfunction baz() {\n\tconsole.log( a );\n}\n\najax( \"http://some.url.1\", foo );\najax( \"http://some.url.2\", bar );\n```\n\nУсловие `if (a == undefined)` допускает только первый из `foo()` или `bar()`, а второй (и любые последующие) вызовы будут просто проигнорированы. Нет ничего хорошего в том, чтобы занять второе место!\n\n**Примечание.** Во всех этих сценариях мы использовали глобальные переменные для упрощения иллюстрации, но в наших рассуждениях здесь нет ничего, что требовало бы этого. Пока рассматриваемые функции могут получить доступ к переменным (через область видимости), они будут работать так, как задумано. Использование переменных с лексической областью видимости (см. название этой серии книг *Scope & Closures*) и фактически глобальных переменных, как в этих примерах, является очевидным недостатком этих форм координации в условиях конкуренции. В следующих нескольких главах мы увидим другие способы координации, которые в этом отношении намного чище.\n\n### Кооперация\n\nДругое выражение координации параллелизма называется «кооперативной конкуренцией» (cooperative concurrency). Здесь основное внимание уделяется не столько взаимодействию через совместное использование значений в областях видимости (хотя это, очевидно, все еще разрешено!). Цель состоит в том, чтобы взять длительный «процесс» и разбить его на шаги или пакеты, чтобы другие конкурирующие «процессы» имели возможность вставить свои операции в очереди цикла событий.\n\nНапример, рассмотрим обработчик ответа Ajax, которому необходимо просмотреть длинный список результатов для преобразования значений. Мы будем использовать `Array#map(..)`, чтобы сделать код короче:\n\n```js\nvar res = [];\n\n// `response(..)` получает массив результатов от Ajax-вызова\nfunction response(data) {\n    // добавляем в существующий массив `res`\n\tres = res.concat(\n        // создаем новый преобразованный массив со всеми удвоенными значениями `data`\n\t\tdata.map( function(val){\n\t\t\treturn val * 2;\n\t\t} )\n\t);\n}\n\najax( \"http://some.url.1\", response );\najax( \"http://some.url.2\", response );\n```\n\nЕсли `\"http://some.url.1\"` сначала получит свои результаты, весь список будет сразу отображен в `res`. Если это несколько тысяч или меньше записей, это, как правило, не имеет большого значения. Но если это, скажем, 10 миллионов записей, это может занять некоторое время (несколько секунд на мощном ноутбуке, намного дольше на мобильном устройстве и т.д.).\n\nВо время выполнения такого «процесса» на странице не может происходить ничего другого, включая другие вызовы `response(..)`, обновления пользовательского интерфейса, даже пользовательские события, такие как прокрутка, ввод текста, нажатие кнопки и тому подобное. Это довольно болезненно.\n\nТаким образом, чтобы сделать более кооперативно конкурентную систему, более дружелюбную и не перегружающую очередь цикла событий, вы можете обрабатывать эти результаты асинхронными пакетами, после того как каждый из них «уступает» обратно в цикл событий, чтобы позволить произойти другим ожидающим событиям.\n\nВот очень простой подход:\n\n```js\nvar res = [];\n\n// `response(..)` получает массив результатов от Ajax-вызова\nfunction response(data) {\n    // давайте просто сделаем 1000 за раз\n\tvar chunk = data.splice( 0, 1000 );\n\n    // добавляем в существующий массив `res`\n\tres = res.concat(\n\t\t// создаем новый преобразованный массив со всеми удвоенными значениями `chunk`\n\t\tchunk.map( function(val){\n\t\t\treturn val * 2;\n\t\t} )\n\t);\n\n    // осталось что-нибудь обработать?\n\tif (data.length > 0) {\n\t\t// асинхронно планируем следующую партию\n\t\tsetTimeout( function(){\n\t\t\tresponse( data );\n\t\t}, 0 );\n\t}\n}\n\najax( \"http://some.url.1\", response );\najax( \"http://some.url.2\", response );\n```\n\nМы обрабатываем набор данных блоками максимального размера по 1000 элементов. Поступая таким образом, мы обеспечиваем кратковременный «процесс», даже если это означает гораздо больше последующих «процессов», поскольку чередование с очередью цикла событий даст нам гораздо более отзывчивый (производительный) сайт/приложение.\n\nКонечно, мы не координируем порядок взаимодействия любого из этих «процессов», поэтому порядок результатов в `res` не будет предсказуемым. Если бы требовался порядок, вам нужно было бы использовать методы взаимодействия, подобные тем, которые мы обсуждали ранее, или те, которые мы рассмотрим в следующих главах этой книги.\n\nМы используем `setTimeout(..0)` (хак) для асинхронного планирования, что в основном просто означает «вставить эту функцию в конец текущей очереди цикла событий».\n\n**Примечание:** `setTimeout(..0)` технически не вставляет элемент непосредственно в очередь цикла событий. Таймер вставит событие при следующей возможности. Например, два последовательных вызова `setTimeout(..0)` не будут строго гарантированы для обработки в порядке вызова, поэтому *возможно* увидеть различные условия, такие как дрейф таймера, когда порядок таких событий не предсказуем. В Node.js аналогичный подход — `process.nextTick(..)`. Несмотря на то, насколько удобным (и, как правило, более производительным) это было бы, не существует единого прямого способа (по крайней мере, пока) во всех средах для обеспечения асинхронного упорядочения событий. Мы рассмотрим эту тему более подробно в следующем разделе.\n\n## Задачи\n\nНачиная с ES6, появилась новая концепция над очередью цикла событий, которая называется \"Очередь задач\". Скорее всего, вам придется столкнуться с асинхронным поведением промисов (см. главу 3).\n\nК сожалению, на данный момент это механизм без открытого API, поэтому демонстрация его немного сложнее. Так что нам нужно просто описать его концептуально, чтобы, когда мы будем обсуждать асинхронное поведение с промисами в главе 3, вы поняли, как эти действия планируются и обрабатываются.\n\nИтак, лучший способ думать об этом, который я нашел, состоит в том, что «Очередь задач» — это очередь, свисающая с конца каждого такта в очереди цикла событий. Некоторые подразумеваемые асинхронные действия, которые могут произойти во время такта цикла событий, не приведут к добавлению нового события в очередь цикла событий, а вместо этого добавят элемент (также известный как задача) в конец очереди задач текущего такта.\n\nЭто все равно, что сказать: «О, вот еще одна вещь, которую мне нужно сделать *позже*, но убедитесь, что это произойдет прямо сейчас, прежде чем что-либо еще может произойти».\n\nИли, если использовать метафору: очередь цикла событий подобна аттракциону в парке развлечений, где, как только вы закончите кататься, вам нужно вернуться в конец очереди, чтобы прокатиться снова. Но очередь задач похожа на то, как если бы вы закончили поездку, но затем встали в очередь и сразу же вернулись.\n\nЗадача также может привести к добавлению дополнительных задач в конец одной и той же очереди. Таким образом, теоретически возможно, что «цикл» задач (задача, которая продолжает добавлять другую задачу и т.д.) может вращаться бесконечно, лишая программу возможности перейти к следующему такту цикла событий. Концептуально это было бы почти так же, как простое выражение длительного или бесконечного цикла (например, `while (true) ..`) в вашем коде.\n\nЗадачи похожи на дух хака `setTimeout(..0)`, но реализованы таким образом, чтобы иметь гораздо более четко определенный и гарантированный порядок: **позже, но как можно скорее**.\n\nДавайте представим API для планирования задач (напрямую, без хаков) и назовем его `schedule(..)`.\n\n```js\nconsole.log( \"A\" );\n\nsetTimeout( function(){\n\tconsole.log( \"B\" );\n}, 0 );\n\n// теоретический \"API задачи\"\nschedule( function(){\n\tconsole.log( \"C\" );\n\n\tschedule( function(){\n\t\tconsole.log( \"D\" );\n\t} );\n} );\n```\n\nВы можете ожидать, что это напечатает `A B C D`, но вместо этого будет напечатано `A C D B`, потому что задачи происходят в конце текущего такта цикла событий, и таймер срабатывает, чтобы запланировать *следующий* такт цикла событий (если доступно!).\n\nВ главе 3 мы увидим, что асинхронное поведение промисов основано на задачах, поэтому важно четко понимать, как это связано с поведением цикла обработки событий.\n\n## Порядок операторов\n\nПорядок, в котором мы выражаем операторы в нашем коде, не обязательно совпадает с порядком, в котором JS-движок будет их выполнять. Это может показаться довольно странным утверждением, поэтому мы кратко рассмотрим его.\n\nНо прежде чем мы это сделаем, мы должны кое-что предельно ясно уяснить: правила/грамматика языка (см. название этой серии книг *Типы и грамматика*) диктуют очень предсказуемое и надежное поведение для упорядочения операторов с точки зрения программы. Итак, то, что мы собираемся обсудить, — это **не то, что вы когда-либо сможете наблюдать** в своей JS-программе.\n\n**Предупреждение:** Если вы когда-либо сможете *наблюдать* переупорядочивание операторов компилятора, как мы собираемся проиллюстрировать, это будет явным нарушением спецификации, и это, несомненно, будет связано с ошибкой в ​​движке JS. в вопросе - тот, который должен быть немедленно сообщен и исправлен! Но гораздо чаще вы *подозреваете* что-то сумасшедшее происходит в движке JS, когда на самом деле это просто ошибка (вероятно, \"состояние гонки\"!) в вашем собственном коде - так что сначала смотрите туда, и снова и снова . Отладчик JS, использующий точки останова и последовательно выполняющий код, станет вашим самым мощным инструментом для обнаружения таких ошибок в *вашем коде*.\n\nРассмотреть возможность:\n\n```js\nvar a, b;\n\na = 10;\nb = 30;\n\na = a + 1;\nb = b + 1;\n\nconsole.log( a + b ); // 42\n```\n\nЭтот код не имеет выраженной асинхронности (за исключением редкого «консольного» асинхронного ввода-вывода, который обсуждался ранее!), поэтому наиболее вероятным предположением будет то, что он будет обрабатывать строку за строкой сверху вниз.\n\nНо *возможно*, что движок JS после компиляции этого кода (да, JS скомпилирован — см. название *Scope & Closures* этой серии книг!) может найти возможности для более быстрого запуска вашего кода, перестраивая (безопасно) порядок этих выражений. По сути, пока вы не можете наблюдать за изменением порядка, все в порядке.\n\nНапример, движок может решить, что на самом деле быстрее выполнить такой код:\n\n```js\nvar a, b;\n\na = 10;\na++;\n\nb = 30;\nb++;\n\nconsole.log( a + b ); // 42\n```\n\nИли это:\n\n```js\nvar a, b;\n\na = 11;\nb = 31;\n\nconsole.log( a + b ); // 42\n```\n\nИли даже:\n\n```js\n// так как `a` и `b` больше не используются, мы можем\n// встроить их и даже не нуждаться в них!\nconsole.log( 42 ); // 42\n```\n\nВо всех этих случаях движок JS выполняет безопасную оптимизацию во время компиляции, так как конечный *наблюдаемый* результат будет одним и тем же.\n\nНо вот сценарий, в котором эти конкретные оптимизации были бы небезопасными и, следовательно, не могли бы быть разрешены (конечно, нельзя сказать, что они вообще не оптимизированы):\n\n```js\nvar a, b;\n\na = 10;\nb = 30;\n\n// нам нужны `a` и `b` в их предварительно увеличенном состоянии!\nconsole.log( a * b ); // 300\n\na = a + 1;\nb = b + 1;\n\nconsole.log( a + b ); // 42\n```\n\nДругие примеры, когда переупорядочивание компилятора может создать наблюдаемые побочные эффекты (и, следовательно, должно быть запрещены), включают в себя такие вещи, как любой вызов функции с побочными эффектами (даже и особенно функции-получатели) или прокси-объекты ES6 (см. заголовок *ES6 & Beyond* статьи эту серию книг).\n\nРассмотрим возможность:\n\n```js\nfunction foo() {\n\tconsole.log( b );\n\treturn 1;\n}\n\nvar a, b, c;\n\n// Синтаксис литерала геттера ES5.1\nc = {\n\tget bar() {\n\t\tconsole.log( a );\n\t\treturn 1;\n\t}\n};\n\na = 10;\nb = 30;\n\na += foo();\t\t\t\t// 11\nb += c.bar;\t\t\t\t// 31\n\nconsole.log( a + b );\t// 42\n```\n\nЕсли бы не операторы `console.log(..)` в этом фрагменте (просто используемые как удобная форма наблюдаемого побочного эффекта для иллюстрации), движок JS, вероятно, мог бы свободно, если бы захотел (кто знает, захочет ли!?), изменить порядок кода:\n\n```js\n// ...\n\na = 10 + foo();\nb = 30 + c.bar;\n\n// ...\n```\n\nВ то время как семантика JS, к счастью, защищает нас от *наблюдаемых* кошмаров, которым может угрожать переупорядочивание операторов компилятора, по-прежнему важно понимать, насколько незначительна связь между способом создания исходного кода (сверху вниз) и как он работает после компиляции.\n\nПереупорядочивание операторов компилятора — это почти микрометафора конкурентности и взаимодействия. В целом такая осведомленность может помочь вам лучше понять проблемы потока асинхронного кода JS.\n\n## Обзор\n\nПрограмма JavaScript (практически) всегда разбивается на две или более частей, где первая часть выполняется *сейчас*, а следующая часть выполняется *позже*, в ответ на событие. Несмотря на то, что программа выполняется по частям, все они имеют одинаковый доступ к области действия и состоянию программы, поэтому каждое изменение состояния выполняется поверх предыдущего состояния.\n\nВсякий раз, когда есть события для запуска, *цикл событий* выполняется до тех пор, пока очередь не станет пустой. Каждая итерация цикла событий — это \"такт\". Взаимодействие с пользователем, ввод-вывод и таймеры помещают события в очередь событий.\n\nВ любой момент времени из очереди может быть обработано только одно событие. Во время выполнения события оно может прямо или косвенно вызывать одно или несколько последующих событий.\n\nКонкурентность — это когда две или более цепочек событий чередуются во времени, так что с точки зрения высокого уровня кажется, что они выполняются *одновременно* (даже если в любой момент обрабатывается только одно событие).\n\nЧасто бывает необходимо выполнить какую-то форму координации взаимодействия между этими конкурирующими «процессами» (в отличие от процессов операционной системы), например, чтобы обеспечить упорядоченность или предотвратить «состояние гонки». Эти «процессы» также могут *взаимодействовать*, разбивая себя на более мелкие фрагменты и допуская чередование других «процессов».\n"
  },
  {
    "path": "async & performance/ch2.md",
    "content": "# Вы не знаете JS: Асинхронность и Выполнение\n# Глава 2: Колбеки\n\nВ главе 1 мы рассмотрели терминологию и концепции асинхронного программирования в JavaScript. Наше внимание сосредоточено на понимании однопоточной (по одному за раз) очереди цикла событий, которая управляет всеми «событиями» (вызовами асинхронных функций). Мы также исследовали различные способы, которыми шаблоны конкурентности объясняют отношения (если они есть!) между *одновременно* запущенными цепочками событий или «процессами» (задачами, вызовами функций и т.д.).\n\nВо всех наших примерах в главе 1 функция использовалась как отдельная, неделимая единица операций, при этом внутри функции операторы выполняются в предсказуемом порядке (выше уровня компилятора!), но на уровне упорядочения функций события (также известные как асинхронные вызовы функций) могут происходить в различных порядках.\n\nВо всех этих случаях функция действует как «обратный вызов», потому что она служит целью цикла обработки событий для «обратного вызова» программы всякий раз, когда обрабатывается этот элемент в очереди.\n\nКак вы, несомненно, заметили, обратные вызовы являются наиболее распространенным способом выражения и управления асинхронностью в JS-программах. Действительно, обратный вызов является наиболее фундаментальным асинхронным шаблоном в языке.\n\nБесчисленные JS-программы, даже очень изощренные и сложные, были написаны только на основе коллбеков (конечно, с использованием шаблонов параллелизма, которые мы рассмотрели в главе 1). Функция обратного вызова — это асинхронная рабочая лошадка для JavaScript, и она достойно выполняет свою работу.\n\nЗа исключением... обратные вызовы не лишены недостатков. Многие разработчики воодушевлены *обещанием* (каламбур!) улучшенных асинхронных шаблонов. Но невозможно эффективно использовать любую абстракцию, если вы не понимаете, что она абстрагирует и почему.\n\nВ этой главе мы подробно рассмотрим пару из них, чтобы понять, почему необходимы и желательны более сложные асинхронные шаблоны (рассматриваемые в последующих главах этой книги).\n\n## Продолжения\n\nДавайте вернемся к примеру с асинхронным обратным вызовом, с которого мы начали в главе 1, но позвольте мне немного изменить его, чтобы проиллюстрировать один момент:\n\n```js\n// A\najax( \"..\", function(..){\n\t// C\n} );\n// B\n```\n\n`// A` и `// B` представляют первую половину программы (она же *сейчас*), а `//C` отмечает вторую половину программы (она же *позже*). Первая половина выполняется сразу, а потом идет \"пауза\" неопределенной длины. В какой-то момент в будущем, если вызов Ajax завершится, программа продолжит с того места, где остановилась, и *продолжит* со второй половиной.\n\nДругими словами, функция обратного вызова оборачивает или инкапсулирует *продолжение* программы.\n\nСделаем код еще проще:\n\n```js\n// A\nsetTimeout( function(){\n\t// C\n}, 1000 );\n// B\n```\n\nОстановитесь на мгновение и спросите себя, как бы вы описали (кому-то другому, менее осведомленному о том, как работает JS) поведение этой программы. Давай, попробуй вслух. Это хорошее упражнение, которое поможет моим следующим пунктам стать более осмысленными.\n\nБольшинство читателей сейчас, вероятно, подумали или сказали что-то вроде: «Выполните A, затем установите тайм-аут на 1000 миллисекунд, затем, как только это сработает, выполните C». Насколько точно было ваше толкование?\n\nВозможно, вы поймали себя на том, что сами отредактировали: «Выполните А, установите тайм-аут на 1000 миллисекунд, затем выполните B, затем, когда истечет тайм-аут, сделайте С». Это более точно, чем первая версия. Вы можете заметить разницу?\n\nНесмотря на то, что вторая версия является более точной, обе версии не могут объяснить этот код таким образом, чтобы наш мозг соответствовал коду, а код — движку JS. Это отключение одновременно тонкое и монументальное, и оно лежит в основе понимания недостатков обратных вызовов как асинхронного выражения и управления.\n\nКак только мы вводим одно продолжение (или несколько десятков, как многие программы!) в виде функции обратного вызова, мы позволяем образоваться расхождению между тем, как работает наш мозг, и тем, как будет работать код. Каждый раз, когда эти двое расходятся (и это далеко не единственное место, где это происходит, как я уверен, вы знаете!), мы сталкиваемся с неизбежным фактом, что наш код становится труднее понимать, анализировать, отлаживать и поддерживать.\n\n## Последовательный мозг\n\nЯ почти уверен, что большинство из вас, читатели, слышали, как кто-то сказал (даже сами заявили): «Я многозадачный». Эффекты от попытки действовать в качестве многозадачного человека варьируются от забавных (например, глупая детская игра «погладь голову-потирай-живот») до обыденных (жуй жвачку на ходу) и откровенно опасных (текстовые сообщения за рулем).\n\nНо многозадачны ли мы? Можем ли мы действительно совершать два сознательных, преднамеренных действия одновременно и думать/рассуждать о них обоих в один и тот же момент? Есть ли у нашего самого высокого уровня функциональности мозга параллельная многопоточность?\n\nОтвет может вас удивить: **вероятно, нет.**\n\nНа самом деле наш мозг просто не так устроен. Мы гораздо больше занимаемся одиночными делами, чем многие из нас (особенно личности типа А!) хотели бы признать. На самом деле мы можем думать только об одном в любой данный момент.\n\nЯ не говорю обо всех наших непроизвольных, подсознательных, автоматических функциях мозга, таких как сердцебиение, дыхание и моргание век. Все это жизненно важные задачи для нашей устойчивой жизни, но мы намеренно не выделяем для них никаких умственных способностей. К счастью, пока мы одержимы проверкой ленты социальных сетей в 15-й раз за три минуты, наш мозг продолжает выполнять все эти важные задачи в фоновом режиме (потоки!)\n\nВместо этого мы говорим о любой задаче, которая находится в центре нашего внимания в данный момент. Для меня это написание текста в этой книге прямо сейчас. Выполняю ли я какую-либо другую функцию мозга более высокого уровня точно в этот же момент? Нет, не совсем. Я отвлекаюсь быстро и легко — несколько десятков раз в этих последних парах абзацев!\n\nКогда мы *имитируем* многозадачность, например, пытаемся что-то напечатать во время разговора с другом или членом семьи по телефону, на самом деле мы, скорее всего, действуем как быстрые переключатели контекста. Другими словами, мы переключаемся между двумя или более задачами в быстрой последовательности, *одновременно* продвигаясь по каждой задаче маленькими, быстрыми порциями. Мы делаем это так быстро, что внешнему миру кажется, будто мы делаем эти вещи *параллельно*.\n\nЗвучит ли это для вас подозрительно как конкурентность с асинхронными событиями (подобная той, что происходит в JS)?! Если нет, вернитесь и прочитайте главу 1 еще раз!\n\nНа самом деле, один из способов упростить (т. е. злоупотребить) невероятно сложный мир неврологии и превратить его в то, что я могу отдалённо надеяться обсудить здесь, заключается в том, что наш мозг работает примерно так же, как очередь цикла событий.\n\nЕсли вы думаете о каждой отдельной букве (или слове), которую я печатаю, как об одном асинхронном событии, только в этом предложении есть несколько десятков возможностей для моего мозга быть прерванным каким-то другим событием, например, от моих органов чувств или даже просто от моего сознания. случайные мысли.\n\nМеня не прерывают и не вовлекают в другой «процесс» при каждой возможности (к счастью, иначе эта книга никогда не была бы написана!). Но достаточно часто случается так, что я чувствую, что мой собственный мозг почти постоянно переключается на разные контексты (также известные как «процессы»). И это очень похоже на то, как, вероятно, чувствовал бы себя движок JS.\n\n### Делать VS Планировать\n\nИтак, наш мозг можно представить как работающий в однопоточной очереди цикла событий подобно движку JS. Это звучит как хорошая аналогия.\n\nНо нам нужно быть более тонкими анализируя это. Существует большая, заметная разница между тем, как мы планируем различные задачи, и тем, как наш мозг на самом деле выполняет эти задачи.\n\nОпять же, вернемся к написанию этого текста как моей метафоры. Мой грубый ментальный план состоит в том, чтобы продолжать писать и писать, последовательно проходя через набор пунктов, которые я упорядочил в своих мыслях. Я не планирую никаких перерывов или нелинейной активности в этом письме. Но тем не менее мой мозг все время переключается.\n\nНесмотря на то, что на операционном уровне наш мозг работает асинхронно, кажется, что мы планируем задачи последовательно и синхронно. «Мне нужно сходить в магазин, потом купить молока, а потом сдать вещи из химчистки».\n\nВы заметите, что это мышление более высокого уровня (планирование) не кажется очень асинхронным в своей формулировке. На самом деле, мы редко намеренно думаем исключительно с точки зрения событий. Вместо этого мы планируем все тщательно, последовательно (А затем Б затем С), и мы допускаем до некоторой степени своего рода временную блокировку, которая заставляет Б ждать А, а С ждать Б.\n\nКогда разработчик пишет код, он планирует ряд действий, которые должны произойти. Если он хороший разработчик, то он **тщательно планирует** это. «Мне нужно установить `z` в значение `x`, а затем `x` в значение `y`» и так далее.\n\nКогда мы пишем синхронный код, оператор за оператором, он работает во многом подобно нашему списку дел:\n\n```js\n// поменять местами `x` и `y` (через временную переменную `z`)\nz = x;\nx = y;\ny = z;\n```\n\nЭти три оператора присваивания являются синхронными, поэтому `x = y` ожидает завершения `z = x`, а `y = z`, в свою очередь, ожидает завершения `x = y`. Другими словами, эти три утверждения связаны во времени с выполнением в определенном порядке, одно за другим. К счастью, нам не нужно беспокоиться о каких-либо подробностях, связанных с асинхронными событиями. Если бы мы это сделали, код быстро стал бы намного сложнее!\nИтак, если синхронное планирование мозга хорошо соотносится с операторами синхронного кода, насколько хорошо наш мозг справляется с планированием асинхронного кода?\n\nОказывается, то, как мы выражаем асинхронность (с обратными вызовами) в нашем коде, совсем не соответствует этому синхронному поведению планирования мозга.\n\nМожете ли вы на самом деле представить, что у вас есть ход мыслей, который планирует ваши дела таким образом?\n\n> \"Мне нужно в магазин, но по дороге я уверен, что мне позвонят, так что \"Привет, мама\", и пока она начнет говорить, я поищу адрес магазина по GPS, но это займет секунду, поэтому я убавлю радио, чтобы лучше слышать маму, а потом пойму, что забыл надеть куртку, а на улице холодно, но неважно, продолжаю ехать и разговариваю с мамой, а затем звон ремня безопасности напоминает мне о том, что нужно пристегнуться, так что «Да, мама, я пристегнут ремнем безопасности, я всегда пристегиваюсь!». Ах, наконец-то GPS получил направление, теперь...»\n\nКак бы нелепо это ни звучало как формулировка того, как мы планируем свой день и думаем о том, что делать и в каком порядке, тем не менее именно так работает наш мозг на функциональном уровне. Помните, что это не многозадачность, это просто быстрое переключение контекста.\n\nПричина, по которой нам, как разработчикам, трудно писать асинхронный код с событиями, особенно когда все, что у нас есть, это обратный вызов, заключается в том, что поток мыслей/планирование потока сознания неестественен для большинства из нас.\n\nМы думаем пошагово, но инструменты (обратные вызовы), доступные нам в коде, не выражаются пошагово, как только мы переходим от синхронного к асинхронному.\n\nИ **вот** почему так сложно точно написать и обосновать асинхронный код JS с обратными вызовами: потому что это не то, как работает наш мозг.\n\n**Примечание:** Единственное, что может быть хуже, чем не знать, почему некоторые коды не работают, — это не знать, почему они вообще работают! Это классический менталитет «карточного домика»: «он работает, но не знаю почему, поэтому никто его не трогает!» Возможно, вы слышали «Ад — это другие люди» (Сартр), а программистский мем — «Ад — это код других людей». Я искренне верю: «Ад - это не понимать собственный код». И обратные вызовы являются одним из основных виновников.\n\n### Вложенные/связанные обратные вызовы\n\nРассмотрим:\n\n```js\nlisten( \"click\", function handler(evt){\n\tsetTimeout( function request(){\n\t\tajax( \"http://some.url.1\", function response(text){\n\t\t\tif (text == \"hello\") {\n\t\t\t\thandler();\n\t\t\t}\n\t\t\telse if (text == \"world\") {\n\t\t\t\trequest();\n\t\t\t}\n\t\t} );\n\t}, 500) ;\n} );\n```\n\nЕсть хорошие шансы, что такой код узнаваем для вас. У нас есть цепочка из трех вложенных друг в друга функций, каждая из которых представляет собой шаг в асинхронной последовательности (задача, «процесс»).\n\nЭтот тип кода часто называют «ад обратных вызовов», а иногда также называют «пирамидой гибели» (из-за его треугольной формы, обращенной вбок из-за вложенного углубления).\n\nНо «ад обратных вызовов» на самом деле не имеет почти ничего общего с вложенностью/отступом. Это гораздо более глубокая проблема. Мы увидим, как и почему, в оставшейся части этой главы.\n\nВо-первых, мы ждем события «click», затем мы ждем срабатывания таймера, затем мы ждем возврата ответа Ajax, после чего он может повторить все это снова.\n\nНа первый взгляд может показаться, что этот код естественным образом связывает свою асинхронность с последовательным мозговым планированием.\n\nСначала (*сейчас*):\n\n```js\nlisten( \"..\", function handler(..){\n\t// ..\n} );\n```\n\n*позже*:\n\n```js\nsetTimeout( function request(..){\n\t// ..\n}, 500) ;\n```\n\n*еще позже*:\n\n```js\najax( \"..\", function response(..){\n\t// ..\n} );\n```\n\nНаконец (наиболее *позже*):\n\n```js\nif ( .. ) {\n\t// ..\n}\nelse ..\n```\n\nНо есть несколько проблем с линейными рассуждениями об этом коде.\n\nВо-первых, случайность примера состоит в том, что наши шаги находятся на следующих строках (1, 2, 3 и 4...). В настоящих асинхронных JS-программах часто присутствует гораздо больше шума, загромождающего вещи, которым мы должны ловко маневрировать в своем мозгу, когда переходим от одной функции к другой. Понимание асинхронного потока в таком перегруженном обратными вызовами коде не является невозможным, но это определенно не естественно и не легко, даже при большой практике.\n\nНо также есть и более глубокая ошибка, которая не очевидна только в этом примере кода. Позвольте мне придумать другой сценарий (псевдокодовый), чтобы проиллюстрировать его:\n\n```js\ndoA( function(){\n\tdoB();\n\n\tdoC( function(){\n\t\tdoD();\n\t} )\n\n\tdoE();\n} );\n\ndoF();\n```\n\nХотя опытные из вас правильно определят здесь истинный порядок операций, я держу пари, что на первый взгляд он более чем немного сбивает с толку, и для его достижения требуется несколько согласованных умственных циклов. Операции будут происходить в таком порядке:\n\n* `doA()`\n* `doF()`\n* `doB()`\n* `doC()`\n* `doE()`\n* `doD()`\n\nВы поняли это правильно, когда впервые взглянули на код?\n\nХорошо, некоторые из вас думают, что я несправедливо назвал свои функции, чтобы намеренно ввести вас в заблуждение. Клянусь, я просто называл в порядке появления сверху вниз. Но позвольте мне попробовать еще раз:\n\n```js\ndoA( function(){\n\tdoC();\n\n\tdoD( function(){\n\t\tdoF();\n\t} )\n\n\tdoE();\n} );\n\ndoB();\n```\n\nТеперь я назвал их в алфавитном порядке в порядке фактического выполнения. Но я все еще держу пари, даже имея опыт в этом сценарии, отслеживание в порядке «A -> B -> C -> D -> E -> F» не является естественным для многих из вас, читатели. Конечно, ваши глаза очень много прыгают вверх и вниз по фрагменту кода, верно?\n\nНо даже если все это кажется вам естественным, есть еще одна опасность, которая может нанести ущерб. Можете ли вы определить, что это такое?\n\nЧто, если `doA(..)` или `doD(..)` на самом деле не являются асинхронными, как мы, очевидно, предполагали? Ой, теперь порядок другой. Если они оба синхронизированы (и, возможно, только иногда, в зависимости от условий программы в то время), порядок теперь будет «A -> C -> D -> F -> E -> B».\n\nТот звук, который вы только что услышали на заднем плане, — это вздохи тысяч JS-разработчиков, которые только что столкнулись лицом к лицу.\n\nЯвляется ли вложение проблемой? Из-за этого так сложно отследить асинхронный поток? Это часть этого, конечно.\n\nНо позвольте мне переписать предыдущий пример вложенного события/тайм-аута/Ajax без использования вложенности:\n\n```js\nlisten( \"click\", handler );\n\nfunction handler() {\n\tsetTimeout( request, 500 );\n}\n\nfunction request(){\n\tajax( \"http://some.url.1\", response );\n}\n\nfunction response(text){\n\tif (text == \"hello\") {\n\t\thandler();\n\t}\n\telse if (text == \"world\") {\n\t\trequest();\n\t}\n}\n```\n\nЭта формулировка кода едва ли так узнаваема, как проблемы вложенности/отступов в его предыдущей форме, и все же она ничуть не менее подвержена «аду обратных вызовов». Почему?\n\nПо мере того, как мы переходим к линейному (последовательному) анализу этого кода, мы должны переходить от одной функции к следующей, к следующей и перемещаться по кодовой базе, чтобы «увидеть» поток последовательности. И помните, это упрощенный код в наилучшем случае. Все мы знаем, что базы кода реальных асинхронных JS-программ зачастую фантастически более запутаны, что на несколько порядков усложняет такие рассуждения.\n\nЕще одна вещь, на которую следует обратить внимание: чтобы связать шаги 2, 3 и 4 вместе, чтобы они выполнялись последовательно, единственный доступный способ, которые обратные вызовы дают нам, — это жестко закодировать шаг 2 в шаг 1, шаг 3 в шаг 2, шаг 4 в шаг 3, и так далее. Жесткое кодирование не обязательно плохо, если это действительно фиксированное условие, что шаг 2 всегда должен вести к шагу 3.\n\nНо жесткое кодирование определенно делает код немного более хрупким, поскольку оно не учитывает никаких ошибок, которые могут вызвать отклонение в последовательности шагов. Например, если шаг 2 терпит неудачу, шаг 3 никогда не достигается, и шаг 2 не повторяется, или выполняется переход к альтернативному потоку обработки ошибок и т.д.\n\nВсе эти проблемы вы *можете* вручную жестко прописать в каждом шаге, но этот код часто очень повторяющийся и не может быть повторно использован на других шагах или в других асинхронных потоках в вашей программе.\n\nНесмотря на то, что наш мозг может планировать ряд задач в последовательном порядке (это, затем это, затем это), событийный характер работы нашего мозга делает восстановление/повторение/разветвление управления потоком практически без усилий. Если вы бегаете по делам и понимаете, что оставили дома список покупок, день не заканчивается, потому что вы не спланировали это заранее. Ваш мозг легко обходит эту заминку: вы идете домой, берете список и сразу же направляетесь обратно в магазин.\n\nНо хрупкая природа жестко закодированных вручную обратных вызовов (даже с жестко запрограммированной обработкой ошибок) часто гораздо менее изящна. Как только вы в конечном итоге укажете (также известное как предварительное планирование) все различные возможности/пути, код станет настолько запутанным, что его трудно будет поддерживать или обновлять.\n\n**Вот это** и есть \"ад обратных вызовов\"! Вложение/отступы - это, по сути, второстепенное шоу, отвлекающий маневр.\n\nИ как будто всего этого недостаточно, мы даже не коснулись того, что происходит, когда две или более цепочек этих продолжений обратного вызова происходят *одновременно*, или когда третий шаг разветвляется на «параллельные» обратные вызовы с воротами или защелками, или... ОМГ, у меня мозг болит, а у тебя?!\n\nУлавливаете ли вы здесь, что наше последовательное, блокирующее поведение планирования мозга просто не очень хорошо отображается в асинхронном коде, ориентированном на обратных вызовах? Это первый существенный недостаток обратных вызовов, о котором нужно сказать: они выражают асинхронность в коде таким образом, что нашему мозгу приходится бороться только за то, чтобы синхронизироваться с ним (каламбур!).\n\n## Проблемы с доверием\n\nНесоответствие между последовательным мозговым планированием и асинхронным кодом JS, управляемым обратными вызовами, — это только часть проблемы с обратными вызовами. Есть кое-что гораздо более глубокое, о чем следует беспокоиться.\n\nДавайте еще раз вернемся к понятию callback-функции как продолжения (она же вторая половина) нашей программы:\n\n```js\n// A\najax( \"..\", function(..){\n\t// C\n} );\n// B\n```\n\n`// A` и `// B` происходят *сейчас* под непосредственным контролем основной JS-программы. Но `// C` откладывается, чтобы произойти *позже*, и находится под контролем другой стороны – в данном случае, функции `ajax(..)`. В общем смысле такая передача управления обычно не вызывает много проблем для программ.\n\nНо пусть вас не вводит в заблуждение его редкость, что этот переключатель управления не имеет большого значения. На самом деле, это одна из самых серьезных (и в то же время наиболее тонких) проблем проектирования, основанного на обратных вызовах. Он вращается вокруг идеи, что иногда `ajax(..)` (т.е. \"сторона\", которой вы передаете продолжение обратного вызова) не является функцией, которую вы написали или которой вы непосредственно управляете. Часто это утилита, предоставляемая третьей стороной.\n\nМы называем это «инверсией управления (IoC)», когда вы берете часть своей программы и передаете контроль над ее выполнением другому третьему лицу. Между вашим кодом и сторонней утилитой существует негласный «контракт» — набор вещей, которые вы ожидаете поддерживать.\n\n### Сказка о пяти обратных вызовах\n\nМожет быть не совсем очевидно, почему это так важно. Позвольте мне построить преувеличенный сценарий, чтобы проиллюстрировать опасности доверия в игре.\n\nПредставьте, что вы разработчик, которому поручено создать систему оплаты электронной торговли для сайта, продающего дорогие телевизоры. У вас уже есть все различные страницы системы оформления заказов, созданные просто отлично. На последней странице, когда пользователь нажимает «подтвердить», чтобы купить телевизор, вам нужно вызвать стороннюю функцию (предоставленную, скажем, какой-то аналитической компанией), чтобы можно было отследить продажу.\n\nВы заметили, что они предоставили то, что выглядит как утилита асинхронного отслеживания, вероятно, ради лучших практик производительности, что означает, что вам нужно передать функцию обратного вызова. В этом продолжении, которое вы передаете, у вас будет окончательный код, который снимает средства с кредитной карты клиента и отображает страницу благодарности.\n\nЭтот код может выглядеть так:\n\n```js\nanalytics.trackPurchase( purchaseData, function(){\n\tchargeCreditCard();\n\tdisplayThankyouPage();\n} );\n```\n\nДостаточно легко, верно? Вы пишете код, тестируете его, все работает, и вы запускаете его в производство. Все счастливы!\n\nПрошло полгода и никаких проблем. Вы почти забыли, что даже написали этот код. Однажды утром вы сидите в кофейне перед работой, небрежно наслаждаясь латте, когда вам звонит в панике начальник и настаивает, чтобы вы бросили кофе и сразу же бросились на работу.\n\nКогда вы приедете, вы узнаете, что с кредитной карты высокопоставленного клиента пять раз списали средства за один и тот же телевизор, и он, по понятным причинам, расстроен. Служба поддержки клиентов уже принесла извинения и обработала возврат средств. Но ваш босс требует знать, как это могло произойти. «Разве у нас нет тестов на подобные вещи!?»\n\nВы даже не помните код, который вы написали. Но вы копаетесь и начинаете пытаться выяснить, что могло пойти не так.\n\nПокопавшись в некоторых логах, вы приходите к выводу, что единственное объяснение в том, что утилита аналитики каким-то образом по какой-то причине вызвала ваш обратный вызов пять раз вместо одного. Ничто в их документации не упоминает ничего об этом.\n\nРазочарованный, вы связываетесь со службой поддержки, которая, конечно, так же удивлена, как и вы. Они соглашаются сообщить об этом своим разработчикам и обещают вернуться к вам. На следующий день вы получаете длинное электронное письмо с объяснением того, что они нашли, и сразу же пересылаете его своему боссу.\n\nСудя по всему, разработчики аналитической компании работали над некоторым экспериментальным кодом, который при определенных условиях будет повторять предоставленный обратный вызов один раз в секунду в течение пяти секунд, прежде чем произойдет сбой с тайм-аутом. Они никогда не собирались продвигать это в производство, но каким-то образом они это сделали, и они полностью смущены и извиняются. Они подробно рассказывают о том, как они определили сбой и что они сделают, чтобы это никогда не повторилось.\n\nЧто дальше?\n\nВы обсуждаете это со своим боссом, но он не чувствует себя особенно довольным положением вещей. Он настаивает, и вы неохотно соглашаетесь, что вы не можете больше доверять *им* (это то, что вас задело), и что вам нужно снова придумать, как защитить код проверки от такой уязвимости.\n\nПосле некоторой доработки вы реализуете простой специальный код, подобный приведенному ниже, который, похоже, устраивает команду:\n\n```js\nvar tracked = false;\n\nanalytics.trackPurchase( purchaseData, function(){\n\tif (!tracked) {\n\t\ttracked = true;\n\t\tchargeCreditCard();\n\t\tdisplayThankyouPage();\n\t}\n} );\n```\n\n**Примечание:** Это должно показаться вам знакомым из главы 1, потому что мы, по сути, создаем защелку для обработки, если произойдет несколько одновременных вызовов нашего обратного вызова.\n\nНо затем один из ваших QA-инженеров спрашивает: «Что произойдет, если они никогда не вызовут обратный вызов?» Упс. Никто из вас не думал об этом.\n\nВы начинаете искать кроличью нору и думаете обо всех возможных вещах, которые могут пойти не так, если они перезвонят вам. Вот примерный список возможных сбоев в работе аналитической утилиты:\n\n* Вызывать обратный вызов слишком рано (до того, как он будет отслежен)\n* Вызов обратного вызова слишком поздно (или никогда)\n* Вызовите обратный вызов слишком мало или слишком много раз (например, проблема, с которой вы столкнулись!)\n* Не удалось передать любую необходимую среду/параметры вашему обратному вызову\n* Проглотить любые ошибки/исключения, которые могут произойти\n* ...\n\nЭто должно показаться тревожным списком, потому что так оно и есть. Вы, вероятно, постепенно начинаете понимать, что вам придется изобретать очень много специальной логики **в каждом обратном вызове**, которая передается утилите, которой вы не уверены, что можете доверять.\n\nТеперь вы немного более полно осознаете, насколько адским является «ад обратных вызовов».\n\n### Не только чужой код\n\nНекоторые из вас могут сейчас скептически отнестись к тому, настолько ли это важно, как я это преподношу. Возможно, вы мало взаимодействуете с действительно сторонними утилитами. Возможно, вы используете версионные API или самостоятельно размещаете такие библиотеки, чтобы их поведение нельзя было изменить без вас.\n\nИтак, подумайте над этим: можете ли вы вообще *действительно* доверять утилитам, которыми вы теоретически управляете (в своей собственной кодовой базе)?\n\nПодумайте об этом так: большинство из нас согласны с тем, что, по крайней мере, в некоторой степени мы должны создавать свои собственные внутренние функции с некоторыми защитными проверками входных параметров, чтобы уменьшить/предотвратить непредвиденные проблемы.\n\nЧрезмерное доверие входным данным:\n```js\nfunction addNumbers(x,y) {\n    // + перегружен приведением,\n    // чтобы также быть конкатенацией строк,\n    // поэтому эта операция не является строго безопасной\n    // в зависимости от того, что передано.\n\treturn x + y;\n}\n\naddNumbers( 21, 21 );\t// 42\naddNumbers( 21, \"21\" );\t// \"2121\"\n```\n\nЗащита от ненадежного ввода:\n```js\nfunction addNumbers(x,y) {\n    // обеспечиваем числовой ввод\n\tif (typeof x != \"number\" || typeof y != \"number\") {\n\t\tthrow Error( \"Bad parameters\" );\n\t}\n\n\t// если мы доберемся сюда, + безопасно выполнит числовое сложение\n\treturn x + y;\n}\n\naddNumbers( 21, 21 );\t// 42\naddNumbers( 21, \"21\" );\t// Error: \"Bad parameters\"\n```\n\nИли, возможно, все еще безопасно, но дружелюбнее:\n```js\nfunction addNumbers(x,y) {\n    // обеспечиваем числовой ввод\n\tx = Number( x );\n\ty = Number( y );\n\n\t// + будет безопасно делать числовое сложение\n\treturn x + y;\n}\n\naddNumbers( 21, 21 );\t// 42\naddNumbers( 21, \"21\" );\t// 42\n```\n\nКак бы вы это ни делали, такого рода проверки/нормализации довольно распространены на входных данных функций, даже с кодом, которому мы теоретически полностью доверяем. Грубо говоря, это похоже на программный эквивалент геополитического принципа «Доверяй, но проверяй».\n\nИтак, не разумно ли, что мы должны делать то же самое с композицией обратных вызовов асинхронных функций, не только с действительно внешним кодом, но даже с кодом, который, как мы знаем, обычно «находится под нашим собственным контролем»? **Конечно, должны.**\n\nНо обратные вызовы на самом деле не предлагают ничего, чтобы помочь нам. Мы должны создавать весь этот механизм сами, и часто это приводит к большому количеству шаблонов/накладных расходов, которые мы повторяем для каждого отдельного асинхронного обратного вызова.\n\nСамая неприятная проблема с обратными вызовами — это *инверсия управления*, ведущая к полному разрыву всех этих линий доверия.\n\nЕсли у вас есть код, который использует обратные вызовы, особенно, но не исключительно, со сторонними утилитами, и вы еще не применяете какую-то логику смягчения для всех этих *инверсии управления* проблем с доверием, ваш код *имеет* ошибки в нем прямо сейчас, хотя они, возможно, еще не укусили вас. Скрытые ошибки остаются ошибками.\n\nДействительно ад.\n\n## Попытка сохранить обратные вызовы\n\nСуществует несколько вариантов дизайна обратного вызова, которые пытались решить некоторые (не все!) проблемы доверия, которые мы только что рассмотрели. Это доблестная, но обреченная попытка спасти шаблон обратного вызова от разрушения самого себя.\n\nНапример, что касается более изящной обработки ошибок, некоторые проекты API предусматривают раздельные обратные вызовы (один для уведомления об успехе, другой для уведомления об ошибке:\n\n```js\nfunction success(data) {\n\tconsole.log( data );\n}\n\nfunction failure(err) {\n\tconsole.error( err );\n}\n\najax( \"http://some.url.1\", success, failure );\n```\n\nВ API такого дизайна часто обработчик ошибок `failure()` является необязательным, и если он не указан, предполагается, что вы хотите проглотить ошибки. Фу.\n\n**Примечание.** Этот дизайн с разделенным обратным вызовом используется API ES6 Promise. Мы рассмотрим обещания ES6 более подробно в следующей главе.\n\nДругой распространенный шаблон обратного вызова называется «стиль с ошибкой в первую очередь» (иногда его также называют «стилем узла», поскольку это также соглашение, используемое почти во всех API-интерфейсах Node.js), где первый аргумент одного обратного вызова зарезервирован для объекта ошибки (если есть). В случае успеха этот аргумент будет пустым/ложным (и любые последующие аргументы будут данными об успехе), но если сигнализируется результат ошибки, первый аргумент устанавливается/истинный (и обычно больше ничего не передается):\n\n```js\nfunction response(err,data) {\n\t// ошибка?\n\tif (err) {\n\t\tconsole.error( err );\n\t}\n\t// в иных случаях успех\n\telse {\n\t\tconsole.log( data );\n\t}\n}\n\najax( \"http://some.url.1\", response );\n```\n\nВ обоих этих случаях следует соблюдать несколько вещей.\n\nВо-первых, это на самом деле не решило большинство проблем с доверием, как может показаться. В обратном вызове нет ничего, что предотвращало бы или отфильтровывало нежелательные повторные вызовы. Более того, сейчас дела обстоят еще хуже, потому что вы можете получить как сигналы об успехе, так и ошибки, или ни одного из них, и вам все равно придется кодировать любое из этих условий.\n\nКроме того, не упустите тот факт, что, хотя это стандартный шаблон, который вы можете использовать, он определенно более многословен и похож на шаблон без особого повторного использования, поэтому вы устанете вводить все это для каждого обратного вызова в вашем приложении.\n\nА как насчет проблемы доверия никогда не быть вызванным? Если это вызывает беспокойство (и, вероятно, должно быть!), вам, вероятно, потребуется установить тайм-аут, который отменяет событие. Вы можете сделать утилиту (показано только доказательство концепции), которая поможет вам в этом:\n\n```js\nfunction timeoutify(fn,delay) {\n\tvar intv = setTimeout( function(){\n\t\t\tintv = null;\n\t\t\tfn( new Error( \"Timeout!\" ) );\n\t\t}, delay )\n\t;\n\n\treturn function() {\n\t\t// timeout уже произошёл?\n\t\tif (intv) {\n\t\t\tclearTimeout( intv );\n\t\t\tfn.apply( this, [ null ].concat( [].slice.call( arguments ) ) );\n\t\t}\n\t};\n}\n```\n\nВот как можно его использовать:\n\n```js\n// использование обратного вызова в стиле «сначала ошибка»\nfunction foo(err,data) {\n\tif (err) {\n\t\tconsole.error( err );\n\t}\n\telse {\n\t\tconsole.log( data );\n\t}\n}\n\najax( \"http://some.url.1\", timeoutify( foo, 500 ) );\n```\n\nЕще одна проблема доверия называется «слишком рано». С точки зрения конкретного приложения это может фактически включать вызов до завершения какой-либо критической задачи. Но в более общем плане проблема проявляется в утилитах, которые могут либо вызывать предоставленный вами обратный вызов *сейчас* (синхронно) или *позже* (асинхронно).\n\nЭтот недетерминизм в отношении синхронного или асинхронного поведения почти всегда приводит к тому, что очень трудно отследить ошибки. В некоторых кругах вымышленный вызывающий безумие монстр по имени Залго используется для описания синхронно-асинхронных кошмаров. «Не выпускайте Залго!» — это распространенный крик, и он приводит к очень здравому совету: всегда вызывайте обратные вызовы асинхронно, даже если это «сразу же» на следующем этапе цикла событий, чтобы все обратные вызовы предсказуемо были асинхронными.\n\n**Примечание.** Дополнительную информацию о Zalgo см. в статье Орена Голана «Не выпускайте Zalgo!» (https://github.com/oren/oren.github.io/blob/master/posts/zalgo.md) и «Разработка API-интерфейсов для асинхронности» Исаака З. Шлютера (http://blog.izs.me/post/59142742143/designing-apis-for-asynchrony).\n\nРассмотрим:\n\n```js\nfunction result(data) {\n\tconsole.log( a );\n}\n\nvar a = 0;\n\najax( \"..pre-cached-url..\", result );\na++;\n```\n\nБудет ли этот код печатать «0» (вызов обратного вызова синхронизации) или «1» (вызов асинхронного обратного вызова)? Зависит... от условий.\n\nВы видите, как быстро непредсказуемость Zalgo может угрожать любой JS-программе. Таким образом, глупо звучащее «никогда не выпускайте Zalgo» на самом деле является невероятно распространенным и надежным советом. Всегда быть асинхронным.\n\nЧто, если вы не знаете, всегда ли рассматриваемый API будет выполняться асинхронно? Вы можете изобрести утилиту, подобную этой `asyncify(..)`, для доказательства концепции:\n\n```js\nfunction asyncify(fn) {\n\tvar orig_fn = fn,\n\t\tintv = setTimeout( function(){\n\t\t\tintv = null;\n\t\t\tif (fn) fn();\n\t\t}, 0 )\n\t;\n\n\tfn = null;\n\n\treturn function() {\n\t\t// срабатывает слишком быстро, прежде чем сработает таймер\n        // `intv`, чтобы показать, что асинхронный ход прошел?\n\t\tif (intv) {\n\t\t\tfn = orig_fn.bind.apply(\n\t\t\t\torig_fn,\n                // добавляем `this` обёртки к `bind(..)`\n                // параметры вызова, а также каррирование любых\n                // передается в параметрах\n\t\t\t\t[this].concat( [].slice.call( arguments ) )\n\t\t\t);\n\t\t}\n        // уже асинхронно\n\t\telse {\n\t\t\t// вызвать исходную функцию\n\t\t\torig_fn.apply( this, arguments );\n\t\t}\n\t};\n}\n```\n\nМожно использовать `asyncify(..)` следующим образом:\n\n```js\nfunction result(data) {\n\tconsole.log( a );\n}\n\nvar a = 0;\n\najax( \"..pre-cached-url..\", asyncify( result ) );\na++;\n```\n\nНезависимо от того, находится ли запрос Ajax в кеше и разрешает попытку немедленного вызова обратного вызова, или его нужно получить по сети и, таким образом, выполнить позже асинхронно, этот код всегда будет выводить `1` вместо `0` -- `result(..)` не может не вызываться асинхронно, что означает, что `a++` имеет шанс запуститься раньше, чем `result(..)`.\n\nУра, еще одна проблема доверия решена! Но это неэффективно и еще больше раздувает шаблон, чтобы отягощать ваш проект.\n\nЭто просто история, снова и снова, с обратными вызовами. Они могут делать почти все, что вы хотите, но вы должны быть готовы много работать, чтобы получить это, и часто эти усилия намного больше, чем вы можете или должны потратить на такие рассуждения о коде.\n\nВозможно, вам понадобятся встроенные API или другие языковые механизмы для решения этих проблем. Наконец-то появился ES6 с отличными ответами, так что продолжайте читать!\n\n## Обзор\n\nОбратные вызовы — это фундаментальная единица асинхронности в JS. Но их недостаточно для меняющегося ландшафта асинхронного программирования по мере взросления JS.\n\nВо-первых, наш мозг планирует вещи последовательным, блокирующим, однопоточным семантическим способом, но обратные вызовы выражают асинхронный поток довольно нелинейным, непоследовательным образом, что значительно усложняет правильное рассмотрение такого кода. Плохие рассуждения о коде — это плохой код, который приводит к серьезным ошибкам.\n\nНам нужен способ выразить асинхронность в более синхронной, последовательной, блокирующей манере, как это делает наш мозг.\n\nВо-вторых, что более важно, обратные вызовы страдают от *инверсии управления*, поскольку они неявно передают управление другой стороне (часто сторонней утилите, не находящейся под вашим контролем!) для вызова *продолжения* вашей программы. Эта передача управления приводит нас к тревожному списку проблем с доверием, например, вызывается ли обратный вызов чаще, чем мы ожидаем.\n\nИзобретение специальной логики для решения этих проблем с доверием возможно, но это сложнее, чем должно быть, и в результате получается более громоздкий и трудный для сопровождения код, а также код, который, вероятно, недостаточно защищен от этих опасностей, пока вы явно не укусите его ошибки.\n\nНам нужно обобщенное решение **всех проблем с доверием**, которое можно будет повторно использовать для любого количества обратных вызовов, которое мы создадим, без дополнительных шаблонных накладных расходов.\n\nНам нужно что-то лучше, чем обратные вызовы. До сих пор они хорошо служили нам, но «будущее» JavaScript требует более сложных и эффективных асинхронных шаблонов. В последующих главах этой книги мы углубимся в эти зарождающиеся эволюции.\n"
  },
  {
    "path": "async & performance/ch3.md",
    "content": "# Вы не знаете JS: Асинхронность и производительность\n# Глава 3: Промисы\n\nВ главе 2 мы определили две главные категории недостатков в использовании колбеков для того, чтобы выразить асинхронность программы и управлять параллельной обработкой: отсутствие последовательного кода и надежности. Теперь, когда мы разобрали эти проблемы досконально, настало время обратить внимание на шаблоны, которые позволят их решить.\n\nПроблема, с которой мы хотим начать - *инверсия управления (IoC)*, это то доверие, которое так тяжело сохранять и так легко потерять.\n\nВспомните как мы обработали *продолжение (continuation)* нашей программы в колбек-функции и передали этот колбек в другую часть кода (потенциально даже во внешний код) и просто скрестили пальцы на удачу, что вызов этого колбэка произойдет корректно.\n\nМы сделали это поскольку мы хотели этим сказать, \"вот то, что должно выполниться *позже*, после того, как завершится текущий шаг программы.\"\n\nНо что если бы мы смогли разинверсировать эту *инверсию управления*? Что если вместо передачи продолжения программы в другой код мы могли бы ожидать от него дать нам возможность узнать когда его задача завершится и затем наш код мог бы решить, что делать дальше?\n\nЭта концепция называется **Промисы**.\n\nПромисы начинают быстро покорять мир JS, поскольку разработчики и создатели спецификаций в равной мере отчаянно ищут возможность избавиться от безумия ада колбеков в своим коде/дизайне. На самом деле, многие новые асинхронные API добавляются в платформу JS/DOM будучи построенным на промисах. Так что, возможно, это неплохая идея уйти с головой и изучить их, Вы так не думаете!?\n\n**Примечание:** Слово \"сразу\" будет часто использоваться в этой главе, в основном указывая на какое-либо действие по разрешению промиса. Однако, в фактически всех случаях, \"сразу\" в терминах поведения очереди заданий означает (см. главу 1) не строго синхронное значение *сейчас*.\n\n## Что такое промис?\n\nКогда разработчики решают изучить новую технологию или шаблон, обычно их первым шагом будет \"Покажите мне код!\". Это вполне естественно для нас просто броситься в омут с головой и изучать по ходу.\n\nОднако бывает так, что одних только API недостаточно, чтобы понять определённые абстракции. Промисы — это как раз тот инструмент, где по тому, как их используют, сразу видно: понимает ли человек, для чего они нужны и как работают, или просто изучил и использует API.\n\nТак что перед тем как я покажу код с промисами, я хочу объяснить целиком и полностью что такое промисы концептуально. Я надеюсь, что это быстрее направит вас на истинный путь по мере того как вы будете постигать теорию интеграции промисов в свой асинхронный поток.\n\nПомня об этом, давайте взглянем на две различные аналогии того что *есть* промисы.\n\n### Будущее значение\n\nПредставьте такой сценарий: Я подхожу к стойке в ресторане быстрого питания и делаю заказ на чизбургер. Я даю кассиру $1.47. Разместив и оплатив свой заказ, я сделал запрос возврата *значения* (чизбургера). Я открыл транзакцию.\n\nНо частенько, чизбургер не сразу мне доступен. Кассир даем мне что-то взамен моего чизбургера: чек с номером заказа в нем. Этот номер заказа - это IOU-*обещание* (промис) (Я должен вам (\"I owe you\")) которое гарантирует, что в итоге я должен получить свой чизбургер.\n\nТак что я храню мой чек и номер заказа. Я знаю, что оно представляет собой мой *будущий чизбургер*, поэтому мне не надо о этом больше волноваться кроме ощущения голода!\n\nПока я жду Я могу заниматься другими делами, например отправить текстовое сообщение другу, говорящее: \"Эй, как насчет присоединиться ко мне за обедом? Я собираюсь съесть чизбургер.\"\n\nЯ уже рассуждаю о своем *будущем чизбургере*, несмотря на то, что у меня еще его нет. Мой мозг способен так делать потому что он воспринимает номер заказа как заменитель чизбургера. Такой заменитель фактически делает значение *независимым от времени*. Это и есть **будущее значение**.\n\nВ итоге я слышу \"Заказ 113!\" и радостно иду обратно к стойке с чеком в руках. Я передаю чек кассиру и взамен беру свой чизбургер.\n\nДругими словами, как только мое *будущее значение* было готово, я обменял промис значения  на само значение.\n\nНо есть и еще один возможный исход. Они называют мой номер заказа, но когда я подхожу, чтобы забрать свой чизбургер кассир с сожалению сообщает мне: \"Мне жаль, но мы судя по всему остались без чизбургеров.\" Оставив в стороне разочарование покупателя в таком сценарии на секундочку, мы можем заметить важную характеристику *будущих значений*: они могут сигнализировать либо о завершении, либо об отказе.\n\nКаждый раз, когда я заказываю чизбургер, я знаю что либо я рано или поздно получу чизбургер, либо получу печальные новости о нехватке чизбургеров и я должен буду придумать что-то другое на обед.\n\n**Примечание:** В реальном коде процесс не такой простой, потому что метафорически номер заказа может никогда не быть назван, и в таком случае мы остаемся в неразрешим состоянии вечно. Мы еще вернемся к этому случаю позже.\n\n#### Значения Сейчас и Позже\n\nВсё это может прозвучать слишком абстрактно для применения в вашем коде. Так давайте внесем больше конкретики.\n\nОднако, перед тем, как мы представим как работают промисы подобным образом, мы собираемся покопаться в коде, который мы уже умеем понимать -- колбеки! -- чтобы понять как обрабатывать эти *будущие значения*.\n\nКогда вы пишете код, чтобы обработать каким-либо образом некое значение, например выполнив математические вычисления над `числом`, то осознанно или нет, вы предполагаете кое-что очень фундаментальное об этом значении, а именно, что это - уже конкретное значение *сейчас*:\n\n```js\nvar x, y = 2;\n\nconsole.log( x + y ); // NaN  <-- потому что в `x` еще не установлено значение\n```\n\nОперация `x + y` предполагает, что оба `x` и `y` уже заданы. В терминах, которые мы вскоре разъясним, мы полагаем что значения `x` и `y` уже *разрешены* (т.е. с уж определенными значениями).\n\nБудет абсурдом ожидать, что оператор `+` сам по себе каким-то магическим образом сможет определить и ждать до тех пор, пока оба `x` и `y` разрешатся (т.е. будут готовы), и только затем выполнит операцию. Это может привести к хаосу в программе, если одни выражения  закончатся *сейчас*, а другие закончатся *позже*, не так ли?\n\nКак вы сможете потенциально рассуждать о связях между двумя выражениями, если одно из них (или оба) могут быть еще не завершены? Если выражение 2 полагается на то, что выражение 1 будет завершено, то возможны два исхода: либо выражение 1 закончится прямо *сейчас* и всё благополучно продолжится, либо statement 1 еще не завершено, и в итоге выражение 2 приведет к ошибке.\n\nЕсли такие вещи звучат знакомо после главы 1, хорошо!\n\nДавайте вернемся к нашей математической операции `x + y`. Представьте, что был бы путь сказать, \"Сложи `x` и `y`, но если кто-то из них еще не подготовлен, просто подожди пока это не произойдет. Сложи их как можно скорее.\"\n\nВаш мозг возможно сразу переключился на колбеки. Хорошо, итак...\n\n```js\nfunction add(getX,getY,cb) {\n\tvar x, y;\n\tgetX( function(xVal){\n\t\tx = xVal;\n\t\t// оба готовы?\n\t\tif (y != undefined) {\n\t\t\tcb( x + y );\t// отправить сумму\n\t\t}\n\t} );\n\tgetY( function(yVal){\n\t\ty = yVal;\n\t\t// оба готовы?\n\t\tif (x != undefined) {\n\t\t\tcb( x + y );\t// отправить сумму\n\t\t}\n\t} );\n}\n\n// `fetchX()` and `fetchY()` синхронные или асинхронные\n// функции\nadd( fetchX, fetchY, function(sum){\n\tconsole.log( sum ); // это было легко, ага?\n} );\n```\n\nПодождите минутку, чтобы позволить красоте (или отсутствию таковой) этого кусочка кода уложиться в голове (терпеливо насвистываю).\n\nХотя это уродство и несомненное, тут есть кое-что очень важное на заметку об этом асинхронном шаблоне.\n\nВ этом кусочке кода, мы трактовали `x` и `y` как будущие значения и мы выразили операцию `add(..)` так, что она (снаружи) не заботится о том, доступен ли `x` или `y` прямо сейчас или нет. Другими словами, он нормализует *сейчас* и *потом* таким образом, что мы можем положиться на предсказуемый результат операции `add(..)`.\n\nПри использовании `add(..)`, которая временно консистентна, она ведет себя одинаково *сейчас* и *потом* - такой асинхронный код легче себе представлять.\n\nВыражаясь более просто: чтобы обработать согласованно оба *сейчас* и *потом*, мы оба их превращаем в *потом*: все операции становятся асинхронными.\n\nКонечно, этот грубый подход, основанный на колбеках, оставляет желать намного лучшего. Это всего-лишь первый крошечный шаг к пониманию преимуществ представления *будущих значений* без беспокойств о временном аспекте того, доступны они или нет.\n\n#### Промис как значение\n\nМы определенно углубимся в детали промисов позже в этой главе, поэтому не волнуйтесь если что-то тут покажется запутанным, а просто мельком взгляните на то, как мы выразим пример `x + y` через `Promise`ы:\n\n```js\nfunction add(xPromise,yPromise) {\n\t// `Promise.all([ .. ])` принимает массив промисов\n\t// и возвращает новый промис, который ожидает завершения всех переданных\n\treturn Promise.all( [xPromise, yPromise] )\n\n\t// когда промис разрешен, давайте возьмем\n\t// полученные значения `X` и `Y` и сложим их.\n\t.then( function(values){\n\t\t// `values` - массив сообщений от\n\t\t// ранее разрешенных промисов\n\t\treturn values[0] + values[1];\n\t} );\n}\n\n// `fetchX()` и `fetchY()` возвращают промисы для\n// своих соответствующих значений, которые могут быть готовы\n// *сейчас* или *позже*.\nadd( fetchX(), fetchY() )\n\n// мы получаем обратно промис с суммой этих\n// двух чисел.\n// теперь мы выполняем в цепочке вызов `then(..)`, чтобы дождаться разрешения\n// этого возвращенного промиса.\n.then( function(sum){\n\tconsole.log( sum ); // это намного легче!\n} );\n```\n\nВ этом кусочке кода есть два слоя промисов.\n\n`fetchX()` и `fetchY()` вызываются напрямую и возвращаемые или значения (промисы!) передаются в `add(..)`. Внутренние значения,  которые представляют эти промисы, могут быть готовы *сейчас* или *позже*, но каждый промис приводит свое поведение к тому, чтобы вести себя одинаково вне зависимости ни о чего. Мы рассуждаем о значениях `X` и `Y` во время-независимой манере. Они -  *будущие значения*.\n\nВторой уровень -  это промис, который создается в `add(..)` (через `Promise.all([ .. ])`) и возвращается, и который мы ожидаем вызвав `then(..)`. Когда операция `add(..)` завершена, наше *будущее значение* `sum` готово и можем вывести его на экран. Внутри `add(..)` мы скрываем всю логику ожидания *будущих значений* `X` и `Y`.\n\n**Примечание** Внутри `add(..)`, вызов `Promise.all([ .. ])` создает промис (который ждем разрешения `promiseX` и `promiseY`). Цепочечный Вызов `.then(..)` создает еще один промис, который сразу же разрешает строку `return values[0] + values[1]` (с результатом сложения). Таким образом, вызов `then(..)`, который мы поместили в конец цепочки вызова `add(..)` в конце фрагмента кода, в сущности работает с этим вторым возвращенным промисом, а не с первым, созданным `Promise.all([ .. ])`. Также, хотя мы и не добавили ничего в конец цепочки второго `then(..)`, он также создает еще один промис, невзирая на то, хотим мы его использовать или нет. Эту штуку с цепочками промисов мы поясним в деталях позже в этой главе.\n\nПрямо как с заказами чизбургеров, есть такая же вероятность того, что промис разрешится отказом вместо исполнения. В отличие от исполненного промиса, где значение всегда программно задано, значение при отказе, обычно называемое \"причиной отказа\", может быть установлено либо напрямую в логике программы, либо может явиться результатом исключения времени выполнения.\n\nС использованием промисов, вызов `then(..)` фактически может принимать две функции: первую - для завершения (как показано ранее), а вторую - для отказа:\n\n```js\nadd( fetchX(), fetchY() )\n.then(\n\t// обработчик завершения\n\tfunction(sum) {\n\t\tconsole.log( sum );\n\t},\n\t// обработчик отказа\n\tfunction(err) {\n\t\tconsole.error( err ); // облом!\n\t}\n);\n```\n\nЕсли что-то пошло не так при получении `X` или `Y`, или что-то каким-либо образом привело к сбою  во время сложения, промис, который возвращается из `add(..)` - отвергается (завершается отказом) и второй колбек-обработчик ошибок, переданный в `then(..)` получит значение отказа из промиса.\n\nПоскольку промисы инкапсулируют в себе состояние, не зависящее от времени, с ожиданием завершения или отказа получения значения операции снаружи, промис сам по себе является независимым от времени и потому промисы можно компоновать (составлять) предсказуемым образом независимо от времени или внутреннего результата.\n\nБолее того, как только промис разрешен, он остается таковым навсегда, он становится *неизменяемым значением* в этот момент и может потом быть *обследован* столько раз, сколько нужно.\n\n**Примечание** Поскольку промис является неизменяемым внешне как только он разрешен, то теперь можно безопасно передавать его куда угодно зная, что он не может быть изменен случайно или злонамеренно. Это особенно верно в связи с тем, что наблюдать за разрешением одного и того же промиса могут разные стороны. Невозможно повлиять на возможность одной стороны наблюдать за разрешением промиса другой стороной. Неизменяемость может прозвучать как какая-то научная тема, но на самом деле это один из самых фундаментальных и важных аспектов дизайна промисов и не должен быть рассмотрен походя мимоходом.\n\nЭто один из самых мощных и важных ключей к пониманию промисов. Проделав достаточно большую работу, вы могли бы специально добиться того же эффекта используя только композицию из уродливых колбеков, но  это не особенно эффективная стратегия, особенно потому, что вы вынуждены делать это снова и снова.\n\nПромисы - это легко повторяемый механизм инкапсуляции и совмещения *будущих значений*.\n\n### Событие завершения\n\nКак мы только что видели, одиночный промис ведет себя как *будущее значение*. Но есть и другой путь представлять разрешение промиса: как механизм потокового управления, временнОе \"это-затем-то\" для двух и более шагов в асинхронной задаче.\n\nДавайте представим вызов функции `foo(..)` для выполнения некой задачи. Мы либо не знаем ничего о ее внутренней реализации, или просто не беспокоимся об этом. Она может завершить задачу сразу или может  занять некоторое время.\n\nНам просто нужно знать когда завершится `foo(..)`, чтобы мы могли двигаться к нашей следующей задаче. Другими словами, нам нужна возможность получить оповещение о завершении `foo(..)`, чтобы мы могли  *продолжить* выполнение.\n\nВ обычном случае в JavaScript если вам нужно получить оповещение, вы вероятно подумаете об этом с точки зрения событий. Таким образом мы можем переформулировать нашу потребность в оповещении как необходимость получить событие *завершения* (или *продолжения*), инициированное функцией `foo(..)`.\n\n**Примечание** Назовете ли вы это \"событием завершения\" или \"событием продолжения\" зависит от вашей точки зрения. На чем больше смещен фокус: на том что случится в `foo(..)` или на том что произойдет *после* завершения `foo(..)`? Обе точки зрения точны и полезны. Уведомление о событии сообщает нам, что `foo(..)` *завершилась*, но также и то, что можно *продолжить* выполнение следующего шага. Безусловно, тот колбек, который вы передаете, чтобы он был вызван для уведомления о событии, сам по себе то, что мы ранее назвали *продолжение*. Потому что *событие завершения* немного более сфокусировано на `foo(..)`, что больше привлекает наше внимание в настоящий момент, мы все же чуть больше отдаем предпочтение *событию завершения* до конца этого текста.\n\nС использованием колбеков, \"уведомлением\" будет наш колбек, вызванный задачей (`foo(..)`). Но с промисами, мы переворачиваем отношения и ожидаем, что можем ждать событие от `foo(..)` и как только получим его может действовать соответственно.\n\nСперва, обратите внимание на этот псевдокод:\n\n```js\nfoo(x) {\n\t// начинаем выполнять что-то, что требует времени\n}\n\nfoo( 42 )\n\non (foo \"completion\") {\n\t// теперь мы можем выполнить следующий шаг!\n}\n\non (foo \"error\") {\n\t// ой, что-то пошло не так в `foo(..)`\n}\n```\n\nМы вызываем `foo(..)`, а затем настраиваем два обработчика событий, один для `\"completion\"` (завершение), а другой для `\"error\"` (сбоя)-- двух возможных *окончательных* исхода вызова `foo(..)`. По сути, не похоже, что `foo(..)` вообще в курсе о том, что вызывающий код подписался на эти события, что ведет к очень хорошему *разделению обязанностей*.\n\nК сожалению, такой код потребовал бы некоторой \"магии\" окружения JS, которое не существует (и которое бы весьма вероятно было бы немного непрактичным). Вот более естественный путь, которым мы может это выразить в JS:\n\n```js\nfunction foo(x) {\n\t// начнем выполнять что-нибудь, требующее времени\n\n\t// создадим обработчик оповещения о событии `listener`,\n\t// чтобы его можно было вернуть из функции\n\n\treturn listener;\n}\n\nvar evt = foo( 42 );\n\nevt.on( \"completion\", function(){\n\t// теперь мы можем выполнить следующий шаг\n} );\n\nevt.on( \"failure\", function(err){\n\t// ой, что-то пошло не так в `foo(..)`\n} );\n```\n\n`foo(..)` специально создает возможность подписки на события, которую можно вернуть из функции и вызывающий код получает и регистрирует два обработчик событий для нее.\n\nИнверсия обычного колбек-ориентированного кода должно быть очевидна и это намеренно. Вместо передачи колбеков `foo(..)`, она возвращает возможность получения событий, которую мы назвали `evt`, которая получает колбеки.\n\nНо если вы вспомните главу 2, колбеки сами по себе являются *инверсией управления* (IoC). Таким образом инвертируя шаблон колбека, в действительности получаем *инверсия инверсии* или *разинверсия управления*, возвращая управление обратно вызывающему коду, туда где оно должно было быть изначально.\n\nОдно важное преимущество - это то, что многим отдельным частях кода можно дать возможность получать события и они все смогут быть независимо уведомлены о том, когда завершится `foo(..)`, чтобы выполнить последующий код после ее завершения:\n\n```js\nvar evt = foo( 42 );\n\n// пусть `bar(..)` получает уведомление о завершении `foo(..)`\nbar( evt );\n\n// пусть `baz(..)` также получает уведомление о завершении `foo(..)`\nbaz( evt );\n```\n\n*Разинверсия управления* открывает возможность лучшего *разделения обязанностей*, где функциям `bar(..)` и `baz(..)` не нужно быть вовлеченными в то, как вызывается `foo(..)`. Аналогично, функции `foo(..)` не нужно ни знать, ни беспокоиться о том, что `bar(..)` и `baz(..)` существуют или ждут уведомления о завершении `foo(..)`.\n\nФактически, это объект `evt` - это нейтральный сторонний посредник между отдельными функциональными обязанностями.\n\n#### \"События\" промиса\n\nКак вы можете теперь предположить, возможность получения события `evt` - это аналогия для промиса.\n\nВ промисо-ориентированном подходе предыдущий блок кода мог бы содержать `foo(..)`, создающую и возвращающую экземпляр `Promise`, и этот промис был бы передан в `bar(..)` и `baz(..)`.\n\n**Примечание** \"События\" разрешения промиса, который мы ждем, не являются событиями в строгом смысле (хотя они определенно ведут себя как события в этом сценарии), и они не просто вызывают `\"completion\"` или `\"error\"`. Вместо этого, мы используем `then(..)`, чтобы зарегистрировать событие `\"then\"`. Или чуть более точно, `then(..)` регистрирует событие(я) `\"fulfillment\"` (выполнения) и/или `\"rejection\"` (отказа), хотя мы и не видим эти термины в явном виде в коде.\n\nВзгляните:\n\n```js\nfunction foo(x) {\n\t// начнем выполнять что-нибудь, требующее времени\n\n\t// создает и возвращаем промис\n\treturn new Promise( function(resolve,reject){\n\t\t// в итоге вызвать `resolve(..)` или `reject(..)`,\n\t\t// которые являются колбеками разрешения для промиса.\n\t} );\n}\n\nvar p = foo( 42 );\n\nbar( p );\n\nbaz( p );\n```\n\n**Примечание** Шаблон, показанный с `new Promise( function(..){ .. } )` - обычно называется[\"открытый конструктор (revealing constructor)\"](http://domenic.me/2014/02/13/the-revealing-constructor-pattern/). Переданная функция выполняется сразу (а не асинхронно отложенным вызовом, как колбеки в `then(..)`) и туда передаются два параметра, которые в этом случае называются `resolve` и `reject`. Это функции разрешения промиса. `resolve(..)` обычно сигнализирует о выполнении, а `reject(..)` - об отказе.\n\nВы вероятно сможете угадать, как выглядят внутри `bar(..)` и `baz(..)`:\n\n```js\nfunction bar(fooPromise) {\n\t// ждать завершения `foo(..)`\n\tfooPromise.then(\n\t\tfunction(){\n\t\t\t// `foo(..)` теперь закончена, так что\n\t\t\t// выполняем задачу `bar(..)`\n\t\t},\n\t\tfunction(){\n\t\t\t// ой, что-то пошло не так в `foo(..)`\n\t\t}\n\t);\n}\n\n// то же самое для `baz(..)`\n```\n\nРазрешение промиса не обязательно требует отправки сообщения, как это было когда мы исследовали промисы как *будущие значения*. Это может быть просто сигнал управления потоком, как это было в предыдущем блоке кода.\n\nЕще один путь добиться этого:\n\n```js\nfunction bar() {\n\t// `foo(..)` определенно завершилась, поэтому\n\t// выполняем задачу `bar(..)`\n}\n\nfunction oopsBar() {\n\t// ой, что-то пошло не так в `foo(..)`,\n\t// поэтому `bar(..)` не был запущен\n}\n\n// то же самое для `baz()` и `oopsBaz()`\n\nvar p = foo( 42 );\n\np.then( bar, oopsBar );\n\np.then( baz, oopsBaz );\n```\n\n**Примечание** Если вы уже видели раньше промис-ориентированный код, у вас может возникнуть соблазн поверить, что две последних строки этого кода можно записать как `p.then( .. ).then( .. )`, используя цепочку вызовов вместо `p.then(..); p.then(..)`. Это было бы совершенно другое поведение, будьте осторожны! Прямо сейчас разница может быть неочевидна, но это на самом деле совершенно другой асинхронный шаблон, нежели мы видели до сих пор: разделение/разветвление. Не волнуйтесь! Мы вернемся к этому позже в этой главе.\n\nВместо передачи промиса `p` в `bar(..)` и `baz(..)`, мы используем промис, чтобы управлять когда `bar(..)` и `baz(..)` будут выполнены, если вообще будут. Главное отличие - в обработке ошибок.\n\nВ подходе, использованном в первом примере кода, `bar(..)` вызывается независимо от того, `foo(..)` или нет, и в нем выполняется своя собственная логика возврата, если получается сообщение о том, что в `foo(..)` произошел сбой. Очевидно, что то же самое верно и для `baz(..)`.\n\nВо втором примере кода, `bar(..)` вызывается только если `foo(..)` завершена, а иначе вызывается `oopsBar(..)`. То же самое для `baz(..)`.\n\nНи один из этих подходов не является *корректным* сам по себе. Будут случаи, когда один будет предпочитаем другому.\n\nВ любом случае, промис `p`, который возвращается из `foo(..)`, используется для контроля того, что произойдет дальше.\n\nБолее того, факт того, что оба примера кода заканчиваются вызовом `then(..)` дважды для одного и того же промиса `p` иллюстрирует рассказанное ранее, то что промисы (если уже разрешены) остаются в том же состоянии разрешения (завершение или отказ) навсегда и могут быть позже исследованы столько раз, сколько нужно.\n\nВсякий раз когда `p` разрешается, следующий шаг будет одним и тем же, и *сейчас*, и *позже*.\n\n## Утиная типизация и наличие then\n\nВ краю промисов важной деталью является то, как узнать наверняка, что какое-то значение - подлинный промис или нет. Или более прямо, ведет ли себя это значение как промис?\n\nУчитывая, что промисы создаются используя синтаксис `new Promise(..)`, вы можете подумать, что `p instanceof Promise` будет приемлемой проверкой. Но к сожалению есть ряд причин, указывающих что этого совершенно недостаточно.\n\nПреимущественно, вы можете получить значение промиса от другого окна браузера (iframe и т.д.), у которого есть свой собственный промис, отличный от того, который в текущем окне/фрейме, и такая проверка на определение промиса была бы неудачной.\n\nБолее того, библиотека или фреймворк могут избрать путь распространения своих собственных промисов и не использовать нативную реализацию ES6 `Promise`. По сути, вы можете вполне успешно пользоваться промисами из библиотек в старых браузерах, у которых совсем нет промисов.\n\nКогда мы будем обсуждать процессы разрешения промисов позже в этой главе, станет более очевидным почему ненативное, но выглядящее как промис значение будет все еще очень важно опознавать и  употреблять. Но на текущий момент, просто поверьте на слово, что это важная часть головоломки.\n\nПоэтому, было определено, что путем определения промиса (или чего-то, что ведет себя как промис) будет определение чего-либо, называемого \"then-содержащим\", как любой объект или функция, у которой есть метод `then(..)`. Предполагается, что любое такое значение является промисо-совместимым   then-содержащим.\n\nОбщее термин для \"проверок типа\", которые делают предположения о \"типе\" значения на основании его формы (какие в нем есть свойства), называется \"утиная типизация\": \"Если это выглядит как утка и крякает как утка, значит это должно быть утка\" (см. раздел *Типы и грамматика* в этой серии книг). Таким образом утиная проверка на наличие then условно будет такой:\n\n```js\nif (\n\tp !== null &&\n\t(\n\t\ttypeof p === \"object\" ||\n\t\ttypeof p === \"function\"\n\t) &&\n\ttypeof p.then === \"function\"\n) {\n\t// предположим, что это содержит then!\n}\nelse {\n\t// не содержит then\n}\n```\n\nТьфу! Оставляя в стороне тот факт, что эта логика немного уродливая для использования в различных местах, тут происходит кое-что поглубже и более проблематичное.\n\nЕсли вы попробуете завершить промис из любого значения объекта/функции, у которых оказалась функция `then(..)`, но вы не хотели интерпретировать его как промис/then-содержащее значение, вам не повезло, потому что он будет автоматически распознан как then-содержащее значение и обработан по специальным правилам (см. позднее в этой главе).\n\nЭто верно даже если вы не осознавали, что у этого значения есть `then(..)`. Например:\n\n```js\nvar o = { then: function(){} };\n\n// сделать чтобы у `v` в качестве `[[Prototype]]` было `o`\nvar v = Object.create( o );\n\nv.someStuff = \"cool\";\nv.otherStuff = \"not so cool\";\n\nv.hasOwnProperty( \"then\" );\t\t// false\n```\n\n`v` совсем не выглядит как промис или then-содержащее значение. Это просто обычный объект с некоторыми свойствами. Возможно вы просто хотите передавать это значение везде как любой другой объект.\n\nНо скрытно от вас, `v` также связано `[[Prototype]]` (см. *this и прототипы объектов* книгу в серии книг) с другим объектом `o`, в котором как оказалось есть `then(..)`. Таким образом проверка утиной типизации на then-содержащее значение подумает и предположит, что `v` - это then-содержащее значение. Ой-ей.\n\nТут даже всё может быть не так явно намеренным:\n\n```js\nObject.prototype.then = function(){};\nArray.prototype.then = function(){};\n\nvar v1 = { hello: \"world\" };\nvar v2 = [ \"Hello\", \"World\" ];\n```\n\nОба `v1` и `v2` будут определены как then-содержащие значения. Вы не можете контролировать или предсказать добавит ли какой-либо код случайно или злонамеренно `then(..)` в `Object.prototype`, `Array.prototype` или любой из других встроенных прототипов. И если то, что указано является функцией, которая не вызывает ни один из своих параметров как колбеки, то любой промис, разрешенный с таким значением просто незаметно повиснет навсегда! Безумие.\n\nЗвучит неправдоподобно или невероятно? Возможно.\n\nНо не забывайте, что есть несколько хорошо известных не-промис библиотек, существовавших в  сообществе до ES6, в кторым случайно оказался метод, названный `then(..)`. Некоторые из этих библиотек решили переименовать свои собственные методы, чтобы избежать коллизий (которые удручают!). Другие просто были отнесены к несчастливому статусу \"несовместим с кодом, использующим промисы\" в награду за их неспособность измениться, чтобы убраться с дороги.\n\nПо стандартам решили украсть ранее незарезервированное и совершенно универсально звучащее имя свойства `then`, что означает что ни одно значение (или любой из его делегатoв), прошлое, настоящее или будущее, не может иметь функцию `then(..)` намеренно или случайно, в противном случае это значение будут путать с then-содержащим в промис-системах, что вероятно повлечет за собой создание ошибок, которые будет действительно трудно отловить.\n\n**Предупреждение:** Мне не нравится как мы закончили материал об утиной типизации then-содержащих значений для определения промисов. Были и другие варианты, такие как \"брэндинг\" или даже \"анти-брэндинг\"; то, что у нас было, казалось наихудшим компромиссом. Но это совсем не конец света. Then-содержащая утиная типизация может быть и полезной как мы увидим позже. Просто будьте осторожны, так как такая утиная типизация по then может быть опасна если она некорректно определяет что-то как промис, которое таковым не является.\n\n## Доверие к промису\n\nСейчас мы увидели две сильные аналогии,  которые объясняют различные аспекты того, что могут делать промисы для нашего асинхронного кода. Но если мы тут и остановимся, мы возможно упустим единственную важнейшую характеристику, которую предоставляет шаблон промисов: доверие.\n\nВ то время как аналогии *будущие значения* и *события завершения* в явном виде происходят в тех шаблонах кода которые мы изучили, будет не совсем очевидно почему или как промисы разработаны, чтобы решить все проблемы доверия *инверсии управления*, которые мы изложили в секции \"Проблемы с доверием\" главы 2. Но слегка покопавшись мы можем вскрыть некоторые важные гарантии, которые восстановят уверенность в асинхронном кодировании, которую разрушила глава 2!\n\nДавайте начнем с рассмотрения проблем доверия при разработке в стиле одних только колбеков. Когда вы  передаете колбек в функцию `foo(..)`, она может:\n\n* Вызвать колбек слишком рано\n* Вызвать колбек слишком поздно (или никогда)\n* Вызвать колбек слишком мало раз или слишком много раз\n* Провалить передачу в колбек любых необходимых окружения/параметров\n* Проглотить любые ошибки/исключения, которые могут произойти\n\nХарактеристики промисов намеренно разработаны, чтобы обеспечить полезные, воспроизводимые ответы на все эти проблемы.\n\n### Вызывая слишком рано\n\nВ первую очередь, эта проблема в том, могут ли проявиться в коде Залго-подобные эффекты (см. главу 2), где иногда задача завершается синхронно, а иногда - асинхронно, что может приводить к состоянию гонки.\n\nПромисы по определению не могут быть подвержены этой проблеме, потому что даже сразу завершенный промис (типа `new Promise(function(resolve){ resolve(42); })`) нельзя *исследовать* синхронно.\n\nТо есть, когда вы вызываете `then(..)` у промиса, даже если промис уже был разрешен, колбек, который вы передаете в `then(..)` **всегда** будет вызван асинхронно (детальнее об этом см. \"Задачи\" в главе 1).\n\nБольше не нужно вставлять свои собственные костыли с `setTimeout(..,0)`. Промисы не допускают Залго автоматически.\n\n### Вызывая слишком поздно\n\nАналогично предыдущему пункту, колбеки наблюдения, зарегистрированные в `then(..)` промиса автоматически планируются к вызову когда вызван либо `resolve(..)`, либо `reject(..)` посредством кода создания промиса. Эти запланированные колбеки будут предсказуемо вызваны в следующий асинхронный момент (см. \"Задачи\" в главе 1).\n\nСинхронное наблюдение тут невозможно, следовательно невозможно запустить синхронную цепочку задач таким образом, чтобы на практике \"отложить\" вызов другого колбека ожидаемым образом. То есть, когда промис разрешен, все зарегистрированные для`then(..)` колбеки будут по порядку вызваны, сразу же при следующей асинхронной возможности (снова, см. \"Задачи\" в главе 1) и ничто, что происходит внутри одного из этих колбеков не может повлиять или задержать вызов остальных колбеков.\n\nНапример:\n\n```js\np.then( function(){\n\tp.then( function(){\n\t\tconsole.log( \"C\" );\n\t} );\n\tconsole.log( \"A\" );\n} );\np.then( function(){\n\tconsole.log( \"B\" );\n} );\n// A B C\n```\n\nЗдесь, `\"C\"` не может прервать и предшествовать `\"B\"`, в силу того как промисам было определено работать.\n\n#### Хитрости планировщика промисов\n\nВажно отметить, впрочем, что есть масса нюансов планировщика, когда относительный порядок между колбеками, выстроенными в цепочки двух отдельных промисов, не является надежно предсказуемым.\n\nЕсли два промиса `p1` и `p2` оба уже разрешены, то будет истиной, что `p1.then(..); p2.then(..)` закончится вызовов колбека(ов) для `p1` до колбеков для `p2`. Но есть некоторые хитрые случаи, когда это может быть и не так, такие как следующий:\n\n```js\nvar p3 = new Promise( function(resolve,reject){\n\tresolve( \"B\" );\n} );\n\nvar p1 = new Promise( function(resolve,reject){\n\tresolve( p3 );\n} );\n\nvar p2 = new Promise( function(resolve,reject){\n\tresolve( \"A\" );\n} );\n\np1.then( function(v){\n\tconsole.log( v );\n} );\n\np2.then( function(v){\n\tconsole.log( v );\n} );\n\n// A B  <-- не B A  как вы могли бы ожидать\n```\n\nМы расскажем об этом позже, но как вы видите `p1` разрешен не с непосредственным значением, а с еще одним промисом `p3`, который сам разрешен со значением `\"B\"`. Указанное поведение - это *распаковать* `p3` внутри `p1`, но асинхронно, таким образом колбек(и) `p1` *позади* колбека(ов) `p2` в очереди асинхронных задач (см. главу 1).\n\nЧтобы избежать таких хитрых кошмаров, вам никогда не следует полагаться на что-либо связанное с порядком/шедулингом колбеков в промисах. На самом деле, хорошей практикой будет не писать код таким образом, чтобы порядок многочисленных колбеков имел хоть какие-то значение. Избегайте этого если сможете.\n\n### Колбек, который никогда не был вызван\n\nЭто - очень распространенная проблема. Она решаема несколькими путями с промисами.\n\nВо-первых, ничто (ни даже JS-ошибка) не может повлиять на уведомление вас от промиса о своем разрешении (если он разрешен). Если вы указываете оба колбека как для завершения, так и для сбоя при создании промиса и промис разрешается,то один из этих двух колбеков всегда будет вызван.\n\nКонечно, если ваши колбеки сами содержат JS-ошибки, вы можете не получить ожидаемый результат, но колбек и в самом деле будет вызван. Мы расскажем позже как получить уведомление об ошибке в своем колбеке, потому что даже эти ошибки не проглатываются.\n\nНо что если сам промис никогда не будет разрешен тем или иным путем? Даже для такой ситуации у промисов есть ответ используя абстракцию более высокого порядка, называемую \"гонка\":\n\n```js\n// функция с промисом по тайм-ауту\nfunction timeoutPromise(delay) {\n\treturn new Promise( function(resolve,reject){\n\t\tsetTimeout( function(){\n\t\t\treject( \"Тайм-аут!\" );\n\t\t}, delay );\n\t} );\n}\n\n// настройка тайм-аута для `foo()`\nPromise.race( [\n\tfoo(),\t\t\t\t\t// попробовать вызвать `foo()`\n\ttimeoutPromise( 3000 )\t// дать на это 3 секунды\n] )\n.then(\n\tfunction(){\n\t\t// `foo(..)` выполнился успешно и вовремя!\n\t},\n\tfunction(err){\n\t\t// либо `foo()` завершилась неудачно, либо она\n\t\t// не завершилась вовремя, так что проверьте\n\t\t// `err` чтобы определить причину\n\t}\n);\n```\n\nЕсть еще много нюансов, которые можно учесть при рассмотрении этого шаблона промисов с тайм-аутом, но мы вернемся к этом позже.\n\nВажно, что мы можем гарантированно просигнализировать о результате `foo()`, чтобы предотвратить зависание нашей программы бесконечно.\n\n### Вызывая слишком мало или много раз\n\nПо определению, *один* - это подходящее число раз, которое колбек должен быть вызван. Случай \"слишком мало\" будет означать ноль вызовов, что то же самое что и случай \"никогда\", который мы только что рассмотрели.\n\nСлучай \"слишком много\" легко объяснить. Промисы определены таким образом, что могут быть разрешены только один раз. Если по каким-либо причинам код создания промиса попытается вызвать `resolve(..)` или `reject(..)` несколько раз или попытается вызвать их обоих, то промис примет во внимание только первый вызов и молча проигнорирует любые последующие попытки.\n\nПоскольку промис можно разрешить лишь раз, любые зарегистрированные колбеки `then(..)` будут вызваны  только по разу (каждый).\n\nКонечно, если зарегистрируете один и ото же колбек более одного раза, (т.е., `p.then(f); p.then(f);`), он будет вызван столько раз, сколько был зарегистрирован. Гарантия того, что функция ответа будет вызвана только раз не препятствует вам выстрелить себе в ногу.\n\n### Сбой при передаче параметров/окружения\n\nУ промисов может быть не больше одного значения разрешения (завершение или отказ).\n\nЕсли вы не разрешаете промис явно с конкретным значением, значение будет `undefined`, как и обычно в таких случаях в JS. Но если ли значение или нет, оно всегда будет передавно во все зарегистрированные (и корректные: завершение или отказ) колбеки, либо *сейчас*, или в будущем.\n\nЧто-то, о чем нужно знать: если вы вызываете `resolve(..)` или `reject(..)` с несколькими параметрами, все параметры, которые следуют за первым, будут молча проигнорированы. Хотя это и может выглядеть как нарушение гарантии, которую мы только что описали, это не совсем так потому что it это представляет собой недопустимое использование механизма промисов. Другие недопустимые случаи использования API (такие как вызов `resolve(..)` несколько раз) *защищены* похожим образом, таким образом поведение промисов тут будет консистентным (если не немного расстраивающим).\n\nЕсли вы хотите передать несколько значений, вы должны обернуть их в еще одно одиночное значение, которое вы и передадите, такое как `array` (массив) или `object` (объект).\n\nЧто касается окружения, функции в JS всегда сохраняют свое замыкание области видимости, в которой они определены (см. *Область видимости и замыкания* в этой серии книг), так что у них, конечно, остается доступ к тому окружающему состоянию, которое вы предоставляете. Конечно, то же самое справедливо и для подхода с одними колбеками, поэтому это не какое-то особенная выгодная добавка от промисов, но это гарантия, на которую мы можем тем ни менее положиться.\n\n### Проглатывание любых ошибок/исключений\n\nВ основе, это просто переформулирование предыдущего пункта. Если вы отклоняете промис с определенной *причиной* (т.е. сообщением об ошибке), то это значение будете передано в колбек(и) отказа.\n\nНо здесь есть нечто гораздо большее. Если в любой точке создания промиса или при исследовании его разрешения произойдет исключение JS, такое как `TypeError` или `ReferenceError`, такое исключение будет захвачено и это заставит завершиться с отказом рассматриваемый промис.\n\nНапример:\n\n```js\nvar p = new Promise( function(resolve,reject){\n\tfoo.bar();\t// `foo` не определена поэтому ошибка!\n\tresolve( 42 );\t// никогда не достигнет этой точки :(\n} );\n\np.then(\n\tfunction fulfilled(){\n\t\t// никогда не достигнет этой точки :(\n\t},\n\tfunction rejected(err){\n\t\t// `err` будет объектом исключения `TypeError`\n\t\t// произошедшим на строке `foo.bar()`.\n\t}\n);\n```\n\nJS-исключение, которое возникает от `foo.bar()`, становится отказом промиса, который вы можете захватить и обработать.\n\nЭто - важная деталь, потому что она успешно решает еще один потенциальный Залго-момент, который заключается в том, что эти ошибки повлечь синхронную реакцию тогда как не-ошибки будут асинхронными. Даже JS-исключения промисы превращают в асинхронное поведение, тем самым значительно уменьшая шансы появления состояния гонки.\n\nНо что произойдет если промис завершен, а произошло JS-исключение во время обработки результата (в зарегистрированном колбеке `then(..)`)? Даже такие исключения не будут потеряны, но вы  можете немного удивиться тому, как они обрабатываются, пока не вникните немного глубже в это:\n\n```js\nvar p = new Promise( function(resolve,reject){\n\tresolve( 42 );\n} );\n\np.then(\n\tfunction fulfilled(msg){\n\t\tfoo.bar();\n\t\tconsole.log( msg );\t// никогда не достигнет этой точки :(\n\t},\n\tfunction rejected(err){\n\t\t// никогда не достигнет и этой точки :(\n\t}\n);\n```\n\nПодождите-ка, тут похоже, что исключение  от `foo.bar()` и в самом деле проглочено. Без паники, оно не пропало. Но кое-что внутри не так, а именно то, что мы не смогли получить уведомление об этом. Вызов `p.then(..)` сам по себе возвращает другой промис и это *тот самый* промис, который будет отклонен с исключением `TypeError`.\n\nТак почему же он не может просто вызвать обработчик ошибок, который мы там объявили? Похоже, что логичное объяснение лежит на поверхности. Но оно нарушило бы основополагающий принцип промисов - **неизменность** после разрешения. `p` уже была завершена со значением `42`, так что она не может быть позднее изменена на отказ только потому, что возникла ошибка в наблюдающей функции разрешения `p`.\n\nКроме нарушения принципа, такое поведение может нанести ущерб, если скажем было несколько зарегистрированных колбеков `then(..)` для промиса `p`, поскольку тогда некоторые будут вызваны, а другие - нет, и это было очень непрозрачно в плане причины почему так произошло.\n\n### Надежный промис?\n\nЕсть одна последняя деталь, чтобы понять как установить доверие, основанное на шаблоне промисов.\n\nБез сомнения вы заметили, что промисы не избавились от колбеков полностью. Они просто поменяли место, куда передается колбек. Вместо передачи колбека в `foo(..)`, мы получаем *нечто* (предположительно настоящий промис) обратно из `foo(..)`, и мы взамен передаем колбек в это *нечто*.\n\nНо почему это было бы надежнее, чем просто колбеки сами по себе? Как мы можем быть уверены в точ, что *нечто*, что мы получаем в ответ на самом деле надежный промис? Не является ли всё это в сущности просто карточным домиком, где мы можем доверять только потому, что мы уже доверяем?\n\nОдна из самых важных, но часто незаслуженно обойденных вниманием деталей промисов - это то, что у них есть решение также и этой проблемы. Включенное в нативную реализацию ES6 `Promise` - `Promise.resolve(..)`.\n\nЕсли вы передаете непосредственное, не являющееся ни промисом, ни then-содержащим, значение в  `Promise.resolve(..)`, вы получили промис, который завершен с этим значением. Другими словами, эти два промиса `p1` и `p2` будут вести себя практически идентично:\n\n```js\nvar p1 = new Promise( function(resolve,reject){\n\tresolve( 42 );\n} );\n\nvar p2 = Promise.resolve( 42 );\n```\n\nНо если вы передадите настоящий промис в `Promise.resolve(..)`, вы просто получите тот же промис обратно:\n\n```js\nvar p1 = Promise.resolve( 42 );\n\nvar p2 = Promise.resolve( p1 );\n\np1 === p2; // true\n```\n\nЧто еще более важно, если вы передаете не-промис then-содержащее значение в `Promise.resolve(..)`, оно попытается распаковать это значение, и распаковка будет продолжаться до тех пор, пока не будет извлечено конкретное окончательное не-промис значение.\n\nПомните наше прошедшее обсуждение then-содержащих?\n\nРассмотрите:\n\n```js\nvar p = {\n\tthen: function(cb) {\n\t\tcb( 42 );\n\t}\n};\n\n// это сработает, но только благодаря удаче\np\n.then(\n\tfunction fulfilled(val){\n\t\tconsole.log( val ); // 42\n\t},\n\tfunction rejected(err){\n\t\t// никогда не достигнет этой точки\n\t}\n);\n```\n\nЭто `p` - then-содержащее, но это не настоящий промис. К счастью, оно разумное, как и большинство какие бывают. Но что если вы получите в ответ что-то, что выглядит как-то так:\n\n```js\nvar p = {\n\tthen: function(cb,errcb) {\n\t\tcb( 42 );\n\t\terrcb( \"злобный смех\" );\n\t}\n};\n\np\n.then(\n\tfunction fulfilled(val){\n\t\tconsole.log( val ); // 42\n\t},\n\tfunction rejected(err){\n\t\t// ой, не должно было сработать\n\t\tconsole.log( err ); // злобный смех\n\t}\n);\n```\n\nЭто `p` - then-содержащее, но оно не ведет себя как хороший промис. Вредоносное ли оно? Или просто игнорирует то, как должны работать промисы? Это не важно, если честно. В любом случае, оно не надежно в том виде, как есть.\n\nТем ни менее, мы может передать любую их этих версий `p` в `Promise.resolve(..)`, и мы получим нормализованный, безопасный результат, который и ожидаем:\n\n```js\nPromise.resolve( p )\n.then(\n\tfunction fulfilled(val){\n\t\tconsole.log( val ); // 42\n\t},\n\tfunction rejected(err){\n\t\t// никогда не достигнет этой точки\n\t}\n);\n```\n\n`Promise.resolve(..)` примет любые then-содержащие аргументы, и распакует их в их не-then-содержащее значение. Но вы получите обратно из `Promise.resolve(..)` настоящий, подлинный промис, **тот, которому вы можете доверять**. Если то, что вы передали, уже является настоящим промисом, вы просто получите его же обратно, так что нет никаких недостатков в том, что фильтровать через `Promise.resolve(..)`, чтобы получить надежность.\n\nДопустим мы вызываем `foo(..)` и не уверены, что можем доверять его возвращаемому значению в том, что оно является правильным промисом, но мы знаем, что оно как минимум then-содержащее. `Promise.resolve(..)` даст нам надежную обертку в виде промиса, которую можно использовать в цепочке:\n\n```js\n// не делайте так:\nfoo( 42 )\n.then( function(v){\n\tconsole.log( v );\n} );\n\n// вместо этого, делайте так:\nPromise.resolve( foo( 42 ) )\n.then( function(v){\n\tconsole.log( v );\n} );\n```\n\n**Примечание** Еще один выгодный побочный эффект оборачивания `Promise.resolve(..)` вокруг любого возвращаемого из функции значения (then-содержащей или нет) - это то, что  это легкий путь к приведению этого вызова функции к правильно ведущей себя асинхронной задаче. Если `foo(42)` иногда возвращает непосредственное значение, а иногда промис, `Promise.resolve( foo(42) )` следит за тем, чтобы это всегда был в результате промис. И избегая Залго приводит к намного лучшему коду.\n\n### Построенное доверие\n\nНадеюсь, что предыдущая дискуссия теперь полностью \"разрешает\" (каламбур) в вашим мозгу факт, почему промис надежен, и более важно, почему это доверие так критично для построения надежного, поддерживаемого ПО.\n\nМожете ли вы писать асинхронный код в JS без какой-либо надежности? Конечно можете. Мы, JS-разработчики, пишем асинхронный код не имея ничего кроме колбеков уже почти два десятилетия.\n\nНо как только вы начинаете задавать вопросы просто о том, насколько вы можете доверять механизмам, на которые вы опираетесь, в самом деле быть предсказуемыми и надежными, вы начинаете осознавать, что у   колбеков довольно шаткий фундамент доверия.\n\nПромисы - это шаблон, который дополняет колбеки надежной семантикой, так что поведение становится более разумным и надежным. Сделав разинверсию *инверсии управления* колбеками, мы передаем управление надежной системе (промисам), которая была специально разработана, чтобы привнести здравый смысл в нашу асинхронность.\n\n## Цепочечный поток\n\nМы уже намекали на это пару раз, но промисы - это не только механизм для одношаговой операции типа *это-затем-то*. Это строительный блок, конечно, но оказывается мы можем связать немного промисов вместе для представления последовательности асинхронных шагов.\n\nКлюч к тому, чтобы это сработало, построен на двух видах поведения, присущих промисам:\n\n* Каждый раз как вы вызываете `then(..)` у промиса, он создает и возвращает новый промис, с которым мы можем составить *цепочку*.\n* Какое бы значение вы ни вернули из колбека завершения `then(..)` (первый параметр) - оно автоматически устанавливается как set как результата нормального завершения промиса *в цепочке*  (из первого пункта).\n\nДавайте сперва проиллюстрируем что это значит, а *затем* (then, туту игра слов) вы выведем как это помодет нам создавать асинхронные последовательности управления потоком. Рассмотрим следующее:\n\n```js\nvar p = Promise.resolve( 21 );\n\nvar p2 = p.then( function(v){\n\tconsole.log( v );\t// 21\n\n\t// завершить `p2` со значением `42`\n\treturn v * 2;\n} );\n\n// составляем цепочку с `p2`\np2.then( function(v){\n\tconsole.log( v );\t// 42\n} );\n```\n\nВозвращая `v * 2` (i.e., `42`), мы завершаем промис `p2` с успешным результатом, который создал и вернул первый вызов `then(..)`. Когда происходит вызов `then(..)` у `p2`, он получает результат из выражения `return v * 2`. Конечно, `p2.then(..)` создает еще один промис, который мы можем сохранить в переменной `p3`.\n\nНо немного раздражает необходимость создавать промежуточную переменную `p2` (или `p3`, и т.д.). К счастью, мы легко можем объединить их в цепочку:\n\n```js\nvar p = Promise.resolve( 21 );\n\np\n.then( function(v){\n\tconsole.log( v );\t// 21\n\n\t// вернуть результат промиса в цепочке со значением `42`\n\treturn v * 2;\n} )\n// вот и промис в цепочке\n.then( function(v){\n\tconsole.log( v );\t// 42\n} );\n```\n\nТаким образом теперь первый `then(..)` - это первый шаг в асинхронной последовательности, а второй `then(..)` - это второй шаг. Это может продолжаться столь долго, сколь вам надо это расширять. Просто продолжайте цепочку от предыдущего `then(..)` автоматически созданным промисом.\n\nНо здесь нет кое-чего. Что если мы хотим, чтобы шаг 2 ждал пока шаг 1 выполнит что-то асинхронное? Мы используем выражение `return` для возврата значения сразу, которое немедленно и завершает промис в цепочке.\n\nКлюч к тому, чтобы заставить последовательность промисов быть истинно асинхронной на каждом шаге - это вспомнить как работает `Promise.resolve(..)` когда то, что вы передаете ему - это промис или then-содержащее вместо конечного значения. `Promise.resolve(..)` прямо возвращает полученный настоящий промис или распаковывает значение полученного then-содержащего и движется рекурсивно пока может распаковывать then-содержащие.\n\nТакой же вид распаковки происходит если вы используете в `return` then-содержащее или промис из обработчика завершения (или отказа). Рассмотрим:\n\n```js\nvar p = Promise.resolve( 21 );\n\np.then( function(v){\n\tconsole.log( v );\t// 21\n\n\t// создаем промис и возвращаем его\n\treturn new Promise( function(resolve,reject){\n\t\t// завершение со значением `42`\n\t\tresolve( v * 2 );\n\t} );\n} )\n.then( function(v){\n\tconsole.log( v );\t// 42\n} );\n```\n\nНесмотря на то, что мы обернули `42` в промис, который вернули, оно все еще распаковано и оказалось в качестве разрешения промиса в цепочке, такого как второй `then(..)`, который тем ни менее получил `42`. Если мы добавим асинхронность для этого оборачивающего промиса, все всё еще будет работать по-прежнему одинаково:\n\n```js\nvar p = Promise.resolve( 21 );\n\np.then( function(v){\n\tconsole.log( v );\t// 21\n\n\t// создаем промис и возвращаем его\n\treturn new Promise( function(resolve,reject){\n\t\t// добавляем асинхронность!\n\t\tsetTimeout( function(){\n\t\t\t// завершение со значением `42`\n\t\t\tresolve( v * 2 );\n\t\t}, 100 );\n\t} );\n} )\n.then( function(v){\n\t// запускается после задержки 100мс на предыдущем шаге\n\tconsole.log( v );\t// 42\n} );\n```\n\nЭто невероятно мощно! Теперь мы можем строить последовательность со сколь угодно большим количеством  асинхронных шагов и каждый шаг может задержать следующий шаг (или не задержать!), если необходимо.\n\nКонечно, значение, передаваемое из шага в шаг в этих примерах, не обязательное. Если вы не вернете явное значение, будет предполагаться  неявное значение `undefined` и промисы все еще будут в цепочке таким же образом. Разрешение каждого промиса, таким образом, является просто сигналом перейти к следующему шагу.\n\nДля дальней иллюстрации цепочки, давайте обобщим создание промиса с задержкой (без вывода сообщений о завершении) в функцию, которую мы можем переиспользовать для нескольких шагов:\n\n```js\nfunction delay(time) {\n\treturn new Promise( function(resolve,reject){\n\t\tsetTimeout( resolve, time );\n\t} );\n}\n\ndelay( 100 ) // шаг 1\n.then( function STEP2(){\n\tconsole.log( \"шаг 2 (после 100мс)\" );\n\treturn delay( 200 );\n} )\n.then( function STEP3(){\n\tconsole.log( \"шаг 3 (после еще 200мс)\" );\n} )\n.then( function STEP4(){\n\tconsole.log( \"шаг 4 (следующая задача)\" );\n\treturn delay( 50 );\n} )\n.then( function STEP5(){\n\tconsole.log( \"шаг 5 (после еще 50мс)\" );\n} )\n...\n```\n\nВызов `delay(200)` создает промис, который завершится через 200мс, а затем вы вернем его из первого колбека завершения `then(..)`, который приведет ко второму промису от `then(..)`, чтобы подождать этот 200мс-промис.\n\n**Примечание** Как было описано, технически есть два промиса в этом обмене: промис с 200мс-задержкой и промис в цепочке, к которому присоединяется второй `then(..)`. Но возможно вам будет проще мысленно объединить эти два промиса вместе, потому что механизм промисов автоматически объединим их состояния для вас. В этом отношении, вы можете думать о `return delay(200)` как о создании промиса, который заменяет ранее возвращенный промис в цепочке.\n\nХотя, если честно, последовательности задержек без передачи полезной нагрузки не очень полезный пример управления потоком промисов. Давайте взглянем на сценарий, который выглядит чуточку более практично.\n\nВместо таймеров, давайте рассмотрим возможность создания Ajax-запросов:\n\n```js\n// предположим есть функция `ajax( {url}, {callback} )`\n\n// Ajax с учетом промисов\nfunction request(url) {\n\treturn new Promise( function(resolve,reject){\n\t\t// колбек `ajax(..)` должен стать нашей\n\t\t// функцией `resolve(..)` промиса\n\t\tajax( url, resolve );\n\t} );\n}\n```\n\nСначала мы определяем функцию `request(..)`, которая создает промис для представления завершения вызова `ajax(..)`:\n\n```js\nrequest( \"http://some.url.1/\" )\n.then( function(response1){\n\treturn request( \"http://some.url.2/?v=\" + response1 );\n} )\n.then( function(response2){\n\tconsole.log( response2 );\n} );\n```\n\n**Примечание** Разработчики часто сталкиваются с ситуациями, когда они хотят получить асинхронное управление потоком промисов для функций, которые сами по себе не поддерживают промисы (как `ajax(..)` здесь, который ожидает на входе колбек). Хотя нативный механизм ES6 `Promise` не решает автоматически этот шаблон за нас, практически все промис-библиотеки *решают*. Они обычно называют этот процесс  \"lifting\" (поднятие) или \"promisifying\" (промисифицирование) или вариации на тему. Мы вернемся к этой технике позже.\n\nИспользуя `request(..)`, умеющий возвращать промис, мы неявно создаем первый шаг в нашей цепочке вызывая его с первым URL, и объединяем в цепочку этот возвращенный промис с первым `then(..)`.\n\nКак только возвращается `response1`, мы используем это значение чтобы создать второй URL и выполнить второй вызов `request(..)`. Этот второй промис из `request(..)` - возвращен `return`ом таким образом, что третий шаг в нашем асинхронном контроле потока ждет завершения этого Ajax-вызова. Наконец, мы выводим `response2` как только он возвращен.\n\nЦепочка промисов, которую мы создали - не только управление потоком, которое отражает многошаговую асинхронную последовательность, но и также действует как канал сообщений для передачи их от шага к шагу.\n\nЧто если что-то пойдет не так в одном из шагов цепочки промисов? Ошибка/исключение соединены со своим промисом, что означает, что есть возможность поймать такую ошибку в любом месте цепочки и такой захват действует как бы как \"сброс\" цепочки обратно к нормальному функционированию в этой точке:\n\n```js\n// шаг 1:\nrequest( \"http://some.url.1/\" )\n\n// шаг 2:\n.then( function(response1){\n\tfoo.bar(); // undefined, ошибка!\n\n\t// никогда не достигнет этой точки\n\treturn request( \"http://some.url.2/?v=\" + response1 );\n} )\n\n// шаг 3:\n.then(\n\tfunction fulfilled(response2){\n\t\t// никогда не достигнет этой точки\n\t},\n\t// обработчик отказа, чтобы поймать ошибку\n\tfunction rejected(err){\n\t\tconsole.log( err );\t// `TypeError` из-за ошибки на `foo.bar()`\n\t\treturn 42;\n\t}\n)\n\n// шаг 4:\n.then( function(msg){\n\tconsole.log( msg );\t\t// 42\n} );\n```\n\nКогда происходит ошибка на шаге 2, обработчик отказа в шаге 3 ловит ее. Возвращаемое значение (`42` в этом примере кода), если таковое есть, из обработчика отказа завершает промис для следующего шага (4), так, чтобы цепочка вернулось обратно в состояние завершения.\n\n**Примечание** Как мы уже говорили ранее, при возврате промиса из обработчика завершения, этот промис не обернут и может задержать следующий шаг. Это также верно при возврате промисов из обработчиков отказа, так что если `return 42` на шаге 3 вернет вместо этого промис, этот промис может задержать шаг 4. Выброшенное исключение внутри либо обработчика завершения, либо отказа в вызове `then(..)` приведет к тому, что следующий (в цепочке) промис будет немедленно отвергнут с этим же исключением.\n\nЕсли вы вызовете `then(..)` у промиса и передадите только обработчик завершения в него, будет подставлен неявный обработчик отказов:\n\n```js\nvar p = new Promise( function(resolve,reject){\n\treject( \"Ой\" );\n} );\n\nvar p2 = p.then(\n\tfunction fulfilled(){\n\t\t// никогда не достигнет этой точки\n\t}\n\t// неявный обработчик отказа, если явно не указан или\n\t// передано любое другое значение - не-функция\n\t// function(err) {\n\t//     throw err;\n\t// }\n);\n```\n\nКак видите, неявный обработчик отказа просто повторно бросает ту же ошибку, что в итоге вынуждает `p2` (промис в цепочке) завершиться отказом с той же самой причиной в виде ошибки. По сути, это позволяет ошибке продолжить путешествовать по цепочке промисов до тех пор, пока не встретится явно заданный обработчик отказа.\n\n**Примечание** Мы расскажем подробнее об обработке ошибок в промисах немного позже, потому что есть и другие нюансы, о которым стоит побеспокоиться.\n\nЕсли в `then(..)` не передана валидная функция в качестве параметра обработчика завершения, также будет подставлен неявный обработчик:\n\n```js\nvar p = Promise.resolve( 42 );\n\np.then(\n\t// неявный обработчик завершения, если явно не указан или\n\t// передано любое другое значение - не-функция\n\t// function(v) {\n\t//     return v;\n\t// }\n\tnull,\n\tfunction rejected(err){\n\t\t// никогда не достигнет этой точки\n\t}\n);\n```\n\nКак видите, обработчик завершения по умолчанию просто передает полученное значение на следующий шаг (промис).\n\n**Примечание** Шаблон `then(null,function(err){ .. })`, обрабатывающий только отказы (если есть), но позволяющий пропускать далее завершения, имеет сокращенную форму в API: `catch(function(err){ .. })`. Мы рассмотрим `catch(..)` более полно в следующем разделе.\n\nДавайте вкратце рассмотрим присущие промисам типы поведения, которые позволяют организовать цепочечное управление потоком:\n\n* Вызов `then(..)` с одним промисом автоматически создает новый промис в качестве возвращаемого значения вызова.\n* Внутри обработчиков завершения/отказа, если вы возвращаете значение или бросается исключение, новый возвращенный промис (который можно присоединить к цепочке) разрешается соответственно с тем же результатом.\n* Если обработчик завершения или отказа возвращают промис, он не обернут, таким образом как бы он не разрешился, это станет разрешением промиса в цепочке, возвращенного из текущего `then(..)`.\n\nХотя цепочечное управление потоком полезное, возможно будет более точным представлять его как побочный эффект того, как промисы объединяются (составляются) вместе, нежели как основной функционал. Как мы подробно обсуждали уже несколько раз, промисы нормализуют асинхронность и скрывают  состояние значения, зависимого от времени, и это *то*, что позволяет нам объединять их в цепочки таким удобным способом.\n\nОпределенно, последовательная выразительность цепочки (это-then-это-then-это...) - это большое улучшение по сравнению с запутанным клубком колбеков, как мы уже выяснили в главе 2. Но все еще есть изрядный объем шаблона (`then(..)` и `function(){ .. }`), через который нужно продираться. В следующей главе мы увидим значительно более приятный шаблон для выразительной организации последовательного управления потоком с помощью генераторов.\n\n### Терминология: Разрешить (Resolve), Завершить (Fulfill) и Отвергнуть (Reject)\n\nСуществует небольшая путаница в терминах \"разрешить (resolve)\", \"Завершить (fulfill)\" и \"отвергнуть (reject)\", которую нам необходимо прояснить до того, как вы погрузитесь слишком глубоко в изучении промисов. Давайте сначала рассмотрим конструктор `Promise(..)`:\n\n```js\nvar p = new Promise( function(X,Y){\n\t// X() для завершения\n\t// Y() для отказа\n} );\n```\n\nКак видите, переданы два колбека (здесь помечены как `X` и `Y`). Первый *обычно* используется для отметки того, что промис завершен, а второй *всегда* помечает промис как отвергнутый. Но о чем это \"обычно\" и что это означает для точного именования этих параметров?\n\nВ конечном счете, это только ваш код и имена идентификаторов не интерпретируются JS-движком как что-то значимое, так что *технически* это не имеет значения; `foo(..)` и `bar(..)` одинаково функциональны. Но слова, которыми вы пользуетесь, могут затронуть не только как вы думаете о коде, но и как другие разработчики в вашей команде будут думать о нем. Думая неправильно о тщательно организованном асинхронном коде - это почти наверняка будет хуже, чем альтернативы из спагетти-колбеков.\n\nТак что на самом деле имеет значение, как вы их называете.\n\nСо вторым параметром легко определиться. Почти вся литература использует `reject(..)` (отвергнуть) как его имя и поскольку это в точности (и только это!) то, что он делает, это и есть очень хороший выбор для этого имени. Я бы настоятельно рекомендовал вам всегда использовать `reject(..)`.\n\nНо вокруг первого параметра чуть больше неясностей, который в литературе о промисах часто обозначается `resolve(..)` (разрешить). Это слово очевидно связано с \"resolution\" (разрешение), которое и используется во всей литературе (включая эту книгу), чтобы описать установку конечного значения/состояния в промисе. Мы уже использовать \"разрешить промис\" несколько раз, чтобы обозначить  либо завершение, или отвергнутый промис.\n\nНо если этот параметр, по-видимому, используется для конкретно завершения промиса, почему бы не назвать его `fulfill(..)` (завершить) вместо `resolve(..)` (разрешить), чтобы быть более точным? Чтобы ответить на этот вопрос, давайте также взглянет на два метода `Promise` API:\n\n```js\nvar fulfilledPr = Promise.resolve( 42 );\n\nvar rejectedPr = Promise.reject( \"Ой\" );\n```\n\n`Promise.resolve(..)` создает промис, который разрешен со переданным значением. В этом примере, `42` - это обычное, не-промис, не-then-содержащее значение, поэтому завершенный промис `fulfilledPr` создан для значения `42`. `Promise.reject(\"Ой\")` создает отвергнутый промис `rejectedPr` для причины `\"Ой\"`.\n\nДавайте теперь проиллюстрируем, почему слово \"resolve\" (разрешить) (такое как в `Promise.resolve(..)`) - является однозначным и более точным, если используется явно в контексте, который должен либо завершиться, либо закончиться отказом:\n\n```js\nvar rejectedTh = {\n\tthen: function(resolved,rejected) {\n\t\trejected( \"Ой\" );\n\t}\n};\n\nvar rejectedPr = Promise.resolve( rejectedTh );\n```\n\nКак мы уже говорили ранее в этой главе, `Promise.resolve(..)` вернет полученный настоящий промис напрямую или распакует полученное then-содержащее. Если распаковка этого then-содержащего покажет отвергнутое состояние, то промис, который был возвращен из `Promise.resolve(..)` - по факту в том же самом отвергнутом состоянии.\n\nТаким образом `Promise.resolve(..)` - это хорошее, точное название для метода API, потому что он может либо завершиться, либо будет отвергнутым.\n\nПервый колбек-параметр конструктора `Promise(..)` распакует либо then-содержащее (идентично `Promise.resolve(..)`), либо настоящий промис:\n\n```js\nvar rejectedPr = new Promise( function(resolve,reject){\n\t// разрешить этот промис отвергнутым промисом\n\tresolve( Promise.reject( \"Ой\" ) );\n} );\n\nrejectedPr.then(\n\tfunction fulfilled(){\n\t\t// никогда не достигнет этой точки\n\t},\n\tfunction rejected(err){\n\t\tconsole.log( err );\t// \"Ой\"\n\t}\n);\n```\n\nТеперь должно быть ясно, что `resolve(..)` - подходящее название для для первого колбек-параметра конструктора `Promise(..)`.\n\n**Предупреждение:** Ранее упомянутый `reject(..)` **не** выполняет распаковку, как это делает `resolve(..)`. Если вы передадите промис или then-содержащее значение в `reject(..)`, то именно это значение нетронутым будет установлено как причина отказа. Последующий обработчик отказа получит настоящий промис/then-содержащее, которое вы передали в `reject(..)`, а не его внутреннее непосредственное значение.\n\nНо теперь давайте обратим наше внимание на колбеки, переданные в `then(..)`. Как их следует назвывать (и в литературе, и в коде)? Я бы предложил `fulfilled(..)` (завершенный) и `rejected(..)` (отвергнутый):\n\n```js\nfunction fulfilled(msg) {\n\tconsole.log( msg );\n}\n\nfunction rejected(err) {\n\tconsole.error( err );\n}\n\np.then(\n\tfulfilled,\n\trejected\n);\n```\n\nВ случае первого параметра в `then(..)` - это однозначно всегда случай завершения, поэтому нет нужны для двойственной терминологии \"resolve\". В качестве примечания, спецификация ES6 использует `onFulfilled(..)` и `onRejected(..)`, чтобы обозначить эти два колбека, поэтому они являются точными терминами.\n\n## Обработка ошибок\n\nМы уже видели несколько примеров того, как отказ промисов, либо намеренно через вызов `reject(..)`, либо случайно через исключение JS, позволяет более разумно обрабатывать ошибки при асинхронной разработке. Давайте вернемся назад и четко сформулируем некоторые детали, которые мы пропустили.\n\nСамая естественная форма обработки ошибок для большинства разработчиков - это синхронная конструкция `try..catch`. К сожалению, она есть только в синхронной форме, поэтому она не поможет в шаблонах асинхронного кода:\n\n```js\nfunction foo() {\n\tsetTimeout( function(){\n\t\tbaz.bar();\n\t}, 100 );\n}\n\ntry {\n\tfoo();\n\t// позднее выбросит глобальную ошибку из `baz.bar()`\n}\ncatch (err) {\n\t// никогда не достигнет этой точки\n}\n```\n\nБыло бы неплохо иметь в арсенале `try..catch`, но он не работает для асинхронных операций. То есть, если только нет какой-то дополнительной поддержки среды, к которой мы вернемся вместе с генераторами в главе 4.\n\nВ колбеках, появились некоторые стандарты для шаблонной обработки ошибок, особенно стиль \"колбек ошибки идет первым\":\n\n```js\nfunction foo(cb) {\n\tsetTimeout( function(){\n\t\ttry {\n\t\t\tvar x = baz.bar();\n\t\t\tcb( null, x ); // успех!\n\t\t}\n\t\tcatch (err) {\n\t\t\tcb( err );\n\t\t}\n\t}, 100 );\n}\n\nfoo( function(err,val){\n\tif (err) {\n\t\tconsole.error( err ); // облом :(\n\t}\n\telse {\n\t\tconsole.log( val );\n\t}\n} );\n```\n\n**Примечание** `try..catch` тут работает только с той точки зрения, что вызов `baz.bar()` немедленно  завершится или прервется со сбоем и при этом синхронно. Если `baz.bar()` сам являлся своей же асинхронной функцией продолжения, то любые асинхронные ошибки внутри него нельзя будет поймать.\n\nКолбек, который мы передаем в `foo(..)`, ожидает получить сигнал об ошибке с помощью зарезервированного первого параметра `err`. Если присутствует, предполагается ошибка. Если нет, то предполагается завершение.\n\nТакой тип обработки ошибок технически *поддерживает асинхронность*, но он совсем не способен к композиции. Множественные уровни колбеков в стиле \"ошибка первая\" сплетенные вместе с этими вездесущими операторами проверок `if` неизбежно приведет вас к опасностям, связанным с адом колбеков (см. главу 2).\n\nТаким образом вы возвращаемся к обработке ошибок с помощью промисов, с передачей обработчика отказов в `then(..)`. Промисы не используют популярный стиль дизайна \"колбек с первым параметром-ошибкой\", а вместо этого используют стиль \"раздельных колбеков\", есть один колбек для завершения и другой - для отказа:\n\n```js\nvar p = Promise.reject( \"Ой\" );\n\np.then(\n\tfunction fulfilled(){\n\t\t// никогда не достигнет этой точки\n\t},\n\tfunction rejected(err){\n\t\tconsole.log( err ); // \"Ой\"\n\t}\n);\n```\n\nНесмотря на то, что этот шаблон обработки ошибок, на первый взгляд, имеет смысл, нюансы обработки ошибок в промисах зачастую гораздо сложнее полностью осознать.\n\nПредставьте:\n\n```js\nvar p = Promise.resolve( 42 );\n\np.then(\n\tfunction fulfilled(msg){\n\t\t// числа не содержат функцией как у строк,\n\t\t// поэтому тут возникнет ошибка\n\t\tconsole.log( msg.toLowerCase() );\n\t},\n\tfunction rejected(err){\n\t\t// никогда не достигнет этой точки\n\t}\n);\n```\n\nЕсли `msg.toLowerCase()` законно выдает ошибку (и это действительно так!), почему же наш обработчик ошибок не вызван? Как мы объясняли ранее, так происходит потому, что *этот* обработчик ошибок - для промиса `p`, который уже был разрешен со значением `42`. Промис `p` - неизменяемый, поэтому единственный промис, который может получить ошибку, тот, что возвращается из `p.then(..)`, который мы в этом случае никак не ловим.\n\nЭто должно дать четкое представление о том, почему обработка ошибок в промисах подвержена ошибкам (каламбур). Слишком легко допустить, чтобы ошибки были \"проглочены\", так как это очень редко то, что вы задумывали изначально.\n\n**Предупреждение:** Если вы используете API промисов неправильным путем и происходит ошибка, то это препятсвует правильному созданию промиса, в результате будет полученное сращу же исключение, но **не отвергнутый промис**. Некоторые примеры некорректного использования, который ломают создание промиса: `new Promise(null)`, `Promise.all()`, `Promise.race(42)`, и т.д.. Вы не сможете получить отвергнутый промис, если вы не используете API промисов достаточно корректно, чтобы на само деле создать в первую очередь сам промис!\n\n### Яма отчаяния\n\nДжефф Этвуд заметил несколько лет назад: языки программирования часто настроены настоены по умолчанию таким образом, что разработчки попадают в \"яму отчаяния\" (http://blog.codinghorror.com/falling-into-the-pit-of-success/), где за инциденты наказывают и что нужно больше стараться, чтобы все получилось. Он призвал нас вместо этого создавать \"яму успеха,\" когда по умолчанию вы попадаете в ожидаемое (успешное) действие, и, следовательно, должны сильно постараться, чтобы потерпеть неудачу.\n\nОбработка ошибок в промисах - несомненно, является дизайном \"ямы отчаяния\". По умолчанию, он предполагает, что вы хотите, чтобы любые ошибки были поглощены состоянием промиса и если вы забудете исследовать этот состояние, ошибка тихо томится/умирает в безвестности, обычно отчаяния.\n\nЧтобы избежать ошибки из-за молчания забытого/заброшенного промиса, некоторые разработчики заявили, что \"лучшей практикой\" для цепочек промисов является всегда завершать цепочку заключительным `catch(..)`, например:\n\n```js\nvar p = Promise.resolve( 42 );\n\np.then(\n\tfunction fulfilled(msg){\n\t\t// числа не содержат функцией как у строк,\n\t\t// поэтому тут возникнет ошибка\n\t\tconsole.log( msg.toLowerCase() );\n\t}\n)\n.catch( handleErrors );\n```\n\nПоскольку мы не передали обработчик отказов в `then(..)`, был подставлен обработчик по умолчанию, который просто передает ошибку следующему промису в цепочке. Таким образом, обе ошибки, идущие в `p`, и ошибки, которые появляются *после* `p` в его разрешении (как в `msg.toLowerCase()`) будут отфильтрованы до конечного `handleErrors(..)`.\n\nПроблема решена, не так ли? Не так быстро!\n\nЧто случится, если `handleErrors(..)` сам содержит ошибку? Кто отловит ее? Остался еще один невыполненный промис: тот, который возвращает `catch(..)`, который мы не ловим и не регистрируем обработчик отказа для него.\n\nВы не можете просто приклеить другой `catch(..)` в конец этой цепочки, потому что он тоже может завершиться ошибкой. Последний шаг в любой цепочек промисов, какой бы он ни был, всегда будет содержать возможность, хоть и в меньшей степени, зависнуть с непойманной ошибкой, застрявшей внутри  неотслеживаемого промиса.\n\nВсе еще звучит как невыполнимая головоломка?\n\n### Обработка непойманного\n\nЭту проблему нелегко решить полностью. Есть и другие способы достичь этого, которые, по мнению многих, являются *лучшими*.\n\nНекоторые промис-библиотеки добавили методы для регистрации чего-то подобного \"глобальному обработчику необработанных отказов\", который бы вызывался вместо глобального выброса ошибки. Но их решение о том, как определить ошибку как \"непойманную\" - это иметь таймер произвольной длительности, скажем 3 секунды, запускаемый от момента отказа. Если промис отвергнут, но не было зарегистрировано ни одного обработчика ошибок до того, как будет запушен таймер, то предполагается, что вы будто и не регистрировали ни одного обработчика, поэтому ошибка \"не поймана\".\n\nНа практике, это хорошо работает для многих библиотек, поскольку большинство использованных подходов  как правило не требуют значительной задержки между отказом промиса и началом наблюдения за ним. Но этот шаблон вызывает проблемы, потому что 3 секунды это очень произвольное время (пусть даже эмпирическое), а также потому, что действительно есть случаи когда вы хотите придержать отказ промиса на некоторый неопределенный период времени и вы на самом деле не хотите, чтобы ваш обработчик \"непойманного\" вызывался для всех этих ложных срабатываний (еще не обработанные \"непойманные ошибки\").\n\nДругое более распространенное предложение заключается в том, что к промисам нужно добавить `done(..)`, что, по сути, отмечает цепочку промисов как \"выполненную\" (done). `done(..)` не создает и не возвращает промис, таким образом колбеки, переданные в `done(..)`, очевидно не подключены для извещения о проблемах в промис в цепочке, который не существует.\n\nИтак, что происходит вместо этого? Она обрабатывается так, как вы обычно ожидаете в условиях не пойманной ошибки: любое исключение внутри обработчика отказа `done(..)` будет выброшено как глобальная непойманная ошибка (в консоль разработчика, по сути):\n\n```js\nvar p = Promise.resolve( 42 );\n\np.then(\n\tfunction fulfilled(msg){\n\t\t// у чисел нет функций как у строк,\n\t\t// поэтому будет выброшена ошибка\n\t\tconsole.log( msg.toLowerCase() );\n\t}\n)\n.done( null, handleErrors );\n\n// если `handleErrors(..)` породила свое собственное исключение, оно\n// будет выброшено тут как глобальное\n```\n\nЭто может показаться более привлекательным, чем бесконечная цепочка или произвольные тайм-ауты. Но самая большая проблема заключается в том, что это не является частью стандарта ES6, поэтому, как бы хорошо это ни звучало, в лучшем случае это еще долго не будет надежным и повсеместным решением.\n\nНеужели мы просто застряли? Не совсем.\n\nБраузеры имеют уникальную возможность, которой нет у нашего кода: они могут отслеживать и точно знать, когда любой объект становится ненужным и собирается сборщиком мусора. Таким образом, браузеры могут отслеживать объекты промисов и всякий раз, когда их собирает сборщик мусора, если они содержат отказ, браузер точно знает, что это была допустимая \"непойманная ошибка\", и поэтому может с уверенностью утверждать, что должен сообщить о ней в консоль разработчика.\n\n**Примечание** На момент написания этой статьи, в обоих Chrome и Firefox есть ранние ранние попытки такого рода возможности \"непойманный отказ\", хотя поддержка в лучшем случае неполная.\n\nОднако, если промис не был собран сборщиком мусора, что очень легко сделать случайно с помощью множества различных шаблонов разработки, осведомленность сборщика мусора браузера не поможет вам  узнать и диагностировать, что у вас есть молча отвергнутый промис, находящийся рядом.\n\nЕсть ли другие альтернативы? Да.\n\n### Яма успеха\n\nНижеследующее является лишь теоретическим, как промисы *могли бы* однажды изменить свое поведение. Я верю, что Я уверен, что это будет намного лучше, чем то, что мы имеем сейчас. И я думаю, что это изменение будет возможно даже в пост-ES6, потому что я не думаю, что это нарушит совместимость с ES6 промисами. Более того, это можно превратить в полифил, если вы будете осторожны. Давайте взглянем:\n\n* Промисы могут по умолчанию сообщать (в консоль разработчика) о любом отказе в следующей задаче или тике цикла событий, если в этот момент для промиса не был зарегистрирован обработчик ошибок.\n* Для случаев, когда вы хотите удерживать отвергнутый промис в таком состоянии на бесконечное количество времени до начала наблюдения за ним, вы могли бы вызвать `defer()`, который подавляет автоматическое уведомление об ошибках в этом промисе.\n\nЕсли промис отвергнут, по умолчанию он шумно сообщает об этом факте в консоль разработчика (вместо тишины по умолчанию). Вы можете отказаться от такой информации, либо неявно (зарегистрировав обработчик ошибок до отказа), или явно (с помощью `defer()`). В любом случае, *вы* управляете ложными срабатываниями.\n\nРассмотрим:\n\n```js\nvar p = Promise.reject( \"Ой\" ).defer();\n\n// `foo(..)` промисоподобная\nfoo( 42 )\n.then(\n\tfunction fulfilled(){\n\t\treturn p;\n\t},\n\tfunction rejected(err){\n\t\t// обработка ошибок в `foo(..)`\n\t}\n);\n...\n```\n\nКогда мы создаем `p`, мы знаем, что мы собираемся подождать некоторое время, чтобы использовать/наблюдать за его отказом, поэтому мы вызываем `defer()` - таким образом, отсутствует глобальная отчетность. `defer()` просто возвращает тот же промис для возможности выстраивания цепочки.\n\nПромис, возвращенный из `foo(..)`, получает обработчик ошибок, привязанный *сразу же*, поэтому она выходит \"из игры\" и никакой глобальной отчетности по этому поводу также не ведется.\n\nА вот у промиса, возвращенного из вызова `then(..)`, нет ни `defer()`, ни присоединенного обработчика ошибок, поэтому если он завершается отказом (изнутри любого обработчика разрешения), то *он* будет сообщен в консоль разработчика как не пойманная ошибка.\n\n**\"Этот подход\" - яма успеха.** По умолчанию, все ошибки либо обрабатываются, либо о них получаются уведомления, то, что почти все разработчики в почти всех случаях ожидали бы. Вы либо должны зарегистрировать обработчик, либо вы должны намеренно отказаться и указать, что вы намерены отложить обработку ошибок на *попозже*, вы берете дополнительную ответственность только в этом конкретном случае.\n\nЕдинственная реальная опасность в этом подходе - если вы отложите (`defer()`) промис, а затем не сможете на деле вообще наблюдать/обработать его отказ.\n\nНо вы должны были намеренно вызвать `defer()`, чтобы опуститься в эту яму отчаяния, изначально была яма успеха, поэтому мы мало что можем сделать, чтобы спасти вас от ваших собственных ошибок.\n\nЯ думаю, что все еще есть надежда на обработку ошибок промисов (пост-ES6). Я надеюсь, что власть предержащие переосмыслят ситуацию и рассмотрят эту альтернативу. Тем временем, вы можете реализовать это сами (непростое упражнение для читателя!) или использовать *более умную* библиотеку промисов, которая сделает это за вас!\n\n**Примечание** Эта конкретная модель обработки ошибок/сообщений реализована в моей библиотеке абстракций над промисами *asynquence*, которую обсудим в приложении A этой книги.\n\n## Шаблоны промисов\n\nМы уже увидено неявно шаблон последовательности в цепочках промисов (управление потоком это-затем-это-затем-то), но существует множество вариаций асинхронных шаблонов, которые мы можем построить как абстракции над промисами. Этим шаблоны служат для упрощения выражения асинхронного управления потоком, который помогает сделать наш код более более разумным и более поддерживаемым, даже в самых сложных частях наших программ.\n\nДва таких шаблона кодируются непосредственно в нативную реализацию ES6 `Promise`, так что мы получаем их бесплатно, чтобы использовать как строительные блоки для других шаблонов.\n\n### Promise.all([ .. ])\n\nВ асинхронной последовательности (цепочке промисов) только одна асинхронная задача координируется в любой момент времени, шаг 2 строго следует за шагом 1, а шаг 3 строго следует за шагом 2. А как насчет выполнения двух и более шагов одновременно (т.е. \"параллельно\")?\n\nВ классической терминологии программирования, \"шлюз\" - это механизм, который ожидает завершения двух или более параллельных/ одновременных задач, прежде чем продолжить работу. Не важно в каком порядке они завершатся, а важно только, что все они должны завершиться чтобы открыть шлюз и позволить потоку управлению потоком идти дальше.\n\nВ API промисов, мы называем этот шаблон `all([ .. ])`.\n\nСкажем вы хотели сделать два Ajax-запроса в одно и то же время и дождаться окончания обоих, независимо от их порядка, до выполнения третьего Ajax-запроса. Рассмотрим:\n\n```js\n// `request(..)` - промис-совместимая Ajax-функция,\n// примерно как та, что мы определяли ранее в главе\n\nvar p1 = request( \"http://some.url.1/\" );\nvar p2 = request( \"http://some.url.2/\" );\n\nPromise.all( [p1,p2] )\n.then( function(msgs){\n\t// оба `p1` and `p2` завершатся успешно и передадут\n\t// свои сообщения сюда\n\treturn request(\n\t\t\"http://some.url.3/?v=\" + msgs.join(\",\")\n\t);\n} )\n.then( function(msg){\n\tconsole.log( msg );\n} );\n```\n\n`Promise.all([ .. ])` ожидает один аргумент, `массив`, состоящий состоящий в целом из экземпляров промисов. Промис, возвращенный из вызова `Promise.all([ .. ])`, получит сообщение о завершении (`msgs` в этом примере кода), которое является `массивом` всех сообщений о завершении от переданных промисов, в том же порядке как они были переданы (независимо от порядка завершения).\n\n**Примечание** Технически, `массив` значений, переданный в `Promise.all([ .. ])`, может содержать промисы, then-содержащие или даже непосредственные значения. Каждое значение в списке по сути, проходит через `Promise.resolve(..)`, чтобы убедиться, что ожидается настоящий промис, таким образом непосредственное значение будет просто приведено в промис для этого значения. Если `массив` пустой, основной промис немедленно завершается.\n\nОсновной промис, возвращенный из `Promise.all([ .. ])`, будет завершен только тогда и если  все входящие в него промисы будут завершены. Если любой из этих промисов вместо этого отвергается, основной промис `Promise.all([ .. ])` сразу же отвергается, отбрасывая все результаты любых других промисов.\n\nПомните о том, чтобы всегда присоединять обработчик отказа/ошибки к каждому промису, даже и особенно к тому, который возвращается из `Promise.all([ .. ])`.\n\n### Promise.race([ .. ])\n\nВ то время как `Promise.all([ .. ])` координирует несколько обещаний одновременно и предполагает,  что все они нужны для завершения, иногда вы хотите всего лишь получить ответ от \"первого же промиса, пересекшего финишную линию\", позволяя других промисам отпасть за ненадобностью.\n\nЭтот шаблон классически называют \"задвижка\" (latch), но в промисах он называется \"гонка\" (race).\n\n**Предупреждение:** В то время как метафора \"только первый, пересёкший финишную черту, выигрывает\" хорошо соответствует поведению, к сожалению \"гонка\" - это своего рода нагруженный термин, потому что \"состояния гонки\" - обычно воспринимаются как ошибки в программах (см. главу 1). Не путайте `Promise.race([ .. ])` с \"состоянием гонки\" (race condition).\n\n`Promise.race([ .. ])` также ожидает единственный аргумент в виде `массива`, содержащий один или более промисов, then-содержащих или непосредственных значений. Не имеет большого практического смысла иметь гонку с непосредственными значениями, потому что первое перечисленное значение очевидно выиграет, как в беге, где один бегун стартует с финиша!\n\nАналогично `Promise.all([ .. ])`, `Promise.race([ .. ])` завершится если и тогда, когда любое из разрешений промисов - успешное, и завершится отказом если и тогда, когда любое из разрешений промисов - это отказ.\n\n**Предупреждение:** \"гонка\" требует по меньшей мере одного \"бегуна\", поэтому если вы передадите пустой `массив`, вместо немедленно разрешения, основной промис `race([..])` никогда не будет разрешен. Это программные \"грабли\"! ES6 должен был указать, что он либо выполняет, либо отклоняет, либо просто выбрасывает какую-то синхронную ошибку. К сожалению, из-за прецедента в библиотеках промисов, предшествующих ES6 `Promise`, им пришлось оставить эту недоработку, поэтому будьте осторожны и никогда не отправляйте пустой `массив`.\n\nДавайте вернемся к нашему предыдущему примеру с параллельным Ajax, но в контексте гонки между `p1` и `p2`:\n\n```js\n// `request(..)` - это промис-совместимая функция,\n// подобно той, что мы ранее определили в этой главе\n\nvar p1 = request( \"http://some.url.1/\" );\nvar p2 = request( \"http://some.url.2/\" );\n\nPromise.race( [p1,p2] )\n.then( function(msg){\n\t// либо `p1`, либо `p2` выиграет гонку\n\treturn request(\n\t\t\"http://some.url.3/?v=\" + msg\n\t);\n} )\n.then( function(msg){\n\tconsole.log( msg );\n} );\n```\n\nПоскольку побеждает только один промис, значение завершения - это одно сообщение, а не  `массив`, как это было в `Promise.all([ .. ])`.\n\n#### Гонка тайм-аутов\n\nМы видели этот пример ранее, иллюстрирующий как `Promise.race([ .. ])` может использоваться для выражения шаблона \"тайм-аут промиса\":\n\n```js\n// `foo()` - функция, поддерживающая промисы\n\n// `timeoutPromise(..)`, определенный ранее, аозвращает\n// промис, который завершается отказом rejects после указанной задержки\n\n// настроить тайм-аут для `foo()`\nPromise.race( [\n\tfoo(),\t\t\t\t\t// попробовать вызвать `foo()`\n\ttimeoutPromise( 3000 )\t// дать ему 3 секунды\n] )\n.then(\n\tfunction(){\n\t\t// `foo(..)` завершилась успешно и вовремя!\n\t},\n\tfunction(err){\n\t\t// либо `foo()` завершился отказом, либо просто\n\t\t// не успеет завершиться вовремя, поэтому загляните в\n\t\t// `err`, чтобы узнать причину\n\t}\n);\n```\n\nЭтот шаблон тайм-аута работает в большинстве случаев. Но есть некоторые нюансы, которые необходимо учитывать, и, честно говоря, они применимы к обоим `Promise.race([ .. ])` и `Promise.all([ .. ])` в равной степени.\n\n#### \"Finally\"\n\nКлючевой вопрос, который необходимо задать: \"Что происходит  с промисами, который который отбрасываются/игнорируются?\" Мы задаем этот вопрос не с точки зрения производительности, они, как правило, попадают в сборку мусора как подходящие кандидаты для этого, а с поведенческий аспекта (побочные эффекты и т.д.). Промисы нельзя отменить, и не должны бы, поскольку это разрушит доверие к внешней неизменяемости, обсуждаемой в секции \"Промис неотменяемый\" позже в этой главе, поэтому их можно только молча игнорировать.\n\nНо что если `foo()` из предыдущего примера резервирует какой-то ресурс для использования, но первым срабатывает тайм-аут и приводит к тому, что этот промис игнорируется? Есть ли в этом шаблоне что-нибудь, что с упреждением освобождает зарезервированный ресурс после истечения тайм-аута или иным образом отменяет любые побочные эффекты, которые он мог иметь? Что если всё, что вы хотели - это зафиксировать факт того, что `foo()` завершился по тайм-ауту?\n\nНекоторые разработчики предлагают, что промису нужна регистрация колбека `finally(..)`, который вызывается всегда, когда промис разрешен, и позволяет вам и позволяет вам указать любую очистку, которая может потребоваться. На текущий момент такого нет в спецификации, но может появиться в ES7+. Подождем и посмотрим.\n\nЭто может выглядеть так:\n\n```js\nvar p = Promise.resolve( 42 );\n\np.then( something )\n.finally( cleanup )\n.then( another )\n.finally( cleanup );\n```\n\n**Примечание** В различных промис-библиотеках `finally(..)` все еще создает и возвращает новый промис (чтобы продолжать цепочку). Если бы функция `cleanup(..)` возвращала промис, его можно было бы соединить в цепочку, что означает, что у вас все еще могли бы быть проблемы с неразрешенными отказами, которые мы ранее обсуждали.\n\nТем временем, мы могли бы создать статическую вспомогательную функцию, которая позволит нам наблюдать (без вмешательства) за разрешением промиса:\n\n```js\n// защитная проверка в стиле безопасного полифила\nif (!Promise.observe) {\n\tPromise.observe = function(pr,cb) {\n\t\t// стороннее наблюдение за разрешением  `pr`\n\t\tpr.then(\n\t\t\tfunction fulfilled(msg){\n\t\t\t\t// запланировать колбек асинхронно (в виде задачи)\n\t\t\t\tPromise.resolve( msg ).then( cb );\n\t\t\t},\n\t\t\tfunction rejected(err){\n\t\t\t\t// запланировать колбек асинхронно (в виде задачи)\n\t\t\t\tPromise.resolve( err ).then( cb );\n\t\t\t}\n\t\t);\n\n\t\t// вернуть оригинальный промис\n\t\treturn pr;\n\t};\n}\n```\n\nВот как мы используем его в предыдущем примере с тайм-аутом:\n\n```js\nPromise.race( [\n\tPromise.observe(\n\t\tfoo(),\t\t\t\t\t// попытка вызова `foo()`\n\t\tfunction cleanup(msg){\n\t\t\t// почистить за `foo()`, даже если она\n\t\t\t// не завершилась после тайм-аута\n\t\t}\n\t),\n\ttimeoutPromise( 3000 )\t// дать функции тайм-аут в 3 секунды\n] )\n```\n\nЭто вспомогательная функция `Promise.observe(..)` - просто иллюстрация того, как вы могли бы наблюдать за завершениями промисов без вмешательства в них. В других библиотеках промисов есть свои собственные решения. Независимо от того, как вы это сделаете, скорее всего, у вас будут места, где вы захотите убедиться, что ваши промисы не будут *просто* молча проигнорированы случайно.\n\n### Вариации на тему all([ .. ]) и race([ .. ])\n\nВ то время как нативные ES6 промисы идут со встроенными `Promise.all([ .. ])` и `Promise.race([ .. ])`, есть несколько других часто используемых паттернов с вариациями этой семантики:\n\n* `none([ .. ])` похож на `all([ .. ])`, но завершения и отказы меняются местами. Все промисы должны быть отвергнуты, отказы становятся значениями завершения, а значения завершения - наоборот.\n* `any([ .. ])` похож на `all([ .. ])`, но она игнорирует любые отказы, поэтому нужно выполнить только один, а не *все*.\n* `first([ .. ])` похож на гонку в сочетании с `any([ .. ])`, которая заключается в том, что она игнорирует любые отказы и завершается, как только завершается первый промис.\n* `last([ .. ])` похож на `first([ .. ])`, но только побеждает самое последнее завершение.\n\nНекоторые библиотеки абстракций над промисами обеспечивают такие функции, но вы также можете определить из сами использую механизмы промисов, `race([ .. ])` и `all([ .. ])`.\n\nНапример, вот как мы могли бы определить `first([ .. ])`:\n\n```js\n// защитная проверка в стиле безопасного полифила\nif (!Promise.first) {\n\tPromise.first = function(prs) {\n\t\treturn new Promise( function(resolve,reject){\n\t\t\t// цикл по всем промисам\n\t\t\tprs.forEach( function(pr){\n\t\t\t\t// нормализовать значение\n\t\t\t\tPromise.resolve( pr )\n\t\t\t\t// кто завершится первым, тот и победил, и\n\t\t\t\t// приводит к разрешению основного промиса\n\t\t\t\t.then( resolve );\n\t\t\t} );\n\t\t} );\n\t};\n}\n```\n\n**Примечание** Такая реализация `first(..)` не завершается отказом если все ее промисы завершаются отказом; она просто зависает, подобно тому, как работает `Promise.race([])`. При необходимости, вы могли бы добавить дополнительную логику для отслеживания каждого отказа промисов и если все они отвергнуты, вызвать `reject()` для основного промиса. Оставим это как упражнение для читателя.\n\n### Одновременные итерации\n\nИногда вы хотите проходить по списку промисов и выполнить некоторую задачу для них всех, так же, как это можно сделать с синхронными `array`s (например, `forEach(..)`, `map(..)`, `some(..)`, and `every(..)`). Если задача, которую нужно выполнить по отношению к каждому промису, является принципиально синхронной, это отлично работает, точно так же, как мы использовали `forEach(..)` в предыдущем отрывке кода.\n\nНо если задачи принципиально асинхронные или могут/должны в противном случае выполняться одновременно, вы можете воспользоваться асинхронными версиями этих функций, предоставляемых многими библиотеками.\n\nНапример, давайте рассмотрим асинхронную функцию `map(..)`, которая принимает `массив` значений (могут быть промисами или чем-то еще), плюс функцию (задачу), для выполнения над каждым значением. `map(..)` сам по себе возвращает промис, чье значение завершения - `массив`, который хранит (в том же порядке) асинхронное значение завершения из каждой задачи:\n\n```js\nif (!Promise.map) {\n\tPromise.map = function(vals,cb) {\n\t\t// новый промис, который ждет все сопоставленные промисы\n\t\treturn Promise.all(\n\t\t\t// примечание: обычная функция массива `map(..)`, превращает\n\t\t\t// массив значений в массив промисов\n\t\t\tvals.map( function(val){\n\t\t\t\t// заменить `val` новым промисом, который\n\t\t\t\t// разрешается после того, как `val` асинхронно отмаплена\n\t\t\t\treturn new Promise( function(resolve){\n\t\t\t\t\tcb( val, resolve );\n\t\t\t\t} );\n\t\t\t} )\n\t\t);\n\t};\n}\n```\n\n**Примечание** В этой реализации `map(..)` вы не можете сигнализировать об асинхронном отказе, но если происходит синхронное исключение/ошибка внутри колбека маппинга (`cb(..)`), основной промис, возвращающийся из the main `Promise.map(..)` будет отвергнут.\n\nДавайте проиллюстрируем использование `map(..)` со списком промисов (вместо простых значений):\n\n```js\nvar p1 = Promise.resolve( 21 );\nvar p2 = Promise.resolve( 42 );\nvar p3 = Promise.reject( \"Ой\" );\n\n// удвоить значения в списке, даже если они в промисах\nPromise.map( [p1,p2,p3], function(pr,done){\n\t// убедиться, что само значение - это промис\n\tPromise.resolve( pr )\n\t.then(\n\t\t// извлечь значение как `v`\n\t\tfunction(v){\n\t\t\t// отмапить значение завершения `v` в новое значение\n\t\t\tdone( v * 2 );\n\t\t},\n\t\t// или отмапить в сообщение отказа промиса\n\t\tdone\n\t);\n} )\n.then( function(vals){\n\tconsole.log( vals );\t// [42,84,\"Ой\"]\n} );\n```\n\n## Обзор API промисов\n\nДавайте проведем обзор ES6 `Promise` API,  которые мы уже в какой-то степени наблюдали в этой главе.\n\n**Примечание** Следующий API является нативным только в ES6, но есть полифилы, совместимые со спецификацией (а не просто расширенные библиотеки промисов), которые могут определить `Promise` и все связанное с ним поведение, так что вы можете использовать нативные промисы даже в до-ES6 браузерах. Один такой полифил - это \"Native Promise Only\" (http://github.com/getify/native-promise-only), который написал я!\n\n### Конструктор new Promise(..)\n\n*Доступный конструктор* `Promise(..)` должен использоваться с `new` и в него нужно передать колбек-функцию, которая вызывается синхронно/немедленно. Это функция передается в в два колбека, которые действуют как возможности для разрешения промиса. Мы обычно называем их `resolve(..)` и `reject(..)`:\n\n```js\nvar p = new Promise( function(resolve,reject){\n\t// `resolve(..)` чтобы разрешить/завершить промис\n\t// `reject(..)` чтобы отвергнуть промис\n} );\n```\n\n`reject(..)` просто отвергает промис, а `resolve(..)` может либо завершить промис или отвергнуть его, в зависимости от того, что передано на вход. Если в `resolve(..)` передано непосредственное, не-промис, не-then-содержащее значение, то промис завершается с этим значением.\n\nНо если в `resolve(..)` передается настоящий промис или then-содержащее значение, то это значение будет рекурсивно распаковано, и какое бы ни было его окончательное разрешение/состояние - оно будет принято промисом.\n\n### Promise.resolve(..) и Promise.reject(..)\n\nКраткий вариант для создания уже отвергнутого  промиса - `Promise.reject(..)`, таким образом эти два промиса равнозначны:\n\n```js\nvar p1 = new Promise( function(resolve,reject){\n\treject( \"Ой\" );\n} );\n\nvar p2 = Promise.reject( \"Ой\" );\n```\n\n`Promise.resolve(..)` обычно используется для создания уже завершенного промиса примерно также как `Promise.reject(..)`. Однако, `Promise.resolve(..)` также распаковывает then-содержащие значения (как уже неоднократно обсуждалось). В этом случае, возвращенный промис принимает окончательное разрешение then-содержащего, которое вы передали, которое может быть либо завершением, либо отказом:\n\n```js\nvar fulfilledTh = {\n\tthen: function(cb) { cb( 42 ); }\n};\nvar rejectedTh = {\n\tthen: function(cb,errCb) {\n\t\terrCb( \"Ой\" );\n\t}\n};\n\nvar p1 = Promise.resolve( fulfilledTh );\nvar p2 = Promise.resolve( rejectedTh );\n\n// `p1` станет завершенным промисом\n// `p2` станет отвергнутым промисом\n```\n\nИ помните, `Promise.resolve(..)` ничего не дает, если то, что вы передаете ему, является настоящим промисом, она просто непосредственно вернет это значение. Поэтому нет никаких затрат на вызов `Promise.resolve(..)` со значениями чью природу вы не знаете, если они уже оказались настоящими промисами.\n\n### then(..) и catch(..)\n\nКаждый экземпляр промиса (но **не** пространства имен `Promise` API) содержит методы `then(..)` и `catch(..)`, которые позволяют зарегистрировать обработчики завершения и отказа для этого промиса. Как только промис разрешен, будет вызван один из этих обработчиков, но не оба, и он всегда будет вызваться асинхронно (см. \"Задачи\" в главе 1).\n\n`then(..)` принимает один или два параметра, первый - для колбека завершения, а второй - для колбека отказа. Если какой-либо из параметров будет опущен или будет передано значение не-функция, то подставляется колбек по умолчанию соответственно. Колбек завершения по умолчанию просто передает сообщение дальше, в то время как колбек отказа по умолчанию просто заново выбрасывает (распространяет дальше) полученную причину ошибки (propagates).\n\n`catch(..)` принимает только колбека отказа как параметр и автоматически подставляет обработчик завершения по умолчанию, как только что упоминалось. Другими словами, это - эквивалент `then(null,..)`:\n\n```js\np.then( fulfilled );\n\np.then( fulfilled, rejected );\n\np.catch( rejected ); // или `p.then( null, rejected )`\n```\n\n`then(..)` и `catch(..)` также создают и возвращают новый промис, который можно использовать для выражения управления потоком цепочки промисов. Если у колбеков завершения или отказа уже есть выброшенное исключение, то возвращаемый промис будет отвергнут. Если какой-либо из колбеков вернет непосредственное, не-промис, не-then-содержащее значение, то это значение будет установлено  как завершение возвращенного промиса. Если обработчик завершения специально возвращает промис или then-содержащее значение, то это значение распаковывается и становится разрешением возвращенного промиса.\n\n### Promise.all([ .. ]) и Promise.race([ .. ])\n\nСтатические вспомогательные функции `Promise.all([ .. ])` и `Promise.race([ .. ])` в ES6 `Promise` API обе создают промис как свое возвращаемое значение. Разрешение этого промиса целиком управляется массивом промисов, который вы передаете на вход.\n\nДля `Promise.all([ .. ])` все промисы, которые вы передаете, должны завершиться, чтобы возвращаемый промис также завершился. Если какой-либо из промисов будет отвергнут, главный возвращаемый промис  будет также немедленно отвергнут (отбрасывая результаты любых других промисов). При завершении вы получаете `массив` всех переданных в промисы значений завершения. При отказе, вы получаете только значение причины отказа первого промиса. Этот шаблон классически называется \"шлюз (gate)\": все должны прибыть до того, как откроется шлюз.\n\nДля `Promise.race([ .. ])`, только первый промис с разрешением (завершение или отказ) \"выигрывает\", и какое бы ни было его разрешение, оно и становится разрешением возвращаемого промиса. Этот шаблон классически называется \"задвижка (latch)\": первый, кто откроет задвижку - проходит. Представьте:\n\n```js\nvar p1 = Promise.resolve( 42 );\nvar p2 = Promise.resolve( \"Привет, мир\" );\nvar p3 = Promise.reject( \"Ой\" );\n\nPromise.race( [p1,p2,p3] )\n.then( function(msg){\n\tconsole.log( msg );\t\t// 42\n} );\n\nPromise.all( [p1,p2,p3] )\n.catch( function(err){\n\tconsole.error( err );\t// \"Ой\"\n} );\n\nPromise.all( [p1,p2] )\n.then( function(msgs){\n\tconsole.log( msgs );\t// [42,\"Привет, мир\"]\n} );\n```\n\n**Предупреждение:** Будьте осторожны! Если в `Promise.all([ .. ])` будет передает пустой массив, то функция завершится немедленно, а вот `Promise.race([ .. ])` повиснет навсегда и никогда не разрешится.\n\nES6 `Promise` API довольно простое и понятное. Оно, по крайней мере, достаточно хорош, чтобы обслуживать самые простые случаи асинхронной работы и это хорошее место для начала перестройки вашего кода из ада колбеков в нечто лучшее.\n\nНо существует целый ряд асинхронных сложностей, которые часто требуются приложениям и для которых промисы сами по себе будут ограничены в решении. В следующем разделе мы погрузимся в эти ограничения как мотивацию для создания библиотек промисов.\n\n## Ограничения промисов\n\nМногие детали, которые мы обсудим в этом разделе, уже упоминались в этой главе, но мы просто рассмотрим эти ограничения отдельно.\n\n### Обработка ошибок последовательностей\n\nМы подробно рассмотрели обработку ошибок с помощью промисов в начале этой главы. Ограничения в том, как разработаны промисы, в частности, как они связываются в цепочки, создают очень легкую ловушку, когда ошибка в цепочке промисов может быть молча проигнорирована случайно.\n\nНо есть еще кое-что, что следует учитывать с ошибками промисов. Поскольку цепочка промисов - это не что иное, как входящие в нее промисы, соединенные вместе, нет никакой сущности, чтобы ссылаться на всю цепочку как на единое *нечто*, что означает, что нет внешнего способа наблюдения за возможными ошибками.\n\nЕсли вы конструируете цепочку промисов, в которой нет обработки ошибок, любая ошибка где бы то ни было в цепочке будет распространяться бесконечно вниз по цепочке, пока не будет замечена (регистрацией обработчика отказов на каком-либо шаге). Так что, в этом конкретном случае, иметь ссылку на *последний* промис в цепочке будет достаточно (`p` в последующем примере кода), потому что вы можете зарегистрировать там обработчик отказов, и он будет уведомлен о любых распространяемых ошибках:\n\n```js\n// `foo(..)`, `STEP2(..)` и `STEP3(..)` -\n// обе функции поддерживают промисы\n\nvar p = foo( 42 )\n.then( STEP2 )\n.then( STEP3 );\n```\n\nХотя это может показаться хитрым и запутанным, `p` здесь не указывает на первый промис в цепочке (тот, что получен из вызова `foo(42)`), а вместо этого из последнего промиса, того, который возвращается из вызова `then(STEP3)`.\n\nКроме того, ни один шаг в цепочке промисов не выполняет собственную обработку ошибок. Это означает, что вы могли бы зарегистрировать обработчик ошибок отказа для `p` и он получит уведомление если возникнет какая-нибудь ошибка в цепочке:\n\n```\np.catch( handleErrors );\n```\n\nНо если любой этап цепочки фактически выполняет собственную обработку ошибок (возможно скрыто/абстрагировано от того, что вы можете увидеть), ваш `handleErrors(..)` не получит уведомлений. Возможно это и будет то, что вы хотите, это же был, в конце концов, \"обработанный отказ\", но это также может и *не* быть тем, что вы хотели. Полное отсутствие возможности получать уведомления (об \"уже обработанных\" ошибках отказа) является ограничением, которое сужает возможности в некоторых сценариях использования.\n\nПо сути, это то же самое ограничение, которое существует для блока `try..catch`, который может поймать исключение и просто проглотить его. Таким образом, это не является ограничением **специфичным для промисов**, но это *то*, для чего мы могли бы захотеть наличия обходного пути.\n\nК сожалению, во многих случаях не сохраняются ссылки на промежуточные шаги в последовательности цепочки промисов, поэтому без таких ссылок вы не сможете подключить обработчики ошибок для надежного наблюдения за ошибками.\n\n### Единственное значение\n\nУ промисов по определению есть только одно значение завершения или одна причина отказа. В простых примерах, это не так уж и важно, но в более сложных сценариях вы можете счесть это ограничением.\n\nТипичный совет - создать обертку для значений (такую как `объект` или `массив`), чтобы хранить эти многочисленные сообщения. Это решение работает, но это может быть довольно неудобно и утомительно - упаковывать и распаковывать ваши сообщения на каждом шаге вашей цепочки промисов.\n\n#### Разделение значений\n\nИногда вы можете воспринять это как сигнал о том, что вы можете/должны разложить проблему на два или более промисов.\n\nПредставьте, что у вас есть функция `foo(..)`, которая обеспечивает два значения (`x` и `y`) асинхронно:\n\n```js\nfunction getY(x) {\n\treturn new Promise( function(resolve,reject){\n\t\tsetTimeout( function(){\n\t\t\tresolve( (3 * x) - 1 );\n\t\t}, 100 );\n\t} );\n}\n\nfunction foo(bar,baz) {\n\tvar x = bar * baz;\n\n\treturn getY( x )\n\t.then( function(y){\n\t\t// упаковать оба значения в контейнер\n\t\treturn [x,y];\n\t} );\n}\n\nfoo( 10, 20 )\n.then( function(msgs){\n\tvar x = msgs[0];\n\tvar y = msgs[1];\n\n\tconsole.log( x, y );\t// 200 599\n} );\n```\n\nСперва, давайте переставим то. что возвращает `foo(..)` чтобы нам не пришлось упаковывать `x` и `y` в единственное значение `массива`, чтобы для передачи через один промис. Вместо этого мы можем обернуть кажое значение в свой собственный промис:\n\n```js\nfunction foo(bar,baz) {\n\tvar x = bar * baz;\n\n\t// вернуть оба промиса\n\treturn [\n\t\tPromise.resolve( x ),\n\t\tgetY( x )\n\t];\n}\n\nPromise.all(\n\tfoo( 10, 20 )\n)\n.then( function(msgs){\n\tvar x = msgs[0];\n\tvar y = msgs[1];\n\n\tconsole.log( x, y );\n} );\n```\n\nДействительно ли `массив` промисов лучше, чем `массив` значений, переданных через один промис? Синтаксически это не является большим улучшением.\n\nНо этот подход больше отвечает теории дизайна промисов. Теперь легче в будущем рефакторить, чтобы разделить вычисление `x` и `y` на отдельные функции. Это Гораздо чище и гибче позволить вызывающему коду решать, как согласовать эти два промиса используя тут `Promise.all([ .. ])`, но, конечно, не единственный вариант, а не абстрагироваться от таких деталей внутри `foo(..)`.\n\n#### Распаковка/разбиение аргументов\n\nПрисвоения `var x = ..` и `var y = ..` - все еще неудобные накладные расходы. Мы можем использовать некоторые функциональные хитрости (благодарим за предоставленную информацию Реджинальда Брейтуэйта (Reginald Braithwaite), @raganwald в твиттере) во вспомогательной функции:\n\n```js\nfunction spread(fn) {\n\treturn Function.apply.bind( fn, null );\n}\n\nPromise.all(\n\tfoo( 10, 20 )\n)\n.then(\n\tspread( function(x,y){\n\t\tconsole.log( x, y );\t// 200 599\n\t} )\n)\n```\n\nЭто немного лучше! Конечно, вы можете встроить функциональную магию, чтобы избежать дополнительную функцию:\n\n```js\nPromise.all(\n\tfoo( 10, 20 )\n)\n.then( Function.apply.bind(\n\tfunction(x,y){\n\t\tconsole.log( x, y );\t// 200 599\n\t},\n\tnull\n) );\n```\n\nЭти трюки могут быть простыми, но у ES6 есть еще более лучший ответ для нас: деструктуризация. Форма присвоения с деструктуризацией массива выглядит как-то так:\n\n```js\nPromise.all(\n\tfoo( 10, 20 )\n)\n.then( function(msgs){\n\tvar [x,y] = msgs;\n\n\tconsole.log( x, y );\t// 200 599\n} );\n```\n\nНо лучше всего, ES6 предлагает формат деструктуризации параметра-массива:\n\n```js\nPromise.all(\n\tfoo( 10, 20 )\n)\n.then( function([x,y]){\n\tconsole.log( x, y );\t// 200 599\n} );\n```\n\nТеперь мы придерживаемся мантры \"одно значение на промис\", но сократили до минимума наш вспомогательный шаблон!\n\n**Примечание** Для получения дополнительной информации о форматах деструктуризации в ES6 см. книгу *За пределами ES6* этой серии.\n\n### Единственное разрешение\n\nОдним из наиболее характерных свойств промисов является то, что промис может быть разрешен только один раз (завершение или отказ). Для многих случаев использования асинхронного кода, вы получаете значение только один раз, поэтому это работает прекрасно.\n\nНо есть также множество асинхронных случаев, которые вписываются в другую модель - те, которые больше похожи на события и/или потоки данных. На первый взгляд неясно, насколько хорошо промисы могут вписаться в такие сценарии использования, если это вообще возможно. Без значительной абстракции поверх промисов, они будут совершенно не подходить для обработки множественного разрешения значений.\n\nПредставьте себе сценарий, в котором вы хотите запустить последовательность асинхронных шагов в ответ на стимул (например, событие), который может произойти несколько раз, например, нажатие кнопки.\n\nЭто, вероятно, не будет работать так, как вы хотите:\n\n```js\n// `click(..)` привязывает событие `\"click\"` к элементу DOM\n// `request(..)` это ранее определенный Ajax-запрос с поддержкой промисов\n\nvar p = new Promise( function(resolve,reject){\n\tclick( \"#mybtn\", resolve );\n} );\n\np.then( function(evt){\n\tvar btnID = evt.currentTarget.id;\n\treturn request( \"http://some.url.1/?id=\" + btnID );\n} )\n.then( function(text){\n\tconsole.log( text );\n} );\n```\n\nПриведенное здесь поведение работает только в том случае, если ваше приложение требует, чтобы кнопка была нажата только один раз. Если кнопка нажата второй раз, промис `p` уже был разрешен, поэтому второй вызов `resolve(..)` будет проигнорирован.\n\nВместо этого вам, вероятно, придется изменить парадигму, создавая совершенно новую цепочку промисов для каждого срабатывания события:\n\n```js\nclick( \"#mybtn\", function(evt){\n\tvar btnID = evt.currentTarget.id;\n\n\trequest( \"http://some.url.1/?id=\" + btnID )\n\t.then( function(text){\n\t\tconsole.log( text );\n\t} );\n} );\n```\n\nЭтот подход *работает* в том смысле, что для каждого события `\"click\"` на кнопке будет запускаться совершенно новая последовательность промисов.\n\nНо помимо безобразия, связанного с необходимостью определять всю цепочку промисов внутри обработчика события, эта конструкция в некоторых отношениях нарушает идею разделения обязанностей/возможностей (SoC). Вполне возможно, что вы захотите определить обработчик события в другом месте вашего кода, а не там, где вы определяете *ответ* на событие (цепочка промисов). Это довольно неудобно делать в этом шаблоне без вспомогательных механизмов..\n\n**Примечание** Другой способ сформулировать это ограничение заключается в том, что было бы неплохо, если бы мы могли создать некую \"наблюдаемую штуку\", на которую мы могли бы подписать цепочку промисов. Существуют библиотеки, которые создали такие абстракции (такие как RxJS -- http://rxjs.codeplex.com/), но абстракции могут показаться настолько тяжелыми, что вы больше не можете видеть природу промисов. Такая тяжелая абстракция заставляет задуматься о таких важных вопросах, как: являются ли (вне промисов) эти механизмы настолько *надежными*, насколько сами промисы были разработаны для этого. Мы вернемся к шаблону \"Наблюдаемый\" в Приложении B.\n\n### Инерция\n\nОдним из конкретных препятствий для начала использования промисов в вашем собственном коде является весь существующий код, который еще не поддерживает промисы. Если у вас много кода, основанного на колбеках, гораздо проще просто продолжать кодировать в том же стиле.\n\n\"Кодовая база в движении (с колбеками) будет оставаться в движении (с колбеками), если не будут приняты меры со стороны умного, знающего промисы разработчика.\"\n\nПромисы предлагают другую парадигму, и поэтому подход к коду может быть разным - от просто немного другого до, в некоторых случаях, радикально другого. Вы должны быть целенаправленными в этом, потому что промисы не будут просто естественным образом вытекать из тех же старых способов выполнения кода, которые до сих пор хорошо вам служили.\n\nРассмотрим следующий сценарий, основанный на колбеке:\n\n```js\nfunction foo(x,y,cb) {\n\tajax(\n\t\t\"http://some.url.1/?x=\" + x + \"&y=\" + y,\n\t\tcb\n\t);\n}\n\nfoo( 11, 31, function(err,text) {\n\tif (err) {\n\t\tconsole.error( err );\n\t}\n\telse {\n\t\tconsole.log( text );\n\t}\n} );\n```\n\nОчевидно ли сразу, каковы первые шаги по преобразованию этого кода, основанного на колбеках, в код, ориентированный на промисы? Зависит от вашего опыта. Чем больше у вас будет практики, тем естественнее оно будет ощущаться. Но, безусловно, Промисы не только в том, что на этикетке написано, как именно это сделать - универсального ответа не существует, так что ответственность лежит на вас.\n\nКак мы уже писали ранее, нам определенно требуется Ajax-функция, которая поддерживает промисы вместо колбеков, которую мы могли бы назвать `request(..)`. Вы можете сделать свою собственную, как мы уже делали. Но накладные расходы, связанные с необходимостью вручную определять промис-совместимые обертки для каждой функции, основанной на колбеках, снижают вероятность того, что вы вообще решите перейти на промис-совместимое кодирование.\n\nПромисы не дают прямого ответа на это ограничение. Однако, большинство библиотек промисов предлагают вспомогательные средства. Но даже без библиотеки, представьте вспомогательный код подобный этому:\n\n```js\n// защитная проверка в стиле безопасного полифила\nif (!Promise.wrap) {\n\tPromise.wrap = function(fn) {\n\t\treturn function() {\n\t\t\tvar args = [].slice.call( arguments );\n\n\t\t\treturn new Promise( function(resolve,reject){\n\t\t\t\tfn.apply(\n\t\t\t\t\tnull,\n\t\t\t\t\targs.concat( function(err,v){\n\t\t\t\t\t\tif (err) {\n\t\t\t\t\t\t\treject( err );\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tresolve( v );\n\t\t\t\t\t\t}\n\t\t\t\t\t} )\n\t\t\t\t);\n\t\t\t} );\n\t\t};\n\t};\n}\n```\n\nХорошо, это больше, чем просто маленькая тривиальная утилита. Однако, хотя это может выглядеть немного пугающе, все не так плохо, как вы думаете. Она принимает функцию, которая ожидает колбек в стиле ошибка-первым-аргументом, как  свой последний параметр и возвращает новый, который автоматически создает промис в качестве возвращаемого значения и подставляет колбек за вас, присоединяя к завершению/отказу промиса.\n\nВместо того, чтобы тратить много времени на обсуждение того, *как* эта вспомогательная функция  `Promise.wrap(..)` работает, давайте просто взглянем на то, как мы ее используем:\n\n```js\nvar request = Promise.wrap( ajax );\n\nrequest( \"http://some.url.1/\" )\n.then( .. )\n..\n```\n\nОго, это было довольно просто!\n\n`Promise.wrap(..)` **не** создает промис. Она создает функцию, которая создаст промисы. В каком-то смысле, промисо-генерирующая функция может рассматриваться как \"фабрика промисов\". Я предлагаю \"promisory\" в качестве названия для такой вещи (\"Promise\" + \"factory\" (промис + фабрика)).\n\nПроцесс обертывания функции, ожидающей колбек, в функцию с поддержкой промисов иногда называют \"поднятием\" (lifting) или \"промисификацией\" (promisifying). Но, похоже, нет стандартного термина для того, как следует называть результирующую функцию, кроме как \"поднятая функция\", поэтому мне больше нравится \"промисофабрика (promisory)\", поскольку я считаю его более описательным.\n\n**Примечание** Promisory - это не выдуманный термин. Это реальное слово, и его определение означает \"содержать или передать промис\". Именно это и делают эти функции, так что получается довольно идеальное терминологическое соответствие!\n\nТаким образом, `Promise.wrap(ajax)` создает промисофабрику для `ajax(..)`, который мы назвали `request(..)` и эта промисофабрика создает промисы для Ajax-ответов.\n\nЕсли бы все функции уже были бы промисофабриками, нам бы не пришлось создавать из самим, так что лишний шаг - это немного досадно. Но, по крайней мере, шаблон упаковки (обычно) повторяемый, поэтому мы можем поместить его во вспомогательную функцию `Promise.wrap(...)`, как показано на примере, чтобы облегчить кодирование промисов.\n\nИтак, возвращаясь к нашему предыдущему примеру, нам нужна промисофабрика для обоих `ajax(..)` и `foo(..)`:\n\n```js\n// создать промисофабрику для `ajax(..)`\nvar request = Promise.wrap( ajax );\n\n// отрефакторить `foo(..)`, но оставить его снаружи\n// на основе колбека для совместимости с другими\n// частями кода пока что, и использовать промис из\n// `request(..)` только внутри.\nfunction foo(x,y,cb) {\n\trequest(\n\t\t\"http://some.url.1/?x=\" + x + \"&y=\" + y\n\t)\n\t.then(\n\t\tfunction fulfilled(text){\n\t\t\tcb( null, text );\n\t\t},\n\t\tcb\n\t);\n}\n\n// теперь, для целей данного кода, сделаем\n// промисофабрику для `foo(..)`\nvar betterFoo = Promise.wrap( foo );\n\n// и используем эту промисофабрику\nbetterFoo( 11, 31 )\n.then(\n\tfunction fulfilled(text){\n\t\tconsole.log( text );\n\t},\n\tfunction rejected(err){\n\t\tconsole.error( err );\n\t}\n);\n```\n\nКонечно, в то время как мы рефакторим `foo(..)`, чтобы использовать нашу новую промисофабрику `request(..)`, мы могли бы просто превратить саму `foo(..)` в промисофабрику, вместо того, чтобы оставлять основу из колбеков и необходимость создания и использования последующей промисофабрики `betterFoo(..)`. Это решение зависит только от того. надо ли оставлять `foo(..)`  колбеко-совместимой с другими частями кода или нет.\n\nПредставим:\n\n```js\n// `foo(..)` теперь является промисофабрикой, поскольку она\n// делегирует работу промисофабрике `request(..)`\nfunction foo(x,y) {\n\treturn request(\n\t\t\"http://some.url.1/?x=\" + x + \"&y=\" + y\n\t);\n}\n\nfoo( 11, 31 )\n.then( .. )\n..\n```\n\nВ то время как ES6 промисы не оснащены нативно вспомогательными функциями для такого обертывания с помощью промисофабрик, многие библиотеки предоставляют их, либо вы можете сами сделать свои собственные. В любом случае, это конкретное ограничение промисов можно устранить без особых проблем. (конечно, по сравнению с муками ада обратных вызовов!).\n\n### Неотменяемый промис\n\nКак только вы создадите промис и зарегистрируете для него обработчик завершения и/или отказа, не будет ничего снаружи, что вы могли бы сделать, чтобы остановить это движение, если произойдет что-то еще, что сделает эту задачу неактуальной.\n\n**Примечание** Многие библиотеки абстракций над промисами предоставляют возможности для отмены промисов, но это ужасная идея! Многие разработчики хотели бы, чтобы промисы были изначально спроектированы с возможностью внешней отмены, но проблема в том, что это позволило бы одному потребителю/наблюдателю промиса влиять на способность другого потребителя наблюдать тот же промис. Это нарушает достоверность (внешнюю неизменяемость) будущего значения и, более того, является воплощением анти-паттерна \"действие на расстоянии\" (\"action at a distance\" (http://en.wikipedia.org/wiki/Action_at_a_distance_%28computer_programming%29)). Каким бы полезным он ни казался, на самом деле он приведет вас к тому же кошмару, что и колбеки.\n\nРассмотрим наш сценарий с тайм-аутом промиса, описанный ранее:\n\n```js\nvar p = foo( 42 );\n\nPromise.race( [\n\tp,\n\ttimeoutPromise( 3000 )\n] )\n.then(\n\tdoSomething,\n\thandleError\n);\n\np.then( function(){\n\t// все равно происходит даже в случае тайм-аута :(\n} );\n```\n\n\"Тайм-аут\" был внешним по отношению к `p`, поэтому само `p` выполняется дальше, чего мы, вероятно, не хотим.\n\nОдним из вариантов может быть инвазивное определение колбеков разрешения:\n\n```js\nvar OK = true;\n\nvar p = foo( 42 );\n\nPromise.race( [\n\tp,\n\ttimeoutPromise( 3000 )\n\t.catch( function(err){\n\t\tOK = false;\n\t\tthrow err;\n\t} )\n] )\n.then(\n\tdoSomething,\n\thandleError\n);\n\np.then( function(){\n\tif (OK) {\n\t\t// выполняется только если не было тайм-аута! :)\n\t}\n} );\n```\n\nЭто ужасно. Это работает, но далеко от идеала. В общем случае следует стараться избегать таких сценариев.\n\nНо если не можете этого избежать, Уродливость этого решения должна быть подсказкой, что *отмена* - это функциональность, которая находится на более высоком уровне абстракции, поверх промисов. Я бы рекомендовал обращаться за помощью к библиотекам абстракций над промисами, а не разрабатывать их самостоятельно.\n\n**Примечание** Моя библиотека абстракций над промисами *asynquence* предоставляет именно такую абстракцию и возможность сделать `abort()` для последовательности, все они будут рассмотрены в Приложении А.\n\nОдиночный промис на самом деле не является механизмом управления потоком (по крайней мере, в сильно значимом смысле), а это именно то, к чему относится *отмена*; поэтому отмена промиса будет выглядеть неловко.\n\nВ отличие от этого, цепочка промисов, взятых в совокупности (то, что я люблю называть \"последовательность\") - *является* выражением управления потоком, и поэтому уместно, чтобы отмена была определена на этом уровне абстракции.\n\nНи один отдельный промис не должен быть отменяемым, но разумно, чтобы отменяемой была *последовательность*, поскольку вы не передаете последовательность как единое неизменяемое значение, как вы делаете это с обещанием.\n\n### Производительность промисов\n\nДанное ограничение является одновременно и простым, и сложным.\n\nСравнивая, сколько частей двигается в базовой цепочке асинхронных задач, основанных на колбеках, с цепочкой промисов, можно заметить, что в промисах происходит гораздо больше операций, а значит, они, естественно, по крайней мере немного медленнее. Вспомните простой список гарантий доверия, которые предоставляют промисы, по сравнению со специальным кодом решения, который пришлось бы накладывать поверх колбеков для достижения того же уровня защиты.\n\nБольше работы, больше защитных мер, что означает, что обещания *медленнее* по сравнению с чистыми, ненадежными колбеками. Это очевидно и, вероятно, просто для восприятия.\n\nНо насколько медленнее? Ну... На этот вопрос, на самом деле, невероятно сложно ответить всесторонне.\n\nЧестно говоря, это своего рода сравнение \"яблок с апельсинами\", так что, вероятно, это неправильный вопрос. На самом деле следует сравнить, насколько специализированная система колбеков со всеми теми же защитами, внедренными вручную, быстрее, чем реализация промисов.\n\nЕсли у промисов и есть обоснованное ограничение производительности, то оно заключается в том, что они не дают возможности выбирать, какие средства защиты надежности вам нужны или не нужны - вы получаете их все и всегда.\n\nТем не менее, если мы признаем, что промис в целом *немного медленнее*, чем его эквивалент в виде не-промис и ненадежного колбека, предполагая, что есть места, где вы можете оправдать отсутствие надежности - означает ли это, что промиса следует избегать повсеместно, как будто все ваше приложение управляется только самым быстрым кодом, какой только может быть?\n\nЕсли ваш код действительно такой, то **подходит ли JavaScript для таких задач?** JavaScript может быть оптимизирован для выполнения приложений с очень высокой производительностью (см. главу 5 и главу 6). Но действительно ли уместно зацикливаться на крошечных компромиссах производительности с промисами в свете всех преимуществ, которые они дают?\n\nЕще одна небольшая проблема заключается в том, что Promises делают *все* асинхронным, а это значит, что некоторые немедленно (синхронно) завершенные шаги все равно откладывают выполнение следующего шага до Задачи (см. главу 1). Это означает, что последовательность задач промиса может выполняться чуть медленнее, чем та же самая последовательность с колбеками.\n\nКонечно, вопрос заключается в следующем: стоят ли эти потенциальные снижения крошечных долей производительности всех остальных преимуществ промисов, которые мы изложили в этой главе?\n\nЯ считаю, что практически во всех случаях, когда производительность промисов кажется вам достаточно низкой, чтобы начать беспокоиться, в действительности это антипаттерн - оптимизировать преимущества надежности и комбинируемости промисов, избегая их полностью.\n\nВместо этого вам следует по умолчанию использовать их во всей кодовой базе, а затем профилировать и анализировать ключевые (критические) места вашего приложения. Являются ли промисы *действительно* узким местом, или они просто теоретически замедляют работу? Только *после этого*, вооружившись реальными контрольными показателями (см. главу 6), можно ответственно и разумно исключить промисы именно в тех критических областях, которые были выявлены.\n\nПромисы немного медленнее, но в обмен на это вы получаете много надежности, не-Залго предсказуемости, и встроенную способность к композиции. Может быть, ограничением является не их производительность, а ваше недостаточное восприятие их преимуществ?\n\n## Обзор\n\nОбещания - это круто. Используйте их. Они решают проблемы *инверсии управления*, которые мучают нас в коде, основанном только на колбеках.\n\nОни не избавляются от колбеков, а просто перепоручают их организацию надежному механизму-посреднику, который находится между нами и другой утилитой.\n\nЦепочки промисов также начинают решать (хотя, конечно, не идеально) проблему лучшего способа последовательного выражения потока асинхронного кода, что помогает нашему мозгу лучше планировать и поддерживать асинхронный JS-код. Мы увидим еще более удачное решение *этой* проблемы в следующей главе!\n"
  },
  {
    "path": "async & performance/ch4.md",
    "content": "# You Don't Know JS: Async & Performance\n# Chapter 4: Generators\n\nIn Chapter 2, we identified two key drawbacks to expressing async flow control with callbacks:\n\n* Callback-based async doesn't fit how our brain plans out steps of a task.\n* Callbacks aren't trustable or composable because of *inversion of control*.\n\nIn Chapter 3, we detailed how Promises uninvert the *inversion of control* of callbacks, restoring trustability/composability.\n\nNow we turn our attention to expressing async flow control in a sequential, synchronous-looking fashion. The \"magic\" that makes it possible is ES6 **generators**.\n\n## Breaking Run-to-Completion\n\nIn Chapter 1, we explained an expectation that JS developers almost universally rely on in their code: once a function starts executing, it runs until it completes, and no other code can interrupt and run in between.\n\nAs bizarre as it may seem, ES6 introduces a new type of function that does not behave with the run-to-completion behavior. This new type of function is called a \"generator.\"\n\nTo understand the implications, let's consider this example:\n\n```js\nvar x = 1;\n\nfunction foo() {\n\tx++;\n\tbar();\t\t\t\t// <-- what about this line?\n\tconsole.log( \"x:\", x );\n}\n\nfunction bar() {\n\tx++;\n}\n\nfoo();\t\t\t\t\t// x: 3\n```\n\nIn this example, we know for sure that `bar()` runs in between `x++` and `console.log(x)`. But what if `bar()` wasn't there? Obviously the result would be `2` instead of `3`.\n\nNow let's twist your brain. What if `bar()` wasn't present, but it could still somehow run between the `x++` and `console.log(x)` statements? How would that be possible?\n\nIn **preemptive** multithreaded languages, it would essentially be possible for `bar()` to \"interrupt\" and run at exactly the right moment between those two statements. But JS is not preemptive, nor is it (currently) multithreaded. And yet, a **cooperative** form of this \"interruption\" (concurrency) is possible, if `foo()` itself could somehow indicate a \"pause\" at that part in the code.\n\n**Note:** I use the word \"cooperative\" not only because of the connection to classical concurrency terminology (see Chapter 1), but because as you'll see in the next snippet, the ES6 syntax for indicating a pause point in code is `yield` -- suggesting a politely *cooperative* yielding of control.\n\nHere's the ES6 code to accomplish such cooperative concurrency:\n\n```js\nvar x = 1;\n\nfunction *foo() {\n\tx++;\n\tyield; // pause!\n\tconsole.log( \"x:\", x );\n}\n\nfunction bar() {\n\tx++;\n}\n```\n\n**Note:** You will likely see most other JS documentation/code that will format a generator declaration as `function* foo() { .. }` instead of as I've done here with `function *foo() { .. }` -- the only difference being the stylistic positioning of the `*`. The two forms are functionally/syntactically identical, as is a third `function*foo() { .. }` (no space) form. There are arguments for both styles, but I basically prefer `function *foo..` because it then matches when I reference a generator in writing with `*foo()`. If I said only `foo()`, you wouldn't know as clearly if I was talking about a generator or a regular function. It's purely a stylistic preference.\n\nNow, how can we run the code in that previous snippet such that `bar()` executes at the point of the `yield` inside of `*foo()`?\n\n```js\n// construct an iterator `it` to control the generator\nvar it = foo();\n\n// start `foo()` here!\nit.next();\nx;\t\t\t\t\t\t// 2\nbar();\nx;\t\t\t\t\t\t// 3\nit.next();\t\t\t\t// x: 3\n```\n\nOK, there's quite a bit of new and potentially confusing stuff in those two code snippets, so we've got plenty to wade through. But before we explain the different mechanics/syntax with ES6 generators, let's walk through the behavior flow:\n\n1. The `it = foo()` operation does *not* execute the `*foo()` generator yet, but it merely constructs an *iterator* that will control its execution. More on *iterators* in a bit.\n2. The first `it.next()` starts the `*foo()` generator, and runs the `x++` on the first line of `*foo()`.\n3. `*foo()` pauses at the `yield` statement, at which point that first `it.next()` call finishes. At the moment, `*foo()` is still running and active, but it's in a paused state.\n4. We inspect the value of `x`, and it's now `2`.\n5. We call `bar()`, which increments `x` again with `x++`.\n6. We inspect the value of `x` again, and it's now `3`.\n7. The final `it.next()` call resumes the `*foo()` generator from where it was paused, and runs the `console.log(..)` statement, which uses the current value of `x` of `3`.\n\nClearly, `*foo()` started, but did *not* run-to-completion -- it paused at the `yield`. We resumed `*foo()` later, and let it finish, but that wasn't even required.\n\nSo, a generator is a special kind of function that can start and stop one or more times, and doesn't necessarily ever have to finish. While it won't be terribly obvious yet why that's so powerful, as we go throughout the rest of this chapter, that will be one of the fundamental building blocks we use to construct generators-as-async-flow-control as a pattern for our code.\n\n### Input and Output\n\nA generator function is a special function with the new processing model we just alluded to. But it's still a function, which means it still has some basic tenets that haven't changed -- namely, that it still accepts arguments (aka \"input\"), and that it can still return a value (aka \"output\"):\n\n```js\nfunction *foo(x,y) {\n\treturn x * y;\n}\n\nvar it = foo( 6, 7 );\n\nvar res = it.next();\n\nres.value;\t\t// 42\n```\n\nWe pass in the arguments `6` and `7` to `*foo(..)` as the parameters `x` and `y`, respectively. And `*foo(..)` returns the value `42` back to the calling code.\n\nWe now see a difference with how the generator is invoked compared to a normal function. `foo(6,7)` obviously looks familiar. But subtly, the `*foo(..)` generator hasn't actually run yet as it would have with a function.\n\nInstead, we're just creating an *iterator* object, which we assign to the variable `it`, to control the `*foo(..)` generator. Then we call `it.next()`, which instructs the `*foo(..)` generator to advance from its current location, stopping either at the next `yield` or end of the generator.\n\nThe result of that `next(..)` call is an object with a `value` property on it holding whatever value (if anything) was returned from `*foo(..)`. In other words, `yield` caused a value to be sent out from the generator during the middle of its execution, kind of like an intermediate `return`.\n\nAgain, it won't be obvious yet why we need this whole indirect *iterator* object to control the generator. We'll get there, I *promise*.\n\n#### Iteration Messaging\n\nIn addition to generators accepting arguments and having return values, there's even more powerful and compelling input/output messaging capability built into them, via `yield` and `next(..)`.\n\nConsider:\n\n```js\nfunction *foo(x) {\n\tvar y = x * (yield);\n\treturn y;\n}\n\nvar it = foo( 6 );\n\n// start `foo(..)`\nit.next();\n\nvar res = it.next( 7 );\n\nres.value;\t\t// 42\n```\n\nFirst, we pass in `6` as the parameter `x`. Then we call `it.next()`, and it starts up `*foo(..)`.\n\nInside `*foo(..)`, the `var y = x ..` statement starts to be processed, but then it runs across a `yield` expression. At that point, it pauses `*foo(..)` (in the middle of the assignment statement!), and essentially requests the calling code to provide a result value for the `yield` expression. Next, we call `it.next( 7 )`, which is passing the `7` value back in to *be* that result of the paused `yield` expression.\n\nSo, at this point, the assignment statement is essentially `var y = 6 * 7`. Now, `return y` returns that `42` value back as the result of the `it.next( 7 )` call.\n\nNotice something very important but also easily confusing, even to seasoned JS developers: depending on your perspective, there's a mismatch between the `yield` and the `next(..)` call. In general, you're going to have one more `next(..)` call than you have `yield` statements -- the preceding snippet has one `yield` and two `next(..)` calls.\n\nWhy the mismatch?\n\nBecause the first `next(..)` always starts a generator, and runs to the first `yield`. But it's the second `next(..)` call that fulfills the first paused `yield` expression, and the third `next(..)` would fulfill the second `yield`, and so on.\n\n##### Tale of Two Questions\n\nActually, which code you're thinking about primarily will affect whether there's a perceived mismatch or not.\n\nConsider only the generator code:\n\n```js\nvar y = x * (yield);\nreturn y;\n```\n\nThis **first** `yield` is basically *asking a question*: \"What value should I insert here?\"\n\nWho's going to answer that question? Well, the **first** `next()` has already run to get the generator up to this point, so obviously *it* can't answer the question. So, the **second** `next(..)` call must answer the question *posed* by the **first** `yield`.\n\nSee the mismatch -- second-to-first?\n\nBut let's flip our perspective. Let's look at it not from the generator's point of view, but from the iterator's point of view.\n\nTo properly illustrate this perspective, we also need to explain that messages can go in both directions -- `yield ..` as an expression can send out messages in response to `next(..)` calls, and `next(..)` can send values to a paused `yield` expression. Consider this slightly adjusted code:\n\n```js\nfunction *foo(x) {\n\tvar y = x * (yield \"Hello\");\t// <-- yield a value!\n\treturn y;\n}\n\nvar it = foo( 6 );\n\nvar res = it.next();\t// first `next()`, don't pass anything\nres.value;\t\t\t\t// \"Hello\"\n\nres = it.next( 7 );\t\t// pass `7` to waiting `yield`\nres.value;\t\t\t\t// 42\n```\n\n`yield ..` and `next(..)` pair together as a two-way message passing system **during the execution of the generator**.\n\nSo, looking only at the *iterator* code:\n\n```js\nvar res = it.next();\t// first `next()`, don't pass anything\nres.value;\t\t\t\t// \"Hello\"\n\nres = it.next( 7 );\t\t// pass `7` to waiting `yield`\nres.value;\t\t\t\t// 42\n```\n\n**Note:** We don't pass a value to the first `next()` call, and that's on purpose. Only a paused `yield` could accept such a value passed by a `next(..)`, and at the beginning of the generator when we call the first `next()`, there **is no paused `yield`** to accept such a value. The specification and all compliant browsers just silently **discard** anything passed to the first `next()`. It's still a bad idea to pass a value, as you're just creating silently \"failing\" code that's confusing. So, always start a generator with an argument-free `next()`.\n\nThe first `next()` call (with nothing passed to it) is basically *asking a question*: \"What *next* value does the `*foo(..)` generator have to give me?\" And who answers this question? The first `yield \"hello\"` expression.\n\nSee? No mismatch there.\n\nDepending on *who* you think about asking the question, there is either a mismatch between the `yield` and `next(..)` calls, or not.\n\nBut wait! There's still an extra `next()` compared to the number of `yield` statements. So, that final `it.next(7)` call is again asking the question about what *next* value the generator will produce. But there's no more `yield` statements left to answer, is there? So who answers?\n\nThe `return` statement answers the question!\n\nAnd if there **is no `return`** in your generator -- `return` is certainly not any more required in generators than in regular functions -- there's always an assumed/implicit `return;` (aka `return undefined;`), which serves the purpose of default answering the question *posed* by the final `it.next(7)` call.\n\nThese questions and answers -- the two-way message passing with `yield` and `next(..)` -- are quite powerful, but it's not obvious at all how these mechanisms are connected to async flow control. We're getting there!\n\n### Multiple Iterators\n\nIt may appear from the syntactic usage that when you use an *iterator* to control a generator, you're controlling the declared generator function itself. But there's a subtlety that's easy to miss: each time you construct an *iterator*, you are implicitly constructing an instance of the generator which that *iterator* will control.\n\nYou can have multiple instances of the same generator running at the same time, and they can even interact:\n\n```js\nfunction *foo() {\n\tvar x = yield 2;\n\tz++;\n\tvar y = yield (x * z);\n\tconsole.log( x, y, z );\n}\n\nvar z = 1;\n\nvar it1 = foo();\nvar it2 = foo();\n\nvar val1 = it1.next().value;\t\t\t// 2 <-- yield 2\nvar val2 = it2.next().value;\t\t\t// 2 <-- yield 2\n\nval1 = it1.next( val2 * 10 ).value;\t\t// 40  <-- x:20,  z:2\nval2 = it2.next( val1 * 5 ).value;\t\t// 600 <-- x:200, z:3\n\nit1.next( val2 / 2 );\t\t\t\t\t// y:300\n\t\t\t\t\t\t\t\t\t\t// 20 300 3\nit2.next( val1 / 4 );\t\t\t\t\t// y:10\n\t\t\t\t\t\t\t\t\t\t// 200 10 3\n```\n\n**Warning:** The most common usage of multiple instances of the same generator running concurrently is not such interactions, but when the generator is producing its own values without input, perhaps from some independently connected resource. We'll talk more about value production in the next section.\n\nLet's briefly walk through the processing:\n\n1. Both instances of `*foo()` are started at the same time, and both `next()` calls reveal a `value` of `2` from the `yield 2` statements, respectively.\n2. `val2 * 10` is `2 * 10`, which is sent into the first generator instance `it1`, so that `x` gets value `20`. `z` is incremented from `1` to `2`, and then `20 * 2` is `yield`ed out, setting `val1` to `40`.\n3. `val1 * 5` is `40 * 5`, which is sent into the second generator instance `it2`, so that `x` gets value `200`. `z` is incremented again, from `2` to `3`, and then `200 * 3` is `yield`ed out, setting `val2` to `600`.\n4. `val2 / 2` is `600 / 2`, which is sent into the first generator instance `it1`, so that `y` gets value `300`, then printing out `20 300 3` for its `x y z` values, respectively.\n5. `val1 / 4` is `40 / 4`, which is sent into the second generator instance `it2`, so that `y` gets value `10`, then printing out `200 10 3` for its `x y z` values, respectively.\n\nThat's a \"fun\" example to run through in your mind. Did you keep it straight?\n\n#### Interleaving\n\nRecall this scenario from the \"Run-to-completion\" section of Chapter 1:\n\n```js\nvar a = 1;\nvar b = 2;\n\nfunction foo() {\n\ta++;\n\tb = b * a;\n\ta = b + 3;\n}\n\nfunction bar() {\n\tb--;\n\ta = 8 + b;\n\tb = a * 2;\n}\n```\n\nWith normal JS functions, of course either `foo()` can run completely first, or `bar()` can run completely first, but `foo()` cannot interleave its individual statements with `bar()`. So, there are only two possible outcomes to the preceding program.\n\nHowever, with generators, clearly interleaving (even in the middle of statements!) is possible:\n\n```js\nvar a = 1;\nvar b = 2;\n\nfunction *foo() {\n\ta++;\n\tyield;\n\tb = b * a;\n\ta = (yield b) + 3;\n}\n\nfunction *bar() {\n\tb--;\n\tyield;\n\ta = (yield 8) + b;\n\tb = a * (yield 2);\n}\n```\n\nDepending on what respective order the *iterators* controlling `*foo()` and `*bar()` are called, the preceding program could produce several different results. In other words, we can actually illustrate (in a sort of fake-ish way) the theoretical \"threaded race conditions\" circumstances discussed in Chapter 1, by interleaving the two generator interations over the same shared variables.\n\nFirst, let's make a helper called `step(..)` that controls an *iterator*:\n\n```js\nfunction step(gen) {\n\tvar it = gen();\n\tvar last;\n\n\treturn function() {\n\t\t// whatever is `yield`ed out, just\n\t\t// send it right back in the next time!\n\t\tlast = it.next( last ).value;\n\t};\n}\n```\n\n`step(..)` initializes a generator to create its `it` *iterator*, then returns a function which, when called, advances the *iterator* by one step. Additionally, the previously `yield`ed out value is sent right back in at the *next* step. So, `yield 8` will just become `8` and `yield b` will just be `b` (whatever it was at the time of `yield`).\n\nNow, just for fun, let's experiment to see the effects of interleaving these different chunks of `*foo()` and `*bar()`. We'll start with the boring base case, making sure `*foo()` totally finishes before `*bar()` (just like we did in Chapter 1):\n\n```js\n// make sure to reset `a` and `b`\na = 1;\nb = 2;\n\nvar s1 = step( foo );\nvar s2 = step( bar );\n\n// run `*foo()` completely first\ns1();\ns1();\ns1();\n\n// now run `*bar()`\ns2();\ns2();\ns2();\ns2();\n\nconsole.log( a, b );\t// 11 22\n```\n\nThe end result is `11` and `22`, just as it was in the Chapter 1 version. Now let's mix up the interleaving ordering and see how it changes the final values of `a` and `b`:\n\n```js\n// make sure to reset `a` and `b`\na = 1;\nb = 2;\n\nvar s1 = step( foo );\nvar s2 = step( bar );\n\ns2();\t\t// b--;\ns2();\t\t// yield 8\ns1();\t\t// a++;\ns2();\t\t// a = 8 + b;\n\t\t\t// yield 2\ns1();\t\t// b = b * a;\n\t\t\t// yield b\ns1();\t\t// a = b + 3;\ns2();\t\t// b = a * 2;\n```\n\nBefore I tell you the results, can you figure out what `a` and `b` are after the preceding program? No cheating!\n\n```js\nconsole.log( a, b );\t// 12 18\n```\n\n**Note:** As an exercise for the reader, try to see how many other combinations of results you can get back rearranging the order of the `s1()` and `s2()` calls. Don't forget you'll always need three `s1()` calls and four `s2()` calls. Recall the discussion earlier about matching `next()` with `yield` for the reasons why.\n\nYou almost certainly won't want to intentionally create *this* level of interleaving confusion, as it creates incredibly difficult to understand code. But the exercise is interesting and instructive to understand more about how multiple generators can run concurrently in the same shared scope, because there will be places where this capability is quite useful.\n\nWe'll discuss generator concurrency in more detail at the end of this chapter.\n\n## Generator'ing Values\n\nIn the previous section, we mentioned an interesting use for generators, as a way to produce values. This is **not** the main focus in this chapter, but we'd be remiss if we didn't cover the basics, especially because this use case is essentially the origin of the name: generators.\n\nWe're going to take a slight diversion into the topic of *iterators* for a bit, but we'll circle back to how they relate to generators and using a generator to *generate* values.\n\n### Producers and Iterators\n\nImagine you're producing a series of values where each value has a definable relationship to the previous value. To do this, you're going to need a stateful producer that remembers the last value it gave out.\n\nYou can implement something like that straightforwardly using a function closure (see the *Scope & Closures* title of this series):\n\n```js\nvar gimmeSomething = (function(){\n\tvar nextVal;\n\n\treturn function(){\n\t\tif (nextVal === undefined) {\n\t\t\tnextVal = 1;\n\t\t}\n\t\telse {\n\t\t\tnextVal = (3 * nextVal) + 6;\n\t\t}\n\n\t\treturn nextVal;\n\t};\n})();\n\ngimmeSomething();\t\t// 1\ngimmeSomething();\t\t// 9\ngimmeSomething();\t\t// 33\ngimmeSomething();\t\t// 105\n```\n\n**Note:** The `nextVal` computation logic here could have been simplified, but conceptually, we don't want to calculate the *next value* (aka `nextVal`) until the *next* `gimmeSomething()` call happens, because in general that could be a resource-leaky design for producers of more persistent or resource-limited values than simple `number`s.\n\nGenerating an arbitrary number series isn't a terribly realistic example. But what if you were generating records from a data source? You could imagine much the same code.\n\nIn fact, this task is a very common design pattern, usually solved by iterators. An *iterator* is a well-defined interface for stepping through a series of values from a producer. The JS interface for iterators, as it is in most languages, is to call `next()` each time you want the next value from the producer.\n\nWe could implement the standard *iterator* interface for our number series producer:\n\n```js\nvar something = (function(){\n\tvar nextVal;\n\n\treturn {\n\t\t// needed for `for..of` loops\n\t\t[Symbol.iterator]: function(){ return this; },\n\n\t\t// standard iterator interface method\n\t\tnext: function(){\n\t\t\tif (nextVal === undefined) {\n\t\t\t\tnextVal = 1;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tnextVal = (3 * nextVal) + 6;\n\t\t\t}\n\n\t\t\treturn { done:false, value:nextVal };\n\t\t}\n\t};\n})();\n\nsomething.next().value;\t\t// 1\nsomething.next().value;\t\t// 9\nsomething.next().value;\t\t// 33\nsomething.next().value;\t\t// 105\n```\n\n**Note:** We'll explain why we need the `[Symbol.iterator]: ..` part of this code snippet in the \"Iterables\" section. Syntactically though, two ES6 features are at play. First, the `[ .. ]` syntax is called a *computed property name* (see the *this & Object Prototypes* title of this series). It's a way in an object literal definition to specify an expression and use the result of that expression as the name for the property. Next, `Symbol.iterator` is one of ES6's predefined special `Symbol` values (see the *ES6 & Beyond* title of this book series).\n\nThe `next()` call returns an object with two properties: `done` is a `boolean` value signaling the *iterator's* complete status; `value` holds the iteration value.\n\nES6 also adds the `for..of` loop, which means that a standard *iterator* can automatically be consumed with native loop syntax:\n\n```js\nfor (var v of something) {\n\tconsole.log( v );\n\n\t// don't let the loop run forever!\n\tif (v > 500) {\n\t\tbreak;\n\t}\n}\n// 1 9 33 105 321 969\n```\n\n**Note:** Because our `something` *iterator* always returns `done:false`, this `for..of` loop would run forever, which is why we put the `break` conditional in. It's totally OK for iterators to be never-ending, but there are also cases where the *iterator* will run over a finite set of values and eventually return a `done:true`.\n\nThe `for..of` loop automatically calls `next()` for each iteration -- it doesn't pass any values in to the `next()` -- and it will automatically terminate on receiving a `done:true`. It's quite handy for looping over a set of data.\n\nOf course, you could manually loop over iterators, calling `next()` and checking for the `done:true` condition to know when to stop:\n\n```js\nfor (\n\tvar ret;\n\t(ret = something.next()) && !ret.done;\n) {\n\tconsole.log( ret.value );\n\n\t// don't let the loop run forever!\n\tif (ret.value > 500) {\n\t\tbreak;\n\t}\n}\n// 1 9 33 105 321 969\n```\n\n**Note:** This manual `for` approach is certainly uglier than the ES6 `for..of` loop syntax, but its advantage is that it affords you the opportunity to pass in values to the `next(..)` calls if necessary.\n\nIn addition to making your own *iterators*, many built-in data structures in JS (as of ES6), like `array`s, also have default *iterators*:\n\n```js\nvar a = [1,3,5,7,9];\n\nfor (var v of a) {\n\tconsole.log( v );\n}\n// 1 3 5 7 9\n```\n\nThe `for..of` loop asks `a` for its *iterator*, and automatically uses it to iterate over `a`'s values.\n\n**Note:** It may seem a strange omission by ES6, but regular `object`s intentionally do not come with a default *iterator* the way `array`s do. The reasons go deeper than we will cover here. If all you want is to iterate over the properties of an object (with no particular guarantee of ordering), `Object.keys(..)` returns an `array`, which can then be used like `for (var k of Object.keys(obj)) { ..`. Such a `for..of` loop over an object's keys would be similar to a `for..in` loop, except that `Object.keys(..)` does not include properties from the `[[Prototype]]` chain while `for..in` does (see the *this & Object Prototypes* title of this series).\n\n### Iterables\n\nThe `something` object in our running example is called an *iterator*, as it has the `next()` method on its interface. But a closely related term is *iterable*, which is an `object` that **contains** an *iterator* that can iterate over its values.\n\nAs of ES6, the way to retrieve an *iterator* from an *iterable* is that the *iterable* must have a function on it, with the name being the special ES6 symbol value `Symbol.iterator`. When this function is called, it returns an *iterator*. Though not required, generally each call should return a fresh new *iterator*.\n\n`a` in the previous snippet is an *iterable*. The `for..of` loop automatically calls its `Symbol.iterator` function to construct an *iterator*. But we could of course call the function manually, and use the *iterator* it returns:\n\n```js\nvar a = [1,3,5,7,9];\n\nvar it = a[Symbol.iterator]();\n\nit.next().value;\t// 1\nit.next().value;\t// 3\nit.next().value;\t// 5\n..\n```\n\nIn the previous code listing that defined `something`, you may have noticed this line:\n\n```js\n[Symbol.iterator]: function(){ return this; }\n```\n\nThat little bit of confusing code is making the `something` value -- the interface of the `something` *iterator* -- also an *iterable*; it's now both an *iterable* and an *iterator*. Then, we pass `something` to the `for..of` loop:\n\n```js\nfor (var v of something) {\n\t..\n}\n```\n\nThe `for..of` loop expects `something` to be an *iterable*, so it looks for and calls its `Symbol.iterator` function. We defined that function to simply `return this`, so it just gives itself back, and the `for..of` loop is none the wiser.\n\n### Generator Iterator\n\nLet's turn our attention back to generators, in the context of *iterators*. A generator can be treated as a producer of values that we extract one at a time through an *iterator* interface's `next()` calls.\n\nSo, a generator itself is not technically an *iterable*, though it's very similar -- when you execute the generator, you get an *iterator* back:\n\n```js\nfunction *foo(){ .. }\n\nvar it = foo();\n```\n\nWe can implement the `something` infinite number series producer from earlier with a generator, like this:\n\n```js\nfunction *something() {\n\tvar nextVal;\n\n\twhile (true) {\n\t\tif (nextVal === undefined) {\n\t\t\tnextVal = 1;\n\t\t}\n\t\telse {\n\t\t\tnextVal = (3 * nextVal) + 6;\n\t\t}\n\n\t\tyield nextVal;\n\t}\n}\n```\n\n**Note:** A `while..true` loop would normally be a very bad thing to include in a real JS program, at least if it doesn't have a `break` or `return` in it, as it would likely run forever, synchronously, and block/lock-up the browser UI. However, in a generator, such a loop is generally totally OK if it has a `yield` in it, as the generator will pause at each iteration, `yield`ing back to the main program and/or to the event loop queue. To put it glibly, \"generators put the `while..true` back in JS programming!\"\n\nThat's a fair bit cleaner and simpler, right? Because the generator pauses at each `yield`, the state (scope) of the function `*something()` is kept around, meaning there's no need for the closure boilerplate to preserve variable state across calls.\n\nNot only is it simpler code -- we don't have to make our own *iterator* interface -- it actually is more reason-able code, because it more clearly expresses the intent. For example, the `while..true` loop tells us the generator is intended to run forever -- to keep *generating* values as long as we keep asking for them.\n\nAnd now we can use our shiny new `*something()` generator with a `for..of` loop, and you'll see it works basically identically:\n\n```js\nfor (var v of something()) {\n\tconsole.log( v );\n\n\t// don't let the loop run forever!\n\tif (v > 500) {\n\t\tbreak;\n\t}\n}\n// 1 9 33 105 321 969\n```\n\nBut don't skip over `for (var v of something()) ..`! We didn't just reference `something` as a value like in earlier examples, but instead called the `*something()` generator to get its *iterator* for the `for..of` loop to use.\n\nIf you're paying close attention, two questions may arise from this interaction between the generator and the loop:\n\n* Why couldn't we say `for (var v of something) ..`? Because `something` here is a generator, which is not an *iterable*. We have to call `something()` to construct a producer for the `for..of` loop to iterate over.\n* The `something()` call produces an *iterator*, but the `for..of` loop wants an *iterable*, right? Yep. The generator's *iterator* also has a `Symbol.iterator` function on it, which basically does a `return this`, just like the `something` *iterable* we defined earlier. In other words, a generator's *iterator* is also an *iterable*!\n\n#### Stopping the Generator\n\nIn the previous example, it would appear the *iterator* instance for the `*something()` generator was basically left in a suspended state forever after the `break` in the loop was called.\n\nBut there's a hidden behavior that takes care of that for you. \"Abnormal completion\" (i.e., \"early termination\") of the `for..of` loop -- generally caused by a `break`, `return`, or an uncaught exception -- sends a signal to the generator's *iterator* for it to terminate.\n\n**Note:** Technically, the `for..of` loop also sends this signal to the *iterator* at the normal completion of the loop. For a generator, that's essentially a moot operation, as the generator's *iterator* had to complete first so the `for..of` loop completed. However, custom *iterators* might desire to receive this additional signal from `for..of` loop consumers.\n\nWhile a `for..of` loop will automatically send this signal, you may wish to send the signal manually to an *iterator*; you do this by calling `return(..)`.\n\nIf you specify a `try..finally` clause inside the generator, it will always be run even when the generator is externally completed. This is useful if you need to clean up resources (database connections, etc.):\n\n```js\nfunction *something() {\n\ttry {\n\t\tvar nextVal;\n\n\t\twhile (true) {\n\t\t\tif (nextVal === undefined) {\n\t\t\t\tnextVal = 1;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tnextVal = (3 * nextVal) + 6;\n\t\t\t}\n\n\t\t\tyield nextVal;\n\t\t}\n\t}\n\t// cleanup clause\n\tfinally {\n\t\tconsole.log( \"cleaning up!\" );\n\t}\n}\n```\n\nThe earlier example with `break` in the `for..of` loop will trigger the `finally` clause. But you could instead manually terminate the generator's *iterator* instance from the outside with `return(..)`:\n\n```js\nvar it = something();\nfor (var v of it) {\n\tconsole.log( v );\n\n\t// don't let the loop run forever!\n\tif (v > 500) {\n\t\tconsole.log(\n\t\t\t// complete the generator's iterator\n\t\t\tit.return( \"Hello World\" ).value\n\t\t);\n\t\t// no `break` needed here\n\t}\n}\n// 1 9 33 105 321 969\n// cleaning up!\n// Hello World\n```\n\nWhen we call `it.return(..)`, it immediately terminates the generator, which of course runs the `finally` clause. Also, it sets the returned `value` to whatever you passed in to `return(..)`, which is how `\"Hello World\"` comes right back out. We also don't need to include a `break` now because the generator's *iterator* is set to `done:true`, so the `for..of` loop will terminate on its next iteration.\n\nGenerators owe their namesake mostly to this *consuming produced values* use. But again, that's just one of the uses for generators, and frankly not even the main one we're concerned with in the context of this book.\n\nBut now that we more fully understand some of the mechanics of how they work, we can *next* turn our attention to how generators apply to async concurrency.\n\n## Iterating Generators Asynchronously\n\nWhat do generators have to do with async coding patterns, fixing problems with callbacks, and the like? Let's get to answering that important question.\n\nWe should revisit one of our scenarios from Chapter 3. Let's recall the callback approach:\n\n```js\nfunction foo(x,y,cb) {\n\tajax(\n\t\t\"http://some.url.1/?x=\" + x + \"&y=\" + y,\n\t\tcb\n\t);\n}\n\nfoo( 11, 31, function(err,text) {\n\tif (err) {\n\t\tconsole.error( err );\n\t}\n\telse {\n\t\tconsole.log( text );\n\t}\n} );\n```\n\nIf we wanted to express this same task flow control with a generator, we could do:\n\n```js\nfunction foo(x,y) {\n\tajax(\n\t\t\"http://some.url.1/?x=\" + x + \"&y=\" + y,\n\t\tfunction(err,data){\n\t\t\tif (err) {\n\t\t\t\t// throw an error into `*main()`\n\t\t\t\tit.throw( err );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// resume `*main()` with received `data`\n\t\t\t\tit.next( data );\n\t\t\t}\n\t\t}\n\t);\n}\n\nfunction *main() {\n\ttry {\n\t\tvar text = yield foo( 11, 31 );\n\t\tconsole.log( text );\n\t}\n\tcatch (err) {\n\t\tconsole.error( err );\n\t}\n}\n\nvar it = main();\n\n// start it all up!\nit.next();\n```\n\nAt first glance, this snippet is longer, and perhaps a little more complex looking, than the callback snippet before it. But don't let that impression get you off track. The generator snippet is actually **much** better! But there's a lot going on for us to explain.\n\nFirst, let's look at this part of the code, which is the most important:\n\n```js\nvar text = yield foo( 11, 31 );\nconsole.log( text );\n```\n\nThink about how that code works for a moment. We're calling a normal function `foo(..)` and we're apparently able to get back the `text` from the Ajax call, even though it's asynchronous.\n\nHow is that possible? If you recall the beginning of Chapter 1, we had almost identical code:\n\n```js\nvar data = ajax( \"..url 1..\" );\nconsole.log( data );\n```\n\nAnd that code didn't work! Can you spot the difference? It's the `yield` used in a generator.\n\nThat's the magic! That's what allows us to have what appears to be blocking, synchronous code, but it doesn't actually block the whole program; it only pauses/blocks the code in the generator itself.\n\nIn `yield foo(11,31)`, first the `foo(11,31)` call is made, which returns nothing (aka `undefined`), so we're making a call to request data, but we're actually then doing `yield undefined`. That's OK, because the code is not currently relying on a `yield`ed value to do anything interesting. We'll revisit this point later in the chapter.\n\nWe're not using `yield` in a message passing sense here, only in a flow control sense to pause/block. Actually, it will have message passing, but only in one direction, after the generator is resumed.\n\nSo, the generator pauses at the `yield`, essentially asking the question, \"what value should I return to assign to the variable `text`?\" Who's going to answer that question?\n\nLook at `foo(..)`. If the Ajax request is successful, we call:\n\n```js\nit.next( data );\n```\n\nThat's resuming the generator with the response data, which means that our paused `yield` expression receives that value directly, and then as it restarts the generator code, that value gets assigned to the local variable `text`.\n\nPretty cool, huh?\n\nTake a step back and consider the implications. We have totally synchronous-looking code inside the generator (other than the `yield` keyword itself), but hidden behind the scenes, inside of `foo(..)`, the operations can complete asynchronously.\n\n**That's huge!** That's a nearly perfect solution to our previously stated problem with callbacks not being able to express asynchrony in a sequential, synchronous fashion that our brains can relate to.\n\nIn essence, we are abstracting the asynchrony away as an implementation detail, so that we can reason synchronously/sequentially about our flow control: \"Make an Ajax request, and when it finishes print out the response.\" And of course, we just expressed two steps in the flow control, but this same capability extends without bounds, to let us express however many steps we need to.\n\n**Tip:** This is such an important realization, just go back and read the last three paragraphs again to let it sink in!\n\n### Synchronous Error Handling\n\nBut the preceding generator code has even more goodness to *yield* to us. Let's turn our attention to the `try..catch` inside the generator:\n\n```js\ntry {\n\tvar text = yield foo( 11, 31 );\n\tconsole.log( text );\n}\ncatch (err) {\n\tconsole.error( err );\n}\n```\n\nHow does this work? The `foo(..)` call is asynchronously completing, and doesn't `try..catch` fail to catch asynchronous errors, as we looked at in Chapter 3?\n\nWe already saw how the `yield` lets the assignment statement pause to wait for `foo(..)` to finish, so that the completed response can be assigned to `text`. The awesome part is that this `yield` pausing *also* allows the generator to `catch` an error. We throw that error into the generator with this part of the earlier code listing:\n\n```js\nif (err) {\n\t// throw an error into `*main()`\n\tit.throw( err );\n}\n```\n\nThe `yield`-pause nature of generators means that not only do we get synchronous-looking `return` values from async function calls, but we can also synchronously `catch` errors from those async function calls!\n\nSo we've seen we can throw errors *into* a generator, but what about throwing errors *out of* a generator? Exactly as you'd expect:\n\n```js\nfunction *main() {\n\tvar x = yield \"Hello World\";\n\n\tyield x.toLowerCase();\t// cause an exception!\n}\n\nvar it = main();\n\nit.next().value;\t\t\t// Hello World\n\ntry {\n\tit.next( 42 );\n}\ncatch (err) {\n\tconsole.error( err );\t// TypeError\n}\n```\n\nOf course, we could have manually thrown an error with `throw ..` instead of causing an exception.\n\nWe can even `catch` the same error that we `throw(..)` into the generator, essentially giving the generator a chance to handle it but if it doesn't, the *iterator* code must handle it:\n\n```js\nfunction *main() {\n\tvar x = yield \"Hello World\";\n\n\t// never gets here\n\tconsole.log( x );\n}\n\nvar it = main();\n\nit.next();\n\ntry {\n\t// will `*main()` handle this error? we'll see!\n\tit.throw( \"Oops\" );\n}\ncatch (err) {\n\t// nope, didn't handle it!\n\tconsole.error( err );\t\t\t// Oops\n}\n```\n\nSynchronous-looking error handling (via `try..catch`) with async code is a huge win for readability and reason-ability.\n\n## Generators + Promises\n\nIn our previous discussion, we showed how generators can be iterated asynchronously, which is a huge step forward in sequential reason-ability over the spaghetti mess of callbacks. But we lost something very important: the trustability and composability of Promises (see Chapter 3)!\n\nDon't worry -- we can get that back. The best of all worlds in ES6 is to combine generators (synchronous-looking async code) with Promises (trustable and composable).\n\nBut how?\n\nRecall from Chapter 3 the Promise-based approach to our running Ajax example:\n\n```js\nfunction foo(x,y) {\n\treturn request(\n\t\t\"http://some.url.1/?x=\" + x + \"&y=\" + y\n\t);\n}\n\nfoo( 11, 31 )\n.then(\n\tfunction(text){\n\t\tconsole.log( text );\n\t},\n\tfunction(err){\n\t\tconsole.error( err );\n\t}\n);\n```\n\nIn our earlier generator code for the running Ajax example, `foo(..)` returned nothing (`undefined`), and our *iterator* control code didn't care about that `yield`ed value.\n\nBut here the Promise-aware `foo(..)` returns a promise after making the Ajax call. That suggests that we could construct a promise with `foo(..)` and then `yield` it from the generator, and then the *iterator* control code would receive that promise.\n\nBut what should the *iterator* do with the promise?\n\nIt should listen for the promise to resolve (fulfillment or rejection), and then either resume the generator with the fulfillment message or throw an error into the generator with the rejection reason.\n\nLet me repeat that, because it's so important. The natural way to get the most out of Promises and generators is **to `yield` a Promise**, and wire that Promise to control the generator's *iterator*.\n\nLet's give it a try! First, we'll put the Promise-aware `foo(..)` together with the generator `*main()`:\n\n```js\nfunction foo(x,y) {\n\treturn request(\n\t\t\"http://some.url.1/?x=\" + x + \"&y=\" + y\n\t);\n}\n\nfunction *main() {\n\ttry {\n\t\tvar text = yield foo( 11, 31 );\n\t\tconsole.log( text );\n\t}\n\tcatch (err) {\n\t\tconsole.error( err );\n\t}\n}\n```\n\nThe most powerful revelation in this refactor is that the code inside `*main()` **did not have to change at all!** Inside the generator, whatever values are `yield`ed out is just an opaque implementation detail, so we're not even aware it's happening, nor do we need to worry about it.\n\nBut how are we going to run `*main()` now? We still have some of the implementation plumbing work to do, to receive and wire up the `yield`ed promise so that it resumes the generator upon resolution. We'll start by trying that manually:\n\n```js\nvar it = main();\n\nvar p = it.next().value;\n\n// wait for the `p` promise to resolve\np.then(\n\tfunction(text){\n\t\tit.next( text );\n\t},\n\tfunction(err){\n\t\tit.throw( err );\n\t}\n);\n```\n\nActually, that wasn't so painful at all, was it?\n\nThis snippet should look very similar to what we did earlier with the manually wired generator controlled by the error-first callback. Instead of an `if (err) { it.throw..`, the promise already splits fulfillment (success) and rejection (failure) for us, but otherwise the *iterator* control is identical.\n\nNow, we've glossed over some important details.\n\nMost importantly, we took advantage of the fact that we knew that `*main()` only had one Promise-aware step in it. What if we wanted to be able to Promise-drive a generator no matter how many steps it has? We certainly don't want to manually write out the Promise chain differently for each generator! What would be much nicer is if there was a way to repeat (aka \"loop\" over) the iteration control, and each time a Promise comes out, wait on its resolution before continuing.\n\nAlso, what if the generator throws out an error (intentionally or accidentally) during the `it.next(..)` call? Should we quit, or should we `catch` it and send it right back in? Similarly, what if we `it.throw(..)` a Promise rejection into the generator, but it's not handled, and comes right back out?\n\n### Promise-Aware Generator Runner\n\nThe more you start to explore this path, the more you realize, \"wow, it'd be great if there was just some utility to do it for me.\" And you're absolutely correct. This is such an important pattern, and you don't want to get it wrong (or exhaust yourself repeating it over and over), so your best bet is to use a utility that is specifically designed to *run* Promise-`yield`ing generators in the manner we've illustrated.\n\nSeveral Promise abstraction libraries provide just such a utility, including my *asynquence* library and its `runner(..)`, which will be discussed in Appendix A of this book.\n\nBut for the sake of learning and illustration, let's just define our own standalone utility that we'll call `run(..)`:\n\n```js\n// thanks to Benjamin Gruenbaum (@benjamingr on GitHub) for\n// big improvements here!\nfunction run(gen) {\n\tvar args = [].slice.call( arguments, 1), it;\n\n\t// initialize the generator in the current context\n\tit = gen.apply( this, args );\n\n\t// return a promise for the generator completing\n\treturn Promise.resolve()\n\t\t.then( function handleNext(value){\n\t\t\t// run to the next yielded value\n\t\t\tvar next = it.next( value );\n\n\t\t\treturn (function handleResult(next){\n\t\t\t\t// generator has completed running?\n\t\t\t\tif (next.done) {\n\t\t\t\t\treturn next.value;\n\t\t\t\t}\n\t\t\t\t// otherwise keep going\n\t\t\t\telse {\n\t\t\t\t\treturn Promise.resolve( next.value )\n\t\t\t\t\t\t.then(\n\t\t\t\t\t\t\t// resume the async loop on\n\t\t\t\t\t\t\t// success, sending the resolved\n\t\t\t\t\t\t\t// value back into the generator\n\t\t\t\t\t\t\thandleNext,\n\n\t\t\t\t\t\t\t// if `value` is a rejected\n\t\t\t\t\t\t\t// promise, propagate error back\n\t\t\t\t\t\t\t// into the generator for its own\n\t\t\t\t\t\t\t// error handling\n\t\t\t\t\t\t\tfunction handleErr(err) {\n\t\t\t\t\t\t\t\treturn Promise.resolve(\n\t\t\t\t\t\t\t\t\tit.throw( err )\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t.then( handleResult );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t})(next);\n\t\t} );\n}\n```\n\nAs you can see, it's a quite a bit more complex than you'd probably want to author yourself, and you especially wouldn't want to repeat this code for each generator you use. So, a utility/library helper is definitely the way to go. Nevertheless, I encourage you to spend a few minutes studying that code listing to get a better sense of how to manage the generator+Promise negotiation.\n\nHow would you use `run(..)` with `*main()` in our *running* Ajax example?\n\n```js\nfunction *main() {\n\t// ..\n}\n\nrun( main );\n```\n\nThat's it! The way we wired `run(..)`, it will automatically advance the generator you pass to it, asynchronously until completion.\n\n**Note:** The `run(..)` we defined returns a promise which is wired to resolve once the generator is complete, or receive an uncaught exception if the generator doesn't handle it. We don't show that capability here, but we'll come back to it later in the chapter.\n\n#### ES7: `async` and `await`?\n\nThe preceding pattern -- generators yielding Promises that then control the generator's *iterator* to advance it to completion -- is such a powerful and useful approach, it would be nicer if we could do it without the clutter of the library utility helper (aka `run(..)`).\n\nThere's probably good news on that front. At the time of this writing, there's early but strong support for a proposal for more syntactic addition in this realm for the post-ES6, ES7-ish timeframe. Obviously, it's too early to guarantee the details, but there's a pretty decent chance it will shake out similar to the following:\n\n```js\nfunction foo(x,y) {\n\treturn request(\n\t\t\"http://some.url.1/?x=\" + x + \"&y=\" + y\n\t);\n}\n\nasync function main() {\n\ttry {\n\t\tvar text = await foo( 11, 31 );\n\t\tconsole.log( text );\n\t}\n\tcatch (err) {\n\t\tconsole.error( err );\n\t}\n}\n\nmain();\n```\n\nAs you can see, there's no `run(..)` call (meaning no need for a library utility!) to invoke and drive `main()` -- it's just called as a normal function. Also, `main()` isn't declared as a generator function anymore; it's a new kind of function: `async function`. And finally, instead of `yield`ing a Promise, we `await` for it to resolve.\n\nThe `async function` automatically knows what to do if you `await` a Promise -- it will pause the function (just like with generators) until the Promise resolves. We didn't illustrate it in this snippet, but calling an async function like `main()` automatically returns a promise that's resolved whenever the function finishes completely.\n\n**Tip:** The `async` / `await` syntax should look very familiar to readers with  experience in C#, because it's basically identical.\n\nThe proposal essentially codifies support for the pattern we've already derived, into a syntactic mechanism: combining Promises with sync-looking flow control code. That's the best of both worlds combined, to effectively address practically all of the major concerns we outlined with callbacks.\n\nThe mere fact that such a ES7-ish proposal already exists and has early support and enthusiasm is a major vote of confidence in the future importance of this async pattern.\n\n### Promise Concurrency in Generators\n\nSo far, all we've demonstrated is a single-step async flow with Promises+generators. But real-world code will often have many async steps.\n\nIf you're not careful, the sync-looking style of generators may lull you into complacency with how you structure your async concurrency, leading to suboptimal performance patterns. So we want to spend a little time exploring the options.\n\nImagine a scenario where you need to fetch data from two different sources, then combine those responses to make a third request, and finally print out the last response. We explored a similar scenario with Promises in Chapter 3, but let's reconsider it in the context of generators.\n\nYour first instinct might be something like:\n\n```js\nfunction *foo() {\n\tvar r1 = yield request( \"http://some.url.1\" );\n\tvar r2 = yield request( \"http://some.url.2\" );\n\n\tvar r3 = yield request(\n\t\t\"http://some.url.3/?v=\" + r1 + \",\" + r2\n\t);\n\n\tconsole.log( r3 );\n}\n\n// use previously defined `run(..)` utility\nrun( foo );\n```\n\nThis code will work, but in the specifics of our scenario, it's not optimal. Can you spot why?\n\nBecause the `r1` and `r2` requests can -- and for performance reasons, *should* -- run concurrently, but in this code they will run sequentially; the `\"http://some.url.2\"` URL isn't Ajax fetched until after the `\"http://some.url.1\"` request is finished. These two requests are independent, so the better performance approach would likely be to have them run at the same time.\n\nBut how exactly would you do that with a generator and `yield`? We know that `yield` is only a single pause point in the code, so you can't really do two pauses at the same time.\n\nThe most natural and effective answer is to base the async flow on Promises, specifically on their capability to manage state in a time-independent fashion (see \"Future Value\" in Chapter 3).\n\nThe simplest approach:\n\n```js\nfunction *foo() {\n\t// make both requests \"in parallel\"\n\tvar p1 = request( \"http://some.url.1\" );\n\tvar p2 = request( \"http://some.url.2\" );\n\n\t// wait until both promises resolve\n\tvar r1 = yield p1;\n\tvar r2 = yield p2;\n\n\tvar r3 = yield request(\n\t\t\"http://some.url.3/?v=\" + r1 + \",\" + r2\n\t);\n\n\tconsole.log( r3 );\n}\n\n// use previously defined `run(..)` utility\nrun( foo );\n```\n\nWhy is this different from the previous snippet? Look at where the `yield` is and is not. `p1` and `p2` are promises for Ajax requests made concurrently (aka \"in parallel\"). It doesn't matter which one finishes first, because promises will hold onto their resolved state for as long as necessary.\n\nThen we use two subsequent `yield` statements to wait for and retrieve the resolutions from the promises (into `r1` and `r2`, respectively). If `p1` resolves first, the `yield p1` resumes first then waits on the `yield p2` to resume. If `p2` resolves first, it will just patiently hold onto that resolution value until asked, but the `yield p1` will hold on first, until `p1` resolves.\n\nEither way, both `p1` and `p2` will run concurrently, and both have to finish, in either order, before the `r3 = yield request..` Ajax request will be made.\n\nIf that flow control processing model sounds familiar, it's basically the same as what we identified in Chapter 3 as the \"gate\" pattern, enabled by the `Promise.all([ .. ])` utility. So, we could also express the flow control like this:\n\n```js\nfunction *foo() {\n\t// make both requests \"in parallel,\" and\n\t// wait until both promises resolve\n\tvar results = yield Promise.all( [\n\t\trequest( \"http://some.url.1\" ),\n\t\trequest( \"http://some.url.2\" )\n\t] );\n\n\tvar r1 = results[0];\n\tvar r2 = results[1];\n\n\tvar r3 = yield request(\n\t\t\"http://some.url.3/?v=\" + r1 + \",\" + r2\n\t);\n\n\tconsole.log( r3 );\n}\n\n// use previously defined `run(..)` utility\nrun( foo );\n```\n\n**Note:** As we discussed in Chapter 3, we can even use ES6 destructuring assignment to simplify the `var r1 = .. var r2 = ..` assignments, with `var [r1,r2] = results`.\n\nIn other words, all of the concurrency capabilities of Promises are available to us in the generator+Promise approach. So in any place where you need more than sequential this-then-that async flow control steps, Promises are likely your best bet.\n\n#### Promises, Hidden\n\nAs a word of stylistic caution, be careful about how much Promise logic you include **inside your generators**. The whole point of using generators for asynchrony in the way we've described is to create simple, sequential, sync-looking code, and to hide as much of the details of asynchrony away from that code as possible.\n\nFor example, this might be a cleaner approach:\n\n```js\n// note: normal function, not generator\nfunction bar(url1,url2) {\n\treturn Promise.all( [\n\t\trequest( url1 ),\n\t\trequest( url2 )\n\t] );\n}\n\nfunction *foo() {\n\t// hide the Promise-based concurrency details\n\t// inside `bar(..)`\n\tvar results = yield bar(\n\t\t\"http://some.url.1\",\n\t\t\"http://some.url.2\"\n\t);\n\n\tvar r1 = results[0];\n\tvar r2 = results[1];\n\n\tvar r3 = yield request(\n\t\t\"http://some.url.3/?v=\" + r1 + \",\" + r2\n\t);\n\n\tconsole.log( r3 );\n}\n\n// use previously defined `run(..)` utility\nrun( foo );\n```\n\nInside `*foo()`, it's cleaner and clearer that all we're doing is just asking `bar(..)` to get us some `results`, and we'll `yield`-wait on that to happen. We don't have to care that under the covers a `Promise.all([ .. ])` Promise composition will be used to make that happen.\n\n**We treat asynchrony, and indeed Promises, as an implementation detail.**\n\nHiding your Promise logic inside a function that you merely call from your generator is especially useful if you're going to do a sophisticated series flow-control. For example:\n\n```js\nfunction bar() {\n\tPromise.all( [\n\t\tbaz( .. )\n\t\t.then( .. ),\n\t\tPromise.race( [ .. ] )\n\t] )\n\t.then( .. )\n}\n```\n\nThat kind of logic is sometimes required, and if you dump it directly inside your generator(s), you've defeated most of the reason why you would want to use generators in the first place. We *should* intentionally abstract such details away from our generator code so that they don't clutter up the higher level task expression.\n\nBeyond creating code that is both functional and performant, you should also strive to make code that is as reason-able and maintainable as possible.\n\n**Note:** Abstraction is not *always* a healthy thing for programming -- many times it can increase complexity in exchange for terseness. But in this case, I believe it's much healthier for your generator+Promise async code than the alternatives. As with all such advice, though, pay attention to your specific situations and make proper decisions for you and your team.\n\n## Generator Delegation\n\nIn the previous section, we showed calling regular functions from inside a generator, and how that remains a useful technique for abstracting away implementation details (like async Promise flow). But the main drawback of using a normal function for this task is that it has to behave by the normal function rules, which means it cannot pause itself with `yield` like a generator can.\n\nIt may then occur to you that you might try to call one generator from another generator, using our `run(..)` helper, such as:\n\n```js\nfunction *foo() {\n\tvar r2 = yield request( \"http://some.url.2\" );\n\tvar r3 = yield request( \"http://some.url.3/?v=\" + r2 );\n\n\treturn r3;\n}\n\nfunction *bar() {\n\tvar r1 = yield request( \"http://some.url.1\" );\n\n\t// \"delegating\" to `*foo()` via `run(..)`\n\tvar r3 = yield run( foo );\n\n\tconsole.log( r3 );\n}\n\nrun( bar );\n```\n\nWe run `*foo()` inside of `*bar()` by using our `run(..)` utility again. We take advantage here of the fact that the `run(..)` we defined earlier returns a promise which is resolved when its generator is run to completion (or errors out), so if we `yield` out to a `run(..)` instance the promise from another `run(..)` call, it automatically pauses `*bar()` until `*foo()` finishes.\n\nBut there's an even better way to integrate calling `*foo()` into `*bar()`, and it's called `yield`-delegation. The special syntax for `yield`-delegation is: `yield * __` (notice the extra `*`). Before we see it work in our previous example, let's look at a simpler scenario:\n\n```js\nfunction *foo() {\n\tconsole.log( \"`*foo()` starting\" );\n\tyield 3;\n\tyield 4;\n\tconsole.log( \"`*foo()` finished\" );\n}\n\nfunction *bar() {\n\tyield 1;\n\tyield 2;\n\tyield *foo();\t// `yield`-delegation!\n\tyield 5;\n}\n\nvar it = bar();\n\nit.next().value;\t// 1\nit.next().value;\t// 2\nit.next().value;\t// `*foo()` starting\n\t\t\t\t\t// 3\nit.next().value;\t// 4\nit.next().value;\t// `*foo()` finished\n\t\t\t\t\t// 5\n```\n\n**Note:** Similar to a note earlier in the chapter where I explained why I prefer `function *foo() ..` instead of `function* foo() ..`, I also prefer -- differing from most other documentation on the topic -- to say `yield *foo()` instead of `yield* foo()`. The placement of the `*` is purely stylistic and up to your best judgment. But I find the consistency of styling attractive.\n\nHow does the `yield *foo()` delegation work?\n\nFirst, calling `foo()` creates an *iterator* exactly as we've already seen. Then, `yield *` delegates/transfers the *iterator* instance control (of the present `*bar()` generator) over to this other `*foo()` *iterator*.\n\nSo, the first two `it.next()` calls are controlling `*bar()`, but when we make the third `it.next()` call, now `*foo()` starts up, and now we're controlling `*foo()` instead of `*bar()`. That's why it's called delegation -- `*bar()` delegated its iteration control to `*foo()`.\n\nAs soon as the `it` *iterator* control exhausts the entire `*foo()` *iterator*, it automatically returns to controlling `*bar()`.\n\nSo now back to the previous example with the three sequential Ajax requests:\n\n```js\nfunction *foo() {\n\tvar r2 = yield request( \"http://some.url.2\" );\n\tvar r3 = yield request( \"http://some.url.3/?v=\" + r2 );\n\n\treturn r3;\n}\n\nfunction *bar() {\n\tvar r1 = yield request( \"http://some.url.1\" );\n\n\t// \"delegating\" to `*foo()` via `yield*`\n\tvar r3 = yield *foo();\n\n\tconsole.log( r3 );\n}\n\nrun( bar );\n```\n\nThe only difference between this snippet and the version used earlier is the use of `yield *foo()` instead of the previous `yield run(foo)`.\n\n**Note:** `yield *` yields iteration control, not generator control; when you invoke the `*foo()` generator, you're now `yield`-delegating to its *iterator*. But you can actually `yield`-delegate to any *iterable*; `yield *[1,2,3]` would consume the default *iterator* for the `[1,2,3]` array value.\n\n### Why Delegation?\n\nThe purpose of `yield`-delegation is mostly code organization, and in that way is symmetrical with normal function calling.\n\nImagine two modules that respectively provide methods `foo()` and `bar()`, where `bar()` calls `foo()`. The reason the two are separate is generally because the proper organization of code for the program calls for them to be in separate functions. For example, there may be cases where `foo()` is called standalone, and other places where `bar()` calls `foo()`.\n\nFor all these exact same reasons, keeping generators separate aids in program readability, maintenance, and debuggability. In that respect, `yield *` is a syntactic shortcut for manually iterating over the steps of `*foo()` while inside of `*bar()`.\n\nSuch manual approach would be especially complex if the steps in `*foo()` were asynchronous, which is why you'd probably need to use that `run(..)` utility to do it. And as we've shown, `yield *foo()` eliminates the need for a sub-instance of the `run(..)` utility (like `run(foo)`).\n\n### Delegating Messages\n\nYou may wonder how this `yield`-delegation works not just with *iterator* control but with the two-way message passing. Carefully follow the flow of messages in and out, through the `yield`-delegation:\n\n```js\nfunction *foo() {\n\tconsole.log( \"inside `*foo()`:\", yield \"B\" );\n\n\tconsole.log( \"inside `*foo()`:\", yield \"C\" );\n\n\treturn \"D\";\n}\n\nfunction *bar() {\n\tconsole.log( \"inside `*bar()`:\", yield \"A\" );\n\n\t// `yield`-delegation!\n\tconsole.log( \"inside `*bar()`:\", yield *foo() );\n\n\tconsole.log( \"inside `*bar()`:\", yield \"E\" );\n\n\treturn \"F\";\n}\n\nvar it = bar();\n\nconsole.log( \"outside:\", it.next().value );\n// outside: A\n\nconsole.log( \"outside:\", it.next( 1 ).value );\n// inside `*bar()`: 1\n// outside: B\n\nconsole.log( \"outside:\", it.next( 2 ).value );\n// inside `*foo()`: 2\n// outside: C\n\nconsole.log( \"outside:\", it.next( 3 ).value );\n// inside `*foo()`: 3\n// inside `*bar()`: D\n// outside: E\n\nconsole.log( \"outside:\", it.next( 4 ).value );\n// inside `*bar()`: 4\n// outside: F\n```\n\nPay particular attention to the processing steps after the `it.next(3)` call:\n\n1. The `3` value is passed (through the `yield`-delegation in `*bar()`) into the waiting `yield \"C\"` expression inside of `*foo()`.\n2. `*foo()` then calls `return \"D\"`, but this value doesn't get returned all the way back to the outside `it.next(3)` call.\n3. Instead, the `\"D\"` value is sent as the result of the waiting `yield *foo()` expression inside of `*bar()` -- this `yield`-delegation expression has essentially been paused while all of `*foo()` was exhausted. So `\"D\"` ends up inside of `*bar()` for it to print out.\n4. `yield \"E\"` is called inside of `*bar()`, and the `\"E\"` value is yielded to the outside as the result of the `it.next(3)` call.\n\nFrom the perspective of the external *iterator* (`it`), it doesn't appear any differently between controlling the initial generator or a delegated one.\n\nIn fact, `yield`-delegation doesn't even have to be directed to another generator; it can just be directed to a non-generator, general *iterable*. For example:\n\n```js\nfunction *bar() {\n\tconsole.log( \"inside `*bar()`:\", yield \"A\" );\n\n\t// `yield`-delegation to a non-generator!\n\tconsole.log( \"inside `*bar()`:\", yield *[ \"B\", \"C\", \"D\" ] );\n\n\tconsole.log( \"inside `*bar()`:\", yield \"E\" );\n\n\treturn \"F\";\n}\n\nvar it = bar();\n\nconsole.log( \"outside:\", it.next().value );\n// outside: A\n\nconsole.log( \"outside:\", it.next( 1 ).value );\n// inside `*bar()`: 1\n// outside: B\n\nconsole.log( \"outside:\", it.next( 2 ).value );\n// outside: C\n\nconsole.log( \"outside:\", it.next( 3 ).value );\n// outside: D\n\nconsole.log( \"outside:\", it.next( 4 ).value );\n// inside `*bar()`: undefined\n// outside: E\n\nconsole.log( \"outside:\", it.next( 5 ).value );\n// inside `*bar()`: 5\n// outside: F\n```\n\nNotice the differences in where the messages were received/reported between this example and the one previous.\n\nMost strikingly, the default `array` *iterator* doesn't care about any messages sent in via `next(..)` calls, so the values `2`, `3`, and `4` are essentially ignored. Also, because that *iterator* has no explicit `return` value (unlike the previously used `*foo()`), the `yield *` expression gets an `undefined` when it finishes.\n\n#### Exceptions Delegated, Too!\n\nIn the same way that `yield`-delegation transparently passes messages through in both directions, errors/exceptions also pass in both directions:\n\n```js\nfunction *foo() {\n\ttry {\n\t\tyield \"B\";\n\t}\n\tcatch (err) {\n\t\tconsole.log( \"error caught inside `*foo()`:\", err );\n\t}\n\n\tyield \"C\";\n\n\tthrow \"D\";\n}\n\nfunction *bar() {\n\tyield \"A\";\n\n\ttry {\n\t\tyield *foo();\n\t}\n\tcatch (err) {\n\t\tconsole.log( \"error caught inside `*bar()`:\", err );\n\t}\n\n\tyield \"E\";\n\n\tyield *baz();\n\n\t// note: can't get here!\n\tyield \"G\";\n}\n\nfunction *baz() {\n\tthrow \"F\";\n}\n\nvar it = bar();\n\nconsole.log( \"outside:\", it.next().value );\n// outside: A\n\nconsole.log( \"outside:\", it.next( 1 ).value );\n// outside: B\n\nconsole.log( \"outside:\", it.throw( 2 ).value );\n// error caught inside `*foo()`: 2\n// outside: C\n\nconsole.log( \"outside:\", it.next( 3 ).value );\n// error caught inside `*bar()`: D\n// outside: E\n\ntry {\n\tconsole.log( \"outside:\", it.next( 4 ).value );\n}\ncatch (err) {\n\tconsole.log( \"error caught outside:\", err );\n}\n// error caught outside: F\n```\n\nSome things to note from this snippet:\n\n1. When we call `it.throw(2)`, it sends the error message `2` into `*bar()`, which delegates that to `*foo()`, which then `catch`es it and handles it gracefully. Then, the `yield \"C\"` sends `\"C\"` back out as the return `value` from the `it.throw(2)` call.\n2. The `\"D\"` value that's next `throw`n from inside `*foo()` propagates out to `*bar()`, which `catch`es it and handles it gracefully. Then the `yield \"E\"` sends `\"E\"` back out as the return `value` from the `it.next(3)` call.\n3. Next, the exception `throw`n from `*baz()` isn't caught in `*bar()` -- though we did `catch` it outside -- so both `*baz()` and `*bar()` are set to a completed state. After this snippet, you would not be able to get the `\"G\"` value out with any subsequent `next(..)` call(s) -- they will just return `undefined` for `value`.\n\n### Delegating Asynchrony\n\nLet's finally get back to our earlier `yield`-delegation example with the multiple sequential Ajax requests:\n\n```js\nfunction *foo() {\n\tvar r2 = yield request( \"http://some.url.2\" );\n\tvar r3 = yield request( \"http://some.url.3/?v=\" + r2 );\n\n\treturn r3;\n}\n\nfunction *bar() {\n\tvar r1 = yield request( \"http://some.url.1\" );\n\n\tvar r3 = yield *foo();\n\n\tconsole.log( r3 );\n}\n\nrun( bar );\n```\n\nInstead of calling `yield run(foo)` inside of `*bar()`, we just call `yield *foo()`.\n\nIn the previous version of this example, the Promise mechanism (controlled by `run(..)`) was used to transport the value from `return r3` in `*foo()` to the local variable `r3` inside `*bar()`. Now, that value is just returned back directly via the `yield *` mechanics.\n\nOtherwise, the behavior is pretty much identical.\n\n### Delegating \"Recursion\"\n\nOf course, `yield`-delegation can keep following as many delegation steps as you wire up. You could even use `yield`-delegation for async-capable generator \"recursion\" -- a generator `yield`-delegating to itself:\n\n```js\nfunction *foo(val) {\n\tif (val > 1) {\n\t\t// generator recursion\n\t\tval = yield *foo( val - 1 );\n\t}\n\n\treturn yield request( \"http://some.url/?v=\" + val );\n}\n\nfunction *bar() {\n\tvar r1 = yield *foo( 3 );\n\tconsole.log( r1 );\n}\n\nrun( bar );\n```\n\n**Note:** Our `run(..)` utility could have been called with `run( foo, 3 )`, because it supports additional parameters being passed along to the initialization of the generator. However, we used a parameter-free `*bar()` here to highlight the flexibility of `yield *`.\n\nWhat processing steps follow from that code? Hang on, this is going to be quite intricate to describe in detail:\n\n1. `run(bar)` starts up the `*bar()` generator.\n2. `foo(3)` creates an *iterator* for `*foo(..)` and passes `3` as its `val` parameter.\n3. Because `3 > 1`, `foo(2)` creates another *iterator* and passes in `2` as its `val` parameter.\n4. Because `2 > 1`, `foo(1)` creates yet another *iterator* and passes in `1` as its `val` parameter.\n5. `1 > 1` is `false`, so we next call `request(..)` with the `1` value, and get a promise back for that first Ajax call.\n6. That promise is `yield`ed out, which comes back to the `*foo(2)` generator instance.\n7. The `yield *` passes that promise back out to the `*foo(3)` generator instance. Another `yield *` passes the promise out to the `*bar()` generator instance. And yet again another `yield *` passes the promise out to the `run(..)` utility, which will wait on that promise (for the first Ajax request) to proceed.\n8. When the promise resolves, its fulfillment message is sent to resume `*bar()`, which passes through the `yield *` into the `*foo(3)` instance, which then passes through the `yield *` to the `*foo(2)` generator instance, which then passes through the `yield *` to the normal `yield` that's waiting in the `*foo(3)` generator instance.\n9. That first call's Ajax response is now immediately `return`ed from the `*foo(3)` generator instance, which sends that value back as the result of the `yield *` expression in the `*foo(2)` instance, and assigned to its local `val` variable.\n10. Inside `*foo(2)`, a second Ajax request is made with `request(..)`, whose promise is `yield`ed back to the `*foo(1)` instance, and then `yield *` propagates all the way out to `run(..)` (step 7 again). When the promise resolves, the second Ajax response propagates all the way back into the `*foo(2)` generator instance, and is assigned to its local `val` variable.\n11. Finally, the third Ajax request is made with `request(..)`, its promise goes out to `run(..)`, and then its resolution value comes all the way back, which is then `return`ed so that it comes back to the waiting `yield *` expression in `*bar()`.\n\nPhew! A lot of crazy mental juggling, huh? You might want to read through that a few more times, and then go grab a snack to clear your head!\n\n## Generator Concurrency\n\nAs we discussed in both Chapter 1 and earlier in this chapter, two simultaneously running \"processes\" can cooperatively interleave their operations, and many times this can *yield* (pun intended) very powerful asynchrony expressions.\n\nFrankly, our earlier examples of concurrency interleaving of multiple generators showed how to make it really confusing. But we hinted that there's places where this capability is quite useful.\n\nRecall a scenario we looked at in Chapter 1, where two different simultaneous Ajax response handlers needed to coordinate with each other to make sure that the data communication was not a race condition. We slotted the responses into the `res` array like this:\n\n```js\nfunction response(data) {\n\tif (data.url == \"http://some.url.1\") {\n\t\tres[0] = data;\n\t}\n\telse if (data.url == \"http://some.url.2\") {\n\t\tres[1] = data;\n\t}\n}\n```\n\nBut how can we use multiple generators concurrently for this scenario?\n\n```js\n// `request(..)` is a Promise-aware Ajax utility\n\nvar res = [];\n\nfunction *reqData(url) {\n\tres.push(\n\t\tyield request( url )\n\t);\n}\n```\n\n**Note:** We're going to use two instances of the `*reqData(..)` generator here, but there's no difference to running a single instance of two different generators; both approaches are reasoned about identically. We'll see two different generators coordinating in just a bit.\n\nInstead of having to manually sort out `res[0]` and `res[1]` assignments, we'll use coordinated ordering so that `res.push(..)` properly slots the values in the expected and predictable order. The expressed logic thus should feel a bit cleaner.\n\nBut how will we actually orchestrate this interaction? First, let's just do it manually, with Promises:\n\n```js\nvar it1 = reqData( \"http://some.url.1\" );\nvar it2 = reqData( \"http://some.url.2\" );\n\nvar p1 = it1.next().value;\nvar p2 = it2.next().value;\n\np1\n.then( function(data){\n\tit1.next( data );\n\treturn p2;\n} )\n.then( function(data){\n\tit2.next( data );\n} );\n```\n\n`*reqData(..)`'s two instances are both started to make their Ajax requests, then paused with `yield`. Then we choose to resume the first instance when `p1` resolves, and then `p2`'s resolution will restart the second instance. In this way, we use Promise orchestration to ensure that `res[0]` will have the first response and `res[1]` will have the second response.\n\nBut frankly, this is awfully manual, and it doesn't really let the generators orchestrate themselves, which is where the true power can lie. Let's try it a different way:\n\n```js\n// `request(..)` is a Promise-aware Ajax utility\n\nvar res = [];\n\nfunction *reqData(url) {\n\tvar data = yield request( url );\n\n\t// transfer control\n\tyield;\n\n\tres.push( data );\n}\n\nvar it1 = reqData( \"http://some.url.1\" );\nvar it2 = reqData( \"http://some.url.2\" );\n\nvar p1 = it1.next().value;\nvar p2 = it2.next().value;\n\np1.then( function(data){\n\tit1.next( data );\n} );\n\np2.then( function(data){\n\tit2.next( data );\n} );\n\nPromise.all( [p1,p2] )\n.then( function(){\n\tit1.next();\n\tit2.next();\n} );\n```\n\nOK, this is a bit better (though still manual!), because now the two instances of `*reqData(..)` run truly concurrently, and (at least for the first part) independently.\n\nIn the previous snippet, the second instance was not given its data until after the first instance was totally finished. But here, both instances receive their data as soon as their respective responses come back, and then each instance does another `yield` for control transfer purposes. We then choose what order to resume them in the `Promise.all([ .. ])` handler.\n\nWhat may not be as obvious is that this approach hints at an easier form for a reusable utility, because of the symmetry. We can do even better. Let's imagine using a utility called `runAll(..)`:\n\n```js\n// `request(..)` is a Promise-aware Ajax utility\n\nvar res = [];\n\nrunAll(\n\tfunction*(){\n\t\tvar p1 = request( \"http://some.url.1\" );\n\n\t\t// transfer control\n\t\tyield;\n\n\t\tres.push( yield p1 );\n\t},\n\tfunction*(){\n\t\tvar p2 = request( \"http://some.url.2\" );\n\n\t\t// transfer control\n\t\tyield;\n\n\t\tres.push( yield p2 );\n\t}\n);\n```\n\n**Note:** We're not including a code listing for `runAll(..)` as it is not only long enough to bog down the text, but is an extension of the logic we've already implemented in `run(..)` earlier. So, as a good supplementary exercise for the reader, try your hand at evolving the code from `run(..)` to work like the imagined `runAll(..)`. Also, my *asynquence* library provides a previously mentioned `runner(..)` utility with this kind of capability already built in, and will be discussed in Appendix A of this book.\n\nHere's how the processing inside `runAll(..)` would operate:\n\n1. The first generator gets a promise for the first Ajax response from `\"http://some.url.1\"`, then `yield`s control back to the `runAll(..)` utility.\n2. The second generator runs and does the same for `\"http://some.url.2\"`, `yield`ing control back to the `runAll(..)` utility.\n3. The first generator resumes, and then `yield`s out its promise `p1`. The `runAll(..)` utility does the same in this case as our previous `run(..)`, in that it waits on that promise to resolve, then resumes the same generator (no control transfer!). When `p1` resolves, `runAll(..)` resumes the first generator again with that resolution value, and then `res[0]` is given its value. When the first generator then finishes, that's an implicit transfer of control.\n4. The second generator resumes, `yield`s out its promise `p2`, and waits for it to resolve. Once it does, `runAll(..)` resumes the second generator with that value, and `res[1]` is set.\n\nIn this running example, we use an outer variable called `res` to store the results of the two different Ajax responses -- that's our concurrency coordination making that possible.\n\nBut it might be quite helpful to further extend `runAll(..)` to provide an inner variable space for the multiple generator instances to *share*, such as an empty object we'll call `data` below. Also, it could take non-Promise values that are `yield`ed and hand them off to the next generator.\n\nConsider:\n\n```js\n// `request(..)` is a Promise-aware Ajax utility\n\nrunAll(\n\tfunction*(data){\n\t\tdata.res = [];\n\n\t\t// transfer control (and message pass)\n\t\tvar url1 = yield \"http://some.url.2\";\n\n\t\tvar p1 = request( url1 ); // \"http://some.url.1\"\n\n\t\t// transfer control\n\t\tyield;\n\n\t\tdata.res.push( yield p1 );\n\t},\n\tfunction*(data){\n\t\t// transfer control (and message pass)\n\t\tvar url2 = yield \"http://some.url.1\";\n\n\t\tvar p2 = request( url2 ); // \"http://some.url.2\"\n\n\t\t// transfer control\n\t\tyield;\n\n\t\tdata.res.push( yield p2 );\n\t}\n);\n```\n\nIn this formulation, the two generators are not just coordinating control transfer, but actually communicating with each other, both through `data.res` and the `yield`ed messages that trade `url1` and `url2` values. That's incredibly powerful!\n\nSuch realization also serves as a conceptual base for a more sophisticated asynchrony technique called CSP (Communicating Sequential Processes), which we will cover in Appendix B of this book.\n\n## Thunks\n\nSo far, we've made the assumption that `yield`ing a Promise from a generator -- and having that Promise resume the generator via a helper utility like `run(..)` -- was the best possible way to manage asynchrony with generators. To be clear, it is.\n\nBut we skipped over another pattern that has some mildly widespread adoption, so in the interest of completeness we'll take a brief look at it.\n\nIn general computer science, there's an old pre-JS concept called a \"thunk.\" Without getting bogged down in the historical nature, a narrow expression of a thunk in JS is a function that -- without any parameters -- is wired to call another function.\n\nIn other words, you wrap a function definition around function call -- with any parameters it needs -- to *defer* the execution of that call, and that wrapping function is a thunk. When you later execute the thunk, you end up calling the original function.\n\nFor example:\n\n```js\nfunction foo(x,y) {\n\treturn x + y;\n}\n\nfunction fooThunk() {\n\treturn foo( 3, 4 );\n}\n\n// later\n\nconsole.log( fooThunk() );\t// 7\n```\n\nSo, a synchronous thunk is pretty straightforward. But what about an async thunk? We can essentially extend the narrow thunk definition to include it receiving a callback.\n\nConsider:\n\n```js\nfunction foo(x,y,cb) {\n\tsetTimeout( function(){\n\t\tcb( x + y );\n\t}, 1000 );\n}\n\nfunction fooThunk(cb) {\n\tfoo( 3, 4, cb );\n}\n\n// later\n\nfooThunk( function(sum){\n\tconsole.log( sum );\t\t// 7\n} );\n```\n\nAs you can see, `fooThunk(..)` only expects a `cb(..)` parameter, as it already has values `3` and `4` (for `x` and `y`, respectively) pre-specified and ready to pass to `foo(..)`. A thunk is just waiting around patiently for the last piece it needs to do its job: the callback.\n\nYou don't want to make thunks manually, though. So, let's invent a utility that does this wrapping for us.\n\nConsider:\n\n```js\nfunction thunkify(fn) {\n\tvar args = [].slice.call( arguments, 1 );\n\treturn function(cb) {\n\t\targs.push( cb );\n\t\treturn fn.apply( null, args );\n\t};\n}\n\nvar fooThunk = thunkify( foo, 3, 4 );\n\n// later\n\nfooThunk( function(sum) {\n\tconsole.log( sum );\t\t// 7\n} );\n```\n\n**Tip:** Here we assume that the original (`foo(..)`) function signature expects its callback in the last position, with any other parameters coming before it. This is a pretty ubiquitous \"standard\" for async JS function standards. You might call it \"callback-last style.\" If for some reason you had a need to handle \"callback-first style\" signatures, you would just make a utility that used `args.unshift(..)` instead of `args.push(..)`.\n\nThe preceding formulation of `thunkify(..)` takes both the `foo(..)` function reference, and any parameters it needs, and returns back the thunk itself (`fooThunk(..)`). However, that's not the typical approach you'll find to thunks in JS.\n\nInstead of `thunkify(..)` making the thunk itself, typically -- if not perplexingly -- the `thunkify(..)` utility would produce a function that produces thunks.\n\nUhhhh... yeah.\n\nConsider:\n\n```js\nfunction thunkify(fn) {\n\treturn function() {\n\t\tvar args = [].slice.call( arguments );\n\t\treturn function(cb) {\n\t\t\targs.push( cb );\n\t\t\treturn fn.apply( null, args );\n\t\t};\n\t};\n}\n```\n\nThe main difference here is the extra `return function() { .. }` layer. Here's how its usage differs:\n\n```js\nvar whatIsThis = thunkify( foo );\n\nvar fooThunk = whatIsThis( 3, 4 );\n\n// later\n\nfooThunk( function(sum) {\n\tconsole.log( sum );\t\t// 7\n} );\n```\n\nObviously, the big question this snippet implies is what is `whatIsThis` properly called? It's not the thunk, it's the thing that will produce thunks from `foo(..)` calls. It's kind of like a \"factory\" for \"thunks.\" There doesn't seem to be any kind of standard agreement for naming such a thing.\n\nSo, my proposal is \"thunkory\" (\"thunk\" + \"factory\").  So, `thunkify(..)` produces a thunkory, and a thunkory produces thunks. That reasoning is symmetric to my proposal for \"promisory\" in Chapter 3:\n\n```js\nvar fooThunkory = thunkify( foo );\n\nvar fooThunk1 = fooThunkory( 3, 4 );\nvar fooThunk2 = fooThunkory( 5, 6 );\n\n// later\n\nfooThunk1( function(sum) {\n\tconsole.log( sum );\t\t// 7\n} );\n\nfooThunk2( function(sum) {\n\tconsole.log( sum );\t\t// 11\n} );\n```\n\n**Note:** The running `foo(..)` example expects a style of callback that's not \"error-first style.\" Of course, \"error-first style\" is much more common. If `foo(..)` had some sort of legitimate error-producing expectation, we could change it to expect and use an error-first callback. None of the subsequent `thunkify(..)` machinery cares what style of callback is assumed. The only difference in usage would be `fooThunk1(function(err,sum){..`.\n\nExposing the thunkory method -- instead of how the earlier `thunkify(..)` hides this intermediary step -- may seem like unnecessary complication. But in general, it's quite useful to make thunkories at the beginning of your program to wrap existing API methods, and then be able to pass around and call those thunkories when you need thunks. The two distinct steps preserve a cleaner separation of capability.\n\nTo illustrate:\n\n```js\n// cleaner:\nvar fooThunkory = thunkify( foo );\n\nvar fooThunk1 = fooThunkory( 3, 4 );\nvar fooThunk2 = fooThunkory( 5, 6 );\n\n// instead of:\nvar fooThunk1 = thunkify( foo, 3, 4 );\nvar fooThunk2 = thunkify( foo, 5, 6 );\n```\n\nRegardless of whether you like to deal with the thunkories explicitly or not, the usage of thunks `fooThunk1(..)` and `fooThunk2(..)` remains the same.\n\n### s/promise/thunk/\n\nSo what's all this thunk stuff have to do with generators?\n\nComparing thunks to promises generally: they're not directly interchangable as they're not equivalent in behavior. Promises are vastly more capable and trustable than bare thunks.\n\nBut in another sense, they both can be seen as a request for a value, which may be async in its answering.\n\nRecall from Chapter 3 we defined a utility for promisifying a function, which we called `Promise.wrap(..)` -- we could have called it `promisify(..)`, too! This Promise-wrapping utility doesn't produce Promises; it produces promisories that in turn produce Promises. This is completely symmetric to the thunkories and thunks presently being discussed.\n\nTo illustrate the symmetry, let's first alter the running `foo(..)` example from earlier to assume an \"error-first style\" callback:\n\n```js\nfunction foo(x,y,cb) {\n\tsetTimeout( function(){\n\t\t// assume `cb(..)` as \"error-first style\"\n\t\tcb( null, x + y );\n\t}, 1000 );\n}\n```\n\nNow, we'll compare using `thunkify(..)` and `promisify(..)` (aka `Promise.wrap(..)` from Chapter 3):\n\n```js\n// symmetrical: constructing the question asker\nvar fooThunkory = thunkify( foo );\nvar fooPromisory = promisify( foo );\n\n// symmetrical: asking the question\nvar fooThunk = fooThunkory( 3, 4 );\nvar fooPromise = fooPromisory( 3, 4 );\n\n// get the thunk answer\nfooThunk( function(err,sum){\n\tif (err) {\n\t\tconsole.error( err );\n\t}\n\telse {\n\t\tconsole.log( sum );\t\t// 7\n\t}\n} );\n\n// get the promise answer\nfooPromise\n.then(\n\tfunction(sum){\n\t\tconsole.log( sum );\t\t// 7\n\t},\n\tfunction(err){\n\t\tconsole.error( err );\n\t}\n);\n```\n\nBoth the thunkory and the promisory are essentially asking a question (for a value), and respectively the thunk `fooThunk` and promise `fooPromise` represent the future answers to that question. Presented in that light, the symmetry is clear.\n\nWith that perspective in mind, we can see that generators which `yield` Promises for asynchrony could instead `yield` thunks for asynchrony. All we'd need is a smarter `run(..)` utility (like from before) that can not only look for and wire up to a `yield`ed Promise but also to provide a callback to a `yield`ed thunk.\n\nConsider:\n\n```js\nfunction *foo() {\n\tvar val = yield request( \"http://some.url.1\" );\n\tconsole.log( val );\n}\n\nrun( foo );\n```\n\nIn this example, `request(..)` could either be a promisory that returns a promise, or a thunkory that returns a thunk. From the perspective of what's going on inside the generator code logic, we don't care about that implementation detail, which is quite powerful!\n\nSo, `request(..)` could be either:\n\n```js\n// promisory `request(..)` (see Chapter 3)\nvar request = Promise.wrap( ajax );\n\n// vs.\n\n// thunkory `request(..)`\nvar request = thunkify( ajax );\n```\n\nFinally, as a thunk-aware patch to our earlier `run(..)` utility, we would need logic like this:\n\n```js\n// ..\n// did we receive a thunk back?\nelse if (typeof next.value == \"function\") {\n\treturn new Promise( function(resolve,reject){\n\t\t// call the thunk with an error-first callback\n\t\tnext.value( function(err,msg) {\n\t\t\tif (err) {\n\t\t\t\treject( err );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tresolve( msg );\n\t\t\t}\n\t\t} );\n\t} )\n\t.then(\n\t\thandleNext,\n\t\tfunction handleErr(err) {\n\t\t\treturn Promise.resolve(\n\t\t\t\tit.throw( err )\n\t\t\t)\n\t\t\t.then( handleResult );\n\t\t}\n\t);\n}\n```\n\nNow, our generators can either call promisories to `yield` Promises, or call thunkories to `yield` thunks, and in either case, `run(..)` would handle that value and use it to wait for the completion to resume the generator.\n\nSymmetry wise, these two approaches look identical. However, we should point out that's true only from the perspective of Promises or thunks representing the future value continuation of a generator.\n\nFrom the larger perspective, thunks do not in and of themselves have hardly any of the trustability or composability guarantees that Promises are designed with. Using a thunk as a stand-in for a Promise in this particular generator asynchrony pattern is workable but should be seen as less than ideal when compared to all the benefits that Promises offer (see Chapter 3).\n\nIf you have the option, prefer `yield pr` rather than `yield th`. But there's nothing wrong with having a `run(..)` utility which can handle both value types.\n\n**Note:** The `runner(..)` utility in my *asynquence* library, which will be discussed in Appendix A, handles `yield`s of Promises, thunks and *asynquence* sequences.\n\n## Pre-ES6 Generators\n\nYou're hopefully convinced now that generators are a very important addition to the async programming toolbox. But it's a new syntax in ES6, which means you can't just polyfill generators like you can Promises (which are just a new API). So what can we do to bring generators to our browser JS if we don't have the luxury of ignoring pre-ES6 browsers?\n\nFor all new syntax extensions in ES6, there are tools -- the most common term for them is transpilers, for trans-compilers -- which can take your ES6 syntax and transform it into equivalent (but obviously uglier!) pre-ES6 code. So, generators can be transpiled into code that will have the same behavior but work in ES5 and below.\n\nBut how? The \"magic\" of `yield` doesn't obviously sound like code that's easy to transpile. We actually hinted at a solution in our earlier discussion of closure-based *iterators*.\n\n### Manual Transformation\n\nBefore we discuss the transpilers, let's derive how manual transpilation would work in the case of generators. This isn't just an academic exercise, because doing so will actually help further reinforce how they work.\n\nConsider:\n\n```js\n// `request(..)` is a Promise-aware Ajax utility\n\nfunction *foo(url) {\n\ttry {\n\t\tconsole.log( \"requesting:\", url );\n\t\tvar val = yield request( url );\n\t\tconsole.log( val );\n\t}\n\tcatch (err) {\n\t\tconsole.log( \"Oops:\", err );\n\t\treturn false;\n\t}\n}\n\nvar it = foo( \"http://some.url.1\" );\n```\n\nThe first thing to observe is that we'll still need a normal `foo()` function that can be called, and it will still need to return an *iterator*. So, let's sketch out the non-generator transformation:\n\n```js\nfunction foo(url) {\n\n\t// ..\n\n\t// make and return an iterator\n\treturn {\n\t\tnext: function(v) {\n\t\t\t// ..\n\t\t},\n\t\tthrow: function(e) {\n\t\t\t// ..\n\t\t}\n\t};\n}\n\nvar it = foo( \"http://some.url.1\" );\n```\n\nThe next thing to observe is that a generator does its \"magic\" by suspending its scope/state, but we can emulate that with function closure (see the *Scope & Closures* title of this series). To understand how to write such code, we'll first annotate different parts of our generator with state values:\n\n```js\n// `request(..)` is a Promise-aware Ajax utility\n\nfunction *foo(url) {\n\t// STATE *1*\n\n\ttry {\n\t\tconsole.log( \"requesting:\", url );\n\t\tvar TMP1 = request( url );\n\n\t\t// STATE *2*\n\t\tvar val = yield TMP1;\n\t\tconsole.log( val );\n\t}\n\tcatch (err) {\n\t\t// STATE *3*\n\t\tconsole.log( \"Oops:\", err );\n\t\treturn false;\n\t}\n}\n```\n\n**Note:** For more accurate illustration, we split up the `val = yield request..` statement into two parts, using the temporary `TMP1` variable. `request(..)` happens in state `*1*`, and the assignment of its completion value to `val` happens in state `*2*`. We'll get rid of that intermediate `TMP1` when we convert the code to its non-generator equivalent.\n\nIn other words, `*1*` is the beginning state, `*2*` is the state if the `request(..)` succeeds, and `*3*` is the state if the `request(..)` fails. You can probably imagine how any extra `yield` steps would just be encoded as extra states.\n\nBack to our transpiled generator, let's define a variable `state` in the closure we can use to keep track of the state:\n\n```js\nfunction foo(url) {\n\t// manage generator state\n\tvar state;\n\n\t// ..\n}\n```\n\nNow, let's define an inner function called `process(..)` inside the closure which handles each state, using a `switch` statement:\n\n```js\n// `request(..)` is a Promise-aware Ajax utility\n\nfunction foo(url) {\n\t// manage generator state\n\tvar state;\n\n\t// generator-wide variable declarations\n\tvar val;\n\n\tfunction process(v) {\n\t\tswitch (state) {\n\t\t\tcase 1:\n\t\t\t\tconsole.log( \"requesting:\", url );\n\t\t\t\treturn request( url );\n\t\t\tcase 2:\n\t\t\t\tval = v;\n\t\t\t\tconsole.log( val );\n\t\t\t\treturn;\n\t\t\tcase 3:\n\t\t\t\tvar err = v;\n\t\t\t\tconsole.log( \"Oops:\", err );\n\t\t\t\treturn false;\n\t\t}\n\t}\n\n\t// ..\n}\n```\n\nEach state in our generator is represented by its own `case` in the `switch` statement. `process(..)` will be called each time we need to process a new state. We'll come back to how that works in just a moment.\n\nFor any generator-wide variable declarations (`val`), we move those to a `var` declaration outside of `process(..)` so they can survive multiple calls to `process(..)`. But the \"block scoped\" `err` variable is only needed for the `*3*` state, so we leave it in place.\n\nIn state `*1*`, instead of `yield request(..)`, we did `return request(..)`. In terminal state `*2*`, there was no explicit `return`, so we just do a `return;` which is the same as `return undefined`. In terminal state `*3*`, there was a `return false`, so we preserve that.\n\nNow we need to define the code in the *iterator* functions so they call `process(..)` appropriately:\n\n```js\nfunction foo(url) {\n\t// manage generator state\n\tvar state;\n\n\t// generator-wide variable declarations\n\tvar val;\n\n\tfunction process(v) {\n\t\tswitch (state) {\n\t\t\tcase 1:\n\t\t\t\tconsole.log( \"requesting:\", url );\n\t\t\t\treturn request( url );\n\t\t\tcase 2:\n\t\t\t\tval = v;\n\t\t\t\tconsole.log( val );\n\t\t\t\treturn;\n\t\t\tcase 3:\n\t\t\t\tvar err = v;\n\t\t\t\tconsole.log( \"Oops:\", err );\n\t\t\t\treturn false;\n\t\t}\n\t}\n\n\t// make and return an iterator\n\treturn {\n\t\tnext: function(v) {\n\t\t\t// initial state\n\t\t\tif (!state) {\n\t\t\t\tstate = 1;\n\t\t\t\treturn {\n\t\t\t\t\tdone: false,\n\t\t\t\t\tvalue: process()\n\t\t\t\t};\n\t\t\t}\n\t\t\t// yield resumed successfully\n\t\t\telse if (state == 1) {\n\t\t\t\tstate = 2;\n\t\t\t\treturn {\n\t\t\t\t\tdone: true,\n\t\t\t\t\tvalue: process( v )\n\t\t\t\t};\n\t\t\t}\n\t\t\t// generator already completed\n\t\t\telse {\n\t\t\t\treturn {\n\t\t\t\t\tdone: true,\n\t\t\t\t\tvalue: undefined\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\t\t\"throw\": function(e) {\n\t\t\t// the only explicit error handling is in\n\t\t\t// state *1*\n\t\t\tif (state == 1) {\n\t\t\t\tstate = 3;\n\t\t\t\treturn {\n\t\t\t\t\tdone: true,\n\t\t\t\t\tvalue: process( e )\n\t\t\t\t};\n\t\t\t}\n\t\t\t// otherwise, an error won't be handled,\n\t\t\t// so just throw it right back out\n\t\t\telse {\n\t\t\t\tthrow e;\n\t\t\t}\n\t\t}\n\t};\n}\n```\n\nHow does this code work?\n\n1. The first call to the *iterator*'s `next()` call would move the generator from the uninitialized state to state `1`, and then call `process()` to handle that state. The return value from `request(..)`, which is the promise for the Ajax response, is returned back as the `value` property from the `next()` call.\n2. If the Ajax request succeeds, the second call to `next(..)` should send in the Ajax response value, which moves our state to `2`. `process(..)` is again called (this time with the passed in Ajax response value), and the `value` property returned from `next(..)` will be `undefined`.\n3. However, if the Ajax request fails, `throw(..)` should be called with the error, which would move the state from `1` to `3` (instead of `2`). Again `process(..)` is called, this time with the error value. That `case` returns `false`, which is set as the `value` property returned from the `throw(..)` call.\n\nFrom the outside -- that is, interacting only with the *iterator* -- this `foo(..)` normal function works pretty much the same as the `*foo(..)` generator would have worked. So we've effectively \"transpiled\" our ES6 generator to pre-ES6 compatibility!\n\nWe could then manually instantiate our generator and control its iterator -- calling `var it = foo(\"..\")` and `it.next(..)` and such -- or better, we could pass it to our previously defined `run(..)` utility as `run(foo,\"..\")`.\n\n### Automatic Transpilation\n\nThe preceding exercise of manually deriving a transformation of our ES6 generator to pre-ES6 equivalent teaches us how generators work conceptually. But that transformation was really intricate and very non-portable to other generators in our code. It would be quite impractical to do this work by hand, and would completely obviate all the benefit of generators.\n\nBut luckily, several tools already exist that can automatically convert ES6 generators to things like what we derived in the previous section. Not only do they do the heavy lifting work for us, but they also handle several complications that we glossed over.\n\nOne such tool is regenerator (https://facebook.github.io/regenerator/), from the smart folks at Facebook.\n\nIf we use regenerator to transpile our previous generator, here's the code produced (at the time of this writing):\n\n```js\n// `request(..)` is a Promise-aware Ajax utility\n\nvar foo = regeneratorRuntime.mark(function foo(url) {\n    var val;\n\n    return regeneratorRuntime.wrap(function foo$(context$1$0) {\n        while (1) switch (context$1$0.prev = context$1$0.next) {\n        case 0:\n            context$1$0.prev = 0;\n            console.log( \"requesting:\", url );\n            context$1$0.next = 4;\n            return request( url );\n        case 4:\n            val = context$1$0.sent;\n            console.log( val );\n            context$1$0.next = 12;\n            break;\n        case 8:\n            context$1$0.prev = 8;\n            context$1$0.t0 = context$1$0.catch(0);\n            console.log(\"Oops:\", context$1$0.t0);\n            return context$1$0.abrupt(\"return\", false);\n        case 12:\n        case \"end\":\n            return context$1$0.stop();\n        }\n    }, foo, this, [[0, 8]]);\n});\n```\n\nThere's some obvious similarities here to our manual derivation, such as the `switch` / `case` statements, and we even see `val` pulled out of the closure just as we did.\n\nOf course, one trade-off is that regenerator's transpilation requires a helper library `regeneratorRuntime` that holds all the reusable logic for managing a general generator / *iterator*. A lot of that boilerplate looks different than our version, but even then, the concepts can be seen, like with `context$1$0.next = 4` keeping track of the next state for the generator.\n\nThe main takeaway is that generators are not restricted to only being useful in ES6+ environments. Once you understand the concepts, you can employ them throughout your code, and use tools to transform the code to be compatible with older environments.\n\nThis is more work than just using a `Promise` API polyfill for pre-ES6 Promises, but the effort is totally worth it, because generators are so much better at expressing async flow control in a reason-able, sensible, synchronous-looking, sequential fashion.\n\nOnce you get hooked on generators, you'll never want to go back to the hell of async spaghetti callbacks!\n\n## Review\n\nGenerators are a new ES6 function type that does not run-to-completion like normal functions. Instead, the generator can be paused in mid-completion (entirely preserving its state), and it can later be resumed from where it left off.\n\nThis pause/resume interchange is cooperative rather than preemptive, which means that the generator has the sole capability to pause itself, using the `yield` keyword, and yet the *iterator* that controls the generator has the sole capability (via `next(..)`) to resume the generator.\n\nThe `yield` / `next(..)` duality is not just a control mechanism, it's actually a two-way message passing mechanism. A `yield ..` expression essentially pauses waiting for a value, and the next `next(..)` call passes a value (or implicit `undefined`) back to that paused `yield` expression.\n\nThe key benefit of generators related to async flow control is that the code inside a generator expresses a sequence of steps for the task in a naturally sync/sequential fashion. The trick is that we essentially hide potential asynchrony behind the `yield` keyword -- moving the asynchrony to the code where the generator's *iterator* is controlled.\n\nIn other words, generators preserve a sequential, synchronous, blocking code pattern for async code, which lets our brains reason about the code much more naturally, addressing one of the two key drawbacks of callback-based async.\n"
  },
  {
    "path": "async & performance/ch5.md",
    "content": "# You Don't Know JS: Async & Performance\n# Глава 5: Производительность программы\n\nДо сих пор эта книга была посвящена тому, как эффективнее использовать паттерны асинхронности. Но мы не рассматривали напрямую, почему асинхронность действительно важна для JS. Самая очевидная и явная причина - это **производительность**.\n\nНапример, если вам нужно выполнить два независимых Ajax-запроса, но вам нужно дождаться их завершения перед выполнением следующей задачи, у вас есть два варианта моделирования этого взаимодействия: последовательный и параллельный.\n\nВы можете сделать первый запрос и ждать начала второго запроса, пока не завершится первый. Или, как мы уже видели на примере обещаний и генераторов, вы можете выполнить оба запроса \"параллельно\" и выразить \"ворота\" для ожидания выполнения обоих запросов, прежде чем двигаться дальше.\n\nОчевидно, что последний вариант, как правило, будет более производительным, чем первый. А лучшая производительность обычно приводит к лучшему пользовательскому опыту\n\nВозможно даже, что асинхронность (чередующийся параллелизм) может улучшить только восприятие производительности, даже если на выполнение программы в целом уходит столько же времени. Восприятие производительности пользователем не менее -- если не более -- важно, чем реальная измеримая производительность.\n\nТеперь мы хотим выйти за рамки локализованных паттернов асинхронности и поговорить о некоторых деталях производительности на уровне программы.\n\n**Примечание:** Вам могут быть интересны вопросы микропроизводительности, например, что быстрее - `a++` или `++a`. Мы рассмотрим такие детали производительности в следующей главе \"Бенчмаркинг и тюнинг\".\n\n## Web Workers\n\nЕсли у вас есть задачи с интенсивной обработкой данных, но вы не хотите, чтобы они выполнялись в главном потоке (что может замедлить работу браузера/интерфейса), вы могли бы пожелать, чтобы JavaScript работал в многопоточном режиме.\n\nВ главе 1 мы подробно рассказывали о том, что JavaScript является однопоточным. И это по-прежнему верно. Но один поток - не единственный способ организовать выполнение программы.\n\nПредставьте, что вы разделили свою программу на две части, запустили одну из них в основном потоке пользовательского интерфейса, а другую - в совершенно отдельном потоке.\n\nКакие проблемы возникнут при такой архитектуре?\n\nНапример, вы бы хотели знать, означает ли выполнение в отдельном потоке, что он работает параллельно (в системах с несколькими процессорами/ядрами), так что долго выполняющийся процесс во втором потоке не будет блокировать основной поток программы. В противном случае \"виртуальные потоки\" не принесут особой пользы по сравнению с тем, что мы уже имеем в JS с асинхронным параллелизмом.\n\nКроме того, вам нужно знать, имеют ли эти две части программы доступ к одной и той же общей области видимости/ресурсам. Если да, то возникают все вопросы, с которыми сталкиваются многопоточные языки (Java, C++ и т. д.), например, необходимость кооперативной или вытесняющей блокировки (мьютексы(взаимное исключение) и т. д.). Это очень много дополнительной работы, и к ней не стоит относиться легкомысленно.\n\nКроме того, вы бы хотели знать, как эти две части могут \"общаться\", если они не могут делиться областью видимости/ресурсами.\n\nВсё это - отличные вопросы для рассмотрения, поскольку мы изучаем функцию, добавленную в веб-платформу примерно во времена HTML5, под названием \"Web Workers\". Это функция браузера (он же хост-окружение), и на самом деле она почти никак не связана с самим языком JS. То есть в JavaScript на данный момент нет никаких функций, поддерживающих многопоточное выполнение.\n\nНо такая среда, как ваш браузер, может легко предоставить несколько экземпляров движка JavaScript, каждый со своим потоком, и позволить вам запускать разные программы в каждом из потоков. Каждый из этих отдельных потоковых частей вашей программы называется \"(Web) Worker\". Такой тип параллелизма называется \"параллелизмом задач (Task parallelism)\", поскольку акцент делается на разделении фрагментов вашей программы для параллельного выполнения.\n\nИз вашей основной JS-программы (или другого Worker) вы создаете Worker следующим образом:\n\n```js\nvar w1 = new Worker( \"http://some.url.1/mycoolworker.js\" );\n```\n\nURL должен указывать на местоположение JS-файла (не HTML-страницы!), который предназначен для загрузки в Worker. После этого браузер запустит отдельный поток и позволит этому файлу выполняться в нем как независимой программе.\n\n**Примечание:** Тип Worker, созданный с помощью такого URL, называется \"Dedicated Worker\". Но вместо URL-адреса внешнего файла вы можете создать \"Inline Worker\", предоставив Blob URL-адрес (еще одна возможность HTML5); по сути, это inline-файл, хранящийся в одном (двоичном) значении. Однако Blob'ы выходят за рамки того, что мы будем обсуждать здесь.\n\nWorkers не имеют общей области видимости или ресурсов друг с другом или с основной программой - это вывело бы на первый план все кошмары многопоточного программирования - но вместо этого их связывает простой механизм обмена сообщениями о событиях.\n\nОбъект `w1` Worker является слушателем событий и триггером, который позволяет вам подписываться на события, посылаемые Worker, а также посылать события Worker.\n\nВот как прослушивать события (если точнее, фиксированное событие `\"message\"`):\n\n```js\nw1.addEventListener( \"message\", function(evt){\n\t// evt.data\n} );\n```\n\nИ вы можете отправить событие `\"message\"` в Worker:\n\n```js\nw1.postMessage( \"something cool to say\" );\n```\n\nВнутри Worker отправка событий полностью симметрична:\n\n```js\n// \"mycoolworker.js\"\n\naddEventListener( \"message\", function(evt){\n\t// evt.data\n} );\n\npostMessage( \"a really cool reply\" );\n```\n\nОбратите внимание, что выделенный Worker находится в отношениях один-к-одному с программой, которая его создала. То есть событие ``message`` не нуждается в устранении неоднозначности, потому что мы уверены, что оно могло произойти только в результате этой связи \"один к одному\" - либо от Worker, либо от главной страницы.\n\nОбычно приложение главной страницы создает Worker'ы, но при необходимости Worker может создавать свои собственные дочерние Worker(ы) - так называемые subworkers. Иногда полезно делегировать такие детали некоему \"главному\" Worker'у, который порождает других Worker'ов для обработки части задачи. К сожалению, на момент написания этой статьи Chrome все еще не поддерживает subworkers, в то время как Firefox поддерживает.\n\nЧтобы немедленно убить Worker из программы, которая его создала, вызовите `terminate()` для объекта Worker (как `w1` в предыдущих сниппетах). Резкое завершение потока Worker не дает ему возможности закончить свою работу или очистить ресурсы. Это похоже на то, как если бы вы закрыли вкладку браузера, чтобы убить страницу.\n\nЕсли в браузере есть две или более страниц (или несколько вкладок с одной и той же страницей!), которые пытаются создать Worker из одного и того же URL-адреса файла, то в итоге они окажутся совершенно отдельными Worker'ами. Вскоре мы обсудим способ \"совместного использования\" Worker'ов.\n\n**Примечание:** Может показаться, что вредоносная или невежественная JS-программа может легко провести атаку на отказ в обслуживании системы (denial-of-service attack), породив сотни Worker'ов, каждый из которых, казалось бы, имеет свой собственный поток. Хотя это правда, что есть некоторая гарантия того, что Worker окажется в отдельном потоке, эта гарантия не безгранична. Система вольна решать, сколько реальных потоков/процессоров/ядер она действительно хочет создать. Невозможно предсказать или гарантировать, к какому количеству потоков вы получите доступ, хотя многие люди полагают, что их будет не меньше, чем количество доступных процессоров/ядер. Я думаю, что самое безопасное предположение - это наличие хотя бы одного другого потока, кроме основного потока пользовательского интерфейса, но это не более того.\n\n### Worker Environment\n\nВнутри Worker у вас нет доступа ни к одному из ресурсов основной программы. Это означает, что вы не можете получить доступ ни к глобальным переменным, ни к DOM страницы, ни к другим ресурсам. Помните: это совершенно отдельный поток.\n\nОднако вы можете выполнять сетевые операции (Ajax, WebSockets) и устанавливать таймеры. Также Worker имеет доступ к собственной копии нескольких важных глобальных переменных/функций, включая `navigator`, `location`, `JSON` и `applicationCache`.\n\nВы также можете загружать в Worker дополнительные JS-скрипты, используя `importScripts(...)`:\n\n```js\n// inside the Worker\nimportScripts( \"foo.js\", \"bar.js\" );\n```\n\nЭти скрипты загружаются синхронно, что означает, что вызов `importScripts(...)` будет блокировать выполнение остальной части Worker'а, пока файл(ы) не закончит(ат) загрузку и выполнение.\n\n**Примечание:** Также обсуждался вопрос о раскрытии API `<canvas>` для Workers, что в сочетании с тем, что холсты будут Transferables(передаваемыми) (см. раздел \"Передача данных\"), позволит Workers выполнять более сложную внепоточную обработку графики, которая может быть полезна для высокопроизводительных игр (WebGL) и других подобных приложений. Хотя такой возможности пока нет ни в одном браузере, она, скорее всего, появится в ближайшем будущем.\n\nКаковы некоторые типичные области применения Web Workers?\n\n* Обработка интенсивных математических вычислений\n* Сортировка больших наборов данных\n* Операции с данными (сжатие, анализ аудио, манипуляции с пикселями изображений и т. д.)\n* Сетевые коммуникации с высоким трафиком\n\n### Передача данных\n\nВы можете заметить общую характеристику большинства этих применений: они требуют передачи большого количества информации через барьер между потоками с помощью механизма событий, возможно, в обоих направлениях.\n\nВ первые дни существования Workers сериализация всех данных в строковое значение была единственным вариантом. Помимо снижения скорости при двусторонней сериализации, другим существенным минусом было то, что данные копировались, а это означало удвоение использования памяти (и последующую возню со сборкой мусора).\n\nК счастью, теперь у нас есть несколько лучших вариантов.\n\nЕсли вы передаете объект, то для копирования/дублирования объекта на другой стороне используется так называемый \"Structured Cloning Algorithm\"(Алгоритм структурированного клонирования) (https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/The_structured_clone_algorithm). Этот алгоритм довольно сложен и может даже обрабатывать дублирование объектов с циклическими ссылками. При подходе не приходится платить штраф за производительность при работе к строке/из строки, но дублирование памяти все равно имеет место. Он поддерживается в IE10 и выше, а также во всех других основных браузерах.\n\nЕще лучший вариант, особенно для больших наборов данных, - это \"Transferable Objects\"(переносимые объекты) (http://updates.html5rocks.com/2011/12/Transferable-Objects-Lightning-Fast). При этом происходит передача \"прав собственности\" на объект, но сами данные не перемещаются. Как только вы передаете объект Worker'у, он становится пустым или недоступным в исходном месте - это устраняет опасность потокового программирования через общую область видимости. Конечно, передача прав собственности может происходить в обоих направлениях.\n\nНа самом деле не так уж много нужно сделать, чтобы выбрать Transferable Object; любая структура данных, реализующая интерфейс Transferable (https://developer.mozilla.org/en-US/docs/Web/API/Transferable), будет автоматически передаваться таким образом (поддержка Firefox и Chrome).\n\nНапример, типизированные массивы типа `Uint8Array` (см. *ES6 & Beyond* часть этой серии) являются \"Transferables\". Вот как вы отправите передаваемый объект с помощью `postMessage(...)`:\n\n```js\n// `foo` - это, например, `Uint8Array`.\n\npostMessage( foo.buffer, [ foo.buffer ] );\n```\n\nПервый параметр - это необработанный буфер, а второй - список того, что нужно передать.\n\nБраузеры, не поддерживающие Transferable Objects, просто переходят к структурированному клонированию, что означает снижение производительности, а не полный отказ от функций.\n\n### Shared Workers\n\nЕсли ваш сайт или приложение позволяет загружать несколько вкладок одной и той же страницы (это распространенная функция), вы вполне можете захотеть снизить потребление ресурсов системы, предотвратив дублирование выделенных Worker'ов. Наиболее распространенным ограниченным ресурсом в этом отношении являются  сетевые соединения через сокеты, поскольку браузеры ограничивают количество одновременных подключений к одному хосту. Разумеется, ограничение множества соединений от клиента также снижает требования к ресурсам сервера.\n\nВ этом случае весьма полезно создать единый централизованный Worker, с которым могут *обмениваться* все экземпляры страниц вашего сайта или приложения.\n\nЭто называется `SharedWorker`, который вы создаете следующим образом (поддержка этого метода ограничена Firefox и Chrome):\n\n```js\nvar w1 = new SharedWorker( \"http://some.url.1/mycoolworker.js\" );\n```\n\nПоскольку общий Worker может быть подключен к нескольким экземплярам программ или страницам на вашем сайте, Worker должен знать, от какой программы пришло сообщение. Этот уникальный идентификатор называется \"port\" - вспомните порты сетевых сокетов. Поэтому вызывающая программа должна использовать объект `port` Worker'а для связи:\n\n```js\nw1.port.addEventListener( \"message\", handleMessages );\n\n// ..\n\nw1.port.postMessage( \"something cool\" );\n```\n\nКроме того, соединение с портом должно быть инициализировано, как:\n\n```js\nw1.port.start();\n```\n\nВнутри общего Worker'а необходимо обработать дополнительное событие: `\"connect\"`. Это событие предоставляет порт `object` для данного конкретного соединения. Наиболее удобным способом разделения нескольких соединений является использование замыкания (см. раздел *Scope & Closures* в этой серии) `port`, как показано ниже, при этом событие прослушивания и передачи для этого соединения определяется в обработчике события `\"connect\"`:\n\n```js\n// внутри общего Worker\naddEventListener( \"connect\", function(evt){\n    // назначенный порт для данного соединения\n\tvar port = evt.ports[0];\n\n\tport.addEventListener( \"message\", function(evt){\n\t\t// ..\n\n\t\tport.postMessage( .. );\n\n\t\t// ..\n\t} );\n\n\t// инициализируем соединение с портом\n\tport.start();\n} );\n```\n\nКроме этого различия, общие и выделенные Worker'ы имеют одинаковые возможности и семантику.\n\n**Примечание:** Shared Workers переживают разрыв соединения с портом, если другие соединения с портом еще живы, в то время как выделенные Worker'ы разрываются при разрыве соединения с инициирующей их программой.\n\n### Полифил Web Workers\n\nWeb Workers очень привлекательны с точки зрения производительности для параллельного выполнения JS-программ. Однако вы можете оказаться в ситуации, когда ваш код должен работать в старых браузерах, в которых отсутствует их поддержка. Поскольку Workers - это API, а не синтаксис, их можно в определенной степени заменить полифилом.\n\nЕсли браузер не поддерживает Workers, то с точки зрения производительности подделать многопоточность просто невозможно. Обычно считается, что Iframe обеспечивают параллельную среду, но во всех современных браузерах они на самом деле выполняются в том же потоке, что и основная страница, поэтому их недостаточно для имитации параллелизма.\n\nКак мы подробно рассказывали в Главе 1, асинхронность (а не параллельность) в JS обеспечивается очередью цикла событий, поэтому вы можете заставить поддельные Worker'ы быть асинхронными с помощью таймеров (`setTimeout(...)` и т. д.). Затем вам просто нужно предоставить полифил для API Worker. Некоторые из них перечислены здесь (https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills#web-workers), но, честно говоря, ни один из них не выглядит хорошо.\n\nЯ написал набросок полифила для `Worker` здесь (https://gist.github.com/getify/1b26accb1a09aa53ad25). Он базовый, но для простой поддержки `Worker` должен подойти, учитывая, что двусторонний обмен сообщениями работает корректно, как и обработка `\"onerror\"`. Возможно, вы сможете расширить его дополнительными функциями, такими как `terminate()` или поддельные Shared Workers, по своему усмотрению.\n\n**Примечание:** Вы не можете подделать синхронную блокировку, поэтому этот полифил просто запрещает использование `importScripts(...)`. Другим вариантом мог бы быть разбор и преобразование кода Worker'а (после загрузки Ajax) для обработки перезаписи в некоторую асинхронную форму полифила `importScripts(...)`, возможно, с интерфейсом, учитывающим Promise(обещания).\n\n## SIMD\n\nSingle instruction, multiple data (SIMD) - это форма \"параллелизма данных\", в отличие от \"параллелизма задач\" в Web Workers, потому что акцент делается не на распараллеливании фрагментов программной логики, а скорее на параллельной обработке нескольких кусочков данных.\n\nПри использовании SIMD потоки не обеспечивают параллелизм. Вместо этого современные процессоры предоставляют возможность SIMD с помощью \"векторов\" чисел - подумайте: специализированные по типу массивы - а также инструкций, которые могут работать параллельно со всеми числами; это низкоуровневые операции, использующие параллелизм на уровне инструкций.\n\nУсилия по раскрытию возможностей SIMD в JavaScript в основном возглавляет компания Intel (https://01.org/node/1495), а именно Мохаммад Хагихат (на момент написания этой статьи), в сотрудничестве с командами Firefox и Chrome. SIMD находится на ранней стадии разработки стандартов и имеет все шансы попасть в будущую редакцию JavaScript, скорее всего, в период ES7.\n\nSIMD JavaScript предлагает предоставлять коду JS короткие векторные типы и API, которые в системах с поддержкой SIMD будут отображать операции непосредственно на эквиваленты процессора, с возвратом к непараллельным операциям \"шимми\" в системах без SIMD.\n\nПреимущества производительности для приложений с большим объемом данных (анализ сигналов, матричные операции на графике и т. д.) при такой параллельной математической обработке совершенно очевидны!\n\nРанние предложения SIMD API на момент написания этой статьи выглядят следующим образом:\n\n```js\nvar v1 = SIMD.float32x4( 3.14159, 21.0, 32.3, 55.55 );\nvar v2 = SIMD.float32x4( 2.1, 3.2, 4.3, 5.4 );\n\nvar v3 = SIMD.int32x4( 10, 101, 1001, 10001 );\nvar v4 = SIMD.int32x4( 10, 20, 30, 40 );\n\nSIMD.float32x4.mul( v1, v2 );\t// [ 6.597339, 67.2, 138.89, 299.97 ]\nSIMD.int32x4.add( v3, v4 );\t\t// [ 20, 121, 1031, 10041 ]\n```\n\nЗдесь показаны два различных типа векторных данных: 32-битные числа с плавающей точкой и 32-битные целые числа. Видно, что размер этих векторов точно соответствует четырем 32-битным элементам, так как это соответствует размерам SIMD-векторов (128 бит), доступных в большинстве современных процессоров. Также возможно, что в будущем мы увидим `x8` (или более крупную!) версию этих API.\n\nПомимо `mul()` и `add()`, вероятно, будет включено множество других операций, таких как `sub()`, `div()`, `abs()`, `neg()`, `qrt()`, `reciprocal()`, `reciprocalSqrt()` (арифметика), `shuffle()` (перестановка элементов вектора), `and()`, `or()`, `xor()`, `not()` (логические), `equal()`, `greaterThan()`, `lessThan()` (сравнение), `shiftLeft()`, `shiftRightLogical()`, `shiftRightArithmetic()` (сдвиги), `fromFloat32x4()`, и `fromInt32x4()` (преобразования).\n\n**Примечание:** Существует официальный \"prollyfill\" (надеющийся, ожидающий, устремленный в будущее полифил) для SIMD-функциональности (https://github.com/johnmccutchan/ecmascript_simd), который иллюстрирует гораздо больше запланированных SIMD-возможностей, чем мы показали в этом разделе.\n\n## asm.js\n\n\"asm.js\" (http://asmjs.org/) - это обозначение высоко оптимизируемого подмножества языка JavaScript. Тщательно избегая определенных механизмов и шаблонов, которые *трудно* оптимизировать (сборка мусора, принуждение и т. д.), код в стиле asm.js может быть распознан движком JS и удостоен особого внимания с помощью агрессивных низкоуровневых оптимизаций.\n\nВ отличие от других механизмов повышения производительности программ, рассмотренных в этой главе, asm.js - это не обязательно что-то, что должно быть принято в спецификации языка JS. Спецификация asm.js *существует* (http://asmjs.org/spec/latest/), но она предназначена в основном для отслеживания согласованного набора выводов-кандидатов на оптимизацию, а не для установления требований к движкам JS.\n\nВ настоящее время не предлагается никакого нового синтаксиса. Вместо этого asm.js предлагает способы распознавания существующего стандартного синтаксиса JS, который соответствует правилам asm.js, и позволяет движкам реализовывать свои собственные оптимизации соответствующим образом.\n\nМежду производителями браузеров существуют некоторые разногласия по поводу того, как именно следует активировать asm.js в программе. В ранних версиях эксперимента с asm.js требовалась прагма `\"use asm\";` (подобно прагме строгого режима `\"use strict\";`), чтобы указать JS-движку на возможности и подсказки для оптимизации asm.js. Другие утверждают, что asm.js должен быть просто набором эвристик, которые движки распознают автоматически, без необходимости делать что-то дополнительное для автора. Это означает, что существующие программы теоретически могут извлечь пользу из оптимизации в стиле asm.js, не делая ничего особенного.\n\n### Как оптимизировать с помощью asm.js\n\nПервое, что нужно понять об оптимизации в asm.js, - это оптимизация типов и принуждения (см. раздел *Типы и грамматика* в этой серии). Если JS-движок должен отслеживать несколько различных типов значений в переменной через различные операции, чтобы при необходимости обрабатывать принуждения между типами, это много дополнительной работы, которая делает оптимизацию программы неоптимальной.\n\n**Примечание:** Мы будем использовать код в стиле asm.js для иллюстрации, но имейте в виду, что обычно не предполагается, что вы будете писать такой код вручную. asm.js больше предназначен для компиляции из других инструментов, таких как Emscripten (https://github.com/kripken/emscripten/wiki). Конечно, можно написать свой собственный код asm.js, но это обычно плохая идея, потому что код очень низкого уровня, и управление им может быть очень трудоемким и чреватым ошибками. Тем не менее, могут быть случаи, когда вы захотите вручную подправить свой код в целях оптимизации asm.js.\n\nЕсть несколько \"трюков\", которые можно использовать, чтобы намекнуть asm.js-aware JS-движку, какой тип предполагается использовать для переменных/операций, чтобы он мог пропустить эти шаги по отслеживанию приведения типов (coercion).\n\nНапример:\n\n```js\nvar a = 42;\n\n// ..\n\nvar b = a;\n```\n\nВ этой программе задание `b = a` оставляет открытой дверь для расхождения типов переменных. Однако вместо этого его можно записать так:\n\n```js\nvar a = 42;\n\n// ..\n\nvar b = a | 0;\n```\n\nЗдесь мы использовали `|` (\"двоичное ИЛИ\") со значением `0`, которое никак не влияет на значение, кроме как убедиться, что оно является 32-битным целым числом. Этот код, запущенный в обычном JS-движке, работает отлично, но при запуске в asm.js-aware JS-движке он *может* сигнализировать, что `b` всегда должно рассматриваться как 32-битное целое число, поэтому отслеживание принуждения можно пропустить.\n\nАналогично, операция сложения между двумя переменными может быть ограничена более производительным целочисленным сложением (вместо сложения с плавающей точкой):\n\n```js\n(a + b) | 0\n```\n\nИ опять же, asm.js-aware JS-движок может увидеть эту подсказку и сделать вывод, что операция `+` должна быть 32-битным целым сложением, потому что конечный результат всего выражения в любом случае автоматически будет соответствовать 32-битному целому числу.\n\n### Модули asm.js\n\nОдним из самых больших факторов, снижающих производительность в JS, является распределение памяти, сборка мусора и доступ к областям видимости. asm.js предлагает один из способов решения этих проблем - объявить более формализованный \"модуль\" asm.js - не путайте их с модулями ES6; см. главу *ES6 & Beyond* этой серии.\n\nДля модуля asm.js необходимо явно передать строго согласованное пространство имен - в спецификации оно называется `stdlib`, поскольку должно представлять необходимые стандартные библиотеки - для импорта необходимых символов, а не просто использовать глобальные переменные через лексическую область видимости. В базовом случае объект `window` является приемлемым объектом `stdlib` для целей модуля asm.js, но вы можете и, возможно, должны создать еще более ограниченный объект.\n\nВы также должны объявить \"heap\" (кучу) - это просто модный термин для обозначения зарезервированного места в памяти, где переменные уже могут использоваться без запроса дополнительной памяти или освобождения ранее использованной памяти - и передать ее, чтобы модулю asm.js не нужно было делать ничего, что могло бы вызвать переполнение памяти; он может просто использовать заранее зарезервированное место.\n\n\"Heap\" - это скорее типизированный `ArrayBuffer`, такой как:\n\n```js\nvar heap = new ArrayBuffer( 0x10000 );\t// 64k heap\n```\n\nИспользуя эти заранее зарезервированные 64k двоичного пространства, модуль asm.js может хранить и извлекать значения в этом буфере без каких-либо штрафов за выделение памяти или сборку мусора. Например, буфер `heap` может быть использован внутри модуля для хранения массива 64-битных значений float следующим образом:\n\n```js\nvar arr = new Float64Array( heap );\n```\n\nИтак, давайте сделаем быстрый и глупый пример модуля в стиле asm.js, чтобы проиллюстрировать, как эти части сочетаются друг с другом. Мы определим `foo(...)`, который берет начальное (`x`) и конечное (`y`) целое число для диапазона, вычисляет все внутренние смежные умножения значений в диапазоне, а затем, наконец, усредняет эти значения вместе:\n\n```js\nfunction fooASM(stdlib,foreign,heap) {\n\t\"use asm\";\n\n\tvar arr = new stdlib.Int32Array( heap );\n\n\tfunction foo(x,y) {\n\t\tx = x | 0;\n\t\ty = y | 0;\n\n\t\tvar i = 0;\n\t\tvar p = 0;\n\t\tvar sum = 0;\n\t\tvar count = ((y|0) - (x|0)) | 0;\n\n\t\t// вычислить все внутренние смежные умножения\n\t\tfor (i = x | 0;\n\t\t\t(i | 0) < (y | 0);\n\t\t\tp = (p + 8) | 0, i = (i + 1) | 0\n\t\t) {\n\t\t\t// сохраняем результат\n\t\t\tarr[ p >> 3 ] = (i * (i + 1)) | 0;\n\t\t}\n\n\t\t// вычислить среднее значение всех промежуточных значений\n\t\tfor (i = 0, p = 0;\n\t\t\t(i | 0) < (count | 0);\n\t\t\tp = (p + 8) | 0, i = (i + 1) | 0\n\t\t) {\n\t\t\tsum = (sum + arr[ p >> 3 ]) | 0;\n\t\t}\n\n\t\treturn +(sum / count);\n\t}\n\n\treturn {\n\t\tfoo: foo\n\t};\n}\n\nvar heap = new ArrayBuffer( 0x1000 );\nvar foo = fooASM( window, null, heap ).foo;\n\nfoo( 10, 20 );\t\t// 233\n```\n\n**Примечание:** Этот пример asm.js написан вручную в целях иллюстрации, поэтому он не представляет собой тот же код, который был бы получен от инструмента компиляции, нацеленного на asm.js. Однако он демонстрирует типичную природу кода asm.js, особенно подсказки типов и использование буфера `heap` для хранения временных переменных.\n\nПервый вызов `fooASM(...)` устанавливает наш модуль asm.js с его `heap` расположением. В результате мы получаем функцию `foo(...)`, которую можем вызывать столько раз, сколько потребуется. Эти вызовы `foo(...)` должны быть специальным образом оптимизированы JS-движком с поддержкой asm.js. Важно отметить, что предыдущий код полностью соответствует стандартному JS и будет прекрасно работать (без специальной оптимизации) на движке, не поддерживающем asm.js.\n\nОчевидно, что природа ограничений, которые делают код asm.js настолько оптимизируемым, значительно сокращает возможные области применения такого кода. asm.js не обязательно будет общим набором оптимизаций для любой конкретной JS-программы. Вместо этого он призван обеспечить оптимизированный способ обработки специализированных задач, таких как интенсивные математические операции (например, используемые при обработке графики в играх).\n\n## Обзор\n\nПервые четыре главы этой книги основаны на мысли, что паттерны асинхронного программирования дают вам возможность писать более производительный код, что в целом является очень важным улучшением. Но асинхронное поведение даёт вам только такую возможность, потому что оно все равно привязано к одному потоку цикла событий.\n\nИтак, в этой главе мы рассмотрели несколько механизмов программного уровня для дальнейшего повышения производительности.\n\nWeb Workers позволяют запускать JS-файл (он же программа) в отдельном потоке, используя асинхронные события для передачи сообщений между потоками. Они отлично подходят для разгрузки длительных или ресурсоемких задач на другой поток, оставляя основной поток пользовательского интерфейса более отзывчивым.\n\nSIMD предлагает перенести параллельные математические операции на уровне процессора в API JavaScript для высокопроизводительных параллельных операций с данными, таких как обработка чисел в больших наборах данных.\n\nНаконец, asm.js описывает небольшое подмножество JavaScript, которое избегает трудно оптимизируемых частей JS (таких как сборка мусора и приведение типов) и позволяет движку JS распознавать и выполнять такой код с помощью агрессивной оптимизации. asm.js может быть создан вручную, но это чрезвычайно утомительно и чревато ошибками, сродни ручному написанию языка assembly (отсюда и название (сборка)). Вместо этого, основная цель состоит в том, чтобы asm.js стал хорошей мишенью для кросс-компиляции из других высоко оптимизированных языков программирования - например, Emscripten (https://github.com/kripken/emscripten/wiki), транслирующий C/C++ в JavaScript.\n\nНесмотря на то, что в этой главе не рассматривается в явном виде, есть еще более радикальные идеи для JavaScript, которые обсуждаются на ранних этапах, включая приближение к прямой потоковой функциональности (а не просто скрытой за API структур данных). Независимо от того, произойдет ли это в явном виде, или мы просто увидим, как больше параллелизма проникает в JS за кулисы, будущее более оптимизированной производительности на уровне программ в JS выглядит действительно *перспективным*.\n"
  },
  {
    "path": "async & performance/ch6.md",
    "content": "# You Don't Know JS: Async & Performance\n# Chapter 6: Benchmarking & Tuning\n\nAs the first four chapters of this book were all about performance as a coding pattern (asynchrony and concurrency), and Chapter 5 was about performance at the macro program architecture level, this chapter goes after the topic of performance at the micro level, focusing on single expressions/statements.\n\nOne of the most common areas of curiosity -- indeed, some developers can get quite obsessed about it -- is in analyzing and testing various options for how to write a line or chunk of code, and which one is faster.\n\nWe're going to look at some of these issues, but it's important to understand from the outset that this chapter is **not** about feeding the obsession of micro-performance tuning, like whether some given JS engine can run `++a` faster than `a++`. The more important goal of this chapter is to figure out what kinds of JS performance matter and which ones don't, *and how to tell the difference*.\n\nBut even before we get there, we need to explore how to most accurately and reliably test JS performance, because there's tons of misconceptions and myths that have flooded our collective cult knowledge base. We've got to sift through all that junk to find some clarity.\n\n## Benchmarking\n\nOK, time to start dispelling some misconceptions. I'd wager the vast majority of JS developers, if asked to benchmark the speed (execution time) of a certain operation, would initially go about it something like this:\n\n```js\nvar start = (new Date()).getTime();\t// or `Date.now()`\n\n// do some operation\n\nvar end = (new Date()).getTime();\n\nconsole.log( \"Duration:\", (end - start) );\n```\n\nRaise your hand if that's roughly what came to your mind. Yep, I thought so. There's a lot wrong with this approach, but don't feel bad; **we've all been there.**\n\nWhat did that measurement tell you, exactly? Understanding what it does and doesn't say about the execution time of the operation in question is key to learning how to appropriately benchmark performance in JavaScript.\n\nIf the duration reported is `0`, you may be tempted to believe that it took less than a millisecond. But that's not very accurate. Some platforms don't have single millisecond precision, but instead only update the timer in larger increments. For example, older versions of windows (and thus IE) had only 15ms precision, which means the operation has to take at least that long for anything other than `0` to be reported!\n\nMoreover, whatever duration is reported, the only thing you really know is that the operation took approximately that long on that exact single run. You have near-zero confidence that it will always run at that speed. You have no idea if the engine or system had some sort of interference at that exact moment, and that at other times the operation could run faster.\n\nWhat if the duration reported is `4`? Are you more sure it took about four milliseconds? Nope. It might have taken less time, and there may have been some other delay in getting either `start` or `end` timestamps.\n\nMore troublingly, you also don't know that the circumstances of this operation test aren't overly optimistic. It's possible that the JS engine figured out a way to optimize your isolated test case, but in a more real program such optimization would be diluted or impossible, such that the operation would run slower than your test.\n\nSo... what do we know? Unfortunately, with those realizations stated, **we know very little.** Something of such low confidence isn't even remotely good enough to build your determinations on. Your \"benchmark\" is basically useless. And worse, it's dangerous in that it implies false confidence, not just to you but also to others who don't think critically about the conditions that led to those results.\n\n### Repetition\n\n\"OK,\" you now say, \"Just put a loop around it so the whole test takes longer.\" If you repeat an operation 100 times, and that whole loop reportedly takes a total of 137ms, then you can just divide by 100 and get an average duration of 1.37ms for each operation, right?\n\nWell, not exactly.\n\nA straight mathematical average by itself is definitely not sufficient for making judgments about performance which you plan to extrapolate to the breadth of your entire application. With a hundred iterations, even a couple of outliers (high or low) can skew the average, and then when you apply that conclusion repeatedly, you even further inflate the skew beyond credulity.\n\nInstead of just running for a fixed number of iterations, you can instead choose to run the loop of tests until a certain amount of time has passed. That might be more reliable, but how do you decide how long to run? You might guess that it should be some multiple of how long your operation should take to run once. Wrong.\n\nActually, the length of time to repeat across should be based on the accuracy of the timer you're using, specifically to minimize the chances of inaccuracy. The less precise your timer, the longer you need to run to make sure you've minimized the error percentage. A 15ms timer is pretty bad for accurate benchmarking; to minimize its uncertainty (aka \"error rate\") to less than 1%, you need to run your each cycle of test iterations for 750ms. A 1ms timer only needs a cycle to run for 50ms to get the same confidence.\n\nBut then, that's just a single sample. To be sure you're factoring out the skew, you'll want lots of samples to average across. You'll also want to understand something about just how slow the worst sample is, how fast the best sample is, how far apart those best and worse cases were, and so on. You'll want to know not just a number that tells you how fast something ran, but also to have some quantifiable measure of how trustable that number is.\n\nAlso, you probably want to combine these different techniques (as well as others), so that you get the best balance of all the possible approaches.\n\nThat's all bare minimum just to get started. If you've been approaching performance benchmarking with anything less serious than what I just glossed over, well... \"you don't know: proper benchmarking.\"\n\n### Benchmark.js\n\nAny relevant and reliable benchmark should be based on statistically sound practices. I am not going to write a chapter on statistics here, so I'll hand wave around some terms: standard deviation, variance, margin of error. If you don't know what those terms really mean -- I took a stats class back in college and I'm still a little fuzzy on them -- you are not actually qualified to write your own benchmarking logic.\n\nLuckily, smart folks like John-David Dalton and Mathias Bynens do understand these concepts, and wrote a statistically sound benchmarking tool called Benchmark.js (http://benchmarkjs.com/). So I can end the suspense by simply saying: \"just use that tool.\"\n\nI won't repeat their whole documentation for how Benchmark.js works; they have fantastic API Docs (http://benchmarkjs.com/docs) you should read. Also there are some great (http://calendar.perfplanet.com/2010/bulletproof-javascript-benchmarks/) writeups (http://monsur.hossa.in/2012/12/11/benchmarkjs.html) on more of the details and methodology.\n\nBut just for quick illustration purposes, here's how you could use Benchmark.js to run a quick performance test:\n\n```js\nfunction foo() {\n\t// operation(s) to test\n}\n\nvar bench = new Benchmark(\n\t\"foo test\",\t\t\t\t// test name\n\tfoo,\t\t\t\t\t// function to test (just contents)\n\t{\n\t\t// ..\t\t\t\t// optional extra options (see docs)\n\t}\n);\n\nbench.hz;\t\t\t\t\t// number of operations per second\nbench.stats.moe;\t\t\t// margin of error\nbench.stats.variance;\t\t// variance across samples\n// ..\n```\n\nThere's *lots* more to learn about using Benchmark.js besides this glance I'm including here. But the point is that it's handling all of the complexities of setting up a fair, reliable, and valid performance benchmark for a given piece of JavaScript code. If you're going to try to test and benchmark your code, this library is the first place you should turn.\n\nWe're showing here the usage to test a single operation like X, but it's fairly common that you want to compare X to Y. This is easy to do by simply setting up two different tests in a \"Suite\" (a Benchmark.js organizational feature). Then, you run them head-to-head, and compare the statistics to conclude whether X or Y was faster.\n\nBenchmark.js can of course be used to test JavaScript in a browser (see the \"jsPerf.com\" section later in this chapter), but it can also run in non-browser environments (Node.js, etc.).\n\nOne largely untapped potential use-case for Benchmark.js is to use it in your Dev or QA environments to run automated performance regression tests against critical path parts of your application's JavaScript. Similar to how you might run unit test suites before deployment, you can also compare the performance against previous benchmarks to monitor if you are improving or degrading application performance.\n\n#### Setup/Teardown\n\nIn the previous code snippet, we glossed over the \"extra options\" `{ .. }` object. But there are two options we should discuss: `setup` and `teardown`.\n\nThese two options let you define functions to be called before and after your test case runs.\n\nIt's incredibly important to understand that your `setup` and `teardown` code **does not run for each test iteration**. The best way to think about it is that there's an outer loop (repeating cycles), and an inner loop (repeating test iterations). `setup` and `teardown` are run at the beginning and end of each *outer* loop (aka cycle) iteration, but not inside the inner loop.\n\nWhy does this matter? Let's imagine you have a test case that looks like this:\n\n```js\na = a + \"w\";\nb = a.charAt( 1 );\n```\n\nThen, you set up your test `setup` as follows:\n\n```js\nvar a = \"x\";\n```\n\nYour temptation is probably to believe that `a` is starting out as `\"x\"` for each test iteration.\n\nBut it's not! It's starting `a` at `\"x\"` for each test cycle, and then your repeated `+ \"w\"` concatenations will be making a larger and larger `a` value, even though you're only ever accessing the character `\"w\"` at the `1` position.\n\nWhere this most commonly bites you is when you make side effect changes to something like the DOM, like appending a child element. You may think your parent element is set as empty each time, but it's actually getting lots of elements added, and that can significantly sway the results of your tests.\n\n## Context Is King\n\nDon't forget to check the context of a particular performance benchmark, especially a comparison between X and Y tasks. Just because your test reveals that X is faster than Y doesn't mean that the conclusion \"X is faster than Y\" is actually relevant.\n\nFor example, let's say a performance test reveals that X runs 10,000,000 operations per second, and Y runs at 8,000,000 operations per second. You could claim that Y is 20% slower than X, and you'd be mathematically correct, but your assertion doesn't hold as much water as you'd think.\n\nLet's think about the results more critically: 10,000,000 operations per second is 10,000 operations per millisecond, and 10 operations per microsecond. In other words, a single operation takes 0.1 microseconds, or 100 nanoseconds. It's hard to fathom just how small 100ns is, but for comparison, it's often cited that the human eye isn't generally capable of distinguishing anything less than 100ms, which is one million times slower than the 100ns speed of the X operation.\n\nEven recent scientific studies showing that maybe the brain can process as quick as 13ms (about 8x faster than previously asserted) would mean that X is still running 125,000 times faster than the human brain can perceive a distinct thing happening. **X is going really, really fast.**\n\nBut more importantly, let's talk about the difference between X and Y, the 2,000,000 operations per second difference. If X takes 100ns, and Y takes 80ns, the difference is 20ns, which in the best case is still one 650-thousandth of the interval the human brain can perceive.\n\nWhat's my point? **None of this performance difference matters, at all!**\n\nBut wait, what if this operation is going to happen a whole bunch of times in a row? Then the difference could add up, right?\n\nOK, so what we're asking then is, how likely is it that operation X is going to be run over and over again, one right after the other, and that this has to happen 650,000 times just to get a sliver of a hope the human brain could perceive it. More likely, it'd have to happen 5,000,000 to 10,000,000 times together in a tight loop to even approach relevance.\n\nWhile the computer scientist in you might protest that this is possible, the louder voice of realism in you should sanity check just how likely or unlikely that really is. Even if it is relevant in rare occasions, it's irrelevant in most situations.\n\nThe vast majority of your benchmark results on tiny operations -- like the `++x` vs `x++` myth -- **are just totally bogus** for supporting the conclusion that X should be favored over Y on a performance basis.\n\n### Engine Optimizations\n\nYou simply cannot reliably extrapolate that if X was 10 microseconds faster than Y in your isolated test, that means X is always faster than Y and should always be used. That's not how performance works. It's vastly more complicated.\n\nFor example, let's imagine (purely hypothetical) that you test some microperformance behavior such as comparing:\n\n```js\nvar twelve = \"12\";\nvar foo = \"foo\";\n\n// test 1\nvar X1 = parseInt( twelve );\nvar X2 = parseInt( foo );\n\n// test 2\nvar Y1 = Number( twelve );\nvar Y2 = Number( foo );\n```\n\nIf you understand what `parseInt(..)` does compared to `Number(..)`, you might intuit that `parseInt(..)` potentially has \"more work\" to do, especially in the `foo` case. Or you might intuit that they should have the same amount of work to do in the `foo` case, as both should be able to stop at the first character `\"f\"`.\n\nWhich intuition is correct? I honestly don't know. But I'll make the case it doesn't matter what your intuition is. What might the results be when you test it? Again, I'm making up a pure hypothetical here, I haven't actually tried, nor do I care.\n\nLet's pretend the test comes back that `X` and `Y` are statistically identical. Have you then confirmed your intuition about the `\"f\"` character thing? Nope.\n\nIt's possible in our hypothetical that the engine might recognize that the variables `twelve` and `foo` are only being used in one place in each test, and so it might decide to inline those values. Then it may realize that `Number( \"12\" )` can just be replaced by `12`. And maybe it comes to the same conclusion with `parseInt(..)`, or maybe not.\n\nOr an engine's dead-code removal heuristic could kick in, and it could realize that variables `X` and `Y` aren't being used, so declaring them is irrelevant, so it doesn't end up doing anything at all in either test.\n\nAnd all that's just made with the mindset of assumptions about a single test run. Modern engines are fantastically more complicated than what we're intuiting here. They do all sorts of tricks, like tracing and tracking how a piece of code behaves over a short period of time, or with a particularly constrained set of inputs.\n\nWhat if the engine optimizes a certain way because of the fixed input, but in your real program you give more varied input and the optimization decisions shake out differently (or not at all!)? Or what if the engine kicks in optimizations because it sees the code being run tens of thousands of times by the benchmarking utility, but in your real program it will only run a hundred times in near proximity, and under those conditions the engine determines the optimizations are not worth it?\n\nAnd all those optimizations we just hypothesized about might happen in our constrained test but maybe the engine wouldn't do them in a more complex program (for various reasons). Or it could be reversed -- the engine might not optimize such trivial code but may be more inclined to optimize it more aggressively when the system is already more taxed by a more sophisticated program.\n\nThe point I'm trying to make is that you really don't know for sure exactly what's going on under the covers. All the guesses and hypothesis you can muster don't amount to hardly anything concrete for really making such decisions.\n\nDoes that mean you can't really do any useful testing? **Definitely not!**\n\nWhat this boils down to is that testing *not real* code gives you *not real* results. In so much as is possible and practical, you should test actual real, non-trivial snippets of your code, and under as best of real conditions as you can actually hope to. Only then will the results you get have a chance to approximate reality.\n\nMicrobenchmarks like `++x` vs `x++` are so incredibly likely to be bogus, we might as well just flatly assume them as such.\n\n## jsPerf.com\n\nWhile Benchmark.js is useful for testing the performance of your code in whatever JS environment you're running, it cannot be stressed enough that you need to compile test results from lots of different environments (desktop browsers, mobile devices, etc.) if you want to have any hope of reliable test conclusions.\n\nFor example, Chrome on a high-end desktop machine is not likely to perform anywhere near the same as Chrome mobile on a smartphone. And a smartphone with a full battery charge is not likely to perform anywhere near the same as a smartphone with 2% battery life left, when the device is starting to power down the radio and processor.\n\nIf you want to make assertions like \"X is faster than Y\" in any reasonable sense across more than just a single environment, you're going to need to actually test as many of those real world environments as possible. Just because Chrome executes some X operation faster than Y doesn't mean that all browsers do. And of course you also probably will want to cross-reference the results of multiple browser test runs with the demographics of your users.\n\nThere's an awesome website for this purpose called jsPerf (http://jsperf.com). It uses the Benchmark.js library we talked about earlier to run statistically accurate and reliable tests, and makes the test on an openly available URL that you can pass around to others.\n\nEach time a test is run, the results are collected and persisted with the test, and the cumulative test results are graphed on the page for anyone to see.\n\nWhen creating a test on the site, you start out with two test cases to fill in, but you can add as many as you need. You also have the ability to set up `setup` code that is run at the beginning of each test cycle and `teardown` code run at the end of each cycle.\n\n**Note:** A trick for doing just one test case (if you're benchmarking a single approach instead of a head-to-head) is to fill in the second test input boxes with placeholder text on first creation, then edit the test and leave the second test blank, which will delete it. You can always add more test cases later.\n\nYou can define the initial page setup (importing libraries, defining utility helper functions, declaring variables, etc.). There are also options for defining setup and teardown behavior if needed -- consult the \"Setup/Teardown\" section in the Benchmark.js discussion earlier.\n\n### Sanity Check\n\njsPerf is a fantastic resource, but there's an awful lot of tests published that when you analyze them are quite flawed or bogus, for any of a variety of reasons as outlined so far in this chapter.\n\nConsider:\n\n```js\n// Case 1\nvar x = [];\nfor (var i=0; i<10; i++) {\n\tx[i] = \"x\";\n}\n\n// Case 2\nvar x = [];\nfor (var i=0; i<10; i++) {\n\tx[x.length] = \"x\";\n}\n\n// Case 3\nvar x = [];\nfor (var i=0; i<10; i++) {\n\tx.push( \"x\" );\n}\n```\n\nSome observations to ponder about this test scenario:\n\n* It's extremely common for devs to put their own loops into test cases, and they forget that Benchmark.js already does all the repetition you need. There's a really strong chance that the `for` loops in these cases are totally unnecessary noise.\n* The declaring and initializing of `x` is included in each test case, possibly unnecessarily. Recall from earlier that if `x = []` were in the `setup` code, it wouldn't actually be run before each test iteration, but instead once at the beginning of each cycle. That means `x` would continue growing quite large, not just the size `10` implied by the `for` loops.\n\n   So is the intent to make sure the tests are constrained only to how the JS engine behaves with very small arrays (size `10`)? That *could* be the intent, but if it is, you have to consider if that's not focusing far too much on nuanced internal implementation details.\n\n   On the other hand, does the intent of the test embrace the context that the arrays will actually be growing quite large? Is the JS engines' behavior with larger arrays relevant and accurate when compared with the intended real world usage?\n\n* Is the intent to find out how much `x.length` or `x.push(..)` add to the performance of the operation to append to the `x` array? OK, that might be a valid thing to test. But then again, `push(..)` is a function call, so of course it's going to be slower than `[..]` access. Arguably, cases 1 and 2 are fairer than case 3.\n\n\nHere's another example that illustrates a common apples-to-oranges flaw:\n\n```js\n// Case 1\nvar x = [\"John\",\"Albert\",\"Sue\",\"Frank\",\"Bob\"];\nx.sort();\n\n// Case 2\nvar x = [\"John\",\"Albert\",\"Sue\",\"Frank\",\"Bob\"];\nx.sort( function mySort(a,b){\n\tif (a < b) return -1;\n\tif (a > b) return 1;\n\treturn 0;\n} );\n```\n\nHere, the obvious intent is to find out how much slower the custom `mySort(..)` comparator is than the built-in default comparator. But by specifying the function `mySort(..)` as inline function expression, you've created an unfair/bogus test. Here, the second case is not only testing a custom user JS function, **but it's also testing creating a new function expression for each iteration.**\n\nWould it surprise you to find out that if you run a similar test but update it to isolate only for creating an inline function expression versus using a pre-declared function, the inline function expression creation can be from 2% to 20% slower!?\n\nUnless your intent with this test *is* to consider the inline function expression creation \"cost,\" a better/fairer test would put `mySort(..)`'s declaration in the page setup -- don't put it in the test `setup` as that's unnecessary redeclaration for each cycle -- and simply reference it by name in the test case: `x.sort(mySort)`.\n\nBuilding on the previous example, another pitfall is in opaquely avoiding or adding \"extra work\" to one test case that creates an apples-to-oranges scenario:\n\n```js\n// Case 1\nvar x = [12,-14,0,3,18,0,2.9];\nx.sort();\n\n// Case 2\nvar x = [12,-14,0,3,18,0,2.9];\nx.sort( function mySort(a,b){\n\treturn a - b;\n} );\n```\n\nSetting aside the previously mentioned inline function expression pitfall, the second case's `mySort(..)` works in this case because you have provided it numbers, but would have of course failed with strings. The first case doesn't throw an error, but it actually behaves differently and has a different outcome! It should be obvious, but: **a different outcome between two test cases almost certainly invalidates the entire test!**\n\nBut beyond the different outcomes, in this case, the built in `sort(..)`'s comparator is actually doing \"extra work\" that `mySort()` does not, in that the built-in one coerces the compared values to strings and does lexicographic comparison. The first snippet results in `[-14, 0, 0, 12, 18, 2.9, 3]` while the second snippet results (likely more accurately based on intent) in `[-14, 0, 0, 2.9, 3, 12, 18]`.\n\nSo that test is unfair because it's not actually doing the same task between the cases. Any results you get are bogus.\n\nThese same pitfalls can even be much more subtle:\n\n```js\n// Case 1\nvar x = false;\nvar y = x ? 1 : 2;\n\n// Case 2\nvar x;\nvar y = x ? 1 : 2;\n```\n\nHere, the intent might be to test the performance impact of the coercion to a Boolean that the `? :` operator will do if the `x` expression is not already a Boolean (see the *Types & Grammar* title of this book series). So, you're apparently OK with the fact that there is extra work to do the coercion in the second case.\n\nThe subtle problem? You're setting `x`'s value in the first case and not setting it in the other, so you're actually doing work in the first case that you're not doing in the second. To eliminate any potential (albeit minor) skew, try:\n\n```js\n// Case 1\nvar x = false;\nvar y = x ? 1 : 2;\n\n// Case 2\nvar x = undefined;\nvar y = x ? 1 : 2;\n```\n\nNow there's an assignment in both cases, so the thing you want to test -- the coercion of `x` or not -- has likely been more accurately isolated and tested.\n\n## Writing Good Tests\n\nLet me see if I can articulate the bigger point I'm trying to make here.\n\nGood test authoring requires careful analytical thinking about what differences exist between two test cases and whether the differences between them are *intentional* or *unintentional*.\n\nIntentional differences are of course normal and OK, but it's too easy to create unintentional differences that skew your results. You have to be really, really careful to avoid that skew. Moreover, you may intend a difference but it may not be obvious to other readers of your test what your intent was, so they may doubt (or trust!) your test incorrectly. How do you fix that?\n\n**Write better, clearer tests.** But also, take the time to document (using the jsPerf.com \"Description\" field and/or code comments) exactly what the intent of your test is, even to the nuanced detail. Call out the intentional differences, which will help others and your future self to better identify unintentional differences that could be skewing the test results.\n\nIsolate things which aren't relevant to your test by pre-declaring them in the page or test setup settings so they're outside the timed parts of the test.\n\nInstead of trying to narrow in on a tiny snippet of your real code and benchmarking just that piece out of context, tests and benchmarks are better when they include a larger (while still relevant) context. Those tests also tend to run slower, which means any differences you spot are more relevant in context.\n\n## Microperformance\n\nOK, until now we've been dancing around various microperformance issues and generally looking disfavorably upon obsessing about them. I want to take just a moment to address them directly.\n\nThe first thing you need to get more comfortable with when thinking about performance benchmarking your code is that the code you write is not always the code the engine actually runs. We briefly looked at that topic back in Chapter 1 when we discussed statement reordering by the compiler, but here we're going to suggest the compiler can sometimes decide to run different code than you wrote, not just in different orders but different in substance.\n\nLet's consider this piece of code:\n\n```js\nvar foo = 41;\n\n(function(){\n\t(function(){\n\t\t(function(baz){\n\t\t\tvar bar = foo + baz;\n\t\t\t// ..\n\t\t})(1);\n\t})();\n})();\n```\n\nYou may think about the `foo` reference in the innermost function as needing to do a three-level scope lookup. We covered in the *Scope & Closures* title of this book series how lexical scope works, and the fact that the compiler generally caches such lookups so that referencing `foo` from different scopes doesn't really practically \"cost\" anything extra.\n\nBut there's something deeper to consider. What if the compiler realizes that `foo` isn't referenced anywhere else but that one location, and it further notices that the value never is anything except the `41` as shown?\n\nIsn't it quite possible and acceptable that the JS compiler could decide to just remove the `foo` variable entirely, and *inline* the value, such as this:\n\n```js\n(function(){\n\t(function(){\n\t\t(function(baz){\n\t\t\tvar bar = 41 + baz;\n\t\t\t// ..\n\t\t})(1);\n\t})();\n})();\n```\n\n**Note:** Of course, the compiler could probably also do a similar analysis and rewrite with the `baz` variable here, too.\n\nWhen you begin to think about your JS code as being a hint or suggestion to the engine of what to do, rather than a literal requirement, you realize that a lot of the obsession over discrete syntactic minutia is most likely unfounded.\n\nAnother example:\n\n```js\nfunction factorial(n) {\n\tif (n < 2) return 1;\n\treturn n * factorial( n - 1 );\n}\n\nfactorial( 5 );\t\t// 120\n```\n\nAh, the good ol' fashioned \"factorial\" algorithm! You might assume that the JS engine will run that code mostly as is. And to be honest, it might -- I'm not really sure.\n\nBut as an anecdote, the same code expressed in C and compiled with advanced optimizations would result in the compiler realizing that the call `factorial(5)` can just be replaced with the constant value `120`, eliminating the function and call entirely!\n\nMoreover, some engines have a practice called \"unrolling recursion,\" where it can realize that the recursion you've expressed can actually be done \"easier\" (i.e., more optimally) with a loop. It's possible the preceding code could be *rewritten* by a JS engine to run as:\n\n```js\nfunction factorial(n) {\n\tif (n < 2) return 1;\n\n\tvar res = 1;\n\tfor (var i=n; i>1; i--) {\n\t\tres *= i;\n\t}\n\treturn res;\n}\n\nfactorial( 5 );\t\t// 120\n```\n\nNow, let's imagine that in the earlier snippet you had been worried about whether `n * factorial(n-1)` or `n *= factorial(--n)` runs faster. Maybe you even did a performance benchmark to try to figure out which was better. But you miss the fact that in the bigger context, the engine may not run either line of code because it may unroll the recursion!\n\nSpeaking of `--`, `--n` versus `n--` is often cited as one of those places where you can optimize by choosing the `--n` version, because theoretically it requires less effort down at the assembly level of processing.\n\nThat sort of obsession is basically nonsense in modern JavaScript. That's the kind of thing you should be letting the engine take care of. You should write the code that makes the most sense. Compare these three `for` loops:\n\n```js\n// Option 1\nfor (var i=0; i<10; i++) {\n\tconsole.log( i );\n}\n\n// Option 2\nfor (var i=0; i<10; ++i) {\n\tconsole.log( i );\n}\n\n// Option 3\nfor (var i=-1; ++i<10; ) {\n\tconsole.log( i );\n}\n```\n\nEven if you have some theory where the second or third option is more performant than the first option by a tiny bit, which is dubious at best, the third loop is more confusing because you have to start with `-1` for `i` to account for the fact that `++i` pre-increment is used. And the difference between the first and second options is really quite irrelevant.\n\nIt's entirely possible that a JS engine may see a place where `i++` is used and realize that it can safely replace it with the `++i` equivalent, which means your time spent deciding which one to pick was completely wasted and the outcome moot.\n\nHere's another common example of silly microperformance obsession:\n\n```js\nvar x = [ .. ];\n\n// Option 1\nfor (var i=0; i < x.length; i++) {\n\t// ..\n}\n\n// Option 2\nfor (var i=0, len = x.length; i < len; i++) {\n\t// ..\n}\n```\n\nThe theory here goes that you should cache the length of the `x` array in the variable `len`, because ostensibly it doesn't change, to avoid paying the price of `x.length` being consulted for each iteration of the loop.\n\nIf you run performance benchmarks around `x.length` usage compared to caching it in a `len` variable, you'll find that while the theory sounds nice, in practice any measured differences are statistically completely irrelevant.\n\nIn fact, in some engines like v8, it can be shown (http://mrale.ph/blog/2014/12/24/array-length-caching.html) that you could make things slightly worse by pre-caching the length instead of letting the engine figure it out for you. Don't try to outsmart your JavaScript engine, you'll probably lose when it comes to performance optimizations.\n\n### Not All Engines Are Alike\n\nThe different JS engines in various browsers can all be \"spec compliant\" while having radically different ways of handling code. The JS specification doesn't require anything performance related -- well, except ES6's \"Tail Call Optimization\" covered later in this chapter.\n\nThe engines are free to decide that one operation will receive its attention to optimize, perhaps trading off for lesser performance on another operation. It can be very tenuous to find an approach for an operation that always runs faster in all browsers.\n\nThere's a movement among some in the JS dev community, especially those who work with Node.js, to analyze the specific internal implementation details of the v8 JavaScript engine and make decisions about writing JS code that is tailored to take best advantage of how v8 works. You can actually achieve a surprisingly high degree of performance optimization with such endeavors, so the payoff for the effort can be quite high.\n\nSome commonly cited examples (https://github.com/petkaantonov/bluebird/wiki/Optimization-killers) for v8:\n\n* Don't pass the `arguments` variable from one function to any other function, as such \"leakage\" slows down the function implementation.\n* Isolate a `try..catch` in its own function. Browsers struggle with optimizing any function with a `try..catch` in it, so moving that construct to its own function means you contain the de-optimization harm while letting the surrounding code be optimizable.\n\nBut rather than focus on those tips specifically, let's sanity check the v8-only optimization approach in a general sense.\n\nAre you genuinely writing code that only needs to run in one JS engine? Even if your code is entirely intended for Node.js *right now*, is the assumption that v8 will *always* be the used JS engine reliable? Is it possible that someday a few years from now, there's another server-side JS platform besides Node.js that you choose to run your code on? What if what you optimized for before is now a much slower way of doing that operation on the new engine?\n\nOr what if your code always stays running on v8 from here on out, but v8 decides at some point to change the way some set of operations works such that what used to be fast is now slow, and vice versa?\n\nThese scenarios aren't just theoretical, either. It used to be that it was faster to put multiple string values into an array and then call `join(\"\")` on the array to concatenate the values than to just use `+` concatenation directly with the values. The historical reason for this is nuanced, but it has to do with internal implementation details about how string values were stored and managed in memory.\n\nAs a result, \"best practice\" advice at the time disseminated across the industry suggesting developers always use the array `join(..)` approach. And many followed.\n\nExcept, somewhere along the way, the JS engines changed approaches for internally managing strings, and specifically put in optimizations for `+` concatenation. They didn't slow down `join(..)` per se, but they put more effort into helping `+` usage, as it was still quite a bit more widespread.\n\n**Note:** The practice of standardizing or optimizing some particular approach based mostly on its existing widespread usage is often called (metaphorically) \"paving the cowpath.\"\n\nOnce that new approach to handling strings and concatenation took hold, unfortunately all the code out in the wild that was using array `join(..)` to concatenate strings was then sub-optimal.\n\nAnother example: at one time, the Opera browser differed from other browsers in how it handled the boxing/unboxing of primitive wrapper objects (see the *Types & Grammar* title of this book series). As such, their advice to developers was to use a `String` object instead of the primitive `string` value if properties like `length` or methods like `charAt(..)` needed to be accessed. This advice may have been correct for Opera at the time, but it was literally completely opposite for other major contemporary browsers, as they had optimizations specifically for the `string` primitives and not their object wrapper counterparts.\n\nI think these various gotchas are at least possible, if not likely, for code even today. So I'm very cautious about making wide ranging performance optimizations in my JS code based purely on engine implementation details, **especially if those details are only true of a single engine**.\n\nThe reverse is also something to be wary of: you shouldn't necessarily change a piece of code to work around one engine's difficulty with running a piece of code in an acceptably performant way.\n\nHistorically, IE has been the brunt of many such frustrations, given that there have been plenty of scenarios in older IE versions where it struggled with some performance aspect that other major browsers of the time seemed not to have much trouble with. The string concatenation discussion we just had was actually a real concern back in the IE6 and IE7 days, where it was possible to get better performance out of `join(..)` than `+`.\n\nBut it's troublesome to suggest that just one browser's trouble with performance is justification for using a code approach that quite possibly could be sub-optimal in all other browsers. Even if the browser in question has a large market share for your site's audience, it may be more practical to write the proper code and rely on the browser to update itself with better optimizations eventually.\n\n\"There is nothing more permanent than a temporary hack.\" Chances are, the code you write now to work around some performance bug will probably outlive the performance bug in the browser itself.\n\nIn the days when a browser only updated once every five years, that was a tougher call to make. But as it stands now, browsers across the board are updating at a much more rapid interval (though obviously the mobile world still lags), and they're all competing to optimize web features better and better.\n\nIf you run across a case where a browser *does* have a performance wart that others don't suffer from, make sure to report it to them through whatever means you have available. Most browsers have open public bug trackers suitable for this purpose.\n\n**Tip:** I'd only suggest working around a performance issue in a browser if it was a really drastic show-stopper, not just an annoyance or frustration. And I'd be very careful to check that the performance hack didn't have noticeable negative side effects in another browser.\n\n### Big Picture\n\nInstead of worrying about all these microperformance nuances, we should instead be looking at big-picture types of optimizations.\n\nHow do you know what's big picture or not? You have to first understand if your code is running on a critical path or not. If it's not on the critical path, chances are your optimizations are not worth much.\n\nEver heard the admonition, \"that's premature optimization!\"? It comes from a famous quote from Donald Knuth: \"premature optimization is the root of all evil.\". Many developers cite this quote to suggest that most optimizations are \"premature\" and are thus a waste of effort. The truth is, as usual, more nuanced.\n\nHere is Knuth's quote, in context:\n\n> Programmers waste enormous amounts of time thinking about, or worrying about, the speed of **noncritical** parts of their programs, and these attempts at efficiency actually have a strong negative impact when debugging and maintenance are considered. We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that **critical** 3%. [emphasis added]\n\n(http://web.archive.org/web/20130731202547/http://pplab.snu.ac.kr/courses/adv_pl05/papers/p261-knuth.pdf, Computing Surveys, Vol 6, No 4, December 1974)\n\nI believe it's a fair paraphrasing to say that Knuth *meant*: \"non-critical path optimization is the root of all evil.\" So the key is to figure out if your code is on the critical path -- you should optimize it! -- or not.\n\nI'd even go so far as to say this: no amount of time spent optimizing critical paths is wasted, no matter how little is saved; but no amount of optimization on noncritical paths is justified, no matter how much is saved.\n\nIf your code is on the critical path, such as a \"hot\" piece of code that's going to be run over and over again, or in UX critical places where users will notice, like an animation loop or CSS style updates, then you should spare no effort in trying to employ relevant, measurably significant optimizations.\n\nFor example, consider a critical path animation loop that needs to coerce a string value to a number. There are of course multiple ways to do that (see the *Types & Grammar* title of this book series), but which one if any is the fastest?\n\n```js\nvar x = \"42\";\t// need number `42`\n\n// Option 1: let implicit coercion automatically happen\nvar y = x / 2;\n\n// Option 2: use `parseInt(..)`\nvar y = parseInt( x, 0 ) / 2;\n\n// Option 3: use `Number(..)`\nvar y = Number( x ) / 2;\n\n// Option 4: use `+` unary operator\nvar y = +x / 2;\n\n// Option 5: use `|` unary operator\nvar y = (x | 0) / 2;\n```\n\n**Note:** I will leave it as an exercise to the reader to set up a test if you're interested in examining the minute differences in performance among these options.\n\nWhen considering these different options, as they say, \"One of these things is not like the others.\" `parseInt(..)` does the job, but it also does a lot more -- it parses the string rather than just coercing. You can probably guess, correctly, that `parseInt(..)` is a slower option, and you should probably avoid it.\n\nOf course, if `x` can ever be a value that **needs parsing**, such as `\"42px\"` (like from a CSS style lookup), then `parseInt(..)` really is the only suitable option!\n\n`Number(..)` is also a function call. From a behavioral perspective, it's identical to the `+` unary operator option, but it may in fact be a little slower, requiring more machinery to execute the function. Of course, it's also possible that the JS engine recognizes this behavioral symmetry and just handles the inlining of `Number(..)`'s behavior (aka `+x`) for you!\n\nBut remember, obsessing about `+x` versus `x | 0` is in most cases likely a waste of effort. This is a microperformance issue, and one that you shouldn't let dictate/degrade the readability of your program.\n\nWhile performance is very important in critical paths of your program, it's not the only factor. Among several options that are roughly similar in performance, readability should be another important concern.\n\n## Tail Call Optimization (TCO)\n\nAs we briefly mentioned earlier, ES6 includes a specific requirement that ventures into the world of performance. It's related to a specific form of optimization that can occur with function calls: *tail call optimization*.\n\nBriefly, a \"tail call\" is a function call that appears at the \"tail\" of another function, such that after the call finishes, there's nothing left to do (except perhaps return its result value).\n\nFor example, here's a non-recursive setup with tail calls:\n\n```js\nfunction foo(x) {\n\treturn x;\n}\n\nfunction bar(y) {\n\treturn foo( y + 1 );\t// tail call\n}\n\nfunction baz() {\n\treturn 1 + bar( 40 );\t// not tail call\n}\n\nbaz();\t\t\t\t\t\t// 42\n```\n\n`foo(y+1)` is a tail call in `bar(..)` because after `foo(..)` finishes, `bar(..)` is also finished except in this case returning the result of the `foo(..)` call. However, `bar(40)` is *not* a tail call because after it completes, its result value must be added to `1` before `baz()` can return it.\n\nWithout getting into too much nitty-gritty detail, calling a new function requires an extra amount of reserved memory to manage the call stack, called a \"stack frame.\" So the preceding snippet would generally require a stack frame for each of `baz()`, `bar(..)`, and `foo(..)` all at the same time.\n\nHowever, if a TCO-capable engine can realize that the `foo(y+1)` call is in *tail position* meaning `bar(..)` is basically complete, then when calling `foo(..)`, it doesn't need to create a new stack frame, but can instead reuse the existing stack frame from `bar(..)`. That's not only faster, but it also uses less memory.\n\nThat sort of optimization isn't a big deal in a simple snippet, but it becomes a *much bigger deal* when dealing with recursion, especially if the recursion could have resulted in hundreds or thousands of stack frames. With TCO the engine can perform all those calls with a single stack frame!\n\nRecursion is a hairy topic in JS because without TCO, engines have had to implement arbitrary (and different!) limits to how deep they will let the recursion stack get before they stop it, to prevent running out of memory. With TCO, recursive functions with *tail position* calls can essentially run unbounded, because there's never any extra usage of memory!\n\nConsider that recursive `factorial(..)` from before, but rewritten to make it TCO friendly:\n\n```js\nfunction factorial(n) {\n\tfunction fact(n,res) {\n\t\tif (n < 2) return res;\n\n\t\treturn fact( n - 1, n * res );\n\t}\n\n\treturn fact( n, 1 );\n}\n\nfactorial( 5 );\t\t// 120\n```\n\nThis version of `factorial(..)` is still recursive, but it's also optimizable with TCO, because both inner `fact(..)` calls are in *tail position*.\n\n**Note:** It's important to note that TCO only applies if there's actually a tail call. If you write recursive functions without tail calls, the performance will still fall back to normal stack frame allocation, and the engines' limits on such recursive call stacks will still apply. Many recursive functions can be rewritten as we just showed with `factorial(..)`, but it takes careful attention to detail.\n\nOne reason that ES6 requires engines to implement TCO rather than leaving it up to their discretion is because the *lack of TCO* actually tends to reduce the chances that certain algorithms will be implemented in JS using recursion, for fear of the call stack limits.\n\nIf the lack of TCO in the engine would just gracefully degrade to slower performance in all cases, it wouldn't probably have been something that ES6 needed to *require*. But because the lack of TCO can actually make certain programs impractical, it's more an important feature of the language than just a hidden implementation detail.\n\nES6 guarantees that from now on, JS developers will be able to rely on this optimization across all ES6+ compliant browsers. That's a win for JS performance!\n\n## Review\n\nEffectively benchmarking performance of a piece of code, especially to compare it to another option for that same code to see which approach is faster, requires careful attention to detail.\n\nRather than rolling your own statistically valid benchmarking logic, just use the Benchmark.js library, which does that for you. But be careful about how you author tests, because it's far too easy to construct a test that seems valid but that's actually flawed -- even tiny differences can skew the results to be completely unreliable.\n\nIt's important to get as many test results from as many different environments as possible to eliminate hardware/device bias. jsPerf.com is a fantastic website for crowdsourcing performance benchmark test runs.\n\nMany common performance tests unfortunately obsess about irrelevant microperformance details like `x++` versus `++x`. Writing good tests means understanding how to focus on big picture concerns, like optimizing on the critical path, and avoiding falling into traps like different JS engines' implementation details.\n\nTail call optimization (TCO) is a required optimization as of ES6 that will make some recursive patterns practical in JS where they would have been impossible otherwise. TCO allows a function call in the *tail position* of another function to execute without needing any extra resources, which means the engine no longer needs to place arbitrary restrictions on call stack depth for recursive algorithms.\n"
  },
  {
    "path": "async & performance/foreword.md",
    "content": "# Вы не знаете JS: Асинхронность и Производительность\n# Введение\n\nМой работодатель доверяет мне проводить собеседования на протяжении многих лет. Если мы ищем JavaScript разработчика, то я начинаю опрос с…, нет, не начинаю, я сначала узнаю не нужно ли моему потенциальному коллеге выйти в туалет и/или попить, потому что важна комфортная обстановка, а потом я начну задавать вопросы, чтобы узнать: \"Он знает JavaScript или jQuery\".\n\nВ jQuery нет ничего плохого. С помощью него можно многое сделать, не зная JavaScript. Но если требуется высокая квалификация и глубокие знания в оптимизации JavaScript, чтобы при необходимости быстро решать проблемы, нам нужен тот кто знает и понимает, как устроены такие библиотеки, как jQuery изнутри, чтобы использовать чистый JavaScript, как это делают другие библиотеки.\n\nКак получить картинку используя только JavaScript, или как делаются замыкания (вы ведь уже читали книгу про [Область видимости и замыкания](https://github.com/azat-io/you-dont-know-js-ru/tree/master/scope%20%26%20closures)) и как получить максимальную пользу от асинхронности, именно об этом будет написано в этой книге.\n\nСначала мы познакомимся с обратными вызовами (callbacks), а в дальнейшем и с обещаниями (promises).\n\nЕсли вы ничего не знаете о обещаниях (promises), сейчас самое время это исправить. Обещания теперь стандарт использования асинхронности в JavaScript и DOM. Все будущие DOM API будут использовать обещания (promises), многие уже это делают, так что будьте готовы! В момент написания этой книги, обещания (promises) поддерживаются в основных браузерах [Подробнее](http://caniuse.com/#search=Promises), а IE уже на подходе. Я надеюсь, что после изучения у вас останется место для следующего курса про генераторы.\n\nГенераторы пробрались в стабильные версии браузеров Chrome и Firefox, от них больше головной боли, чем пользы. Именно так я думал пока не увидел их в вместе с обещаниями (promises). Там они стали важным инструментом в читабельности и поддержке кода.\n\nНа десерт, я не буду портить сюрприз, приготовьтесь увидеть будущее JavaScript! Особенности, которые дают вам больше контроля над параллельностью и асинхронностью.\n\nЧто ж, я больше не буду задерживать вас от прочтения этой книги. Если вы уже прочитали часть книги перед тем, как прочитать это предисловие, то дайте себе 10 очков по асинхронности! Вы действительно их заслуживаете!\n\nДжейк Арчибальд<br>\n[jakearchibald.com](https://jakearchibald.com), [@jaffathecake](https://twitter.com/jaffathecake)<br>\nGoogle Chrome Разработчик\n"
  },
  {
    "path": "async & performance/toc.md",
    "content": "# Вы не знаете JS: Асинхронность и Производительность\n\n## Содержимое\n\n* Предисловие\n* Preface\n* Chapter 1: Asynchrony: Now & Later\n\t* A Program In Chunks\n\t* Event Loop\n\t* Parallel Threading\n\t* Concurrency\n\t* Jobs\n\t* Statement Ordering\n* Chapter 2: Callbacks\n\t* Continuations\n\t* Sequential Brain\n\t* Trust Issues\n\t* Trying To Save Callbacks\n* Chapter 3: Promises\n\t* What is a Promise?\n\t* Thenable Duck-Typing\n\t* Promise Trust\n\t* Chain Flow\n\t* Error Handling\n\t* Promise Patterns\n\t* Promise API Recap\n\t* Promise Limitations\n* Chapter 4: Generators\n\t* Breaking Run-to-completion\n\t* Generator'ing Values\n\t* Iterating Generators Asynchronously\n\t* Generators + Promises\n\t* Generator Delegation\n\t* Generator Concurrency\n\t* Thunks\n\t* Pre-ES6 Generators\n* Chapter 5: Program Performance\n\t* Web Workers\n\t* SIMD\n\t* asm.js\n* Chapter 6: Benchmarking & Tuning\n\t* Benchmarking\n\t* Context Is King\n\t* jsPerf.com\n\t* Writing Good Tests\n\t* Microperformance\n\t* Tail Call Optimization (TCO)\n* Appendix A: *asynquence* Library\n* Appendix B: Advanced Async Patterns\n* Appendix C: Acknowledgments\n"
  },
  {
    "path": "es6 & beyond/README.md",
    "content": "# Вы не знаете JS: ES6 и не только\n\n<img src=\"cover.jpg\" width=\"300\">\n\n-----\n\n**[Купить цифровую или печатную книгу от издательства O'Reilly (англ.)](http://shop.oreilly.com/product/0636920033769.do)**\n\n-----\n\n[Оглавление](toc.md)\n\n* [Введение](foreword.md) (by [Rick Waldron](http://bocoup.com/weblog/author/rick-waldron/))\n* [Предисловие](../preface.md)\n* [Глава 1: ES: современность и будущее](ch1.md)\n* [Глава 2: Синтаксис](ch2.md)\n* [Глава 3: Структура](ch3.md)\n* [Глава 4: Управление асинхронными операциями](ch4.md)\n* [Глава 5: Коллекции](ch5.md)\n* [Глава 6: Дополнения к API](ch6.md)\n* [Глава 7: Метапрограммирование](ch7.md)\n* [Глава 8: За пределами ES6](ch8.md)\n* [Приложение A: Благодарности!](apA.md)\n"
  },
  {
    "path": "es6 & beyond/apA.md",
    "content": "# Вы не знаете JS: ES6 и не только\n# Приложение A: Благодарности\n\nЕсть множество людей, которых нужно поблагодарить за то, что появилась на свет эта книга и вся серия.\n\nВо-первых, я должен поблагодарить мою жену Кристен Симпсон (Christen Simpson) и двух моих детей Итана (Ethan) и Эмили (Emily), за то, что мирились с тем, что их папу вечно надо было отрывать от компьютера. Даже когда я не писал книги, моя одержимость JavaScript приклеивала мой взгляд к экрану больше, чем следовало. То время, которое я занял у моей семьи, и есть причина, по которой эти книги могут так глубоко и полностью объяснить JavaScript для вас, читатель. Я в большом долгу перед своей семьей.\n\nХочу поблагодарить моих редакторов в O'Reilly, а именно Simon St.Laurent и Brian MacDonald, как и остальных в команде редакторов и маркетинга. Работать с ними — одно удовольствие, и хочется особенно поблагодарить их за создание подходящих условий во время этого эксперимента с написанием \"open source\"-книги, за редактирование и выпуск.\n\nСпасибо всем тем, кто участвовал в улучшении этой серии книг присылая предложения по редактированию и корректировке, включая Shelley Powers, Tim Ferro, Evan Borden, Forrest L. Norvell, Jennifer Davis, Jesse Harlin и многих других. Большое спасибо Shane Hudson за написание предисловия к этой серии книг.\n\nСпасибо бесчисленным участникам сообщества, включая членов комитета TC39, кто поделился столько многим с нами и особенно за терпеливое отношение к моим бесконечным вопросам и изысканиям. John-David Dalton, Juriy \"kangax\" Zaytsev, Mathias Bynens, Axel Rauschmayer, Nicholas Zakas, Angus Croll, Reginald Braithwaite, Dave Herman, Brendan Eich, Allen Wirfs-Brock, Bradley Meck, Domenic Denicola, David Walsh, Tim Disney, Peter van der Zee, Andrea Giammarchi, Kit Cambridge, Eric Elliott и многие другие, я упомянул лишь малую часть.\n\nСерия книг *Вы не знаете JS* родилась на Kickstarter, поэтому я также хочу поблагодарить всех моих (почти) 500 щедрых инвесторов, без которых эта серия книг не появилась бы:\n\n> Jan Szpila, nokiko, Murali Krishnamoorthy, Ryan Joy, Craig Patchett, pdqtrader, Dale Fukami, ray hatfield, R0drigo Perez [Mx], Dan Petitt, Jack Franklin, Andrew Berry, Brian Grinstead, Rob Sutherland, Sergi Meseguer, Phillip Gourley, Mark Watson, Jeff Carouth, Alfredo Sumaran, Martin Sachse, Marcio Barrios, Dan, AimelyneM, Matt Sullivan, Delnatte Pierre-Antoine, Jake Smith, Eugen Tudorancea, Iris, David Trinh, simonstl, Ray Daly, Uros Gruber, Justin Myers, Shai Zonis, Mom & Dad, Devin Clark, Dennis Palmer, Brian Panahi Johnson, Josh Marshall, Marshall, Dennis Kerr, Matt Steele, Erik Slagter, Sacah, Justin Rainbow, Christian Nilsson, Delapouite, D.Pereira, Nicolas Hoizey, George V. Reilly, Dan Reeves, Bruno Laturner, Chad Jennings, Shane King, Jeremiah Lee Cohick, od3n, Stan Yamane, Marko Vucinic, Jim B, Stephen Collins, Ægir Þorsteinsson, Eric Pederson, Owain, Nathan Smith, Jeanetteurphy, Alexandre ELISÉ, Chris Peterson, Rik Watson, Luke Matthews, Justin Lowery, Morten Nielsen, Vernon Kesner, Chetan Shenoy, Paul Tregoing, Marc Grabanski, Dion Almaer, Andrew Sullivan, Keith Elsass, Tom Burke, Brian Ashenfelter, David Stuart, Karl Swedberg, Graeme, Brandon Hays, John Christopher, Gior, manoj reddy, Chad Smith, Jared Harbour, Minoru TODA, Chris Wigley, Daniel Mee, Mike, Handyface, Alex Jahraus, Carl Furrow, Rob Foulkrod, Max Shishkin, Leigh Penny Jr., Robert Ferguson, Mike van Hoenselaar, Hasse Schougaard, rajan venkataguru, Jeff Adams, Trae Robbins, Rolf Langenhuijzen, Jorge Antunes, Alex Koloskov, Hugh Greenish, Tim Jones, Jose Ochoa, Michael Brennan-White, Naga Harish Muvva, Barkóczi Dávid, Kitt Hodsden, Paul McGraw, Sascha Goldhofer, Andrew Metcalf, Markus Krogh, Michael Mathews, Matt Jared, Juanfran, Georgie Kirschner, Kenny Lee, Ted Zhang, Amit Pahwa, Inbal Sinai, Dan Raine, Schabse Laks, Michael Tervoort, Alexandre Abreu, Alan Joseph Williams, NicolasD, Cindy Wong, Reg Braithwaite, LocalPCGuy, Jon Friskics, Chris Merriman, John Pena, Jacob Katz, Sue Lockwood, Magnus Johansson, Jeremy Crapsey, Grzegorz Pawłowski, nico nuzzaci, Christine Wilks, Hans Bergren, charles montgomery, Ariel בר-לבב Fogel, Ivan Kolev, Daniel Campos, Hugh Wood, Christian Bradford, Frédéric Harper, Ionuţ Dan Popa, Jeff Trimble, Rupert Wood, Trey Carrico, Pancho Lopez, Joël kuijten, Tom A Marra, Jeff Jewiss, Jacob Rios, Paolo Di Stefano, Soledad Penades, Chris Gerber, Andrey Dolganov, Wil Moore III, Thomas Martineau, Kareem, Ben Thouret, Udi Nir, Morgan Laupies, jory carson-burson, Nathan L Smith, Eric Damon Walters, Derry Lozano-Hoyland, Geoffrey Wiseman, mkeehner, KatieK, Scott MacFarlane, Brian LaShomb, Adrien Mas, christopher ross, Ian Littman, Dan Atkinson, Elliot Jobe, Nick Dozier, Peter Wooley, John Hoover, dan, Martin A. Jackson, Héctor Fernando Hurtado, andy ennamorato, Paul Seltmann, Melissa Gore, Dave Pollard, Jack Smith, Philip Da Silva, Guy Israeli, @megalithic, Damian Crawford, Felix Gliesche, April Carter Grant, Heidi, jim tierney, Andrea Giammarchi, Nico Vignola, Don Jones, Chris Hartjes, Alex Howes, john gibbon, David J. Groom, BBox, Yu 'Dilys' Sun, Nate Steiner, Brandon Satrom, Brian Wyant, Wesley Hales, Ian Pouncey, Timothy Kevin Oxley, George Terezakis, sanjay raj, Jordan Harband, Marko McLion, Wolfgang Kaufmann, Pascal Peuckert, Dave Nugent, Markus Liebelt, Welling Guzman, Nick Cooley, Daniel Mesquita, Robert Syvarth, Chris Coyier, Rémy Bach, Adam Dougal, Alistair Duggin, David Loidolt, Ed Richer, Brian Chenault, GoldFire Studios, Carles Andrés, Carlos Cabo, Yuya Saito, roberto ricardo, Barnett Klane, Mike Moore, Kevin Marx, Justin Love, Joe Taylor, Paul Dijou, Michael Kohler, Rob Cassie, Mike Tierney, Cody Leroy Lindley, tofuji, Shimon Schwartz, Raymond, Luc De Brouwer, David Hayes, Rhys Brett-Bowen, Dmitry, Aziz Khoury, Dean, Scott Tolinski - Level Up, Clement Boirie, Djordje Lukic, Anton Kotenko, Rafael Corral, Philip Hurwitz, Jonathan Pidgeon, Jason Campbell, Joseph C., SwiftOne, Jan Hohner, Derick Bailey, getify, Daniel Cousineau, Chris Charlton, Eric Turner, David Turner, Joël Galeran, Dharma Vagabond, adam, Dirk van Bergen, dave ♥♫★ furf, Vedran Zakanj, Ryan McAllen, Natalie Patrice Tucker, Eric J. Bivona, Adam Spooner, Aaron Cavano, Kelly Packer, Eric J, Martin Drenovac, Emilis, Michael Pelikan, Scott F. Walter, Josh Freeman, Brandon Hudgeons, vijay chennupati, Bill Glennon, Robin R., Troy Forster, otaku_coder, Brad, Scott, Frederick Ostrander, Adam Brill, Seb Flippence, Michael Anderson, Jacob, Adam Randlett, Standard, Joshua Clanton, Sebastian Kouba, Chris Deck, SwordFire, Hannes Papenberg, Richard Woeber, hnzz, Rob Crowther, Jedidiah Broadbent, Sergey Chernyshev, Jay-Ar Jamon, Ben Combee, luciano bonachela, Mark Tomlinson, Kit Cambridge, Michael Melgares, Jacob Adams, Adrian Bruinhout, Bev Wieber, Scott Puleo, Thomas Herzog, April Leone, Daniel Mizieliński, Kees van Ginkel, Jon Abrams, Erwin Heiser, Avi Laviad, David newell, Jean-Francois Turcot, Niko Roberts, Erik Dana, Charles Neill, Aaron Holmes, Grzegorz Ziółkowski, Nathan Youngman, Timothy, Jacob Mather, Michael Allan, Mohit Seth, Ryan Ewing, Benjamin Van Treese, Marcelo Santos, Denis Wolf, Phil Keys, Chris Yung, Timo Tijhof, Martin Lekvall, Agendine, Greg Whitworth, Helen Humphrey, Dougal Campbell, Johannes Harth, Bruno Girin, Brian Hough, Darren Newton, Craig McPheat, Olivier Tille, Dennis Roethig, Mathias Bynens, Brendan Stromberger, sundeep, John Meyer, Ron Male, John F Croston III, gigante, Carl Bergenhem, B.J. May, Rebekah Tyler, Ted Foxberry, Jordan Reese, Terry Suitor, afeliz, Tom Kiefer, Darragh Duffy, Kevin Vanderbeken, Andy Pearson, Simon Mac Donald, Abid Din, Chris Joel, Tomas Theunissen, David Dick, Paul Grock, Brandon Wood, John Weis, dgrebb, Nick Jenkins, Chuck Lane, Johnny Megahan, marzsman, Tatu Tamminen, Geoffrey Knauth, Alexander Tarmolov, Jeremy Tymes, Chad Auld, Sean Parmelee, Rob Staenke, Dan Bender, Yannick derwa, Joshua Jones, Geert Plaisier, Tom LeZotte, Christen Simpson, Stefan Bruvik, Justin Falcone, Carlos Santana, Michael Weiss, Pablo Villoslada, Peter deHaan, Dimitris Iliopoulos, seyDoggy, Adam Jordens, Noah Kantrowitz, Amol M, Matthew Winnard, Dirk Ginader, Phinam Bui, David Rapson, Andrew Baxter, Florian Bougel, Michael George, Alban Escalier, Daniel Sellers, Sasha Rudan, John Green, Robert Kowalski, David I. Teixeira (@ditma, Charles Carpenter, Justin Yost, Sam S, Denis Ciccale, Kevin Sheurs, Yannick Croissant, Pau Fracés, Stephen McGowan, Shawn Searcy, Chris Ruppel, Kevin Lamping, Jessica Campbell, Christopher Schmitt, Sablons, Jonathan Reisdorf, Bunni Gek, Teddy Huff, Michael Mullany, Michael Fürstenberg, Carl Henderson, Rick Yoesting, Scott Nichols, Hernán Ciudad, Andrew Maier, Mike Stapp, Jesse Shawl, Sérgio Lopes, jsulak, Shawn Price, Joel Clermont, Chris Ridmann, Sean Timm, Jason Finch, Aiden Montgomery, Elijah Manor, Derek Gathright, Jesse Harlin, Dillon Curry, Courtney Myers, Diego Cadenas, Arne de Bree, João Paulo Dubas, James Taylor, Philipp Kraeutli, Mihai Păun, Sam Gharegozlou, joshjs, Matt Murchison, Eric Windham, Timo Behrmann, Andrew Hall, joshua price, Théophile Villard\n\nЭта серия книг выпускается в стиле \"open source\", включая редактирование и выпуск. Мы отдаем дань благодарности GitHub за предоставление такой возможности для сообщества!\n\nЕще раз спасибо всех бесчисленным людям, которых я не перечислил по имени, но кого я тем не менее должен поблагодарить. Пусть эта серия книг будет \"принадлежать\" всем нам и служить вкладом в увеличение информированности и понимании языка JavaScript, на благо все нынешних и будущих вкладчиков в общее дело сообщества.\n"
  },
  {
    "path": "es6 & beyond/ch1.md",
    "content": "# Вы не знаете JS: ES6 и не только\n# Глава 1: ES: современность и будущее\n\nДля чтения этой книги вы должны хорошо владеть языком JavaScript вплоть до последнего (на момент написания книги) стандарта, который называется ES5 (точнее, ES5.1), поскольку мы с вами будем рассматривать новый стандарт ES6, попутно пытаясь понять, какие перспективы ждут JS.\n\nЕсли вы не очень уверены в своих знаниях JavaScript, рекомендую предварительно ознакомиться с предшествующими книгами серии You Don’t Know JS.\n\n* *Up & Going*: Вы только начинаете изучать программирование и JS? Перед вами карта, которая поможет вам в путешествии по новой области знаний.\n* *Scope & Closures*: Известно ли вам, что в основе лексического контекста JS лежит семантика компилятора (а не интерпретатора)? Можете ли вы объяснить, каким образом замыкания являются прямым результатом лексической области видимости и функций как значений?\n* *this & Object Prototypes*: Можете ли вы назвать четыре варианта значения ключевого слова this в зависимости от контекста вызова? Приходилось ли вам путаться в псевдоклассах JS, вместо того чтобы воспользоваться более простым шаблоном проектирования behavior delegation? А слышали ли вы когда-нибудь про объекты, связанные с другими объектами (OLOO)?\n* *Types & Grammar*: Знакомы ли вы со встроенными типами в JS и, что более важно, знаете ли способы корректного и безопасного приведения типов? Насколько уверенно вы разбираетесь в нюансах грамматики и синтаксиса этого языка?\n* *Async & Performance*: Вы все еще используете обратные вызовы для управления асинхронными действиями? А можете ли вы объяснить, что такое объект promise и как он позволяет избежать ситуации, когда каждая фоновая операция возвращает свой результат (или ошибку) в обратном вызове? Знаете ли вы, как с помощью генераторов улучшить читабельность асинхронного кода? Наконец, известно ли вам, что представляет собой полноценная оптимизация JS-программи отдельных операций?\n\nЕсли вы уже прочитали все эти книги и освоили рассматриваемые там темы, значит, пришло время погрузиться в эволюцию языка JS и исследовать перемены, которые ждут нас как в ближайшее время, так и в отдаленной перспективе.\n\nВ отличие от предыдущего стандарта, ES6 нельзя назвать еще одним скромным набором добавленных к языку API. Он принес с собой\nмножество новых синтаксических форм, и к некоторым из них, вполне возможно, будет не так-то просто привыкнуть. Появились также новые структуры и новые вспомогательные модули API для различных типов данных.\n\nES6 — это шаг далеко вперед. Даже если вы считаете, что хорошо знаете JS стандарта ES5, вы столкнетесь с множеством незнакомых\nвещей, так что будьте готовы! В книге рассмотрены все основные нововведения ES6, без которых невозможно войти в курс дела, а также дан краткий обзор планируемых функций — о них имеет смысл знать уже сейчас.\n\n**Внимание:** Весь приведенный в книге код рассчитан на среду исполнения ES6+. На момент написания этих строк уровень поддержки ES6 в браузерах и в JS-средах (таких, как Node.js) несколько разнился, так что вы можете обнаружить, что полученный вами результат отличается от описанного..\n\n## Поддержка версий\n\nСтандарт JavaScript официально называется ECMAScript (или сокращенно ES), и до недавнего времени все его версии обозначались только целыми числами. ES1 и ES2 не получили известности и массовой реализации. Первой широко распространившейся основой для JavaScript стал ES3 — стандарт этого языка для браузеров Internet Explorer с 6-й по 8-ю версию и для мобильных браузеров Android 2.x. По политическим причинам, о которых я умолчу, злополучная версия ES4 так и не увидела света.\n\nВ 2009 году был официально завершен ES5 (ES5.1 появился в 2011-м), получивший распространение в качестве стандарта для множества современных браузеров, таких как Firefox, Chrome, Opera, Safari и др.\n\nСледующая версия JS (появление которой было перенесено с 2013-го сначала на 2014-й, а затем на 2015 год) в обсуждениях\nфигурировала под очевидным именем ES6. Но позднее стали поступать предложения перейти к схеме именования, основанной на годе выхода очередной версии, например ES2016 (она же ES7), которая будет закончена до конца 2016 года. Согласны с таким подходом далеко не все, но есть вероятность, что стандарт ES6 станет известен пользователям под названием ES2015. А появление версии ES2016 станет свидетельством окончательного перехода на\nновую схему именования.\n\nКроме того, было отмечено, что скорость эволюции JS превышает одну версию в год. Как только в обсуждениях стандарта возникает новая идея, разработчики браузеров предлагают прототипы нового функционала, а программисты-первопроходцы принимаются экспериментировать с кодом.\n\nОбычно задолго до официального одобрения новый функционал становится стандартом де-факто благодаря ранним прототипам движка и инструментария. Соответственно, имеет смысл рассматривать будущие версии JS как связанные с появлением нового функционала, а не с произвольным набором основных особенностей (как делается сейчас) или с годом (как планируется).\n\nВ этом случае номер версии перестает иметь ту важность, которой обладал раньше, а JavaScript превращается в живой, постоянно\nменяющийся стандарт. И лучше не говорить о коде как о «написанном в соответствии с таким-то стандартом», а рассматривать его в зависимости от поддерживаемых функциональных особенностей.\n\n## Транскомпиляция\n\nБыстрая эволюция функционала ставит серьезную проблему перед разработчиками, желающими использовать новые возможности в ситуации, когда их сайты или приложения работают в более старых браузерах, не поддерживающих нововведения.\n\nПо всей видимости, ES5 не прижился во многих местах, потому что в основном базу кода не приводили в соответствие с новым стандартом до тех пор, пока не прекратилась поддержка большинства, если не всех, предшествующих платформ. В результате многие разработчики только недавно начали пользоваться такими вещами, как, к примеру, строгий режим, появившийся в ES5 более пяти лет назад.\n\nПодобные многолетние промедления повсеместно считаются вредными для будущего экосистемы JS. Люди, занимающиеся развитием языка, мечтают, чтобы разработчики начинали создавать код с учетом новых функциональных особенностей и шаблонов, сразу же после того, как будет утверждена спецификация, и браузеры смогут все это реализовывать.\n\nКак же разрешить противоречие? Здесь на помощь приходят специальные инструменты, в частности техника транскомпиляции. Грубо говоря, вы посредством специального инструмента преобразуете код ES6 в эквивалент (или нечто близкое к таковому), работающий в окружениях ES5.\n\nВ качестве примера возьмем сокращенные определения свойства (см. раздел «Расширения объектных литералов» в главе 2). Вот как это делается в ES6:\n\n```js\nvar foo = [1,2,3];\n\nvar obj = {\n\tfoo\t\t// означает `foo: foo`\n};\n\nobj.foo;\t// [1,2,3]\n```\n\nА вот каким образом (примерно) он транскомпилируется:\n\n```js\nvar foo = [1,2,3];\n\nvar obj = {\n\tfoo: foo\n};\n\nobj.foo;\t// [1,2,3]\n```\n\nТакое небольшое, но удобное преобразование позволяет в случае одинаковых имен сократить объявление объектного литерала foo: foo до foo. Действия транскомпилятора в этом случае представляют собой встроенный рабочий процесс, аналогичный линтингу, минификации и другим подобным операциям.\n\n### Библиотеки Shim (полизаполнения)\n\nДалеко не всем новым функциональным особенностям ES6 требуется транскомпилятор. Полизаполнения (polyfills), которые также называют библиотеками Shim, представляют собой шаблоны для определения поведений из новой среды для более старых сред. В синтаксисе полизаполнения недопустимы, но для различных API их вполне можно использовать.\n\nДавайте рассмотрим новый метод `Object.is(..)`, предназначенный для проверки строгой эквивалентности двух значений, но без подробных исключений, которые есть у оператора `===` для значений `NaN и -0`. Полизаполнение для метода `Object.is(..)` создается очень\nпросто:\n\n```js\nif (!Object.is) {\n\tObject.is = function(v1, v2) {\n\t\t// проверка для значения `-0`\n\t\tif (v1 === 0 && v2 === 0) {\n\t\t\treturn 1 / v1 === 1 / v2;\n\t\t}\n\t\t// проверка для значения `NaN`\n\t\tif (v1 !== v1) {\n\t\t\treturn v2 !== v2;\n\t\t}\n\t\t// все остальное\n\t\treturn v1 === v2;\n\t};\n}\n```\n\n**Tip:** Обратите внимание на внешнее граничное условие оператора `if`, охватывающее полизаполнение. Это важная деталь, означающая, что резервное поведение данный фрагмент кода включает только в более старых контекстах, где рассматриваемый API еще не определен; необходимости переписывать существующий API практически никогда не возникает.\n\nЕсть замечательная коллекция ES6 Shim (https://github.com/paulmillr/es6-shim/), которую стоит включать во все новые JS-проекты.\n\nПредполагается, что JS ждет непрерывное развитие и что поддержка в браузерах новых функций будет реализовываться постепенно по мере их появления, а не большими фрагментами. Так что самая лучшая стратегия сохранения актуальности — это добавление в базу кода полизаполнений, включение транскомпиляции в процесс сборки и постоянная готовность самого разработчика к изменениям.\n\nТе же, кто мыслит консервативно и откладывает использование нового функционала, пока не исчезнут все работающие без него браузеры, всегда будут плестись далеко позади. Их обойдут стороной все инновации, позволяющие сделать написание кода на JavaScript более результативным, рациональным и надежным.\n\n## Подводим итоги\n\nНа момент написания книги стандарт ES6 (кто-то называет его ES2015) только появился, поэтому вам предстоит многому научиться.\n\nОднако куда важнее перестроить свое мировоззрение в соответствии с новым вариантом развития языка JavaScript. Обыкновение годами ждать официальных документов, одобряющих смену стандарта, должно остаться в прошлом.\n\nТеперь новые функциональные особенности JavaScript сразу же после своего появления реализуются в браузерах, и только от вас\nзависит, начнете вы пользоваться ими немедленно или же продолжите действовать неэффективно в попытках запрыгнуть в уходящий поезд.\n\nНеважно, какие еще формы примет JavaScript, — теперь это будет происходить быстрее, чем когда-либо в прошлом. Транскомпиляторы и полизаполнения — вот инструменты, которые позволят вам все время оставаться на переднем крае развития языка. Вы должны принять новую реальность JavaScript, где разработчикам настоятельно рекомендуется перейти от выжидания к активной позиции. А начнется все с изучения ES6.\n"
  },
  {
    "path": "es6 & beyond/ch2.md",
    "content": "# You Don't Know JS: ES6 & Beyond\n# Chapter 2: Syntax\n\nIf you've been writing JS for any length of time, odds are the syntax is pretty familiar to you. There are certainly many quirks, but overall it's a fairly reasonable and straightforward syntax that draws many similarities from other languages.\n\nHowever, ES6 adds quite a few new syntactic forms that take some getting used to. In this chapter, we'll tour through them to find out what's in store.\n\n**Tip:** At the time of this writing, some of the features discussed in this book have been implemented in various browsers (Firefox, Chrome, etc.), but some have only been partially implemented and many others have not been implemented at all. Your experience may be mixed trying these examples directly. If so, try them out with transpilers, as most of these features are covered by those tools. ES6Fiddle (http://www.es6fiddle.net/) is a great, easy-to-use playground for trying out ES6, as is the online REPL for the Babel transpiler (http://babeljs.io/repl/).\n\n## Block-Scoped Declarations\n\nYou're probably aware that the fundamental unit of variable scoping in JavaScript has always been the `function`. If you needed to create a block of scope, the most prevalent way to do so other than a regular function declaration was the immediately invoked function expression (IIFE). For example:\n\n```js\nvar a = 2;\n\n(function IIFE(){\n\tvar a = 3;\n\tconsole.log( a );\t// 3\n})();\n\nconsole.log( a );\t\t// 2\n```\n\n### `let` Declarations\n\nHowever, we can now create declarations that are bound to any block, called (unsurprisingly) *block scoping*. This means all we need is a pair of `{ .. }` to create a scope. Instead of using `var`, which always declares variables attached to the enclosing function (or global, if top level) scope, use `let`:\n\n```js\nvar a = 2;\n\n{\n\tlet a = 3;\n\tconsole.log( a );\t// 3\n}\n\nconsole.log( a );\t\t// 2\n```\n\nIt's not very common or idiomatic thus far in JS to use a standalone `{ .. }` block, but it's always been valid. And developers from other languages that have *block scoping* will readily recognize that pattern.\n\nI believe this is the best way to create block-scoped variables, with a dedicated `{ .. }` block. Moreover, you should always put the `let` declaration(s) at the very top of that block. If you have more than one to declare, I'd recommend using just one `let`.\n\nStylistically, I even prefer to put the `let` on the same line as the opening `{`, to make it clearer that this block is only for the purpose of declaring the scope for those variables.\n\n```js\n{\tlet a = 2, b, c;\n\t// ..\n}\n```\n\nNow, that's going to look strange and it's not likely going to match the recommendations given in most other ES6 literature. But I have reasons for my madness.\n\nThere's another experimental (not standardized) form of the `let` declaration called the `let`-block, which looks like:\n\n```js\nlet (a = 2, b, c) {\n\t// ..\n}\n```\n\nThat form is what I call *explicit* block scoping, whereas the `let ..` declaration form that mirrors `var` is more *implicit*, as it kind of hijacks whatever `{ .. }` pair it's found in. Generally developers find *explicit* mechanisms a bit more preferable than *implicit* mechanisms, and I claim this is one of those cases.\n\nIf you compare the previous two snippet forms, they're very similar, and in my opinion both qualify stylistically as *explicit* block scoping. Unfortunately, the `let (..) { .. }` form, the most *explicit* of the options, was not adopted in ES6. That may be revisited post-ES6, but for now the former option is our best bet, I think.\n\nTo reinforce the *implicit* nature of `let ..` declarations, consider these usages:\n\n```js\nlet a = 2;\n\nif (a > 1) {\n\tlet b = a * 3;\n\tconsole.log( b );\t\t// 6\n\n\tfor (let i = a; i <= b; i++) {\n\t\tlet j = i + 10;\n\t\tconsole.log( j );\n\t}\n\t// 12 13 14 15 16\n\n\tlet c = a + b;\n\tconsole.log( c );\t\t// 8\n}\n```\n\nQuick quiz without looking back at that snippet: which variable(s) exist only inside the `if` statement, and which variable(s) exist only inside the `for` loop?\n\nThe answers: the `if` statement contains `b` and `c` block-scoped variables, and the `for` loop contains `i` and `j` block-scoped variables.\n\nDid you have to think about it for a moment? Does it surprise you that `i` isn't added to the enclosing `if` statement scope? That mental pause and questioning -- I call it a \"mental tax\" -- comes from the fact that this `let` mechanism is not only new to us, but it's also *implicit*.\n\nThere's also hazard in the `let c = ..` declaration appearing so far down in the scope. Unlike traditional `var`-declared variables, which are attached to the entire enclosing function scope regardless of where they appear, `let` declarations attach to the block scope but are not initialized until they appear in the block.\n\nAccessing a `let`-declared variable earlier than its `let ..` declaration/initialization causes an error, whereas with `var` declarations the ordering doesn't matter (except stylistically).\n\nConsider:\n\n```js\n{\n\tconsole.log( a );\t// undefined\n\tconsole.log( b );\t// ReferenceError!\n\n\tvar a;\n\tlet b;\n}\n```\n\n**Warning:** This `ReferenceError` from accessing too-early `let`-declared references is technically called a *Temporal Dead Zone (TDZ)* error -- you're accessing a variable that's been declared but not yet initialized. This will not be the only time we see TDZ errors -- they crop up in several places in ES6. Also, note that \"initialized\" doesn't require explicitly assigning a value in your code, as `let b;` is totally valid. A variable that's not given an assignment at declaration time is assumed to have been assigned the `undefined` value, so `let b;` is the same as `let b = undefined;`. Explicit assignment or not, you cannot access `b` until the `let b` statement is run.\n\nOne last gotcha: `typeof` behaves differently with TDZ variables than it does with undeclared (or declared!) variables. For example:\n\n```js\n{\n\t// `a` is not declared\n\tif (typeof a === \"undefined\") {\n\t\tconsole.log( \"cool\" );\n\t}\n\n\t// `b` is declared, but in its TDZ\n\tif (typeof b === \"undefined\") {\t\t// ReferenceError!\n\t\t// ..\n\t}\n\n\t// ..\n\n\tlet b;\n}\n```\n\nThe `a` is not declared, so `typeof` is the only safe way to check for its existence or not. But `typeof b` throws the TDZ error because farther down in the code there happens to be a `let b` declaration. Oops.\n\nNow it should be clearer why I insist that `let` declarations should all be at the top of their scope. That totally avoids the accidental errors of accessing too early. It also makes it more *explicit* when you look at the start of a block, any block, what variables it contains.\n\nYour blocks (`if` statements, `while` loops, etc.) don't have to share their original behavior with scoping behavior.\n\nThis explicitness on your part, which is up to you to maintain with discipline, will save you lots of refactor headaches and footguns down the line.\n\n**Note:** For more information on `let` and block scoping, see Chapter 3 of the *Scope & Closures* title of this series.\n\n#### `let` + `for`\n\nThe only exception I'd make to the preference for the *explicit* form of `let` declaration blocking is a `let` that appears in the header of a `for` loop. The reason may seem nuanced, but I believe it to be one of the more important ES6 features.\n\nConsider:\n\n```js\nvar funcs = [];\n\nfor (let i = 0; i < 5; i++) {\n\tfuncs.push( function(){\n\t\tconsole.log( i );\n\t} );\n}\n\nfuncs[3]();\t\t// 3\n```\n\nThe `let i` in the `for` header declares an `i` not just for the `for` loop itself, but it redeclares a new `i` for each iteration of the loop. That means that closures created inside the loop iteration close over those per-iteration variables the way you'd expect.\n\nIf you tried that same snippet but with `var i` in the `for` loop header, you'd get `5` instead of `3`, because there'd only be one `i` in the outer scope that was closed over, instead of a new `i` for each iteration's function to close over.\n\nYou could also have accomplished the same thing slightly more verbosely:\n\n```js\nvar funcs = [];\n\nfor (var i = 0; i < 5; i++) {\n\tlet j = i;\n\tfuncs.push( function(){\n\t\tconsole.log( j );\n\t} );\n}\n\nfuncs[3]();\t\t// 3\n```\n\nHere, we forcibly create a new `j` for each iteration, and then the closure works the same way. I prefer the former approach; that extra special capability is why I endorse the `for (let .. ) ..` form. It could be argued it's somewhat more *implicit*, but it's *explicit* enough, and useful enough, for my tastes.\n\n`let` also works the same way with `for..in` and `for..of` loops (see \"`for..of` Loops\").\n\n### `const` Declarations\n\nThere's one other form of block-scoped declaration to consider: the `const`, which creates *constants*.\n\nWhat exactly is a constant? It's a variable that's read-only after its initial value is set. Consider:\n\n```js\n{\n\tconst a = 2;\n\tconsole.log( a );\t// 2\n\n\ta = 3;\t\t\t\t// TypeError!\n}\n```\n\nYou are not allowed to change the value the variable holds once it's been set, at declaration time. A `const` declaration must have an explicit initialization. If you wanted a *constant* with the `undefined` value, you'd have to declare `const a = undefined` to get it.\n\nConstants are not a restriction on the value itself, but on the variable's assignment of that value. In other words, the value is not frozen or immutable because of `const`, just the assignment of it. If the value is complex, such as an object or array, the contents of the value can still be modified:\n\n```js\n{\n\tconst a = [1,2,3];\n\ta.push( 4 );\n\tconsole.log( a );\t\t// [1,2,3,4]\n\n\ta = 42;\t\t\t\t\t// TypeError!\n}\n```\n\nThe `a` variable doesn't actually hold a constant array; rather, it holds a constant reference to the array. The array itself is freely mutable.\n\n**Warning:** Assigning an object or array as a constant means that value will not be able to be garbage collected until that constant's lexical scope goes away, as the reference to the value can never be unset. That may be desirable, but be careful if it's not your intent!\n\nEssentially, `const` declarations enforce what we've stylistically signaled with our code for years, where we declared a variable name of all uppercase letters and assigned it some literal value that we took care never to change. There's no enforcement on a `var` assignment, but there is now with a `const` assignment, which can help you catch unintended changes.\n\n`const` *can* be used with variable declarations of `for`, `for..in`, and `for..of` loops (see \"`for..of` Loops\"). However, an error will be thrown if there's any attempt to reassign, such as the typical `i++` clause of a `for` loop.\n\n#### `const` Or Not\n\nThere's some rumored assumptions that a `const` could be more optimizable by the JS engine in certain scenarios than a `let` or `var` would be. Theoretically, the engine more easily knows the variable's value/type will never change, so it can eliminate some possible tracking.\n\nWhether `const` really helps here or this is just our own fantasies and intuitions, the much more important decision to make is if you intend constant behavior or not. Remember: one of the most important roles for source code is to communicate clearly, not only to you, but your future self and other code collaborators, what your intent is.\n\nSome developers prefer to start out every variable declaration as a `const` and then relax a declaration back to a `let` if it becomes necessary for its value to change in the code. This is an interesting perspective, but it's not clear that it genuinely improves the readability or reason-ability of code.\n\nIt's not really a *protection*, as many believe, because any later developer who wants to change a value of a `const` can just blindly change `const` to `let` on the declaration. At best, it protects accidental change. But again, other than our intuitions and sensibilities, there doesn't appear to be objective and clear measure of what constitutes \"accidents\" or prevention thereof. Similar mindsets exist around type enforcement.\n\nMy advice: to avoid potentially confusing code, only use `const` for variables that you're intentionally and obviously signaling will not change. In other words, don't *rely on* `const` for code behavior, but instead use it as a tool for signaling intent, when intent can be signaled clearly.\n\n### Block-scoped Functions\n\nStarting with ES6, function declarations that occur inside of blocks are now specified to be scoped to that block. Prior to ES6, the specification did not call for this, but many implementations did it anyway. So now the specification meets reality.\n\nConsider:\n\n```js\n{\n\tfoo();\t\t\t\t\t// works!\n\n\tfunction foo() {\n\t\t// ..\n\t}\n}\n\nfoo();\t\t\t\t\t\t// ReferenceError\n```\n\nThe `foo()` function is declared inside the `{ .. }` block, and as of ES6 is block-scoped there. So it's not available outside that block. But also note that it is \"hoisted\" within the block, as opposed to `let` declarations, which suffer the TDZ error trap mentioned earlier.\n\nBlock-scoping of function declarations could be a problem if you've ever written code like this before, and relied on the old legacy non-block-scoped behavior:\n\n```js\nif (something) {\n\tfunction foo() {\n\t\tconsole.log( \"1\" );\n\t}\n}\nelse {\n\tfunction foo() {\n\t\tconsole.log( \"2\" );\n\t}\n}\n\nfoo();\t\t// ??\n```\n\nIn pre-ES6 environments, `foo()` would print `\"2\"` regardless of the value of `something`, because both function declarations were hoisted out of the blocks, and the second one always wins.\n\nIn ES6, that last line throws a `ReferenceError`.\n\n## Spread/Rest\n\nES6 introduces a new `...` operator that's typically referred to as the *spread* or *rest* operator, depending on where/how it's used. Let's take a look:\n\n```js\nfunction foo(x,y,z) {\n\tconsole.log( x, y, z );\n}\n\nfoo( ...[1,2,3] );\t\t\t\t// 1 2 3\n```\n\nWhen `...` is used in front of an array (actually, any *iterable*, which we cover in Chapter 3), it acts to \"spread\" it out into its individual values.\n\nYou'll typically see that usage as is shown in that previous snippet, when spreading out an array as a set of arguments to a function call. In this usage, `...` acts to give us a simpler syntactic replacement for the `apply(..)` method, which we would typically have used pre-ES6 as:\n\n```js\nfoo.apply( null, [1,2,3] );\t\t// 1 2 3\n```\n\nBut `...` can be used to spread out/expand a value in other contexts as well, such as inside another array declaration:\n\n```js\nvar a = [2,3,4];\nvar b = [ 1, ...a, 5 ];\n\nconsole.log( b );\t\t\t\t\t// [1,2,3,4,5]\n```\n\nIn this usage, `...` is basically replacing `concat(..)`, as it behaves like `[1].concat( a, [5] )` here.\n\nThe other common usage of `...` can be seen as essentially the opposite; instead of spreading a value out, the `...` *gathers* a set of values together into an array. Consider:\n\n```js\nfunction foo(x, y, ...z) {\n\tconsole.log( x, y, z );\n}\n\nfoo( 1, 2, 3, 4, 5 );\t\t\t// 1 2 [3,4,5]\n```\n\nThe `...z` in this snippet is essentially saying: \"gather the *rest* of the arguments (if any) into an array called `z`.\" Because `x` was assigned `1`, and `y` was assigned `2`, the rest of the arguments `3`, `4`, and `5` were gathered into `z`.\n\nOf course, if you don't have any named parameters, the `...` gathers all arguments:\n\n```js\nfunction foo(...args) {\n\tconsole.log( args );\n}\n\nfoo( 1, 2, 3, 4, 5);\t\t\t// [1,2,3,4,5]\n```\n\n**Note:** The `...args` in the `foo(..)` function declaration is usually called \"rest parameters,\" because you're collecting the rest of the parameters. I prefer \"gather,\" because it's more descriptive of what it does rather than what it contains.\n\nThe best part about this usage is that it provides a very solid alternative to using the long-since-deprecated `arguments` array -- actually, it's not really an array, but an array-like object. Because `args` (or whatever you call it -- a lot of people prefer `r` or `rest`) is a real array, we can get rid of lots of silly pre-ES6 tricks we jumped through to make `arguments` into something we can treat as an array.\n\nConsider:\n\n```js\n// doing things the new ES6 way\nfunction foo(...args) {\n\t// `args` is already a real array\n\n\t// discard first element in `args`\n\targs.shift();\n\n\t// pass along all of `args` as arguments\n\t// to `console.log(..)`\n\tconsole.log( ...args );\n}\n\n// doing things the old-school pre-ES6 way\nfunction bar() {\n\t// turn `arguments` into a real array\n\tvar args = Array.prototype.slice.call( arguments );\n\n\t// add some elements on the end\n\targs.push( 4, 5 );\n\n\t// filter out odd numbers\n\targs = args.filter( function(v){\n\t\treturn v % 2 == 0;\n\t} );\n\n\t// pass along all of `args` as arguments\n\t// to `foo(..)`\n\tfoo.apply( null, args );\n}\n\nbar( 0, 1, 2, 3 );\t\t\t\t\t// 2 4\n```\n\nThe `...args` in the `foo(..)` function declaration gathers arguments, and the `...args` in the `console.log(..)` call spreads them out. That's a good illustration of the symmetric but opposite uses of the `...` operator.\n\nBesides the `...` usage in a function declaration, there's another case where `...` is used for gathering values, and we'll look at it in the \"Too Many, Too Few, Just Enough\" section later in this chapter.\n\n## Default Parameter Values\n\nPerhaps one of the most common idioms in JavaScript relates to setting a default value for a function parameter. The way we've done this for years should look quite familiar:\n\n```js\nfunction foo(x,y) {\n\tx = x || 11;\n\ty = y || 31;\n\n\tconsole.log( x + y );\n}\n\nfoo();\t\t\t\t// 42\nfoo( 5, 6 );\t\t// 11\nfoo( 5 );\t\t\t// 36\nfoo( null, 6 );\t\t// 17\n```\n\nOf course, if you've used this pattern before, you know that it's both helpful and a little bit dangerous, if for example you need to be able to pass in what would otherwise be considered a falsy value for one of the parameters. Consider:\n\n```js\nfoo( 0, 42 );\t\t// 53 <-- Oops, not 42\n```\n\nWhy? Because the `0` is falsy, and so the `x || 11` results in `11`, not the directly passed in `0`.\n\nTo fix this gotcha, some people will instead write the check more verbosely like this:\n\n```js\nfunction foo(x,y) {\n\tx = (x !== undefined) ? x : 11;\n\ty = (y !== undefined) ? y : 31;\n\n\tconsole.log( x + y );\n}\n\nfoo( 0, 42 );\t\t\t// 42\nfoo( undefined, 6 );\t// 17\n```\n\nOf course, that means that any value except `undefined` can be directly passed in. However, `undefined` will be assumed to signal, \"I didn't pass this in.\" That works great unless you actually need to be able to pass `undefined` in.\n\nIn that case, you could test to see if the argument is actually omitted, by it actually not being present in the `arguments` array, perhaps like this:\n\n```js\nfunction foo(x,y) {\n\tx = (0 in arguments) ? x : 11;\n\ty = (1 in arguments) ? y : 31;\n\n\tconsole.log( x + y );\n}\n\nfoo( 5 );\t\t\t\t// 36\nfoo( 5, undefined );\t// NaN\n```\n\nBut how would you omit the first `x` argument without the ability to pass in any kind of value (not even `undefined`) that signals \"I'm omitting this argument\"?\n\n`foo(,5)` is tempting, but it's invalid syntax. `foo.apply(null,[,5])` seems like it should do the trick, but `apply(..)`'s quirks here mean that the arguments are treated as `[undefined,5]`, which of course doesn't omit.\n\nIf you investigate further, you'll find you can only omit arguments on the end (i.e., righthand side) by simply passing fewer arguments than \"expected,\" but you cannot omit arguments in the middle or at the beginning of the arguments list. It's just not possible.\n\nThere's a principle applied to JavaScript's design here that is important to remember: `undefined` means *missing*. That is, there's no difference between `undefined` and *missing*, at least as far as function arguments go.\n\n**Note:** There are, confusingly, other places in JS where this particular design principle doesn't apply, such as for arrays with empty slots. See the *Types & Grammar* title of this series for more information.\n\nWith all this in mind, we can now examine a nice helpful syntax added as of ES6 to streamline the assignment of default values to missing arguments:\n\n```js\nfunction foo(x = 11, y = 31) {\n\tconsole.log( x + y );\n}\n\nfoo();\t\t\t\t\t// 42\nfoo( 5, 6 );\t\t\t// 11\nfoo( 0, 42 );\t\t\t// 42\n\nfoo( 5 );\t\t\t\t// 36\nfoo( 5, undefined );\t// 36 <-- `undefined` is missing\nfoo( 5, null );\t\t\t// 5  <-- null coerces to `0`\n\nfoo( undefined, 6 );\t// 17 <-- `undefined` is missing\nfoo( null, 6 );\t\t\t// 6  <-- null coerces to `0`\n```\n\nNotice the results and how they imply both subtle differences and similarities to the earlier approaches.\n\n`x = 11` in a function declaration is more like `x !== undefined ? x : 11` than the much more common idiom `x || 11`, so you'll need to be careful in converting your pre-ES6 code to this ES6 default parameter value syntax.\n\n**Note:** A rest/gather parameter (see \"Spread/Rest\") cannot have a default value. So, while `function foo(...vals=[1,2,3]) {` might seem an intriguing capability, it's not valid syntax. You'll need to continue to apply that sort of logic manually if necessary.\n\n### Default Value Expressions\n\nFunction default values can be more than just simple values like `31`; they can be any valid expression, even a function call:\n\n```js\nfunction bar(val) {\n\tconsole.log( \"bar called!\" );\n\treturn y + val;\n}\n\nfunction foo(x = y + 3, z = bar( x )) {\n\tconsole.log( x, z );\n}\n\nvar y = 5;\nfoo();\t\t\t\t\t\t\t\t// \"bar called\"\n\t\t\t\t\t\t\t\t\t// 8 13\nfoo( 10 );\t\t\t\t\t\t\t// \"bar called\"\n\t\t\t\t\t\t\t\t\t// 10 15\ny = 6;\nfoo( undefined, 10 );\t\t\t\t// 9 10\n```\n\nAs you can see, the default value expressions are lazily evaluated, meaning they're only run if and when they're needed -- that is, when a parameter's argument is omitted or is `undefined`.\n\nIt's a subtle detail, but the formal parameters in a function declaration are in their own scope (think of it as a scope bubble wrapped around just the `( .. )` of the function declaration), not in the function body's scope. That means a reference to an identifier in a default value expression first matches the formal parameters' scope before looking to an outer scope. See the *Scope & Closures* title of this series for more information.\n\nConsider:\n\n```js\nvar w = 1, z = 2;\n\nfunction foo( x = w + 1, y = x + 1, z = z + 1 ) {\n\tconsole.log( x, y, z );\n}\n\nfoo();\t\t\t\t\t// ReferenceError\n```\n\nThe `w` in the `w + 1` default value expression looks for `w` in the formal parameters' scope, but does not find it, so the outer scope's `w` is used. Next, The `x` in the `x + 1` default value expression finds `x` in the formal parameters' scope, and luckily `x` has already been initialized, so the assignment to `y` works fine.\n\nHowever, the `z` in `z + 1` finds `z` as a not-yet-initialized-at-that-moment parameter variable, so it never tries to find the `z` from the outer scope.\n\nAs we mentioned in the \"`let` Declarations\" section earlier in this chapter, ES6 has a TDZ, which prevents a variable from being accessed in its uninitialized state. As such, the `z + 1` default value expression throws a TDZ `ReferenceError` error.\n\nThough it's not necessarily a good idea for code clarity, a default value expression can even be an inline function expression call -- commonly referred to as an immediately invoked function expression (IIFE):\n\n```js\nfunction foo( x =\n\t(function(v){ return v + 11; })( 31 )\n) {\n\tconsole.log( x );\n}\n\nfoo();\t\t\t// 42\n```\n\nThere will very rarely be any cases where an IIFE (or any other executed inline function expression) will be appropriate for default value expressions. If you find yourself tempted to do this, take a step back and reevaluate!\n\n**Warning:** If the IIFE had tried to access the `x` identifier and had not declared its own `x`, this would also have been a TDZ error, just as discussed before.\n\nThe default value expression in the previous snippet is an IIFE in that in the sense that it's a function that's executed right inline, via `(31)`. If we had left that part off, the default value assigned to `x` would have just been a function reference itself, perhaps like a default callback. There will probably be cases where that pattern will be quite useful, such as:\n\n```js\nfunction ajax(url, cb = function(){}) {\n\t// ..\n}\n\najax( \"http://some.url.1\" );\n```\n\nIn this case, we essentially want to default `cb` to be a no-op empty function call if not otherwise specified. The function expression is just a function reference, not a function call itself (no invoking `()` on the end of it), which accomplishes that goal.\n\nSince the early days of JS, there's been a little-known but useful quirk available to us: `Function.prototype` is itself an empty no-op function. So, the declaration could have been `cb = Function.prototype` and saved the inline function expression creation.\n\n## Destructuring\n\nES6 introduces a new syntactic feature called *destructuring*, which may be a little less confusing if you instead think of it as *structured assignment*. To understand this meaning, consider:\n\n```js\nfunction foo() {\n\treturn [1,2,3];\n}\n\nvar tmp = foo(),\n\ta = tmp[0], b = tmp[1], c = tmp[2];\n\nconsole.log( a, b, c );\t\t\t\t// 1 2 3\n```\n\nAs you can see, we created a manual assignment of the values in the array that `foo()` returns to individual variables `a`, `b`, and `c`, and to do so we (unfortunately) needed the `tmp` variable.\n\nSimilarly, we can do the following with objects:\n\n```js\nfunction bar() {\n\treturn {\n\t\tx: 4,\n\t\ty: 5,\n\t\tz: 6\n\t};\n}\n\nvar tmp = bar(),\n\tx = tmp.x, y = tmp.y, z = tmp.z;\n\nconsole.log( x, y, z );\t\t\t\t// 4 5 6\n```\n\nThe `tmp.x` property value is assigned to the `x` variable, and likewise for `tmp.y` to `y` and `tmp.z` to `z`.\n\nManually assigning indexed values from an array or properties from an object can be thought of as *structured assignment*. ES6 adds a dedicated syntax for *destructuring*, specifically *array destructuring* and *object destructuring*. This syntax eliminates the need for the `tmp` variable in the previous snippets, making them much cleaner. Consider:\n\n```js\nvar [ a, b, c ] = foo();\nvar { x: x, y: y, z: z } = bar();\n\nconsole.log( a, b, c );\t\t\t\t// 1 2 3\nconsole.log( x, y, z );\t\t\t\t// 4 5 6\n```\n\nYou're likely more accustomed to seeing syntax like `[a,b,c]` on the righthand side of an `=` assignment, as the value being assigned.\n\nDestructuring symmetrically flips that pattern, so that `[a,b,c]` on the lefthand side of the `=` assignment is treated as a kind of \"pattern\" for decomposing the righthand side array value into separate variable assignments.\n\nSimilarly, `{ x: x, y: y, z: z }` specifies a \"pattern\" to decompose the object value from `bar()` into separate variable assignments.\n\n### Object Property Assignment Pattern\n\nLet's dig into that `{ x: x, .. }` syntax from the previous snippet. If the property name being matched is the same as the variable you want to declare, you can actually shorten the syntax:\n\n```js\nvar { x, y, z } = bar();\n\nconsole.log( x, y, z );\t\t\t\t// 4 5 6\n```\n\nPretty cool, right?\n\nBut is `{ x, .. }` leaving off the `x: ` part or leaving off the `: x` part? We're actually leaving off the `x: ` part when we use the shorter syntax. That may not seem like an important detail, but you'll understand its importance in just a moment.\n\nIf you can write the shorter form, why would you ever write out the longer form? Because that longer form actually allows you to assign a property to a different variable name, which can sometimes be quite useful:\n\n```js\nvar { x: bam, y: baz, z: bap } = bar();\n\nconsole.log( bam, baz, bap );\t\t// 4 5 6\nconsole.log( x, y, z );\t\t\t\t// ReferenceError\n```\n\nThere's a subtle but super-important quirk to understand about this variation of the object destructuring form. To illustrate why it can be a gotcha you need to be careful of, let's consider the \"pattern\" of how normal object literals are specified:\n\n```js\nvar X = 10, Y = 20;\n\nvar o = { a: X, b: Y };\n\nconsole.log( o.a, o.b );\t\t\t// 10 20\n```\n\nIn `{ a: X, b: Y }`, we know that `a` is the object property, and `X` is the source value that gets assigned to it. In other words, the syntactic pattern is `target: source`, or more obviously, `property-alias: value`. We intuitively understand this because it's the same as `=` assignment, where the pattern is `target = source`.\n\nHowever, when you use object destructuring assignment -- that is, putting the `{ .. }` object literal-looking syntax on the lefthand side of the `=` operator -- you invert that `target: source` pattern.\n\nRecall:\n\n```js\nvar { x: bam, y: baz, z: bap } = bar();\n```\n\nThe syntactic pattern here is `source: target` (or `value: variable-alias`). `x: bam` means the `x` property is the source value and `bam` is the target variable to assign to. In other words, object literals are `target <-- source`, and object destructuring assignments are `source --> target`. See how that's flipped?\n\nThere's another way to think about this syntax though, which may help ease the confusion. Consider:\n\n```js\nvar aa = 10, bb = 20;\n\nvar o = { x: aa, y: bb };\nvar     { x: AA, y: BB } = o;\n\nconsole.log( AA, BB );\t\t\t\t// 10 20\n```\n\nIn the `{ x: aa, y: bb }` line, the `x` and `y` represent the object properties. In the `{ x: AA, y: BB }` line, the `x` and the `y` *also* represent the object properties.\n\nRecall how earlier I asserted that `{ x, .. }` was leaving off the `x: ` part? In those two lines, if you erase the `x: ` and `y: ` parts in that snippet, you're left only with `aa, bb` and `AA, BB`, which in effect -- only conceptually, not actually -- are assignments from `aa` to `AA` and from `bb` to `BB`.\n\nSo, that symmetry may help to explain why the syntactic pattern was intentionally flipped for this ES6 feature.\n\n**Note:** I would have preferred the syntax to be `{ AA: x , BB: y }` for the destructuring assignment, as that would have preserved consistency of the more familiar `target: source` pattern for both usages. Alas, I'm having to train my brain for the inversion, as some readers may also have to do.\n\n### Not Just Declarations\n\nSo far, we've used destructuring assignment with `var` declarations (of course, they could also use `let` and `const`), but destructuring is a general assignment operation, not just a declaration.\n\nConsider:\n\n```js\nvar a, b, c, x, y, z;\n\n[a,b,c] = foo();\n( { x, y, z } = bar() );\n\nconsole.log( a, b, c );\t\t\t\t// 1 2 3\nconsole.log( x, y, z );\t\t\t\t// 4 5 6\n```\n\nThe variables can already be declared, and then the destructuring only does assignments, exactly as we've already seen.\n\n**Note:** For the object destructuring form specifically, when leaving off a `var`/`let`/`const` declarator, we had to surround the whole assignment expression in `( )`, because otherwise the `{ .. }` on the lefthand side as the first element in the statement is taken to be a block statement instead of an object.\n\nIn fact, the assignment expressions (`a`, `y`, etc.) don't actually need to be just variable identifiers. Anything that's a valid assignment expression is allowed. For example:\n\n```js\nvar o = {};\n\n[o.a, o.b, o.c] = foo();\n( { x: o.x, y: o.y, z: o.z } = bar() );\n\nconsole.log( o.a, o.b, o.c );\t\t// 1 2 3\nconsole.log( o.x, o.y, o.z );\t\t// 4 5 6\n```\n\nYou can even use computed property expressions in the destructuring. Consider:\n\n```js\nvar which = \"x\",\n\to = {};\n\n( { [which]: o[which] } = bar() );\n\nconsole.log( o.x );\t\t\t\t\t// 4\n```\n\nThe `[which]:` part is the computed property, which results in `x` -- the property to destructure from the object in question as the source of the assignment. The `o[which]` part is just a normal object key reference, which equates to `o.x` as the target of the assignment.\n\nYou can use the general assignments to create object mappings/transformations, such as:\n\n```js\nvar o1 = { a: 1, b: 2, c: 3 },\n\to2 = {};\n\n( { a: o2.x, b: o2.y, c: o2.z } = o1 );\n\nconsole.log( o2.x, o2.y, o2.z );\t// 1 2 3\n```\n\nOr you can map an object to an array, such as:\n\n```js\nvar o1 = { a: 1, b: 2, c: 3 },\n\ta2 = [];\n\n( { a: a2[0], b: a2[1], c: a2[2] } = o1 );\n\nconsole.log( a2 );\t\t\t\t\t// [1,2,3]\n```\n\nOr the other way around:\n\n```js\nvar a1 = [ 1, 2, 3 ],\n\to2 = {};\n\n[ o2.a, o2.b, o2.c ] = a1;\n\nconsole.log( o2.a, o2.b, o2.c );\t// 1 2 3\n```\n\nOr you could reorder one array to another:\n\n```js\nvar a1 = [ 1, 2, 3 ],\n\ta2 = [];\n\n[ a2[2], a2[0], a2[1] ] = a1;\n\nconsole.log( a2 );\t\t\t\t\t// [2,3,1]\n```\n\nYou can even solve the traditional \"swap two variables\" task without a temporary variable:\n\n```js\nvar x = 10, y = 20;\n\n[ y, x ] = [ x, y ];\n\nconsole.log( x, y );\t\t\t\t// 20 10\n```\n\n**Warning:** Be careful: you shouldn't mix in declaration with assignment unless you want all of the assignment expressions *also* to be treated as declarations. Otherwise, you'll get syntax errors. That's why in the earlier example I had to do `var a2 = []` separately from the `[ a2[0], .. ] = ..` destructuring assignment. It wouldn't make any sense to try `var [ a2[0], .. ] = ..`, because `a2[0]` isn't a valid declaration identifier; it also obviously couldn't implicitly create a `var a2 = []` declaration to use.\n\n### Repeated Assignments\n\nThe object destructuring form allows a source property (holding any value type) to be listed multiple times. For example:\n\n```js\nvar { a: X, a: Y } = { a: 1 };\n\nX;\t// 1\nY;\t// 1\n```\n\nThat also means you can both destructure a sub-object/array property and also capture the sub-object/array's value itself. Consider:\n\n```js\nvar { a: { x: X, x: Y }, a } = { a: { x: 1 } };\n\nX;\t// 1\nY;\t// 1\na;\t// { x: 1 }\n\n( { a: X, a: Y, a: [ Z ] } = { a: [ 1 ] } );\n\nX.push( 2 );\nY[0] = 10;\n\nX;\t// [10,2]\nY;\t// [10,2]\nZ;\t// 1\n```\n\nA word of caution about destructuring: it may be tempting to list destructuring assignments all on a single line as has been done thus far in our discussion. However, it's a much better idea to spread destructuring assignment patterns over multiple lines, using proper indentation -- much like you would in JSON or with an object literal value -- for readability sake.\n\n```js\n// harder to read:\nvar { a: { b: [ c, d ], e: { f } }, g } = obj;\n\n// better:\nvar {\n\ta: {\n\t\tb: [ c, d ],\n\t\te: { f }\n\t},\n\tg\n} = obj;\n```\n\nRemember: **the purpose of destructuring is not just less typing, but more declarative readability.**\n\n#### Destructuring Assignment Expressions\n\nThe assignment expression with object or array destructuring has as its completion value the full righthand object/array value. Consider:\n\n```js\nvar o = { a:1, b:2, c:3 },\n\ta, b, c, p;\n\np = { a, b, c } = o;\n\nconsole.log( a, b, c );\t\t\t// 1 2 3\np === o;\t\t\t\t\t\t// true\n```\n\nIn the previous snippet, `p` was assigned the `o` object reference, not one of the `a`, `b`, or `c` values. The same is true of array destructuring:\n\n```js\nvar o = [1,2,3],\n\ta, b, c, p;\n\np = [ a, b, c ] = o;\n\nconsole.log( a, b, c );\t\t\t// 1 2 3\np === o;\t\t\t\t\t\t// true\n```\n\nBy carrying the object/array value through as the completion, you can chain destructuring assignment expressions together:\n\n```js\nvar o = { a:1, b:2, c:3 },\n\tp = [4,5,6],\n\ta, b, c, x, y, z;\n\n( {a} = {b,c} = o );\n[x,y] = [z] = p;\n\nconsole.log( a, b, c );\t\t\t// 1 2 3\nconsole.log( x, y, z );\t\t\t// 4 5 4\n```\n\n### Too Many, Too Few, Just Enough\n\nWith both array destructuring assignment and object destructuring assignment, you do not have to assign all the values that are present. For example:\n\n```js\nvar [,b] = foo();\nvar { x, z } = bar();\n\nconsole.log( b, x, z );\t\t\t\t// 2 4 6\n```\n\nThe `1` and `3` values that came back from `foo()` are discarded, as is the `5` value from `bar()`.\n\nSimilarly, if you try to assign more values than are present in the value you're destructuring/decomposing, you get graceful fallback to `undefined`, as you'd expect:\n\n```js\nvar [,,c,d] = foo();\nvar { w, z } = bar();\n\nconsole.log( c, z );\t\t\t\t// 3 6\nconsole.log( d, w );\t\t\t\t// undefined undefined\n```\n\nThis behavior follows symmetrically from the earlier stated \"`undefined` is missing\" principle.\n\nWe examined the `...` operator earlier in this chapter, and saw that it can sometimes be used to spread an array value out into its separate values, and sometimes it can be used to do the opposite: to gather a set of values together into an array.\n\nIn addition to the gather/rest usage in function declarations, `...` can perform the same behavior in destructuring assignments. To illustrate, let's recall a snippet from earlier in this chapter:\n\n```js\nvar a = [2,3,4];\nvar b = [ 1, ...a, 5 ];\n\nconsole.log( b );\t\t\t\t\t// [1,2,3,4,5]\n```\n\nHere we see that `...a` is spreading `a` out, because it appears in the array `[ .. ]` value position. If `...a` appears in an array destructuring position, it performs the gather behavior:\n\n```js\nvar a = [2,3,4];\nvar [ b, ...c ] = a;\n\nconsole.log( b, c );\t\t\t\t// 2 [3,4]\n```\n\nThe `var [ .. ] = a` destructuring assignment spreads `a` out to be assigned to the pattern described inside the `[ .. ]`. The first part names `b` for the first value in `a` (`2`). But then `...c` gathers the rest of the values (`3` and `4`) into an array and calls it `c`.\n\n**Note:** We've seen how `...` works with arrays, but what about with objects? It's not an ES6 feature, but see Chapter 8 for discussion of a possible \"beyond ES6\" feature where `...` works with spreading or gathering objects.\n\n### Default Value Assignment\n\nBoth forms of destructuring can offer a default value option for an assignment, using the `=` syntax similar to the default function argument values discussed earlier.\n\nConsider:\n\n```js\nvar [ a = 3, b = 6, c = 9, d = 12 ] = foo();\nvar { x = 5, y = 10, z = 15, w = 20 } = bar();\n\nconsole.log( a, b, c, d );\t\t\t// 1 2 3 12\nconsole.log( x, y, z, w );\t\t\t// 4 5 6 20\n```\n\nYou can combine the default value assignment with the alternative assignment expression syntax covered earlier. For example:\n\n```js\nvar { x, y, z, w: WW = 20 } = bar();\n\nconsole.log( x, y, z, WW );\t\t\t// 4 5 6 20\n```\n\nBe careful about confusing yourself (or other developers who read your code) if you use an object or array as the default value in a destructuring. You can create some really hard to understand code:\n\n```js\nvar x = 200, y = 300, z = 100;\nvar o1 = { x: { y: 42 }, z: { y: z } };\n\n( { y: x = { y: y } } = o1 );\n( { z: y = { y: z } } = o1 );\n( { x: z = { y: x } } = o1 );\n```\n\nCan you tell from that snippet what values `x`, `y`, and `z` have at the end? Takes a moment of pondering, I would imagine. I'll end the suspense:\n\n```js\nconsole.log( x.y, y.y, z.y );\t\t// 300 100 42\n```\n\nThe takeaway here: destructuring is great and can be very useful, but it's also a sharp sword that can cause injury (to someone's brain) if used unwisely.\n\n### Nested Destructuring\n\nIf the values you're destructuring have nested objects or arrays, you can destructure those nested values as well:\n\n```js\nvar a1 = [ 1, [2, 3, 4], 5 ];\nvar o1 = { x: { y: { z: 6 } } };\n\nvar [ a, [ b, c, d ], e ] = a1;\nvar { x: { y: { z: w } } } = o1;\n\nconsole.log( a, b, c, d, e );\t\t// 1 2 3 4 5\nconsole.log( w );\t\t\t\t\t// 6\n```\n\nNested destructuring can be a simple way to flatten out object namespaces. For example:\n\n```js\nvar App = {\n\tmodel: {\n\t\tUser: function(){ .. }\n\t}\n};\n\n// instead of:\n// var User = App.model.User;\n\nvar { model: { User } } = App;\n```\n\n### Destructuring Parameters\n\nIn the following snippet, can you spot the assignment?\n\n```js\nfunction foo(x) {\n\tconsole.log( x );\n}\n\nfoo( 42 );\n```\n\nThe assignment is kinda hidden: `42` (the argument) is assigned to `x` (the parameter) when `foo(42)` is executed. If parameter/argument pairing is an assignment, then it stands to reason that it's an assignment that could be destructured, right? Of course!\n\nConsider array destructuring for parameters:\n\n```js\nfunction foo( [ x, y ] ) {\n\tconsole.log( x, y );\n}\n\nfoo( [ 1, 2 ] );\t\t\t\t\t// 1 2\nfoo( [ 1 ] );\t\t\t\t\t\t// 1 undefined\nfoo( [] );\t\t\t\t\t\t\t// undefined undefined\n```\n\nObject destructuring for parameters works, too:\n\n```js\nfunction foo( { x, y } ) {\n\tconsole.log( x, y );\n}\n\nfoo( { y: 1, x: 2 } );\t\t\t\t// 2 1\nfoo( { y: 42 } );\t\t\t\t\t// undefined 42\nfoo( {} );\t\t\t\t\t\t\t// undefined undefined\n```\n\nThis technique is an approximation of named arguments (a long requested feature for JS!), in that the properties on the object map to the destructured parameters of the same names. That also means that we get optional parameters (in any position) for free, as you can see leaving off the `x` \"parameter\" worked as we'd expect.\n\nOf course, all the previously discussed variations of destructuring are available to us with parameter destructuring, including nested destructuring, default values, and more. Destructuring also mixes fine with other ES6 function parameter capabilities, like default parameter values and rest/gather parameters.\n\nConsider these quick illustrations (certainly not exhaustive of the possible variations):\n\n```js\nfunction f1([ x=2, y=3, z ]) { .. }\nfunction f2([ x, y, ...z], w) { .. }\nfunction f3([ x, y, ...z], ...w) { .. }\n\nfunction f4({ x: X, y }) { .. }\nfunction f5({ x: X = 10, y = 20 }) { .. }\nfunction f6({ x = 10 } = {}, { y } = { y: 10 }) { .. }\n```\n\nLet's take one example from this snippet and examine it, for illustration purposes:\n\n```js\nfunction f3([ x, y, ...z], ...w) {\n\tconsole.log( x, y, z, w );\n}\n\nf3( [] );\t\t\t\t\t\t\t// undefined undefined [] []\nf3( [1,2,3,4], 5, 6 );\t\t\t\t// 1 2 [3,4] [5,6]\n```\n\nThere are two `...` operators in use here, and they're both gathering values in arrays (`z` and `w`), though `...z` gathers from the rest of the values left over in the first array argument, while `...w` gathers from the rest of the main arguments left over after the first.\n\n#### Destructuring Defaults + Parameter Defaults\n\nThere's one subtle point you should be particularly careful to notice -- the difference in behavior between a destructuring default value and a function parameter default value. For example:\n\n```js\nfunction f6({ x = 10 } = {}, { y } = { y: 10 }) {\n\tconsole.log( x, y );\n}\n\nf6();\t\t\t\t\t\t\t\t// 10 10\n```\n\nAt first, it would seem that we've declared a default value of `10` for both the `x` and `y` parameters, but in two different ways. However, these two different approaches will behave differently in certain cases, and the difference is awfully subtle.\n\nConsider:\n\n```js\nf6( {}, {} );\t\t\t\t\t\t// 10 undefined\n```\n\nWait, why did that happen? It's pretty clear that named parameter `x` is defaulting to `10` if not passed as a property of that same name in the first argument's object.\n\nBut what about `y` being `undefined`? The `{ y: 10 }` value is an object as a function parameter default value, not a destructuring default value. As such, it only applies if the second argument is not passed at all, or is passed as `undefined`.\n\nIn the previous snippet, we *are* passing a second argument (`{}`), so the default `{ y: 10 }` value is not used, and the `{ y }` destructuring occurs against the passed in `{}` empty object value.\n\nNow, compare `{ y } = { y: 10 }` to `{ x = 10 } = {}`.\n\nFor the `x`'s form usage, if the first function argument is omitted or `undefined`, the `{}` empty object default applies. Then, whatever value is in the first argument position -- either the default `{}` or whatever you passed in -- is destructured with the `{ x = 10 }`, which checks to see if an `x` property is found, and if not found (or `undefined`), the `10` default value is applied to the `x` named parameter.\n\nDeep breath. Read back over those last few paragraphs a couple of times. Let's review via code:\n\n```js\nfunction f6({ x = 10 } = {}, { y } = { y: 10 }) {\n\tconsole.log( x, y );\n}\n\nf6();\t\t\t\t\t\t\t\t// 10 10\nf6( undefined, undefined );\t\t\t// 10 10\nf6( {}, undefined );\t\t\t\t// 10 10\n\nf6( {}, {} );\t\t\t\t\t\t// 10 undefined\nf6( undefined, {} );\t\t\t\t// 10 undefined\n\nf6( { x: 2 }, { y: 3 } );\t\t\t// 2 3\n```\n\nIt would generally seem that the defaulting behavior of the `x` parameter is probably the more desirable and sensible case compared to that of `y`. As such, it's important to understand why and how `{ x = 10 } = {}` form is different from `{ y } = { y: 10 }` form.\n\nIf that's still a bit fuzzy, go back and read it again, and play with this yourself. Your future self will thank you for taking the time to get this very subtle gotcha nuance detail straight.\n\n#### Nested Defaults: Destructured and Restructured\n\nAlthough it may at first be difficult to grasp, an interesting idiom emerges for setting defaults for a nested object's properties: using object destructuring along with what I'd call *restructuring*.\n\nConsider a set of defaults in a nested object structure, like the following:\n\n```js\n// taken from: http://es-discourse.com/t/partial-default-arguments/120/7\n\nvar defaults = {\n\toptions: {\n\t\tremove: true,\n\t\tenable: false,\n\t\tinstance: {}\n\t},\n\tlog: {\n\t\twarn: true,\n\t\terror: true\n\t}\n};\n```\n\nNow, let's say that you have an object called `config`, which has some of these applied, but perhaps not all, and you'd like to set all the defaults into this object in the missing spots, but not override specific settings already present:\n\n```js\nvar config = {\n\toptions: {\n\t\tremove: false,\n\t\tinstance: null\n\t}\n};\n```\n\nYou can of course do so manually, as you might have done in the past:\n\n```js\nconfig.options = config.options || {};\nconfig.options.remove = (config.options.remove !== undefined) ?\n\tconfig.options.remove : defaults.options.remove;\nconfig.options.enable = (config.options.enable !== undefined) ?\n\tconfig.options.enable : defaults.options.enable;\n...\n```\n\nYuck.\n\nOthers may prefer the assign-overwrite approach to this task. You might be tempted by the ES6 `Object.assign(..)` utility (see Chapter 6) to clone the properties first from `defaults` and then overwritten with the cloned properties from `config`, as so:\n\n```js\nconfig = Object.assign( {}, defaults, config );\n```\n\nThat looks way nicer, huh? But there's a major problem! `Object.assign(..)` is shallow, which means when it copies `defaults.options`, it just copies that object reference, not deep cloning that object's properties to a `config.options` object. `Object.assign(..)` would need to be applied (sort of \"recursively\") at all levels of your object's tree to get the deep cloning you're expecting.\n\n**Note:** Many JS utility libraries/frameworks provide their own option for deep cloning of an object, but those approaches and their gotchas are beyond our scope to discuss here.\n\nSo let's examine if ES6 object destructuring with defaults can help at all:\n\n```js\nconfig.options = config.options || {};\nconfig.log = config.log || {};\n({\n\toptions: {\n\t\tremove: config.options.remove = defaults.options.remove,\n\t\tenable: config.options.enable = defaults.options.enable,\n\t\tinstance: config.options.instance = defaults.options.instance\n\t} = {},\n\tlog: {\n\t\twarn: config.log.warn = defaults.log.warn,\n\t\terror: config.log.error = defaults.log.error\n\t} = {}\n} = config);\n```\n\nNot as nice as the false promise of `Object.assign(..)` (being that it's shallow only), but it's better than the manual approach by a fair bit, I think. It is still unfortunately verbose and repetitive, though.\n\nThe previous snippet's approach works because I'm hacking the destructuring and defaults mechanism to do the property `=== undefined` checks and assignment decisions for me. It's a trick in that I'm destructuring `config` (see the `= config` at the end of the snippet), but I'm reassigning all the destructured values right back into `config`, with the `config.options.enable` assignment references.\n\nStill too much, though. Let's see if we can make anything better.\n\nThe following trick works best if you know that all the various properties you're destructuring are uniquely named. You can still do it even if that's not the case, but it's not as nice -- you'll have to do the destructuring in stages, or create unique local variables as temporary aliases.\n\nIf we fully destructure all the properties into top-level variables, we can then immediately restructure to reconstitute the original nested object structure.\n\nBut all those temporary variables hanging around would pollute scope. So, let's use block scoping (see \"Block-Scoped Declarations\" earlier in this chapter) with a general `{ }` enclosing block:\n\n```js\n// merge `defaults` into `config`\n{\n\t// destructure (with default value assignments)\n\tlet {\n\t\toptions: {\n\t\t\tremove = defaults.options.remove,\n\t\t\tenable = defaults.options.enable,\n\t\t\tinstance = defaults.options.instance\n\t\t} = {},\n\t\tlog: {\n\t\t\twarn = defaults.log.warn,\n\t\t\terror = defaults.log.error\n\t\t} = {}\n\t} = config;\n\n\t// restructure\n\tconfig = {\n\t\toptions: { remove, enable, instance },\n\t\tlog: { warn, error }\n\t};\n}\n```\n\nThat seems a fair bit nicer, huh?\n\n**Note:** You could also accomplish the scope enclosure with an arrow IIFE instead of the general `{ }` block and `let` declarations. Your destructuring assignments/defaults would be in the parameter list and your restructuring would be the `return` statement in the function body.\n\nThe `{ warn, error }` syntax in the restructuring part may look new to you; that's called \"concise properties\" and we cover it in the next section!\n\n## Object Literal Extensions\n\nES6 adds a number of important convenience extensions to the humble `{ .. }` object literal.\n\n### Concise Properties\n\nYou're certainly familiar with declaring object literals in this form:\n\n```js\nvar x = 2, y = 3,\n\to = {\n\t\tx: x,\n\t\ty: y\n\t};\n```\n\nIf it's always felt redundant to say `x: x` all over, there's good news. If you need to define a property that is the same name as a lexical identifier, you can shorten it from `x: x` to `x`. Consider:\n\n```js\nvar x = 2, y = 3,\n\to = {\n\t\tx,\n\t\ty\n\t};\n```\n\n### Concise Methods\n\nIn a similar spirit to concise properties we just examined, functions attached to properties in object literals also have a concise form, for convenience.\n\nThe old way:\n\n```js\nvar o = {\n\tx: function(){\n\t\t// ..\n\t},\n\ty: function(){\n\t\t// ..\n\t}\n}\n```\n\nAnd as of ES6:\n\n```js\nvar o = {\n\tx() {\n\t\t// ..\n\t},\n\ty() {\n\t\t// ..\n\t}\n}\n```\n\n**Warning:** While `x() { .. }` seems to just be shorthand for `x: function(){ .. }`, concise methods have special behaviors that their older counterparts don't; specifically, the allowance for `super` (see \"Object `super`\" later in this chapter).\n\nGenerators (see Chapter 4) also have a concise method form:\n\n```js\nvar o = {\n\t*foo() { .. }\n};\n```\n\n#### Concisely Unnamed\n\nWhile that convenience shorthand is quite attractive, there's a subtle gotcha to be aware of. To illustrate, let's examine pre-ES6 code like the following, which you might try to refactor to use concise methods:\n\n```js\nfunction runSomething(o) {\n\tvar x = Math.random(),\n\t\ty = Math.random();\n\n\treturn o.something( x, y );\n}\n\nrunSomething( {\n\tsomething: function something(x,y) {\n\t\tif (x > y) {\n\t\t\t// recursively call with `x`\n\t\t\t// and `y` swapped\n\t\t\treturn something( y, x );\n\t\t}\n\n\t\treturn y - x;\n\t}\n} );\n```\n\nThis obviously silly code just generates two random numbers and subtracts the smaller from the bigger. But what's important here isn't what it does, but rather how it's defined. Let's focus on the object literal and function definition, as we see here:\n\n```js\nrunSomething( {\n\tsomething: function something(x,y) {\n\t\t// ..\n\t}\n} );\n```\n\nWhy do we say both `something:` and `function something`? Isn't that redundant? Actually, no, both are needed for different purposes. The property `something` is how we can call `o.something(..)`, sort of like its public name. But the second `something` is a lexical name to refer to the function from inside itself, for recursion purposes.\n\nCan you see why the line `return something(y,x)` needs the name `something` to refer to the function? There's no lexical name for the object, such that it could have said `return o.something(y,x)` or something of that sort.\n\nThat's actually a pretty common practice when the object literal does have an identifying name, such as:\n\n```js\nvar controller = {\n\tmakeRequest: function(..){\n\t\t// ..\n\t\tcontroller.makeRequest(..);\n\t}\n};\n```\n\nIs this a good idea? Perhaps, perhaps not. You're assuming that the name `controller` will always point to the object in question. But it very well may not -- the `makeRequest(..)` function doesn't control the outer code and so can't force that to be the case. This could come back to bite you.\n\nOthers prefer to use `this` to define such things:\n\n```js\nvar controller = {\n\tmakeRequest: function(..){\n\t\t// ..\n\t\tthis.makeRequest(..);\n\t}\n};\n```\n\nThat looks fine, and should work if you always invoke the method as `controller.makeRequest(..)`. But you now have a `this` binding gotcha if you do something like:\n\n```js\nbtn.addEventListener( \"click\", controller.makeRequest, false );\n```\n\nOf course, you can solve that by passing `controller.makeRequest.bind(controller)` as the handler reference to bind the event to. But yuck -- it isn't very appealing.\n\nOr what if your inner `this.makeRequest(..)` call needs to be made from a nested function? You'll have another `this` binding hazard, which people will often solve with the hacky `var self = this`, such as:\n\n```js\nvar controller = {\n\tmakeRequest: function(..){\n\t\tvar self = this;\n\n\t\tbtn.addEventListener( \"click\", function(){\n\t\t\t// ..\n\t\t\tself.makeRequest(..);\n\t\t}, false );\n\t}\n};\n```\n\nMore yuck.\n\n**Note:** For more information on `this` binding rules and gotchas, see Chapters 1-2 of the *this & Object Prototypes* title of this series.\n\nOK, what does all this have to do with concise methods? Recall our `something(..)` method definition:\n\n```js\nrunSomething( {\n\tsomething: function something(x,y) {\n\t\t// ..\n\t}\n} );\n```\n\nThe second `something` here provides a super convenient lexical identifier that will always point to the function itself, giving us the perfect reference for recursion, event binding/unbinding, and so on -- no messing around with `this` or trying to use an untrustable object reference.\n\nGreat!\n\nSo, now we try to refactor that function reference to this ES6 concise method form:\n\n```js\nrunSomething( {\n\tsomething(x,y) {\n\t\tif (x > y) {\n\t\t\treturn something( y, x );\n\t\t}\n\n\t\treturn y - x;\n\t}\n} );\n```\n\nSeems fine at first glance, except this code will break. The `return something(..)` call will not find a `something` identifier, so you'll get a `ReferenceError`. Oops. But why?\n\nThe above ES6 snippet is interpreted as meaning:\n\n```js\nrunSomething( {\n\tsomething: function(x,y){\n\t\tif (x > y) {\n\t\t\treturn something( y, x );\n\t\t}\n\n\t\treturn y - x;\n\t}\n} );\n```\n\nLook closely. Do you see the problem? The concise method definition implies `something: function(x,y)`. See how the second `something` we were relying on has been omitted? In other words, concise methods imply anonymous function expressions.\n\nYeah, yuck.\n\n**Note:** You may be tempted to think that `=>` arrow functions are a good solution here, but they're equally insufficient, as they're also anonymous function expressions. We'll cover them in \"Arrow Functions\" later in this chapter.\n\nThe partially redeeming news is that our `something(x,y)` concise method won't be totally anonymous. See \"Function Names\" in Chapter 7 for information about ES6 function name inference rules. That won't help us for our recursion, but it helps with debugging at least.\n\nSo what are we left to conclude about concise methods? They're short and sweet, and a nice convenience. But you should only use them if you're never going to need them to do recursion or event binding/unbinding. Otherwise, stick to your old-school `something: function something(..)` method definitions.\n\nA lot of your methods are probably going to benefit from concise method definitions, so that's great news! Just be careful of the few where there's an un-naming hazard.\n\n#### ES5 Getter/Setter\n\nTechnically, ES5 defined getter/setter literals forms, but they didn't seem to get used much, mostly due to the lack of transpilers to handle that new syntax (the only major new syntax added in ES5, really). So while it's not a new ES6 feature, we'll briefly refresh on that form, as it's probably going to be much more useful with ES6 going forward.\n\nConsider:\n\n```js\nvar o = {\n\t__id: 10,\n\tget id() { return this.__id++; },\n\tset id(v) { this.__id = v; }\n}\n\no.id;\t\t\t// 10\no.id;\t\t\t// 11\no.id = 20;\no.id;\t\t\t// 20\n\n// and:\no.__id;\t\t\t// 21\no.__id;\t\t\t// 21 -- still!\n```\n\nThese getter and setter literal forms are also present in classes; see Chapter 3.\n\n**Warning:** It may not be obvious, but the setter literal must have exactly one declared parameter; omitting it or listing others is illegal syntax. The single required parameter *can* use destructuring and defaults (e.g., `set id({ id: v = 0 }) { .. }`), but the gather/rest `...` is not allowed (`set id(...v) { .. }`).\n\n### Computed Property Names\n\nYou've probably been in a situation like the following snippet, where you have one or more property names that come from some sort of expression and thus can't be put into the object literal:\n\n```js\nvar prefix = \"user_\";\n\nvar o = {\n\tbaz: function(..){ .. }\n};\n\no[ prefix + \"foo\" ] = function(..){ .. };\no[ prefix + \"bar\" ] = function(..){ .. };\n..\n```\n\nES6 adds a syntax to the object literal definition which allows you to specify an expression that should be computed, whose result is the property name assigned. Consider:\n\n```js\nvar prefix = \"user_\";\n\nvar o = {\n\tbaz: function(..){ .. },\n\t[ prefix + \"foo\" ]: function(..){ .. },\n\t[ prefix + \"bar\" ]: function(..){ .. }\n\t..\n};\n```\n\nAny valid expression can appear inside the `[ .. ]` that sits in the property name position of the object literal definition.\n\nProbably the most common use of computed property names will be with `Symbol`s (which we cover in \"Symbols\" later in this chapter), such as:\n\n```js\nvar o = {\n\t[Symbol.toStringTag]: \"really cool thing\",\n\t..\n};\n```\n\n`Symbol.toStringTag` is a special built-in value, which we evaluate with the `[ .. ]` syntax, so we can assign the `\"really cool thing\"` value to the special property name.\n\nComputed property names can also appear as the name of a concise method or a concise generator:\n\n```js\nvar o = {\n\t[\"f\" + \"oo\"]() { .. }\t// computed concise method\n\t*[\"b\" + \"ar\"]() { .. }\t// computed concise generator\n};\n```\n\n### Setting `[[Prototype]]`\n\nWe won't cover prototypes in detail here, so for more information, see the *this & Object Prototypes* title of this series.\n\nSometimes it will be helpful to assign the `[[Prototype]]` of an object at the same time you're declaring its object literal. The following has been a nonstandard extension in many JS engines for a while, but is standardized as of ES6:\n\n```js\nvar o1 = {\n\t// ..\n};\n\nvar o2 = {\n\t__proto__: o1,\n\t// ..\n};\n```\n\n`o2` is declared with a normal object literal, but it's also `[[Prototype]]`-linked to `o1`. The `__proto__` property name here can also be a string `\"__proto__\"`, but note that it *cannot* be the result of a computed property name (see the previous section).\n\n`__proto__` is controversial, to say the least. It's a decades-old proprietary extension to JS that is finally standardized, somewhat begrudgingly it seems, in ES6. Many developers feel it shouldn't ever be used. In fact, it's in \"Annex B\" of ES6, which is the section that lists things JS feels it has to standardize for compatibility reasons only.\n\n**Warning:** Though I'm narrowly endorsing `__proto__` as a key in an object literal definition, I definitely do not endorse using it in its object property form, like `o.__proto__`. That form is both a getter and setter (again for compatibility reasons), but there are definitely better options. See the *this & Object Prototypes* title of this series for more information.\n\nFor setting the `[[Prototype]]` of an existing object, you can use the ES6 utility `Object.setPrototypeOf(..)`. Consider:\n\n```js\nvar o1 = {\n\t// ..\n};\n\nvar o2 = {\n\t// ..\n};\n\nObject.setPrototypeOf( o2, o1 );\n```\n\n**Note:** We'll discuss `Object` again in Chapter 6. \"`Object.setPrototypeOf(..)` Static Function\" provides additional details on `Object.setPrototypeOf(..)`. Also see \"`Object.assign(..)` Static Function\" for another form that relates `o2` prototypically to `o1`.\n\n### Object `super`\n\n`super` is typically thought of as being only related to classes. However, due to JS's classless-objects-with-prototypes nature, `super` is equally effective, and nearly the same in behavior, with plain objects' concise methods.\n\nConsider:\n\n```js\nvar o1 = {\n\tfoo() {\n\t\tconsole.log( \"o1:foo\" );\n\t}\n};\n\nvar o2 = {\n\tfoo() {\n\t\tsuper.foo();\n\t\tconsole.log( \"o2:foo\" );\n\t}\n};\n\nObject.setPrototypeOf( o2, o1 );\n\no2.foo();\t\t// o1:foo\n\t\t\t\t// o2:foo\n```\n\n**Warning:** `super` is only allowed in concise methods, not regular function expression properties. It also is only allowed in `super.XXX` form (for property/method access), not in `super()` form.\n\nThe `super` reference in the `o2.foo()` method is locked statically to `o2`, and specifically to the `[[Prototype]]` of `o2`. `super` here would basically be `Object.getPrototypeOf(o2)` -- resolves to `o1` of course -- which is how it finds and calls `o1.foo()`.\n\nFor complete details on `super`, see \"Classes\" in Chapter 3.\n\n## Template Literals\n\nAt the very outset of this section, I'm going to have to call out the name of this ES6 feature as being awfully... misleading, depending on your experiences with what the word *template* means.\n\nMany developers think of templates as being reusable renderable pieces of text, such as the capability provided by most template engines (Mustache, Handlebars, etc.). ES6's use of the word *template* would imply something similar, like a way to declare inline template literals that can be re-rendered. However, that's not at all the right way to think about this feature.\n\nSo, before we go on, I'm renaming to what it should have been called: *interpolated string literals* (or *interpoliterals* for short).\n\nYou're already well aware of declaring string literals with `\"` or `'` delimiters, and you also know that these are not *smart strings* (as some languages have), where the contents would be parsed for interpolation expressions.\n\nHowever, ES6 introduces a new type of string literal, using the `` ` `` backtick as the delimiter. These string literals allow basic string interpolation expressions to be embedded, which are then automatically parsed and evaluated.\n\nHere's the old pre-ES6 way:\n\n```js\nvar name = \"Kyle\";\n\nvar greeting = \"Hello \" + name + \"!\";\n\nconsole.log( greeting );\t\t\t// \"Hello Kyle!\"\nconsole.log( typeof greeting );\t\t// \"string\"\n```\n\nNow, consider the new ES6 way:\n\n```js\nvar name = \"Kyle\";\n\nvar greeting = `Hello ${name}!`;\n\nconsole.log( greeting );\t\t\t// \"Hello Kyle!\"\nconsole.log( typeof greeting );\t\t// \"string\"\n```\n\nAs you can see, we used the `` `..` `` around a series of characters, which are interpreted as a string literal, but any expressions of the form `${..}` are parsed and evaluated inline immediately. The fancy term for such parsing and evaluating is *interpolation* (much more accurate than templating).\n\nThe result of the interpolated string literal expression is just a plain old normal string, assigned to the `greeting` variable.\n\n**Warning:** `typeof greeting == \"string\"` illustrates why it's important not to think of these entities as special template values, as you cannot assign the unevaluated form of the literal to something and reuse it. The `` `..` `` string literal is more like an IIFE in the sense that it's automatically evaluated inline. The result of a `` `..` `` string literal is, simply, just a string.\n\nOne really nice benefit of interpolated string literals is they are allowed to split across multiple lines:\n\n```js\nvar text =\n`Now is the time for all good men\nto come to the aid of their\ncountry!`;\n\nconsole.log( text );\n// Now is the time for all good men\n// to come to the aid of their\n// country!\n```\n\nThe line breaks (newlines) in the interpolated string literal were preserved in the string value.\n\nUnless appearing as explicit escape sequences in the literal value, the value of the `\\r` carriage return character (code point `U+000D`) or the value of the `\\r\\n` carriage return + line feed sequence (code points `U+000D` and `U+000A`) are both normalized to a `\\n` line feed character (code point `U+000A`). Don't worry though; this normalization is rare and would likely only happen if copy-pasting text into your JS file.\n\n### Interpolated Expressions\n\nAny valid expression is allowed to appear inside `${..}` in an interpolated string literal, including function calls, inline function expression calls, and even other interpolated string literals!\n\nConsider:\n\n```js\nfunction upper(s) {\n\treturn s.toUpperCase();\n}\n\nvar who = \"reader\";\n\nvar text =\n`A very ${upper( \"warm\" )} welcome\nto all of you ${upper( `${who}s` )}!`;\n\nconsole.log( text );\n// A very WARM welcome\n// to all of you READERS!\n```\n\nHere, the inner `` `${who}s` `` interpolated string literal was a little bit nicer convenience for us when combining the `who` variable with the `\"s\"` string, as opposed to `who + \"s\"`. There will be cases that nesting interpolated string literals is helpful, but be wary if you find yourself doing that kind of thing often, or if you find yourself nesting several levels deep.\n\nIf that's the case, the odds are good that your string value production could benefit from some abstractions.\n\n**Warning:** As a word of caution, be very careful about the readability of your code with such new found power. Just like with default value expressions and destructuring assignment expressions, just because you *can* do something doesn't mean you *should* do it. Never go so overboard with new ES6 tricks that your code becomes more clever than you or your other team members.\n\n#### Expression Scope\n\nOne quick note about the scope that is used to resolve variables in expressions. I mentioned earlier that an interpolated string literal is kind of like an IIFE, and it turns out thinking about it like that explains the scoping behavior as well.\n\nConsider:\n\n```js\nfunction foo(str) {\n\tvar name = \"foo\";\n\tconsole.log( str );\n}\n\nfunction bar() {\n\tvar name = \"bar\";\n\tfoo( `Hello from ${name}!` );\n}\n\nvar name = \"global\";\n\nbar();\t\t\t\t\t// \"Hello from bar!\"\n```\n\nAt the moment the `` `..` `` string literal is expressed, inside the `bar()` function, the scope available to it finds `bar()`'s `name` variable with value `\"bar\"`. Neither the global `name` nor `foo(..)`'s `name` matter. In other words, an interpolated string literal is just lexically scoped where it appears, not dynamically scoped in any way.\n\n### Tagged Template Literals\n\nAgain, renaming the feature for sanity sake: *tagged string literals*.\n\nTo be honest, this is one of the cooler tricks that ES6 offers. It may seem a little strange, and perhaps not all that generally practical at first. But once you've spent some time with it, tagged string literals may just surprise you in their usefulness.\n\nFor example:\n\n```js\nfunction foo(strings, ...values) {\n\tconsole.log( strings );\n\tconsole.log( values );\n}\n\nvar desc = \"awesome\";\n\nfoo`Everything is ${desc}!`;\n// [ \"Everything is \", \"!\"]\n// [ \"awesome\" ]\n```\n\nLet's take a moment to consider what's happening in the previous snippet. First, the most jarring thing that jumps out is ``foo`Everything...`;``. That doesn't look like anything we've seen before. What is it?\n\nIt's essentially a special kind of function call that doesn't need the `( .. )`. The *tag* -- the `foo` part before the `` `..` `` string literal -- is a function value that should be called. Actually, it can be any expression that results in a function, even a function call that returns another function, like:\n\n```js\nfunction bar() {\n\treturn function foo(strings, ...values) {\n\t\tconsole.log( strings );\n\t\tconsole.log( values );\n\t}\n}\n\nvar desc = \"awesome\";\n\nbar()`Everything is ${desc}!`;\n// [ \"Everything is \", \"!\"]\n// [ \"awesome\" ]\n```\n\nBut what gets passed to the `foo(..)` function when invoked as a tag for a string literal?\n\nThe first argument -- we called it `strings` -- is an array of all the plain strings (the stuff between any interpolated expressions). We get two values in the `strings` array: `\"Everything is \"` and `\"!\"`.\n\nFor convenience sake in our example, we then gather up all subsequent arguments into an array called `values` using the `...` gather/rest operator (see the \"Spread/Rest\" section earlier in this chapter), though you could of course have left them as individual named parameters following the `strings` parameter.\n\nThe argument(s) gathered into our `values` array are the results of the already-evaluated interpolation expressions found in the string literal. So obviously the only element in `values` in our example is `\"awesome\"`.\n\nYou can think of these two arrays as: the values in `values` are the separators if you were to splice them in between the values in `strings`, and then if you joined everything together, you'd get the complete interpolated string value.\n\nA tagged string literal is like a processing step after the interpolation expressions are evaluated but before the final string value is compiled, allowing you more control over generating the string from the literal.\n\nTypically, the string literal tag function (`foo(..)` in the previous snippets) should compute an appropriate string value and return it, so that you can use the tagged string literal as a value just like untagged string literals:\n\n```js\nfunction tag(strings, ...values) {\n\treturn strings.reduce( function(s,v,idx){\n\t\treturn s + (idx > 0 ? values[idx-1] : \"\") + v;\n\t}, \"\" );\n}\n\nvar desc = \"awesome\";\n\nvar text = tag`Everything is ${desc}!`;\n\nconsole.log( text );\t\t\t// Everything is awesome!\n```\n\nIn this snippet, `tag(..)` is a pass-through operation, in that it doesn't perform any special modifications, but just uses `reduce(..)` to loop over and splice/interleave `strings` and `values` together the same way an untagged string literal would have done.\n\nSo what are some practical uses? There are many advanced ones that are beyond our scope to discuss here. But here's a simple idea that formats numbers as U.S. dollars (sort of like basic localization):\n\n```js\nfunction dollabillsyall(strings, ...values) {\n\treturn strings.reduce( function(s,v,idx){\n\t\tif (idx > 0) {\n\t\t\tif (typeof values[idx-1] == \"number\") {\n\t\t\t\t// look, also using interpolated\n\t\t\t\t// string literals!\n\t\t\t\ts += `$${values[idx-1].toFixed( 2 )}`;\n\t\t\t}\n\t\t\telse {\n\t\t\t\ts += values[idx-1];\n\t\t\t}\n\t\t}\n\n\t\treturn s + v;\n\t}, \"\" );\n}\n\nvar amt1 = 11.99,\n\tamt2 = amt1 * 1.08,\n\tname = \"Kyle\";\n\nvar text = dollabillsyall\n`Thanks for your purchase, ${name}! Your\nproduct cost was ${amt1}, which with tax\ncomes out to ${amt2}.`\n\nconsole.log( text );\n// Thanks for your purchase, Kyle! Your\n// product cost was $11.99, which with tax\n// comes out to $12.95.\n```\n\nIf a `number` value is encountered in the `values` array, we put `\"$\"` in front of it and format it to two decimal places with `toFixed(2)`. Otherwise, we let the value pass-through untouched.\n\n#### Raw Strings\n\nIn the previous snippets, our tag functions receive the first argument we called `strings`, which is an array. But there's an additional bit of data included: the raw unprocessed versions of all the strings. You can access those raw string values using the `.raw` property, like this:\n\n```js\nfunction showraw(strings, ...values) {\n\tconsole.log( strings );\n\tconsole.log( strings.raw );\n}\n\nshowraw`Hello\\nWorld`;\n// [ \"Hello\n// World\" ]\n// [ \"Hello\\nWorld\" ]\n```\n\nThe raw version of the value preserves the raw escaped `\\n` sequence (the `\\` and the `n` are separate characters), while the processed version considers it a single newline character. However, the earlier mentioned line-ending normalization is applied to both values.\n\nES6 comes with a built-in function that can be used as a string literal tag: `String.raw(..)`. It simply passes through the raw versions of the `strings` values:\n\n```js\nconsole.log( `Hello\\nWorld` );\n// Hello\n// World\n\nconsole.log( String.raw`Hello\\nWorld` );\n// Hello\\nWorld\n\nString.raw`Hello\\nWorld`.length;\n// 12\n```\n\nOther uses for string literal tags included special processing for internationalization, localization, and more!\n\n## Arrow Functions\n\nWe've touched on `this` binding complications with functions earlier in this chapter, and they're covered at length in the *this & Object Prototypes* title of this series. It's important to understand the frustrations that `this`-based programming with normal functions brings, because that is the primary motivation for the new ES6 `=>` arrow function feature.\n\nLet's first illustrate what an arrow function looks like, as compared to normal functions:\n\n```js\nfunction foo(x,y) {\n\treturn x + y;\n}\n\n// versus\n\nvar foo = (x,y) => x + y;\n```\n\nThe arrow function definition consists of a parameter list (of zero or more parameters, and surrounding `( .. )` if there's not exactly one parameter), followed by the `=>` marker, followed by a function body.\n\nSo, in the previous snippet, the arrow function is just the `(x,y) => x + y` part, and that function reference happens to be assigned to the variable `foo`.\n\nThe body only needs to be enclosed by `{ .. }` if there's more than one expression, or if the body consists of a non-expression statement. If there's only one expression, and you omit the surrounding `{ .. }`, there's an implied `return` in front of the expression, as illustrated in the previous snippet.\n\nHere's some other arrow function variations to consider:\n\n```js\nvar f1 = () => 12;\nvar f2 = x => x * 2;\nvar f3 = (x,y) => {\n\tvar z = x * 2 + y;\n\ty++;\n\tx *= 3;\n\treturn (x + y + z) / 2;\n};\n```\n\nArrow functions are *always* function expressions; there is no arrow function declaration. It also should be clear that they are anonymous function expressions -- they have no named reference for the purposes of recursion or event binding/unbinding -- though \"Function Names\" in Chapter 7 will describe ES6's function name inference rules for debugging purposes.\n\n**Note:** All the capabilities of normal function parameters are available to arrow functions, including default values, destructuring, rest parameters, and so on.\n\nArrow functions have a nice, shorter syntax, which makes them on the surface very attractive for writing terser code. Indeed, nearly all literature on ES6 (other than the titles in this series) seems to immediately and exclusively adopt the arrow function as \"the new function.\"\n\nIt is telling that nearly all examples in discussion of arrow functions are short single statement utilities, such as those passed as callbacks to various utilities. For example:\n\n```js\nvar a = [1,2,3,4,5];\n\na = a.map( v => v * 2 );\n\nconsole.log( a );\t\t\t\t// [2,4,6,8,10]\n```\n\nIn those cases, where you have such inline function expressions, and they fit the pattern of computing a quick calculation in a single statement and returning that result, arrow functions indeed look to be an attractive and lightweight alternative to the more verbose `function` keyword and syntax.\n\nMost people tend to *ooh and aah* at nice terse examples like that, as I imagine you just did!\n\nHowever, I would caution you that it would seem to me somewhat a misapplication of this feature to use arrow function syntax with otherwise normal, multistatement functions, especially those that would otherwise be naturally expressed as function declarations.\n\nRecall the `dollabillsyall(..)` string literal tag function from earlier in this chapter -- let's change it to use `=>` syntax:\n\n```js\nvar dollabillsyall = (strings, ...values) =>\n\tstrings.reduce( (s,v,idx) => {\n\t\tif (idx > 0) {\n\t\t\tif (typeof values[idx-1] == \"number\") {\n\t\t\t\t// look, also using interpolated\n\t\t\t\t// string literals!\n\t\t\t\ts += `$${values[idx-1].toFixed( 2 )}`;\n\t\t\t}\n\t\t\telse {\n\t\t\t\ts += values[idx-1];\n\t\t\t}\n\t\t}\n\n\t\treturn s + v;\n\t}, \"\" );\n```\n\nIn this example,  the only modifications I made were the removal of `function`, `return`, and some `{ .. }`, and then the insertion of `=>` and a `var`. Is this a significant improvement in the readability of the code? Meh.\n\nI'd actually argue that the lack of `return` and outer `{ .. }` partially obscures the fact that the `reduce(..)` call is the only statement in the `dollabillsyall(..)` function and that its result is the intended result of the call. Also, the trained eye that is so used to hunting for the word `function` in code to find scope boundaries now needs to look for the `=>` marker, which can definitely be harder to find in the thick of the code.\n\nWhile not a hard-and-fast rule, I'd say that the readability gains from `=>` arrow function conversion are inversely proportional to the length of the function being converted. The longer the function, the less `=>` helps; the shorter the function, the more `=>` can shine.\n\nI think it's probably more sensible and reasonable to adopt `=>` for the places in code where you do need short inline function expressions, but leave your normal-length main functions as is.\n\n### Not Just Shorter Syntax, But `this`\n\nMost of the popular attention toward `=>` has been on saving those precious keystrokes by dropping `function`, `return`, and `{ .. }` from your code.\n\nBut there's a big detail we've skipped over so far. I said at the beginning of the section that `=>` functions are closely related to `this` binding behavior. In fact, `=>` arrow functions are *primarily designed* to alter `this` behavior in a specific way, solving a particular and common pain point with `this`-aware coding.\n\nThe saving of keystrokes is a red herring, a misleading sideshow at best.\n\nLet's revisit another example from earlier in this chapter:\n\n```js\nvar controller = {\n\tmakeRequest: function(..){\n\t\tvar self = this;\n\n\t\tbtn.addEventListener( \"click\", function(){\n\t\t\t// ..\n\t\t\tself.makeRequest(..);\n\t\t}, false );\n\t}\n};\n```\n\nWe used the `var self = this` hack, and then referenced `self.makeRequest(..)`, because inside the callback function we're passing to `addEventListener(..)`, the `this` binding will not be the same as it is in `makeRequest(..)` itself. In other words, because `this` bindings are dynamic, we fall back to the predictability of lexical scope via the `self` variable.\n\nHerein we finally can see the primary design characteristic of `=>` arrow functions. Inside arrow functions, the `this` binding is not dynamic, but is instead lexical. In the previous snippet, if we used an arrow function for the callback, `this` will be predictably what we wanted it to be.\n\nConsider:\n\n```js\nvar controller = {\n\tmakeRequest: function(..){\n\t\tbtn.addEventListener( \"click\", () => {\n\t\t\t// ..\n\t\t\tthis.makeRequest(..);\n\t\t}, false );\n\t}\n};\n```\n\nLexical `this` in the arrow function callback in the previous snippet now points to the same value as in the enclosing `makeRequest(..)` function. In other words, `=>` is a syntactic stand-in for `var self = this`.\n\nIn cases where `var self = this` (or, alternatively, a function `.bind(this)` call) would normally be helpful, `=>` arrow functions are a nicer alternative operating on the same prinicple. Sounds great, right?\n\nNot quite so simple.\n\nIf `=>` replaces `var self = this` or `.bind(this)` and it helps, guess what happens if you use `=>` with a `this`-aware function that *doesn't* need `var self = this` to work? You might be able to guess that it's going to mess things up. Yeah.\n\nConsider:\n\n```js\nvar controller = {\n\tmakeRequest: (..) => {\n\t\t// ..\n\t\tthis.helper(..);\n\t},\n\thelper: (..) => {\n\t\t// ..\n\t}\n};\n\ncontroller.makeRequest(..);\n```\n\nAlthough we invoke as `controller.makeRequest(..)`, the `this.helper` reference fails, because `this` here doesn't point to `controller` as it normally would. Where does it point? It lexically inherits `this` from the surrounding scope. In this previous snippet, that's the global scope, where `this` points to the global object. Ugh.\n\nIn addition to lexical `this`, arrow functions also have lexical `arguments` -- they don't have their own `arguments` array but instead inherit from their parent -- as well as lexical `super` and `new.target` (see \"Classes\" in Chapter 3).\n\nSo now we can conclude a more nuanced set of rules for when `=>` is appropriate and not:\n\n* If you have a short, single-statement inline function expression, where the only statement is a `return` of some computed value, *and* that function doesn't already make a `this` reference inside it, *and* there's no self-reference (recursion, event binding/unbinding), *and* you don't reasonably expect the function to ever be that way, you can probably safely refactor it to be an `=>` arrow function.\n* If you have an inner function expression that's relying on a `var self = this` hack or a `.bind(this)` call on it in the enclosing function to ensure proper `this` binding, that inner function expression can probably safely become an `=>` arrow function.\n* If you have an inner function expression that's relying on something like `var args = Array.prototype.slice.call(arguments)` in the enclosing function to make a lexical copy of `arguments`, that inner function expression can probably safely become an `=>` arrow function.\n* For everything else -- normal function declarations, longer multistatement function expressions, functions that need a lexical name identifier self-reference (recursion, etc.), and any other function that doesn't fit the previous characteristics -- you should probably avoid `=>` function syntax.\n\nBottom line: `=>` is about lexical binding of `this`, `arguments`, and `super`. These are intentional features designed to fix some common problems, not bugs, quirks, or mistakes in ES6.\n\nDon't believe any hype that `=>` is primarily, or even mostly, about fewer keystrokes. Whether you save keystrokes or waste them, you should know exactly what you are intentionally doing with every character typed.\n\n**Tip:** If you have a function that for any of these articulated reasons is not a good match for an `=>` arrow function, but it's being declared as part of an object literal, recall from \"Concise Methods\" earlier in this chapter that there's another option for shorter function syntax.\n\nIf you prefer a visual decision chart for how/why to pick an arrow function:\n\n<img src=\"fig1.png\">\n\n## `for..of` Loops\n\nJoining the `for` and `for..in` loops from the JavaScript we're all familiar with, ES6 adds a `for..of` loop, which loops over the set of values produced by an *iterator*.\n\nThe value you loop over with `for..of` must be an *iterable*, or it must be a value which can be coerced/boxed to an object (see the *Types & Grammar* title of this series) that is an iterable. An iterable is simply an object that is able to produce an iterator, which the loop then uses.\n\nLet's compare `for..of` to `for..in` to illustrate the difference:\n\n```js\nvar a = [\"a\",\"b\",\"c\",\"d\",\"e\"];\n\nfor (var idx in a) {\n\tconsole.log( idx );\n}\n// 0 1 2 3 4\n\nfor (var val of a) {\n\tconsole.log( val );\n}\n// \"a\" \"b\" \"c\" \"d\" \"e\"\n```\n\nAs you can see, `for..in` loops over the keys/indexes in the `a` array, while `for..of` loops over the values in `a`.\n\nHere's the pre-ES6 version of the `for..of` from that previous snippet:\n\n```js\nvar a = [\"a\",\"b\",\"c\",\"d\",\"e\"],\n\tk = Object.keys( a );\n\nfor (var val, i = 0; i < k.length; i++) {\n\tval = a[ k[i] ];\n\tconsole.log( val );\n}\n// \"a\" \"b\" \"c\" \"d\" \"e\"\n```\n\nAnd here's the ES6 but non-`for..of` equivalent, which also gives a glimpse at manually iterating an iterator (see \"Iterators\" in Chapter 3):\n\n```js\nvar a = [\"a\",\"b\",\"c\",\"d\",\"e\"];\n\nfor (var val, ret, it = a[Symbol.iterator]();\n\t(ret = it.next()) && !ret.done;\n) {\n\tval = ret.value;\n\tconsole.log( val );\n}\n// \"a\" \"b\" \"c\" \"d\" \"e\"\n```\n\nUnder the covers, the `for..of` loop asks the iterable for an iterator (using the built-in `Symbol.iterator`; see \"Well-Known Symbols\" in Chapter 7), then it repeatedly calls the iterator and assigns its produced value to the loop iteration variable.\n\nStandard built-in values in JavaScript that are by default iterables (or provide them) include:\n\n* Arrays\n* Strings\n* Generators (see Chapter 3)\n* Collections / TypedArrays (see Chapter 5)\n\n**Warning:** Plain objects are not by default suitable for `for..of` looping. That's because they don't have a default iterator, which is intentional, not a mistake. However, we won't go any further into those nuanced reasonings here. In \"Iterators\" in Chapter 3, we'll see how to define iterators for our own objects, which lets `for..of` loop over any object to get a set of values we define.\n\nHere's how to loop over the characters in a primitive string:\n\n```js\nfor (var c of \"hello\") {\n\tconsole.log( c );\n}\n// \"h\" \"e\" \"l\" \"l\" \"o\"\n```\n\nThe `\"hello\"` primitive string value is coerced/boxed to the `String` object wrapper equivalent, which is an iterable by default.\n\nIn `for (XYZ of ABC)..`, the `XYZ` clause can either be an assignment expression or a declaration, identical to that same clause in `for` and `for..in` loops. So you can do stuff like this:\n\n```js\nvar o = {};\n\nfor (o.a of [1,2,3]) {\n\tconsole.log( o.a );\n}\n// 1 2 3\n\nfor ({x: o.a} of [ {x: 1}, {x: 2}, {x: 3} ]) {\n  console.log( o.a );\n}\n// 1 2 3\n```\n\n`for..of` loops can be prematurely stopped, just like other loops, with `break`, `continue`, `return` (if in a function), and thrown exceptions. In any of these cases, the iterator's `return(..)` function is automatically called (if one exists) to let the iterator perform cleanup tasks, if necessary.\n\n**Note:** See \"Iterators\" in Chapter 3 for more complete coverage on iterables and iterators.\n\n## Regular Expressions\n\nLet's face it: regular expressions haven't changed much in JS in a long time. So it's a great thing that they've finally learned a couple of new tricks in ES6. We'll briefly cover the additions here, but the overall topic of regular expressions is so dense that you'll need to turn to chapters/books dedicated to it (of which there are many!) if you need a refresher.\n\n### Unicode Flag\n\nWe'll cover the topic of Unicode in more detail in \"Unicode\" later in this chapter. Here, we'll just look briefly at the new `u` flag for ES6+ regular expressions, which turns on Unicode matching for that expression.\n\nJavaScript strings are typically interpreted as sequences of 16-bit characters, which correspond to the characters in the *Basic Multilingual Plane (BMP)* (http://en.wikipedia.org/wiki/Plane_%28Unicode%29). But there are many UTF-16 characters that fall outside this range, and so strings may have these multibyte characters in them.\n\nPrior to ES6, regular expressions could only match based on BMP characters, which means that those extended characters were treated as two separate characters for matching purposes. This is often not ideal.\n\nSo, as of ES6, the `u` flag tells a regular expression to process a string with the interpretation of Unicode (UTF-16) characters, such that such an extended character will be matched as a single entity.\n\n**Warning:** Despite the name implication, \"UTF-16\" doesn't strictly mean 16 bits. Modern Unicode uses 21 bits, and standards like UTF-8 and UTF-16 refer roughly to how many bits are used in the representation of a character.\n\nAn example (straight from the ES6 specification): 𝄞 (the musical symbol G-clef) is Unicode point U+1D11E (0x1D11E).\n\nIf this character appears in a regular expression pattern (like `/𝄞/`), the standard BMP interpretation would be that it's two separate characters (0xD834 and 0xDD1E) to match with. But the new ES6 Unicode-aware mode means that `/𝄞/u` (or the escaped Unicode form `/\\u{1D11E}/u`) will match `\"𝄞\"` in a string as a single matched character.\n\nYou might be wondering why this matters? In non-Unicode BMP mode, the pattern is treated as two separate characters, but would still find the match in a string with the `\"𝄞\"` character in it, as you can see if you try:\n\n```js\n/𝄞/.test( \"𝄞-clef\" );\t\t\t// true\n```\n\nThe length of the match is what matters. For example:\n\n```js\n/^.-clef/ .test( \"𝄞-clef\" );\t\t// false\n/^.-clef/u.test( \"𝄞-clef\" );\t\t// true\n```\n\nThe `^.-clef` in the pattern says to match only a single character at the beginning before the normal `\"-clef\"` text. In standard BMP mode, the match fails (two characters), but with `u` Unicode mode flagged on, the match succeeds (one character).\n\nIt's also important to note that `u` makes quantifiers like `+` and `*` apply to the entire Unicode code point as a single character, not just the *lower surrogate* (aka rightmost half of the symbol) of the character. The same goes for Unicode characters appearing in character classes, like `/[💩-💫]/u`.\n\n**Note:** There's plenty more nitty-gritty details about `u` behavior in regular expressions, which Mathias Bynens (https://twitter.com/mathias) has written extensively about (https://mathiasbynens.be/notes/es6-unicode-regex).\n\n### Sticky Flag\n\nAnother flag mode added to ES6 regular expressions is `y`, which is often called \"sticky mode.\" *Sticky* essentially means the regular expression has a virtual anchor at its beginning that keeps it rooted to matching at only the position indicated by the regular expression's `lastIndex` property.\n\nTo illustrate, let's consider two regular expressions, the first without sticky mode and the second with:\n\n```js\nvar re1 = /foo/,\n\tstr = \"++foo++\";\n\nre1.lastIndex;\t\t\t// 0\nre1.test( str );\t\t// true\nre1.lastIndex;\t\t\t// 0 -- not updated\n\nre1.lastIndex = 4;\nre1.test( str );\t\t// true -- ignored `lastIndex`\nre1.lastIndex;\t\t\t// 4 -- not updated\n```\n\nThree things to observe about this snippet:\n\n* `test(..)` doesn't pay any attention to `lastIndex`'s value, and always just performs its match from the beginning of the input string.\n* Because our pattern does not have a `^` start-of-input anchor, the search for `\"foo\"` is free to move ahead through the whole string looking for a match.\n* `lastIndex` is not updated by `test(..)`.\n\nNow, let's try a sticky mode regular expression:\n\n```js\nvar re2 = /foo/y,\t\t// <-- notice the `y` sticky flag\n\tstr = \"++foo++\";\n\nre2.lastIndex;\t\t\t// 0\nre2.test( str );\t\t// false -- \"foo\" not found at `0`\nre2.lastIndex;\t\t\t// 0\n\nre2.lastIndex = 2;\nre2.test( str );\t\t// true\nre2.lastIndex;\t\t\t// 5 -- updated to after previous match\n\nre2.test( str );\t\t// false\nre2.lastIndex;\t\t\t// 0 -- reset after previous match failure\n```\n\nAnd so our new observations about sticky mode:\n\n* `test(..)` uses `lastIndex` as the exact and only position in `str` to look to make a match. There is no moving ahead to look for the match -- it's either there at the `lastIndex` position or not.\n* If a match is made, `test(..)` updates `lastIndex` to point to the character immediately following the match. If a match fails, `test(..)` resets `lastIndex` back to `0`.\n\nNormal non-sticky patterns that aren't otherwise `^`-rooted to the start-of-input are free to move ahead in the input string looking for a match. But sticky mode restricts the pattern to matching just at the position of `lastIndex`.\n\nAs I suggested at the beginning of this section, another way of looking at this is that `y` implies a virtual anchor at the beginning of the pattern that is relative (aka constrains the start of the match) to exactly the `lastIndex` position.\n\n**Warning:** In previous literature on the topic, it has alternatively been asserted that this behavior is like `y` implying a `^` (start-of-input) anchor in the pattern. This is inaccurate. We'll explain in further detail in \"Anchored Sticky\" later.\n\n#### Sticky Positioning\n\nIt may seem strangely limiting that to use `y` for repeated matches, you have to manually ensure `lastIndex` is in the exact right position, as it has no move-ahead capability for matching.\n\nHere's one possible scenario: if you know that the match you care about is always going to be at a position that's a multiple of a number (e.g., `0`, `10`, `20`, etc.), you can just construct a limited pattern matching what you care about, but then manually set `lastIndex` each time before match to those fixed positions.\n\nConsider:\n\n```js\nvar re = /f../y,\n\tstr = \"foo       far       fad\";\n\nstr.match( re );\t\t// [\"foo\"]\n\nre.lastIndex = 10;\nstr.match( re );\t\t// [\"far\"]\n\nre.lastIndex = 20;\nstr.match( re );\t\t// [\"fad\"]\n```\n\nHowever, if you're parsing a string that isn't formatted in fixed positions like that, figuring out what to set `lastIndex` to before each match is likely going to be untenable.\n\nThere's a saving nuance to consider here. `y` requires that `lastIndex` be in the exact position for a match to occur. But it doesn't strictly require that *you* manually set `lastIndex`.\n\nInstead, you can construct your expressions in such a way that they capture in each main match everything before and after the thing you care about, up to right before the next thing you'll care to match.\n\nBecause `lastIndex` will set to the next character beyond the end of a match, if you've matched everything up to that point, `lastIndex` will always be in the correct position for the `y` pattern to start from the next time.\n\n**Warning:** If you can't predict the structure of the input string in a sufficiently patterned way like that, this technique may not be suitable and you may not be able to use `y`.\n\nHaving structured string input is likely the most practical scenario where `y` will be capable of performing repeated matching throughout a string. Consider:\n\n```js\nvar re = /\\d+\\.\\s(.*?)(?:\\s|$)/y\n\tstr = \"1. foo 2. bar 3. baz\";\n\nstr.match( re );\t\t// [ \"1. foo \", \"foo\" ]\n\nre.lastIndex;\t\t\t// 7 -- correct position!\nstr.match( re );\t\t// [ \"2. bar \", \"bar\" ]\n\nre.lastIndex;\t\t\t// 14 -- correct position!\nstr.match( re );\t\t// [\"3. baz\", \"baz\"]\n```\n\nThis works because I knew something ahead of time about the structure of the input string: there is always a numeral prefix like `\"1. \"` before the desired match (`\"foo\"`, etc.), and either a space after it, or the end of the string (`$` anchor). So the regular expression I constructed captures all of that in each main match, and then I use a matching group `( )` so that the stuff I really care about is separated out for convenience.\n\nAfter the first match (`\"1. foo \"`), the `lastIndex` is `7`, which is already the position needed to start the next match, for `\"2. bar \"`, and so on.\n\nIf you're going to use `y` sticky mode for repeated matches, you'll probably want to look for opportunities to have `lastIndex` automatically positioned as we've just demonstrated.\n\n#### Sticky Versus Global\n\nSome readers may be aware that you can emulate something like this `lastIndex`-relative matching with the `g` global match flag and the `exec(..)` method, as so:\n\n```js\nvar re = /o+./g,\t\t// <-- look, `g`!\n\tstr = \"foot book more\";\n\nre.exec( str );\t\t\t// [\"oot\"]\nre.lastIndex;\t\t\t// 4\n\nre.exec( str );\t\t\t// [\"ook\"]\nre.lastIndex;\t\t\t// 9\n\nre.exec( str );\t\t\t// [\"or\"]\nre.lastIndex;\t\t\t// 13\n\nre.exec( str );\t\t\t// null -- no more matches!\nre.lastIndex;\t\t\t// 0 -- starts over now!\n```\n\nWhile it's true that `g` pattern matches with `exec(..)` start their matching from `lastIndex`'s current value, and also update `lastIndex` after each match (or failure), this is not the same thing as `y`'s behavior.\n\nNotice in the previous snippet that `\"ook\"`, located at position `6`, was matched and found by the second `exec(..)` call, even though at the time, `lastIndex` was `4` (from the end of the previous match). Why? Because as we said earlier, non-sticky matches are free to move ahead in their matching. A sticky mode expression would have failed here, because it would not be allowed to move ahead.\n\nIn addition to perhaps undesired move-ahead matching behavior, another downside to just using `g` instead of `y` is that `g` changes the behavior of some matching methods, like `str.match(re)`.\n\nConsider:\n\n```js\nvar re = /o+./g,\t\t// <-- look, `g`!\n\tstr = \"foot book more\";\n\nstr.match( re );\t\t// [\"oot\",\"ook\",\"or\"]\n```\n\nSee how all the matches were returned at once? Sometimes that's OK, but sometimes that's not what you want.\n\nThe `y` sticky flag will give you one-at-a-time progressive matching with utilities like `test(..)` and `match(..)`. Just make sure the `lastIndex` is always in the right position for each match!\n\n#### Anchored Sticky\n\nAs we warned earlier, it's inaccurate to think of sticky mode as implying a pattern starts with `^`. The `^` anchor has a distinct meaning in regular expressions, which is *not altered* by sticky mode. `^` is an anchor that *always* refers to the beginning of the input, and *is not* in any way relative to `lastIndex`.\n\nBesides poor/inaccurate documentation on this topic, the confusion is unfortunately strengthened further because an older pre-ES6 experiment with sticky mode in Firefox *did* make `^` relative to `lastIndex`, so that behavior has been around for years.\n\nES6 elected not to do it that way. `^` in a pattern means start-of-input absolutely and only.\n\nAs a consequence, a pattern like `/^foo/y` will always and only find a `\"foo\"` match at the beginning of a string, *if it's allowed to match there*. If `lastIndex` is not `0`, the match will fail. Consider:\n\n```js\nvar re = /^foo/y,\n\tstr = \"foo\";\n\nre.test( str );\t\t\t// true\nre.test( str );\t\t\t// false\nre.lastIndex;\t\t\t// 0 -- reset after failure\n\nre.lastIndex = 1;\nre.test( str );\t\t\t// false -- failed for positioning\nre.lastIndex;\t\t\t// 0 -- reset after failure\n```\n\nBottom line: `y` plus `^` plus `lastIndex > 0` is an incompatible combination that will always cause a failed match.\n\n**Note:** While `y` does not alter the meaning of `^` in any way, the `m` multiline mode *does*, such that `^` means start-of-input *or* start of text after a newline. So, if you combine `y` and `m` flags together for a pattern, you can find multiple `^`-rooted matches in a string. But remember: because it's `y` sticky, you'll have to make sure `lastIndex` is pointing at the correct new line position (likely by matching to the end of the line) each subsequent time, or no subsequent matches will be made.\n\n### Regular Expression `flags`\n\nPrior to ES6, if you wanted to examine a regular expression object to see what flags it had applied, you needed to parse them out -- ironically, probably with another regular expression -- from the content of the `source` property, such as:\n\n```js\nvar re = /foo/ig;\n\nre.toString();\t\t\t// \"/foo/ig\"\n\nvar flags = re.toString().match( /\\/([gim]*)$/ )[1];\n\nflags;\t\t\t\t\t// \"ig\"\n```\n\nAs of ES6, you can now get these values directly, with the new `flags` property:\n\n```js\nvar re = /foo/ig;\n\nre.flags;\t\t\t\t// \"gi\"\n```\n\nIt's a small nuance, but the ES6 specification calls for the expression's flags to be listed in this order: `\"gimuy\"`, regardless of what order the original pattern was specified with. That's the reason for the difference between `/ig` and `\"gi\"`.\n\nNo, the order of flags specified or listed doesn't matter.\n\nAnother tweak from ES6 is that the `RegExp(..)` constructor is now `flags`-aware if you pass it an existing regular expression:\n\n```js\nvar re1 = /foo*/y;\nre1.source;\t\t\t\t\t\t\t// \"foo*\"\nre1.flags;\t\t\t\t\t\t\t// \"y\"\n\nvar re2 = new RegExp( re1 );\nre2.source;\t\t\t\t\t\t\t// \"foo*\"\nre2.flags;\t\t\t\t\t\t\t// \"y\"\n\nvar re3 = new RegExp( re1, \"ig\" );\nre3.source;\t\t\t\t\t\t\t// \"foo*\"\nre3.flags;\t\t\t\t\t\t\t// \"gi\"\n```\n\nPrior to ES6, the `re3` construction would throw an error, but as of ES6 you can override the flags when duplicating.\n\n## Number Literal Extensions\n\nPrior to ES5, number literals looked like the following -- the octal form was not officially specified, only allowed as an extension that browsers had come to de facto agreement on:\n\n```js\nvar dec = 42,\n\toct = 052,\n\thex = 0x2a;\n```\n\n**Note:** Though you are specifying a number in different bases, the number's mathematic value is what is stored, and the default output interpretation is always base-10. The three variables in the previous snippet all have the `42` value stored in them.\n\nTo further illustrate that `052` was a nonstandard form extension, consider:\n\n```js\nNumber( \"42\" );\t\t\t\t// 42\nNumber( \"052\" );\t\t\t// 52\nNumber( \"0x2a\" );\t\t\t// 42\n```\n\nES5 continued to permit the browser-extended octal form (including such inconsistencies), except that in strict mode, the octal literal (`052`) form is disallowed. This restriction was done mainly because many developers had the habit (from other languages) of seemingly innocuously prefixing otherwise base-10 numbers with `0`'s for code alignment purposes, and then running into the accidental fact that they'd changed the number value entirely!\n\nES6 continues the legacy of changes/variations to how number literals outside base-10 numbers can be represented. There's now an official octal form, an amended hexadecimal form, and a brand-new binary form. For web compatibility reasons, the old octal `052` form will continue to be legal (though unspecified) in non-strict mode, but should really never be used anymore.\n\nHere are the new ES6 number literal forms:\n\n```js\nvar dec = 42,\n\toct = 0o52,\t\t\t// or `0O52` :(\n\thex = 0x2a,\t\t\t// or `0X2a` :/\n\tbin = 0b101010;\t\t// or `0B101010` :/\n```\n\nThe only decimal form allowed is base-10. Octal, hexadecimal, and binary are all integer forms.\n\nAnd the string representations of these forms are all able to be coerced/converted to their number equivalent:\n\n```js\nNumber( \"42\" );\t\t\t// 42\nNumber( \"0o52\" );\t\t// 42\nNumber( \"0x2a\" );\t\t// 42\nNumber( \"0b101010\" );\t// 42\n```\n\nThough not strictly new to ES6, it's a little-known fact that you can actually go the opposite direction of conversion (well, sort of):\n\n```js\nvar a = 42;\n\na.toString();\t\t\t// \"42\" -- also `a.toString( 10 )`\na.toString( 8 );\t\t// \"52\"\na.toString( 16 );\t\t// \"2a\"\na.toString( 2 );\t\t// \"101010\"\n```\n\nIn fact, you can represent a number this way in any base from `2` to `36`, though it'd be rare that you'd go outside the standard bases: 2, 8, 10, and 16.\n\n## Unicode\n\nLet me just say that this section is not an exhaustive everything-you-ever-wanted-to-know-about-Unicode resource. I want to cover what you need to know that's *changing* for Unicode in ES6, but we won't go much deeper than that. Mathias Bynens (http://twitter.com/mathias) has written/spoken extensively and brilliantly about JS and Unicode (see https://mathiasbynens.be/notes/javascript-unicode and http://fluentconf.com/javascript-html-2015/public/content/2015/02/18-javascript-loves-unicode).\n\nThe Unicode characters that range from `0x0000` to `0xFFFF` contain all the standard printed characters (in various languages) that you're likely to have seen or interacted with. This group of characters is called the *Basic Multilingual Plane (BMP)*. The BMP even contains fun symbols like this cool snowman: ☃ (U+2603).\n\nThere are lots of other extended Unicode characters beyond this BMP set, which range up to `0x10FFFF`. These symbols are often referred to as *astral* symbols, as that's the name given to the set of 16 *planes* (e.g., layers/groupings) of characters beyond the BMP. Examples of astral symbols include 𝄞 (U+1D11E) and 💩 (U+1F4A9).\n\nPrior to ES6, JavaScript strings could specify Unicode characters using Unicode escaping, such as:\n\n```js\nvar snowman = \"\\u2603\";\nconsole.log( snowman );\t\t\t// \"☃\"\n```\n\nHowever, the `\\uXXXX` Unicode escaping only supports four hexadecimal characters, so you can only represent the BMP set of characters in this way. To represent an astral character using Unicode escaping prior to ES6, you need to use a *surrogate pair* -- basically two specially calculated Unicode-escaped characters side by side, which JS interprets together as a single astral character:\n\n```js\nvar gclef = \"\\uD834\\uDD1E\";\nconsole.log( gclef );\t\t\t// \"𝄞\"\n```\n\nAs of ES6, we now have a new form for Unicode escaping (in strings and regular expressions), called Unicode *code point escaping*:\n\n```js\nvar gclef = \"\\u{1D11E}\";\nconsole.log( gclef );\t\t\t// \"𝄞\"\n```\n\nAs you can see, the difference is the presence of the `{ }` in the escape sequence, which allows it to contain any number of hexadecimal characters. Because you only need six to represent the highest possible code point value in Unicode (i.e., 0x10FFFF), this is sufficient.\n\n### Unicode-Aware String Operations\n\nBy default, JavaScript string operations and methods are not sensitive to astral symbols in string values. So, they treat each BMP character individually, even the two surrogate halves that make up an otherwise single astral character. Consider:\n\n```js\nvar snowman = \"☃\";\nsnowman.length;\t\t\t\t\t// 1\n\nvar gclef = \"𝄞\";\ngclef.length;\t\t\t\t\t// 2\n```\n\nSo, how do we accurately calculate the length of such a string? In this scenario, the following trick will work:\n\n```js\nvar gclef = \"𝄞\";\n\n[...gclef].length;\t\t\t\t// 1\nArray.from( gclef ).length;\t\t// 1\n```\n\nRecall from the \"`for..of` Loops\" section earlier in this chapter that ES6 strings have built-in iterators. This iterator happens to be Unicode-aware, meaning it will automatically output an astral symbol as a single value. We take advantage of that using the `...` spread operator in an array literal, which creates an array of the string's symbols. Then we just inspect the length of that resultant array. ES6's `Array.from(..)` does basically the same thing as `[...XYZ]`, but we'll cover that utility in detail in Chapter 6.\n\n**Warning:** It should be noted that constructing and exhausting an iterator just to get the length of a string is quite expensive on performance, relatively speaking, compared to what a theoretically optimized native utility/property would do.\n\nUnfortunately, the full answer is not as simple or straightforward. In addition to the surrogate pairs (which the string iterator takes care of), there are special Unicode code points that behave in other special ways, which is much harder to account for. For example, there's a set of code points that modify the previous adjacent character, known as *Combining Diacritical Marks*.\n\nConsider these two string outputs:\n\n```js\nconsole.log( s1 );\t\t\t\t// \"é\"\nconsole.log( s2 );\t\t\t\t// \"é\"\n```\n\nThey look the same, but they're not! Here's how we created `s1` and `s2`:\n\n```js\nvar s1 = \"\\xE9\",\n\ts2 = \"e\\u0301\";\n```\n\nAs you can probably guess, our previous `length` trick doesn't work with `s2`:\n\n```js\n[...s1].length;\t\t\t\t\t// 1\n[...s2].length;\t\t\t\t\t// 2\n```\n\nSo what can we do? In this case, we can perform a *Unicode normalization* on the value before inquiring about its length, using the ES6 `String#normalize(..)` utility (which we'll cover more in Chapter 6):\n\n```js\nvar s1 = \"\\xE9\",\n\ts2 = \"e\\u0301\";\n\ns1.normalize().length;\t\t\t// 1\ns2.normalize().length;\t\t\t// 1\n\ns1 === s2;\t\t\t\t\t\t// false\ns1 === s2.normalize();\t\t\t// true\n```\n\nEssentially, `normalize(..)` takes a sequence like `\"e\\u0301\"` and normalizes it to `\"\\xE9\"`. Normalization can even combine multiple adjacent combining marks if there's a suitable Unicode character they combine to:\n\n```js\nvar s1 = \"o\\u0302\\u0300\",\n\ts2 = s1.normalize(),\n\ts3 = \"ồ\";\n\ns1.length;\t\t\t\t\t\t// 3\ns2.length;\t\t\t\t\t\t// 1\ns3.length;\t\t\t\t\t\t// 1\n\ns2 === s3;\t\t\t\t\t\t// true\n```\n\nUnfortunately, normalization isn't fully perfect here, either. If you have multiple combining marks modifying a single character, you may not get the length count you'd expect, because there may not be a single defined normalized character that represents the combination of all the marks. For example:\n\n```js\nvar s1 = \"e\\u0301\\u0330\";\n\nconsole.log( s1 );\t\t\t\t// \"ḛ́\"\n\ns1.normalize().length;\t\t\t// 2\n```\n\nThe further you go down this rabbit hole, the more you realize that it's difficult to get one precise definition for \"length.\" What we see visually rendered as a single character -- more precisely called a *grapheme* -- doesn't always strictly relate to a single \"character\" in the program processing sense.\n\n**Tip:** If you want to see just how deep this rabbit hole goes, check out the \"Grapheme Cluster Boundaries\" algorithm (http://www.Unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries).\n\n### Character Positioning\n\nSimilar to length complications, what does it actually mean to ask, \"what is the character at position 2?\" The naive pre-ES6 answer comes from `charAt(..)`, which will not respect the atomicity of an astral character, nor will it take into account combining marks.\n\nConsider:\n\n```js\nvar s1 = \"abc\\u0301d\",\n\ts2 = \"ab\\u0107d\",\n\ts3 = \"ab\\u{1d49e}d\";\n\nconsole.log( s1 );\t\t\t\t// \"abćd\"\nconsole.log( s2 );\t\t\t\t// \"abćd\"\nconsole.log( s3 );\t\t\t\t// \"ab𝒞d\"\n\ns1.charAt( 2 );\t\t\t\t\t// \"c\"\ns2.charAt( 2 );\t\t\t\t\t// \"ć\"\ns3.charAt( 2 );\t\t\t\t\t// \"\" <-- unprintable surrogate\ns3.charAt( 3 );\t\t\t\t\t// \"\" <-- unprintable surrogate\n```\n\nSo, is ES6 giving us a Unicode-aware version of `charAt(..)`? Unfortunately, no. At the time of this writing, there's a proposal for such a utility that's under consideration for post-ES6.\n\nBut with what we explored in the previous section (and of course with the limitations noted thereof!), we can hack an ES6 answer:\n\n```js\nvar s1 = \"abc\\u0301d\",\n\ts2 = \"ab\\u0107d\",\n\ts3 = \"ab\\u{1d49e}d\";\n\n[...s1.normalize()][2];\t\t\t// \"ć\"\n[...s2.normalize()][2];\t\t\t// \"ć\"\n[...s3.normalize()][2];\t\t\t// \"𝒞\"\n```\n\n**Warning:** Reminder of an earlier warning: constructing and exhausting an iterator each time you want to get at a single character is... very not ideal, performance wise. Let's hope we get a built-in and optimized utility for this soon, post-ES6.\n\nWhat about a Unicode-aware version of the `charCodeAt(..)` utility? ES6 gives us `codePointAt(..)`:\n\n```js\nvar s1 = \"abc\\u0301d\",\n\ts2 = \"ab\\u0107d\",\n\ts3 = \"ab\\u{1d49e}d\";\n\ns1.normalize().codePointAt( 2 ).toString( 16 );\n// \"107\"\n\ns2.normalize().codePointAt( 2 ).toString( 16 );\n// \"107\"\n\ns3.normalize().codePointAt( 2 ).toString( 16 );\n// \"1d49e\"\n```\n\nWhat about the other direction? A Unicode-aware version of `String.fromCharCode(..)` is ES6's `String.fromCodePoint(..)`:\n\n```js\nString.fromCodePoint( 0x107 );\t\t// \"ć\"\n\nString.fromCodePoint( 0x1d49e );\t// \"𝒞\"\n```\n\nSo wait, can we just combine `String.fromCodePoint(..)` and `codePointAt(..)` to get a better version of a Unicode-aware `charAt(..)` from earlier? Yep!\n\n```js\nvar s1 = \"abc\\u0301d\",\n\ts2 = \"ab\\u0107d\",\n\ts3 = \"ab\\u{1d49e}d\";\n\nString.fromCodePoint( s1.normalize().codePointAt( 2 ) );\n// \"ć\"\n\nString.fromCodePoint( s2.normalize().codePointAt( 2 ) );\n// \"ć\"\n\nString.fromCodePoint( s3.normalize().codePointAt( 2 ) );\n// \"𝒞\"\n```\n\nThere's quite a few other string methods we haven't addressed here, including `toUpperCase()`, `toLowerCase()`, `substring(..)`, `indexOf(..)`, `slice(..)`, and a dozen others. None of these have been changed or augmented for full Unicode awareness, so you should be very careful -- probably just avoid them! -- when working with strings containing astral symbols.\n\nThere are also several string methods that use regular expressions for their behavior, like `replace(..)` and `match(..)`. Thankfully, ES6 brings Unicode awareness to regular expressions, as we covered in \"Unicode Flag\" earlier in this chapter.\n\nOK, there we have it! JavaScript's Unicode string support is significantly better over pre-ES6 (though still not perfect) with the various additions we've just covered.\n\n### Unicode Identifier Names\n\nUnicode can also be used in identifier names (variables, properties, etc.). Prior to ES6, you could do this with Unicode-escapes, like:\n\n```js\nvar \\u03A9 = 42;\n\n// same as: var Ω = 42;\n```\n\nAs of ES6, you can also use the earlier explained code point escape syntax:\n\n```js\nvar \\u{2B400} = 42;\n\n// same as: var 𫐀 = 42;\n```\n\nThere's a complex set of rules around exactly which Unicode characters are allowed. Furthermore, some are allowed only if they're not the first character of the identifier name.\n\n**Note:** Mathias Bynens has a great post (https://mathiasbynens.be/notes/javascript-identifiers-es6) on all the nitty-gritty details.\n\nThe reasons for using such unusual characters in identifier names are rather rare and academic. You typically won't be best served by writing code that relies on these esoteric capabilities.\n\n## Symbols\n\nWith ES6, for the first time in quite a while, a new primitive type has been added to JavaScript: the `symbol`. Unlike the other primitive types, however, symbols don't have a literal form.\n\nHere's how you create a symbol:\n\n```js\nvar sym = Symbol( \"some optional description\" );\n\ntypeof sym;\t\t// \"symbol\"\n```\n\nSome things to note:\n\n* You cannot and should not use `new` with `Symbol(..)`. It's not a constructor, nor are you producing an object.\n* The parameter passed to `Symbol(..)` is optional. If passed, it should be a string that gives a friendly description for the symbol's purpose.\n* The `typeof` output is a new value (`\"symbol\"`) that is the primary way to identify a symbol.\n\nThe description, if provided, is solely used for the stringification representation of the symbol:\n\n```js\nsym.toString();\t\t// \"Symbol(some optional description)\"\n```\n\nSimilar to how primitive string values are not instances of `String`, symbols are also not instances of `Symbol`. If, for some reason, you want to construct a boxed wrapper object form of a symbol value, you can do the following:\n\n```js\nsym instanceof Symbol;\t\t// false\n\nvar symObj = Object( sym );\nsymObj instanceof Symbol;\t// true\n\nsymObj.valueOf() === sym;\t// true\n```\n\n**Note:** `symObj` in this snippet is interchangeable with `sym`; either form can be used in all places symbols are utilized. There's not much reason to use the boxed wrapper object form (`symObj`) instead of the primitive form (`sym`). Keeping with similar advice for other primitives, it's probably best to prefer `sym` over `symObj`.\n\nThe internal value of a symbol itself -- referred to as its `name` -- is hidden from the code and cannot be obtained. You can think of this symbol value as an automatically generated, unique (within your application) string value.\n\nBut if the value is hidden and unobtainable, what's the point of having a symbol at all?\n\nThe main point of a symbol is to create a string-like value that can't collide with any other value. So, for example, consider using a symbol as a constant representing an event name:\n\n```js\nconst EVT_LOGIN = Symbol( \"event.login\" );\n```\n\nYou'd then use `EVT_LOGIN` in place of a generic string literal like `\"event.login\"`:\n\n```js\nevthub.listen( EVT_LOGIN, function(data){\n\t// ..\n} );\n```\n\nThe benefit here is that `EVT_LOGIN` holds a value that cannot be duplicated (accidentally or otherwise) by any other value, so it is impossible for there to be any confusion of which event is being dispatched or handled.\n\n**Note:** Under the covers, the `evthub` utility assumed in the previous snippet would almost certainly be using the symbol value from the `EVT_LOGIN` argument directly as the property/key in some internal object (hash) that tracks event handlers. If `evthub` instead needed to use the symbol value as a real string, it would need to explicitly coerce with `String(..)` or `toString()`, as implicit string coercion of symbols is not allowed.\n\nYou may use a symbol directly as a property name/key in an object, such as a special property that you want to treat as hidden or meta in usage. It's important to know that although you intend to treat it as such, it is not *actually* a hidden or untouchable property.\n\nConsider this module that implements the *singleton* pattern behavior -- that is, it only allows itself to be created once:\n\n```js\nconst INSTANCE = Symbol( \"instance\" );\n\nfunction HappyFace() {\n\tif (HappyFace[INSTANCE]) return HappyFace[INSTANCE];\n\n\tfunction smile() { .. }\n\n\treturn HappyFace[INSTANCE] = {\n\t\tsmile: smile\n\t};\n}\n\nvar me = HappyFace(),\n\tyou = HappyFace();\n\nme === you;\t\t\t// true\n```\n\nThe `INSTANCE` symbol value here is a special, almost hidden, meta-like property stored statically on the `HappyFace()` function object.\n\nIt could alternatively have been a plain old property like `__instance`, and the behavior would have been identical. The usage of a symbol simply improves the metaprogramming style, keeping this `INSTANCE` property set apart from any other normal properties.\n\n### Symbol Registry\n\nOne mild downside to using symbols as in the last few examples is that the `EVT_LOGIN` and `INSTANCE` variables had to be stored in an outer scope (perhaps even the global scope), or otherwise somehow stored in a publicly available location, so that all parts of the code that need to use the symbols can access them.\n\nTo aid in organizing code with access to these symbols, you can create symbol values with the *global symbol registry*. For example:\n\n```js\nconst EVT_LOGIN = Symbol.for( \"event.login\" );\n\nconsole.log( EVT_LOGIN );\t\t// Symbol(event.login)\n```\n\nAnd:\n\n```js\nfunction HappyFace() {\n\tconst INSTANCE = Symbol.for( \"instance\" );\n\n\tif (HappyFace[INSTANCE]) return HappyFace[INSTANCE];\n\n\t// ..\n\n\treturn HappyFace[INSTANCE] = { .. };\n}\n```\n\n`Symbol.for(..)` looks in the global symbol registry to see if a symbol is already stored with the provided description text, and returns it if so. If not, it creates one to return. In other words, the global symbol registry treats symbol values, by description text, as singletons themselves.\n\nBut that also means that any part of your application can retrieve the symbol from the registry using `Symbol.for(..)`, as long as the matching description name is used.\n\nIronically, symbols are basically intended to replace the use of *magic strings* (arbitrary string values given special meaning) in your application. But you precisely use *magic* description string values to uniquely identify/locate them in the global symbol registry!\n\nTo avoid accidental collisions, you'll probably want to make your symbol descriptions quite unique. One easy way of doing that is to include prefix/context/namespacing information in them.\n\nFor example, consider a utility such as the following:\n\n```js\nfunction extractValues(str) {\n\tvar key = Symbol.for( \"extractValues.parse\" ),\n\t\tre = extractValues[key] ||\n\t\t\t/[^=&]+?=([^&]+?)(?=&|$)/g,\n\t\tvalues = [], match;\n\n\twhile (match = re.exec( str )) {\n\t\tvalues.push( match[1] );\n\t}\n\n\treturn values;\n}\n```\n\nWe use the magic string value `\"extractValues.parse\"` because it's quite unlikely that any other symbol in the registry would ever collide with that description.\n\nIf a user of this utility wants to override the parsing regular expression, they can also use the symbol registry:\n\n```js\nextractValues[Symbol.for( \"extractValues.parse\" )] =\n\t/..some pattern../g;\n\nextractValues( \"..some string..\" );\n```\n\nAside from the assistance the symbol registry provides in globally storing these values, everything we're seeing here could have been done by just actually using the magic string `\"extractValues.parse\"` as the key, rather than the symbol. The improvements exist at the metaprogramming level more than the functional level.\n\nYou may have occasion to use a symbol value that has been stored in the registry to look up what description text (key) it's stored under. For example, you may need to signal to another part of your application how to locate a symbol in the registry because you cannot pass the symbol value itself.\n\nYou can retrieve a registered symbol's description text (key) using `Symbol.keyFor(..)`:\n\n```js\nvar s = Symbol.for( \"something cool\" );\n\nvar desc = Symbol.keyFor( s );\nconsole.log( desc );\t\t\t// \"something cool\"\n\n// get the symbol from the registry again\nvar s2 = Symbol.for( desc );\n\ns2 === s;\t\t\t\t\t\t// true\n```\n\n### Symbols as Object Properties\n\nIf a symbol is used as a property/key of an object, it's stored in a special way so that the property will not show up in a normal enumeration of the object's properties:\n\n```js\nvar o = {\n\tfoo: 42,\n\t[ Symbol( \"bar\" ) ]: \"hello world\",\n\tbaz: true\n};\n\nObject.getOwnPropertyNames( o );\t// [ \"foo\",\"baz\" ]\n```\n\nTo retrieve an object's symbol properties:\n\n```js\nObject.getOwnPropertySymbols( o );\t// [ Symbol(bar) ]\n```\n\nThis makes it clear that a property symbol is not actually hidden or inaccessible, as you can always see it in the `Object.getOwnPropertySymbols(..)` list.\n\n#### Built-In Symbols\n\nES6 comes with a number of predefined built-in symbols that expose various meta behaviors on JavaScript object values. However, these symbols are *not* registered in the global symbol registry, as one might expect.\n\nInstead, they're stored as properties on the `Symbol` function object. For example, in the \"`for..of`\" section earlier in this chapter, we introduced the `Symbol.iterator` value:\n\n```js\nvar a = [1,2,3];\n\na[Symbol.iterator];\t\t\t// native function\n```\n\nThe specification uses the `@@` prefix notation to refer to the built-in symbols, the most common ones being: `@@iterator`, `@@toStringTag`, `@@toPrimitive`. Several others are defined as well, though they probably won't be used as often.\n\n**Note:** See \"Well Known Symbols\" in Chapter 7 for detailed information about how these built-in symbols are used for meta programming purposes.\n\n## Review\n\nES6 adds a heap of new syntax forms to JavaScript, so there's plenty to learn!\n\nMost of these are designed to ease the pain points of common programming idioms, such as setting default values to function parameters and gathering the \"rest\" of the parameters into an array. Destructuring is a powerful tool for more concisely expressing assignments of values from arrays and nested objects.\n\nWhile features like `=>` arrow functions appear to also be all about shorter and nicer-looking syntax, they actually have very specific behaviors that you should intentionally use only in appropriate situations.\n\nExpanded Unicode support, new tricks for regular expressions, and even a new primitive `symbol` type round out the syntactic evolution of ES6.\n"
  },
  {
    "path": "es6 & beyond/ch3.md",
    "content": "# You Don't Know JS: ES6 & Beyond\n# Chapter 3: Organization\n\nIt's one thing to write JS code, but it's another to properly organize it. Utilizing common patterns for organization and reuse goes a long way to improving the readability and understandability of your code. Remember: code is at least as much about communicating to other developers as it is about feeding the computer instructions.\n\nES6 has several important features that help significantly improve these patterns, including: iterators, generators, modules, and classes.\n\n## Iterators\n\nAn *iterator* is a structured pattern for pulling information from a source in one-at-a-time fashion. This pattern has been around programming for a long time. And to be sure, JS developers have been ad hoc designing and implementing iterators in JS programs since before anyone can remember, so it's not at all a new topic.\n\nWhat ES6 has done is introduce an implicit standardized interface for iterators. Many of the built-in data structures in JavaScript will now expose an iterator implementing this standard. And you can also construct your own iterators adhering to the same standard, for maximal interoperability.\n\nIterators are a way of organizing ordered, sequential, pull-based consumption of data.\n\nFor example, you may implement a utility that produces a new unique identifier each time it's requested. Or you may produce an infinite series of values that rotate through a fixed list, in round-robin fashion. Or you could attach an iterator to a database query result to pull out new rows one at a time.\n\nAlthough they have not commonly been used in JS in such a manner, iterators can also be thought of as controlling behavior one step at a time. This can be illustrated quite clearly when considering generators (see \"Generators\" later in this chapter), though you can certainly do the same without generators.\n\n### Interfaces\n\nAt the time of this writing, ES6 section 25.1.1.2 (https://people.mozilla.org/~jorendorff/es6-draft.html#sec-iterator-interface) details the `Iterator` interface as having the following requirement:\n\n```\nIterator [required]\n\tnext() {method}: retrieves next IteratorResult\n```\n\nThere are two optional members that some iterators are extended with:\n\n```\nIterator [optional]\n\treturn() {method}: stops iterator and returns IteratorResult\n\tthrow() {method}: signals error and returns IteratorResult\n```\n\nThe `IteratorResult` interface is specified as:\n\n```\nIteratorResult\n\tvalue {property}: current iteration value or final return value\n\t\t(optional if `undefined`)\n\tdone {property}: boolean, indicates completion status\n```\n\n**Note:** I call these interfaces implicit not because they're not explicitly called out in the specification -- they are! -- but because they're not exposed as direct objects accessible to code. JavaScript does not, in ES6, support any notion of \"interfaces,\" so adherence for your own code is purely conventional. However, wherever JS expects an iterator -- a `for..of` loop, for instance -- what you provide must adhere to these interfaces or the code will fail.\n\nThere's also an `Iterable` interface, which describes objects that must be able to produce iterators:\n\n```\nIterable\n\t@@iterator() {method}: produces an Iterator\n```\n\nIf you recall from \"Built-In Symbols\" in Chapter 2, `@@iterator` is the special built-in symbol representing the method that can produce iterator(s) for the object.\n\n#### IteratorResult\n\nThe `IteratorResult` interface specifies that the return value from any iterator operation will be an object of the form:\n\n```js\n{ value: .. , done: true / false }\n```\n\nBuilt-in iterators will always return values of this form, but more properties are, of course, allowed to be present on the return value, as necessary.\n\nFor example, a custom iterator may add additional metadata to the result object (e.g., where the data came from, how long it took to retrieve, cache expiration length, frequency for the appropriate next request, etc.).\n\n**Note:** Technically, `value` is optional if it would otherwise be considered absent or unset, such as in the case of the value `undefined`. Because accessing `res.value` will produce `undefined` whether it's present with that value or absent entirely, the presence/absence of the property is more an implementation detail or an optimization (or both), rather than a functional issue.\n\n### `next()` Iteration\n\nLet's look at an array, which is an iterable, and the iterator it can produce to consume its values:\n\n```js\nvar arr = [1,2,3];\n\nvar it = arr[Symbol.iterator]();\n\nit.next();\t\t// { value: 1, done: false }\nit.next();\t\t// { value: 2, done: false }\nit.next();\t\t// { value: 3, done: false }\n\nit.next();\t\t// { value: undefined, done: true }\n```\n\nEach time the method located at `Symbol.iterator` (see Chapters 2 and 7) is invoked on this `arr` value, it will produce a new fresh iterator. Most structures will do the same, including all the built-in data structures in JS.\n\nHowever, a structure like an event queue consumer might only ever produce a single iterator (singleton pattern). Or a structure might only allow one unique iterator at a time, requiring the current one to be completed before a new one can be created.\n\nThe `it` iterator in the previous snippet doesn't report `done: true` when you receive the `3` value. You have to call `next()` again, in essence going beyond the end of the array's values, to get the complete signal `done: true`. It may not be clear why until later in this section, but that design decision will typically be considered a best practice.\n\nPrimitive string values are also iterables by default:\n\n```js\nvar greeting = \"hello world\";\n\nvar it = greeting[Symbol.iterator]();\n\nit.next();\t\t// { value: \"h\", done: false }\nit.next();\t\t// { value: \"e\", done: false }\n..\n```\n\n**Note:** Technically, the primitive value itself isn't iterable, but thanks to \"boxing\", `\"hello world\"` is coerced/converted to its `String` object wrapper form, which *is* an iterable. See the *Types & Grammar* title of this series for more information.\n\nES6 also includes several new data structures, called collections (see Chapter 5). These collections are not only iterables themselves, but they also provide API method(s) to generate an iterator, such as:\n\n```js\nvar m = new Map();\nm.set( \"foo\", 42 );\nm.set( { cool: true }, \"hello world\" );\n\nvar it1 = m[Symbol.iterator]();\nvar it2 = m.entries();\n\nit1.next();\t\t// { value: [ \"foo\", 42 ], done: false }\nit2.next();\t\t// { value: [ \"foo\", 42 ], done: false }\n..\n```\n\nThe `next(..)` method of an iterator can optionally take one or more arguments. The built-in iterators mostly do not exercise this capability, though a generator's iterator definitely does (see \"Generators\" later in this chapter).\n\nBy general convention, including all the built-in iterators, calling `next(..)` on an iterator that's already been exhausted is not an error, but will simply continue to return the result `{ value: undefined, done: true }`.\n\n### Optional: `return(..)` and `throw(..)`\n\nThe optional methods on the iterator interface -- `return(..)` and `throw(..)` -- are not implemented on most of the built-in iterators. However, they definitely do mean something in the context of generators, so see \"Generators\" for more specific information.\n\n`return(..)` is defined as sending a signal to an iterator that the consuming code is complete and will not be pulling any more values from it. This signal can be used to notify the producer (the iterator responding to `next(..)` calls) to perform any cleanup it may need to do, such as releasing/closing network, database, or file handle resources.\n\nIf an iterator has a `return(..)` present and any condition occurs that can automatically be interpreted as abnormal or early termination of consuming the iterator, `return(..)` will automatically be called. You can call `return(..)` manually as well.\n\n`return(..)` will return an `IteratorResult` object just like `next(..)` does. In general, the optional value you send to `return(..)` would be sent back as `value` in this `IteratorResult`, though there are nuanced cases where that might not be true.\n\n`throw(..)` is used to signal an exception/error to an iterator, which possibly may be used differently by the iterator than the completion signal implied by `return(..)`. It does not necessarily imply a complete stop of the iterator as `return(..)` generally does.\n\nFor example, with generator iterators, `throw(..)` actually injects a thrown exception into the generator's paused execution context, which can be caught with a `try..catch`. An uncaught `throw(..)` exception would end up abnormally aborting the generator's iterator.\n\n**Note:** By general convention, an iterator should not produce any more results after having called `return(..)` or `throw(..)`.\n\n### Iterator Loop\n\nAs we covered in the \"`for..of`\" section in Chapter 2, the ES6 `for..of` loop directly consumes a conforming iterable.\n\nIf an iterator is also an iterable, it can be used directly with the `for..of` loop. You make an iterator an iterable by giving it a `Symbol.iterator` method that simply returns the iterator itself:\n\n```js\nvar it = {\n\t// make the `it` iterator an iterable\n\t[Symbol.iterator]() { return this; },\n\n\tnext() { .. },\n\t..\n};\n\nit[Symbol.iterator]() === it;\t\t// true\n```\n\nNow we can consume the `it` iterator with a `for..of` loop:\n\n```js\nfor (var v of it) {\n\tconsole.log( v );\n}\n```\n\nTo fully understand how such a loop works, recall the `for` equivalent of a `for..of` loop from Chapter 2:\n\n```js\nfor (var v, res; (res = it.next()) && !res.done; ) {\n\tv = res.value;\n\tconsole.log( v );\n}\n```\n\nIf you look closely, you'll see that `it.next()` is called before each iteration, and then `res.done` is consulted. If `res.done` is `true`, the expression evaluates to `false` and the iteration doesn't occur.\n\nRecall earlier that we suggested iterators should in general not return `done: true` along with the final intended value from the iterator. Now you can see why.\n\nIf an iterator returned `{ done: true, value: 42 }`, the `for..of` loop would completely discard the `42` value and it'd be lost. For this reason, assuming that your iterator may be consumed by patterns like the `for..of` loop or its manual `for` equivalent, you should probably wait to return `done: true` for signaling completion until after you've already returned all relevant iteration values.\n\n**Warning:** You can, of course, intentionally design your iterator to return some relevant `value` at the same time as returning `done: true`. But don't do this unless you've documented that as the case, and thus implicitly forced consumers of your iterator to use a different pattern for iteration than is implied by `for..of` or its manual equivalent we depicted.\n\n### Custom Iterators\n\nIn addition to the standard built-in iterators, you can make your own! All it takes to make them interoperate with ES6's consumption facilities (e.g., the `for..of` loop and the `...` operator) is to adhere to the proper interface(s).\n\nLet's try constructing an iterator that produces the infinite series of numbers in the Fibonacci sequence:\n\n```js\nvar Fib = {\n\t[Symbol.iterator]() {\n\t\tvar n1 = 1, n2 = 1;\n\n\t\treturn {\n\t\t\t// make the iterator an iterable\n\t\t\t[Symbol.iterator]() { return this; },\n\n\t\t\tnext() {\n\t\t\t\tvar current = n2;\n\t\t\t\tn2 = n1;\n\t\t\t\tn1 = n1 + current;\n\t\t\t\treturn { value: current, done: false };\n\t\t\t},\n\n\t\t\treturn(v) {\n\t\t\t\tconsole.log(\n\t\t\t\t\t\"Fibonacci sequence abandoned.\"\n\t\t\t\t);\n\t\t\t\treturn { value: v, done: true };\n\t\t\t}\n\t\t};\n\t}\n};\n\nfor (var v of Fib) {\n\tconsole.log( v );\n\n\tif (v > 50) break;\n}\n// 1 1 2 3 5 8 13 21 34 55\n// Fibonacci sequence abandoned.\n```\n\n**Warning:** If we hadn't inserted the `break` condition, this `for..of` loop would have run forever, which is probably not the desired result in terms of breaking your program!\n\nThe `Fib[Symbol.iterator]()` method when called returns the iterator object with `next()` and `return(..)` methods on it. State is maintained via `n1` and `n2` variables, which are kept by the closure.\n\nLet's *next* consider an iterator that is designed to run through a series (aka a queue) of actions, one item at a time:\n\n```js\nvar tasks = {\n\t[Symbol.iterator]() {\n\t\tvar steps = this.actions.slice();\n\n\t\treturn {\n\t\t\t// make the iterator an iterable\n\t\t\t[Symbol.iterator]() { return this; },\n\n\t\t\tnext(...args) {\n\t\t\t\tif (steps.length > 0) {\n\t\t\t\t\tlet res = steps.shift()( ...args );\n\t\t\t\t\treturn { value: res, done: false };\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treturn { done: true }\n\t\t\t\t}\n\t\t\t},\n\n\t\t\treturn(v) {\n\t\t\t\tsteps.length = 0;\n\t\t\t\treturn { value: v, done: true };\n\t\t\t}\n\t\t};\n\t},\n\tactions: []\n};\n```\n\nThe iterator on `tasks` steps through functions found in the `actions` array property, if any, and executes them one at a time, passing in whatever arguments you pass to `next(..)`, and returning any return value to you in the standard `IteratorResult` object.\n\nHere's how we could use this `tasks` queue:\n\n```js\ntasks.actions.push(\n\tfunction step1(x){\n\t\tconsole.log( \"step 1:\", x );\n\t\treturn x * 2;\n\t},\n\tfunction step2(x,y){\n\t\tconsole.log( \"step 2:\", x, y );\n\t\treturn x + (y * 2);\n\t},\n\tfunction step3(x,y,z){\n\t\tconsole.log( \"step 3:\", x, y, z );\n\t\treturn (x * y) + z;\n\t}\n);\n\nvar it = tasks[Symbol.iterator]();\n\nit.next( 10 );\t\t\t// step 1: 10\n\t\t\t\t\t\t// { value:   20, done: false }\n\nit.next( 20, 50 );\t\t// step 2: 20 50\n\t\t\t\t\t\t// { value:  120, done: false }\n\nit.next( 20, 50, 120 );\t// step 3: 20 50 120\n\t\t\t\t\t\t// { value: 1120, done: false }\n\nit.next();\t\t\t\t// { done: true }\n```\n\nThis particular usage reinforces that iterators can be a pattern for organizing functionality, not just data. It's also reminiscent of what we'll see with generators in the next section.\n\nYou could even get creative and define an iterator that represents meta operations on a single piece of data. For example, we could define an iterator for numbers that by default ranges from `0` up to (or down to, for negative numbers) the number in question.\n\nConsider:\n\n```js\nif (!Number.prototype[Symbol.iterator]) {\n\tObject.defineProperty(\n\t\tNumber.prototype,\n\t\tSymbol.iterator,\n\t\t{\n\t\t\twritable: true,\n\t\t\tconfigurable: true,\n\t\t\tenumerable: false,\n\t\t\tvalue: function iterator(){\n\t\t\t\tvar i, inc, done = false, top = +this;\n\n\t\t\t\t// iterate positively or negatively?\n\t\t\t\tinc = 1 * (top < 0 ? -1 : 1);\n\n\t\t\t\treturn {\n\t\t\t\t\t// make the iterator itself an iterable!\n\t\t\t\t\t[Symbol.iterator](){ return this; },\n\n\t\t\t\t\tnext() {\n\t\t\t\t\t\tif (!done) {\n\t\t\t\t\t\t\t// initial iteration always 0\n\t\t\t\t\t\t\tif (i == null) {\n\t\t\t\t\t\t\t\ti = 0;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// iterating positively\n\t\t\t\t\t\t\telse if (top >= 0) {\n\t\t\t\t\t\t\t\ti = Math.min(top,i + inc);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// iterating negatively\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\ti = Math.max(top,i + inc);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// done after this iteration?\n\t\t\t\t\t\t\tif (i == top) done = true;\n\n\t\t\t\t\t\t\treturn { value: i, done: false };\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\treturn { done: true };\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t);\n}\n```\n\nNow, what tricks does this creativity afford us?\n\n```js\nfor (var i of 3) {\n\tconsole.log( i );\n}\n// 0 1 2 3\n\n[...-3];\t\t\t\t// [0,-1,-2,-3]\n```\n\nThose are some fun tricks, though the practical utility is somewhat debatable. But then again, one might wonder why ES6 didn't just ship with such a minor but delightful feature easter egg!?\n\nI'd be remiss if I didn't at least remind you that extending native prototypes as I'm doing in the previous snippet is something you should only do with caution and awareness of potential hazards.\n\nIn this case, the chances that you'll have a collision with other code or even a future JS feature is probably exceedingly low. But just beware of the slight possibility. And document what you're doing verbosely for posterity's sake.\n\n**Note:** I've expounded on this particular technique in this blog post (http://blog.getify.com/iterating-es6-numbers/) if you want more details. And this comment (http://blog.getify.com/iterating-es6-numbers/comment-page-1/#comment-535294) even suggests a similar trick but for making string character ranges.\n\n### Iterator Consumption\n\nWe've already shown consuming an iterator item by item with the `for..of` loop. But there are other ES6 structures that can consume iterators.\n\nLet's consider the iterator attached to this array (though any iterator we choose would have the following behaviors):\n\n```js\nvar a = [1,2,3,4,5];\n```\n\nThe `...` spread operator fully exhausts an iterator. Consider:\n\n```js\nfunction foo(x,y,z,w,p) {\n\tconsole.log( x + y + z + w + p );\n}\n\nfoo( ...a );\t\t\t// 15\n```\n\n`...` can also spread an iterator inside an array:\n\n```js\nvar b = [ 0, ...a, 6 ];\nb;\t\t\t\t\t\t// [0,1,2,3,4,5,6]\n```\n\nArray destructuring (see \"Destructuring\" in Chapter 2) can partially or completely (if paired with a `...` rest/gather operator) consume an iterator:\n\n```js\nvar it = a[Symbol.iterator]();\n\nvar [x,y] = it;\t\t\t// take just the first two elements from `it`\nvar [z, ...w] = it;\t\t// take the third, then the rest all at once\n\n// is `it` fully exhausted? Yep.\nit.next();\t\t\t\t// { value: undefined, done: true }\n\nx;\t\t\t\t\t\t// 1\ny;\t\t\t\t\t\t// 2\nz;\t\t\t\t\t\t// 3\nw;\t\t\t\t\t\t// [4,5]\n```\n\n## Generators\n\nAll functions run to completion, right? In other words, once a function starts running, it finishes before anything else can interrupt.\n\nAt least that's how it's been for the whole history of JavaScript up to this point. As of ES6, a new somewhat exotic form of function is being introduced, called a generator. A generator can pause itself in mid-execution, and can be resumed either right away or at a later time. So it clearly does not hold the run-to-completion guarantee that normal functions do.\n\nMoreover, each pause/resume cycle in mid-execution is an opportunity for two-way message passing, where the generator can return a value, and the controlling code that resumes it can send a value back in.\n\nAs with iterators in the previous section, there are multiple ways to think about what a generator is, or rather what it's most useful for. There's no one right answer, but we'll try to consider several angles.\n\n**Note:** See the *Async & Performance* title of this series for more information about generators, and also see Chapter 4 of this current title.\n\n### Syntax\n\nThe generator function is declared with this new syntax:\n\n```js\nfunction *foo() {\n\t// ..\n}\n```\n\nThe position of the `*` is not functionally relevant. The same declaration could be written as any of the following:\n\n```js\nfunction *foo()  { .. }\nfunction* foo()  { .. }\nfunction * foo() { .. }\nfunction*foo()   { .. }\n..\n```\n\nThe *only* difference here is stylistic preference. Most other literature seems to prefer `function* foo(..) { .. }`. I prefer `function *foo(..) { .. }`, so that's how I'll present them for the rest of this title.\n\nMy reason is purely didactic in nature. In this text, when referring to a generator function, I will use `*foo(..)`, as opposed to `foo(..)` for a normal function. I observe that `*foo(..)` more closely matches the `*` positioning of `function *foo(..) { .. }`.\n\nMoreover, as we saw in Chapter 2 with concise methods, there's a concise generator form in object literals:\n\n```js\nvar a = {\n\t*foo() { .. }\n};\n```\n\nI would say that with concise generators, `*foo() { .. }` is rather more natural than `* foo() { .. }`. So that further argues for matching the consistency with `*foo()`.\n\nConsistency eases understanding and learning.\n\n#### Executing a Generator\n\nThough a generator is declared with `*`, you still execute it like a normal function:\n\n```js\nfoo();\n```\n\nYou can still pass it arguments, as in:\n\n```js\nfunction *foo(x,y) {\n\t// ..\n}\n\nfoo( 5, 10 );\n```\n\nThe major difference is that executing a generator, like `foo(5,10)` doesn't actually run the code in the generator. Instead, it produces an iterator that will control the generator to execute its code.\n\nWe'll come back to this later in \"Iterator Control,\" but briefly:\n\n```js\nfunction *foo() {\n\t// ..\n}\n\nvar it = foo();\n\n// to start/advanced `*foo()`, call\n// `it.next(..)`\n```\n\n#### `yield`\n\nGenerators also have a new keyword you can use inside them, to signal the pause point: `yield`. Consider:\n\n```js\nfunction *foo() {\n\tvar x = 10;\n\tvar y = 20;\n\n\tyield;\n\n\tvar z = x + y;\n}\n```\n\nIn this `*foo()` generator, the operations on the first two lines would run at the beginning, then `yield` would pause the generator. If and when resumed, the last line of `*foo()` would run. `yield` can appear any number of times (or not at all, technically!) in a generator.\n\nYou can even put `yield` inside a loop, and it can represent a repeated pause point. In fact, a loop that never completes just means a generator that never completes, which is completely valid, and sometimes entirely what you need.\n\n`yield` is not just a pause point. It's an expression that sends out a value when pausing the generator. Here's a `while..true` loop in a generator that for each iteration `yield`s a new random number:\n\n```js\nfunction *foo() {\n\twhile (true) {\n\t\tyield Math.random();\n\t}\n}\n```\n\nThe `yield ..` expression not only sends a value -- `yield` without a value is the same as `yield undefined` -- but also receives (e.g., is replaced by) the eventual resumption value. Consider:\n\n```js\nfunction *foo() {\n\tvar x = yield 10;\n\tconsole.log( x );\n}\n```\n\nThis generator will first `yield` out the value `10` when pausing itself. When you resume the generator -- using the `it.next(..)` we referred to earlier -- whatever value (if any) you resume with will replace/complete the whole `yield 10` expression, meaning that value will be assigned to the `x` variable.\n\nA `yield ..` expression can appear anywhere a normal expression can. For example:\n\n```js\nfunction *foo() {\n\tvar arr = [ yield 1, yield 2, yield 3 ];\n\tconsole.log( arr, yield 4 );\n}\n```\n\n`*foo()` here has four `yield ..` expressions. Each `yield` results in the generator pausing to wait for a resumption value that's then used in the various expression contexts.\n\n`yield` is not technically an operator, though when used like `yield 1` it sure looks like it. Because `yield` can be used all by itself as in `var x = yield;`, thinking of it as an operator can sometimes be confusing.\n\nTechnically, `yield ..` is of the same \"expression precedence\" -- similar conceptually to operator precedence -- as an assignment expression like `a = 3`. That means `yield ..` can basically appear anywhere `a = 3` can validly appear.\n\nLet's illustrate the symmetry:\n\n```js\nvar a, b;\n\na = 3;\t\t\t\t\t// valid\nb = 2 + a = 3;\t\t\t// invalid\nb = 2 + (a = 3);\t\t// valid\n\nyield 3;\t\t\t\t// valid\na = 2 + yield 3;\t\t// invalid\na = 2 + (yield 3);\t\t// valid\n```\n\n**Note:** If you think about it, it makes a sort of conceptual sense that a `yield ..` expression would behave similar to an assignment expression. When a paused `yield` expression is resumed, it's completed/replaced by the resumption value in a way that's not terribly dissimilar from being \"assigned\" that value.\n\nThe takeaway: if you need `yield ..` to appear in a position where an assignment like `a = 3` would not itself be allowed, it needs to be wrapped in a `( )`.\n\nBecause of the low precedence of the `yield` keyword, almost any expression after a `yield ..` will be computed first before being sent with `yield`. Only the `...` spread operator and the `,` comma operator have lower precedence, meaning they'd bind after the `yield` has been evaluated.\n\nSo just like with multiple operators in normal statements, another case where `( )` might be needed is to override (elevate) the low precedence of `yield`, such as the difference between these expressions:\n\n```js\nyield 2 + 3;\t\t\t// same as `yield (2 + 3)`\n\n(yield 2) + 3;\t\t\t// `yield 2` first, then `+ 3`\n```\n\nJust like `=` assignment, `yield` is also \"right-associative,\" which means that multiple `yield` expressions in succession are treated as having been `( .. )` grouped from right to left. So, `yield yield yield 3` is treated as `yield (yield (yield 3))`. A \"left-associative\" interpretation like `((yield) yield) yield 3` would make no sense.\n\nJust like with operators, it's a good idea to use `( .. )` grouping, even if not strictly required, to disambiguate your intent if `yield` is combined with other operators or `yield`s.\n\n**Note:** See the *Types & Grammar* title of this series for more information about operator precedence and associativity.\n\n#### `yield *`\n\nIn the same way that the `*` makes a `function` declaration into `function *` generator declaration, a `*` makes `yield` into `yield *`, which is a very different mechanism, called *yield delegation*. Grammatically, `yield *..` will behave the same as a `yield ..`, as discussed in the previous section.\n\n`yield * ..` requires an iterable; it then invokes that iterable's iterator, and delegates its own host generator's control to that iterator until it's exhausted. Consider:\n\n```js\nfunction *foo() {\n\tyield *[1,2,3];\n}\n```\n\n**Note:** As with the `*` position in a generator's declaration (discussed earlier), the `*` positioning in `yield *` expressions is stylistically up to you. Most other literature prefers `yield* ..`, but I prefer `yield *..`, for very symmetrical reasons as already discussed.\n\nThe `[1,2,3]` value produces an iterator that will step through its values, so the `*foo()` generator will yield those values out as it's consumed. Another way to illustrate the behavior is in yield delegating to another generator:\n\n```js\nfunction *foo() {\n\tyield 1;\n\tyield 2;\n\tyield 3;\n}\n\nfunction *bar() {\n\tyield *foo();\n}\n```\n\nThe iterator produced when `*bar()` calls `*foo()` is delegated to via `yield *`, meaning whatever value(s) `*foo()` produces will be produced by `*bar()`.\n\nWhereas with `yield ..` the completion value of the expression comes from resuming the generator with `it.next(..)`, the completion value of the `yield *..` expression comes from the return value (if any) from the delegated-to iterator.\n\nBuilt-in iterators generally don't have return values, as we covered at the end of the \"Iterator Loop\" section earlier in this chapter. But if you define your own custom iterator (or generator), you can design it to `return` a value, which `yield *..` would capture:\n\n```js\nfunction *foo() {\n\tyield 1;\n\tyield 2;\n\tyield 3;\n\treturn 4;\n}\n\nfunction *bar() {\n\tvar x = yield *foo();\n\tconsole.log( \"x:\", x );\n}\n\nfor (var v of bar()) {\n\tconsole.log( v );\n}\n// 1 2 3\n// x: { value: 4, done: true }\n```\n\nWhile the `1`, `2`, and `3` values are `yield`ed out of `*foo()` and then out of `*bar()`, the `4` value returned from `*foo()` is the completion value of the `yield *foo()` expression, which then gets assigned to `x`.\n\nBecause `yield *` can call another generator (by way of delegating to its iterator), it can also perform a sort of generator recursion by calling itself:\n\n```js\nfunction *foo(x) {\n\tif (x < 3) {\n\t\tx = yield *foo( x + 1 );\n\t}\n\treturn x * 2;\n}\n\nfoo( 1 );\n```\n\nThe result from `foo(1)` and then calling the iterator's `next()` to run it through its recursive steps will be `24`. The first `*foo(..)` run has `x` at value `1`, which is `x < 3`. `x + 1` is passed recursively to `*foo(..)`, so `x` is then `2`. One more recursive call results in `x` of `3`.\n\nNow, because `x < 3` fails, the recursion stops, and `return 3 * 2` gives `6` back to the previous call's `yield *..` expression, which is then assigned to `x`. Another `return 6 * 2` returns `12` back to the previous call's `x`. Finally `12 * 2`, or `24`, is returned from the completed run of the `*foo(..)` generator.\n\n### Iterator Control\n\nEarlier, we briefly introduced the concept that generators are controlled by iterators. Let's fully dig into that now.\n\nRecall the recursive `*foo(..)` from the previous section. Here's how we'd run it:\n\n```js\nfunction *foo(x) {\n\tif (x < 3) {\n\t\tx = yield *foo( x + 1 );\n\t}\n\treturn x * 2;\n}\n\nvar it = foo( 1 );\nit.next();\t\t\t\t// { value: 24, done: true }\n```\n\nIn this case, the generator doesn't really ever pause, as there's no `yield ..` expression. Instead, `yield *` just keeps the current iteration step going via the recursive call. So, just one call to the iterator's `next()` function fully runs the generator.\n\nNow let's consider a generator that will have multiple steps and thus multiple produced values:\n\n```js\nfunction *foo() {\n\tyield 1;\n\tyield 2;\n\tyield 3;\n}\n```\n\nWe already know we can consume an iterator, even one attached to a generator like `*foo()`, with a `for..of` loop:\n\n```js\nfor (var v of foo()) {\n\tconsole.log( v );\n}\n// 1 2 3\n```\n\n**Note:** The `for..of` loop requires an iterable. A generator function reference (like `foo`) by itself is not an iterable; you must execute it with `foo()` to get the iterator (which is also an iterable, as we explained earlier in this chapter). You could theoretically extend the `GeneratorPrototype` (the prototype of all generator functions) with a `Symbol.iterator` function that essentially just does `return this()`. That would make the `foo` reference itself an iterable, which means `for (var v of foo) { .. }` (notice no `()` on `foo`) will work.\n\nLet's instead iterate the generator manually:\n\n```js\nfunction *foo() {\n\tyield 1;\n\tyield 2;\n\tyield 3;\n}\n\nvar it = foo();\n\nit.next();\t\t\t\t// { value: 1, done: false }\nit.next();\t\t\t\t// { value: 2, done: false }\nit.next();\t\t\t\t// { value: 3, done: false }\n\nit.next();\t\t\t\t// { value: undefined, done: true }\n```\n\nIf you look closely, there are three `yield` statements and four `next()` calls. That may seem like a strange mismatch. In fact, there will always be one more `next()` call than `yield` expression, assuming all are evaluated and the generator is fully run to completion.\n\nBut if you look at it from the opposite perspective (inside-out instead of outside-in), the matching between `yield` and `next()` makes more sense.\n\nRecall that the `yield ..` expression will be completed by the value you resume the generator with. That means the argument you pass to `next(..)` completes whatever `yield ..` expression is currently paused waiting for a completion.\n\nLet's illustrate this perspective this way:\n\n```js\nfunction *foo() {\n\tvar x = yield 1;\n\tvar y = yield 2;\n\tvar z = yield 3;\n\tconsole.log( x, y, z );\n}\n```\n\nIn this snippet, each `yield ..` is sending a value out (`1`, `2`, `3`), but more directly, it's pausing the generator to wait for a value. In other words, it's almost like asking the question, \"What value should I use here? I'll wait to hear back.\"\n\nNow, here's how we control `*foo()` to start it up:\n\n```js\nvar it = foo();\n\nit.next();\t\t\t\t// { value: 1, done: false }\n```\n\nThat first `next()` call is starting up the generator from its initial paused state, and running it to the first `yield`. At the moment you call that first `next()`, there's no `yield ..` expression waiting for a completion. If you passed a value to that first `next()` call, it would currently just be thrown away, because no `yield` is waiting to receive such a value.\n\n**Note:** An early proposal for the \"beyond ES6\" timeframe *would* let you access a value passed to an initial `next(..)` call via a separate meta property (see Chapter 7) inside the generator.\n\nNow, let's answer the currently pending question, \"What value should I assign to `x`?\" We'll answer it by sending a value to the *next* `next(..)` call:\n\n```js\nit.next( \"foo\" );\t\t// { value: 2, done: false }\n```\n\nNow, the `x` will have the value `\"foo\"`, but we've also asked a new question, \"What value should I assign to `y`?\" And we answer:\n\n```js\nit.next( \"bar\" );\t\t// { value: 3, done: false }\n```\n\nAnswer given, another question asked. Final answer:\n\n```js\nit.next( \"baz\" );\t\t// \"foo\" \"bar\" \"baz\"\n\t\t\t\t\t\t// { value: undefined, done: true }\n```\n\nNow it should be clearer how each `yield ..` \"question\" is answered by the *next* `next(..)` call, and so the \"extra\" `next()` call we observed is always just the initial one that starts everything going.\n\nLet's put all those steps together:\n\n```js\nvar it = foo();\n\n// start up the generator\nit.next();\t\t\t\t// { value: 1, done: false }\n\n// answer first question\nit.next( \"foo\" );\t\t// { value: 2, done: false }\n\n// answer second question\nit.next( \"bar\" );\t\t// { value: 3, done: false }\n\n// answer third question\nit.next( \"baz\" );\t\t// \"foo\" \"bar\" \"baz\"\n\t\t\t\t\t\t// { value: undefined, done: true }\n```\n\nYou can think of a generator as a producer of values, in which case each iteration is simply producing a value to be consumed.\n\nBut in a more general sense, perhaps it's appropriate to think of generators as controlled, progressive code execution, much like the `tasks` queue example from the earlier \"Custom Iterators\" section.\n\n**Note:** That perspective is exactly the motivation for how we'll revisit generators in Chapter 4. Specifically, there's no reason that `next(..)` has to be called right away after the previous `next(..)` finishes. While the generator's inner execution context is paused, the rest of the program continues unblocked, including the ability for asynchronous actions to control when the generator is resumed.\n\n### Early Completion\n\nAs we covered earlier in this chapter, the iterator attached to a generator supports the optional `return(..)` and `throw(..)` methods. Both of them have the effect of aborting a paused generator immediately.\n\nConsider:\n\n```js\nfunction *foo() {\n\tyield 1;\n\tyield 2;\n\tyield 3;\n}\n\nvar it = foo();\n\nit.next();\t\t\t\t// { value: 1, done: false }\n\nit.return( 42 );\t\t// { value: 42, done: true }\n\nit.next();\t\t\t\t// { value: undefined, done: true }\n```\n\n`return(x)` is kind of like forcing a `return x` to be processed at exactly that moment, such that you get the specified value right back. Once a generator is completed, either normally or early as shown, it no longer processes any code or returns any values.\n\nIn addition to `return(..)` being callable manually, it's also called automatically at the end of iteration by any of the ES6 constructs that consume iterators, such as the `for..of` loop and the `...` spread operator.\n\nThe purpose for this capability is so the generator can be notified if the controlling code is no longer going to iterate over it anymore, so that it can perhaps do any cleanup tasks (freeing up resources, resetting status, etc.). Identical to a normal function cleanup pattern, the main way to accomplish this is to use a `finally` clause:\n\n```js\nfunction *foo() {\n\ttry {\n\t\tyield 1;\n\t\tyield 2;\n\t\tyield 3;\n\t}\n\tfinally {\n\t\tconsole.log( \"cleanup!\" );\n\t}\n}\n\nfor (var v of foo()) {\n\tconsole.log( v );\n}\n// 1 2 3\n// cleanup!\n\nvar it = foo();\n\nit.next();\t\t\t\t// { value: 1, done: false }\nit.return( 42 );\t\t// cleanup!\n\t\t\t\t\t\t// { value: 42, done: true }\n```\n\n**Warning:** Do not put a `yield` statement inside the `finally` clause! It's valid and legal, but it's a really terrible idea. It acts in a sense as deferring the completion of the `return(..)` call you made, as any `yield ..` expressions in the `finally` clause are respected to pause and send messages; you don't immediately get a completed generator as expected. There's basically no good reason to opt in to that crazy *bad part*, so avoid doing so!\n\nIn addition to the previous snippet showing how `return(..)` aborts the generator while still triggering the `finally` clause, it also demonstrates that a generator produces a whole new iterator each time it's called. In fact, you can use multiple iterators attached to the same generator concurrently:\n\n```js\nfunction *foo() {\n\tyield 1;\n\tyield 2;\n\tyield 3;\n}\n\nvar it1 = foo();\nit1.next();\t\t\t\t// { value: 1, done: false }\nit1.next();\t\t\t\t// { value: 2, done: false }\n\nvar it2 = foo();\nit2.next();\t\t\t\t// { value: 1, done: false }\n\nit1.next();\t\t\t\t// { value: 3, done: false }\n\nit2.next();\t\t\t\t// { value: 2, done: false }\nit2.next();\t\t\t\t// { value: 3, done: false }\n\nit2.next();\t\t\t\t// { value: undefined, done: true }\nit1.next();\t\t\t\t// { value: undefined, done: true }\n```\n\n#### Early Abort\n\nInstead of calling `return(..)`, you can call `throw(..)`. Just like `return(x)` is essentially injecting a `return x` into the generator at its current pause point, calling `throw(x)` is essentially like injecting a `throw x` at the pause point.\n\nOther than the exception behavior (we cover what that means to `try` clauses in the next section), `throw(..)` produces the same sort of early completion that aborts the generator's run at its current pause point. For example:\n\n```js\nfunction *foo() {\n\tyield 1;\n\tyield 2;\n\tyield 3;\n}\n\nvar it = foo();\n\nit.next();\t\t\t\t// { value: 1, done: false }\n\ntry {\n\tit.throw( \"Oops!\" );\n}\ncatch (err) {\n\tconsole.log( err );\t// Exception: Oops!\n}\n\nit.next();\t\t\t\t// { value: undefined, done: true }\n```\n\nBecause `throw(..)` basically injects a `throw ..` in replacement of the `yield 1` line of the generator, and nothing handles this exception, it immediately propagates back out to the calling code, which handles it with a `try..catch`.\n\nUnlike `return(..)`, the iterator's `throw(..)` method is never called automatically.\n\nOf course, though not shown in the previous snippet, if a `try..finally` clause was waiting inside the generator when you call `throw(..)`, the `finally` clause would be given a chance to complete before the exception is propagated back to the calling code.\n\n### Error Handling\n\nAs we've already hinted, error handling with generators can be expressed with `try..catch`, which works in both inbound and outbound directions:\n\n```js\nfunction *foo() {\n\ttry {\n\t\tyield 1;\n\t}\n\tcatch (err) {\n\t\tconsole.log( err );\n\t}\n\n\tyield 2;\n\n\tthrow \"Hello!\";\n}\n\nvar it = foo();\n\nit.next();\t\t\t\t// { value: 1, done: false }\n\ntry {\n\tit.throw( \"Hi!\" );\t// Hi!\n\t\t\t\t\t\t// { value: 2, done: false }\n\tit.next();\n\n\tconsole.log( \"never gets here\" );\n}\ncatch (err) {\n\tconsole.log( err );\t// Hello!\n}\n```\n\nErrors can also propagate in both directions through `yield *` delegation:\n\n```js\nfunction *foo() {\n\ttry {\n\t\tyield 1;\n\t}\n\tcatch (err) {\n\t\tconsole.log( err );\n\t}\n\n\tyield 2;\n\n\tthrow \"foo: e2\";\n}\n\nfunction *bar() {\n\ttry {\n\t\tyield *foo();\n\n\t\tconsole.log( \"never gets here\" );\n\t}\n\tcatch (err) {\n\t\tconsole.log( err );\n\t}\n}\n\nvar it = bar();\n\ntry {\n\tit.next();\t\t\t// { value: 1, done: false }\n\n\tit.throw( \"e1\" );\t// e1\n\t\t\t\t\t\t// { value: 2, done: false }\n\n\tit.next();\t\t\t// foo: e2\n\t\t\t\t\t\t// { value: undefined, done: true }\n}\ncatch (err) {\n\tconsole.log( \"never gets here\" );\n}\n\nit.next();\t\t\t\t// { value: undefined, done: true }\n```\n\nWhen `*foo()` calls `yield 1`, the `1` value passes through `*bar()` untouched, as we've already seen.\n\nBut what's most interesting about this snippet is that when `*foo()` calls `throw \"foo: e2\"`, this error propagates to `*bar()` and is immediately caught by `*bar()`'s `try..catch` block. The error doesn't pass through `*bar()` like the `1` value did.\n\n`*bar()`'s `catch` then does a normal output of `err` (`\"foo: e2\"`) and then `*bar()` finishes normally, which is why the `{ value: undefined, done: true }` iterator result comes back from `it.next()`.\n\nIf `*bar()` didn't have a `try..catch` around the `yield *..` expression, the error would of course propagate all the way out, and on the way through it still would complete (abort) `*bar()`.\n\n### Transpiling a Generator\n\nIs it possible to represent a generator's capabilities prior to ES6? It turns out it is, and there are several great tools that do so, including most notably Facebook's Regenerator tool (https://facebook.github.io/regenerator/).\n\nBut just to better understand generators, let's try our hand at manually converting. Basically, we're going to create a simple closure-based state machine.\n\nWe'll keep our source generator really simple:\n\n```js\nfunction *foo() {\n\tvar x = yield 42;\n\tconsole.log( x );\n}\n```\n\nTo start, we'll need a function called `foo()` that we can execute, which needs to return an iterator:\n\n```js\nfunction foo() {\n\t// ..\n\n\treturn {\n\t\tnext: function(v) {\n\t\t\t// ..\n\t\t}\n\n\t\t// we'll skip `return(..)` and `throw(..)`\n\t};\n}\n```\n\nNow, we need some inner variable to keep track of where we are in the steps of our \"generator\"'s logic. We'll call it `state`. There will be three states: `0` initially, `1` while waiting to fulfill the `yield` expression, and `2` once the generator is complete.\n\nEach time `next(..)` is called, we need to process the next step, and then increment `state`. For convenience, we'll put each step into a `case` clause of a `switch` statement, and we'll hold that in an inner function called `nextState(..)` that `next(..)` can call. Also, because `x` is a variable across the overall scope of the \"generator,\" it needs to live outside the `nextState(..)` function.\n\nHere it is all together (obviously somewhat simplified, to keep the conceptual illustration clearer):\n\n```js\nfunction foo() {\n\tfunction nextState(v) {\n\t\tswitch (state) {\n\t\t\tcase 0:\n\t\t\t\tstate++;\n\n\t\t\t\t// the `yield` expression\n\t\t\t\treturn 42;\n\t\t\tcase 1:\n\t\t\t\tstate++;\n\n\t\t\t\t// `yield` expression fulfilled\n\t\t\t\tx = v;\n\t\t\t\tconsole.log( x );\n\n\t\t\t\t// the implicit `return`\n\t\t\t\treturn undefined;\n\n\t\t\t// no need to handle state `2`\n\t\t}\n\t}\n\n\tvar state = 0, x;\n\n\treturn {\n\t\tnext: function(v) {\n\t\t\tvar ret = nextState( v );\n\n\t\t\treturn { value: ret, done: (state == 2) };\n\t\t}\n\n\t\t// we'll skip `return(..)` and `throw(..)`\n\t};\n}\n```\n\nAnd finally, let's test our pre-ES6 \"generator\":\n\n```js\nvar it = foo();\n\nit.next();\t\t\t\t// { value: 42, done: false }\n\nit.next( 10 );\t\t\t// 10\n\t\t\t\t\t\t// { value: undefined, done: true }\n```\n\nNot bad, huh? Hopefully this exercise solidifies in your mind that generators are actually just simple syntax for state machine logic. That makes them widely applicable.\n\n### Generator Uses\n\nSo, now that we much more deeply understand how generators work, what are they useful for?\n\nWe've seen two major patterns:\n\n* *Producing a series of values:* This usage can be simple (e.g., random strings or incremented numbers), or it can represent more structured data access (e.g., iterating over rows returned from a database query).\n\n   Either way, we use the iterator to control a generator so that some logic can be invoked for each call to `next(..)`. Normal iterators on data structures merely pull values without any controlling logic.\n* *Queue of tasks to perform serially:* This usage often represents flow control for the steps in an algorithm, where each step requires retrieval of data from some external source. The fulfillment of each piece of data may be immediate, or may be asynchronously delayed.\n\n   From the perspective of the code inside the generator, the details of sync or async at a `yield` point are entirely opaque. Moreover, these details are intentionally abstracted away, such as not to obscure the natural sequential expression of steps with such implementation complications. Abstraction also means the implementations can be swapped/refactored often without touching the code in the generator at all.\n\nWhen generators are viewed in light of these uses, they become a lot more than just a different or nicer syntax for a manual state machine. They are a powerful abstraction tool for organizing and controlling orderly production and consumption of data.\n\n## Modules\n\nI don't think it's an exaggeration to suggest that the single most important code organization pattern in all of JavaScript is, and always has been, the module. For myself, and I think for a large cross-section of the community, the module pattern drives the vast majority of code.\n\n### The Old Way\n\nThe traditional module pattern is based on an outer function with inner variables and functions, and a returned \"public API\" with methods that have closure over the inner data and capabilities. It's often expressed like this:\n\n```js\nfunction Hello(name) {\n\tfunction greeting() {\n\t\tconsole.log( \"Hello \" + name + \"!\" );\n\t}\n\n\t// public API\n\treturn {\n\t\tgreeting: greeting\n\t};\n}\n\nvar me = Hello( \"Kyle\" );\nme.greeting();\t\t\t// Hello Kyle!\n```\n\nThis `Hello(..)` module can produce multiple instances by being called subsequent times. Sometimes, a module is only called for as a singleton (i.e., it just needs one instance), in which case a slight variation on the previous snippet, using an IIFE, is common:\n\n```js\nvar me = (function Hello(name){\n\tfunction greeting() {\n\t\tconsole.log( \"Hello \" + name + \"!\" );\n\t}\n\n\t// public API\n\treturn {\n\t\tgreeting: greeting\n\t};\n})( \"Kyle\" );\n\nme.greeting();\t\t\t// Hello Kyle!\n```\n\nThis pattern is tried and tested. It's also flexible enough to have a wide assortment of variations for a number of different scenarios.\n\nOne of the most common is the Asynchronous Module Definition (AMD), and another is the Universal Module Definition (UMD). We won't cover the particulars of these patterns and techniques here, but they're explained extensively in many places online.\n\n### Moving Forward\n\nAs of ES6, we no longer need to rely on the enclosing function and closure to provide us with module support. ES6 modules have first class syntactic and functional support.\n\nBefore we get into the specific syntax, it's important to understand some fairly significant conceptual differences with ES6 modules compared to how you may have dealt with modules in the past:\n\n* ES6 uses file-based modules, meaning one module per file. At this time, there is no standardized way of combining multiple modules into a single file.\n\n   That means that if you are going to load ES6 modules directly into a browser web application, you will be loading them individually, not as a large bundle in a single file as has been common in performance optimization efforts.\n\n   It's expected that the contemporaneous advent of HTTP/2 will significantly mitigate any such performance concerns, as it operates on a persistent socket connection and thus can very efficiently load many smaller files in parallel and interleaved with one another.\n* The API of an ES6 module is static. That is, you define statically what all the top-level exports are on your module's public API, and those cannot be amended later.\n\n   Some uses are accustomed to being able to provide dynamic API definitions, where methods can be added/removed/replaced in response to runtime conditions. Either these uses will have to change to fit with ES6 static APIs, or they will have to restrain the dynamic changes to properties/methods of a second-level object.\n* ES6 modules are singletons. That is, there's only one instance of the module, which maintains its state. Every time you import that module into another module, you get a reference to the one centralized instance. If you want to be able to produce multiple module instances, your module will need to provide some sort of factory to do it.\n* The properties and methods you expose on a module's public API are not just normal assignments of values or references. They are actual bindings (almost like pointers) to the identifiers in your inner module definition.\n\n   In pre-ES6 modules, if you put a property on your public API that holds a primitive value like a number or string, that property assignment was by value-copy, and any internal update of a corresponding variable would be separate and not affect the public copy on the API object.\n\n   With ES6, exporting a local private variable, even if it currently holds a primitive string/number/etc, exports a binding to the variable. If the module changes the  variable's value, the external import binding now resolves to that new value.\n* Importing a module is the same thing as statically requesting it to load (if it hasn't already). If you're in a browser, that implies a blocking load over the network. If you're on a server (i.e., Node.js), it's a blocking load from the filesystem.\n\n   However, don't panic about the performance implications. Because ES6 modules have static definitions, the import requirements can be statically scanned, and loads will happen preemptively, even before you've used the module.\n\n   ES6 doesn't actually specify or handle the mechanics of how these load requests work. There's a separate notion of a Module Loader, where each hosting environment (browser, Node.js, etc.) provides a default Loader appropriate to the environment. The importing of a module uses a string value to represent where to get the module (URL, file path, etc.), but this value is opaque in your program and only meaningful to the Loader itself.\n\n   You can define your own custom Loader if you want more fine-grained control than the default Loader affords -- which is basically none, as it's totally hidden from your program's code.\n\nAs you can see, ES6 modules will serve the overall use case of organizing code with encapsulation, controlling public APIs, and referencing dependency imports. But they have a very particular way of doing so, and that may or may not fit very closely with how you've already been doing modules for years.\n\n#### CommonJS\n\nThere's a similar, but not fully compatible, module syntax called CommonJS, which is familiar to those in the Node.js ecosystem.\n\nFor lack of a more tactful way to say this, in the long run, ES6 modules essentially are bound to supersede all previous formats and standards for modules, even CommonJS, as they are built on syntactic support in the language. This will, in time, inevitably win out as the superior approach, if for no other reason than ubiquity.\n\nWe face a fairly long road to get to that point, though. There are literally hundreds of thousands of CommonJS style modules in the server-side JavaScript world, and 10 times that many modules of varying format standards (UMD, AMD, ad hoc) in the browser world. It will take many years for the transitions to make any significant progress.\n\nIn the interim, module transpilers/converters will be an absolute necessity. You might as well just get used to that new reality. Whether you author in regular modules, AMD, UMD, CommonJS, or ES6, these tools will have to parse and convert to a format that is suitable for whatever environment your code will run in.\n\nFor Node.js, that probably means (for now) that the target is CommonJS. For the browser, it's probably UMD or AMD. Expect lots of flux on this over the next few years as these tools mature and best practices emerge.\n\nFrom here on out, my best advice on modules is this: whatever format you've been religiously attached to with strong affinity, also develop an appreciation for and understanding of ES6 modules, such as they are, and let your other module tendencies fade. They *are* the future of modules in JS, even if that reality is a bit of a ways off.\n\n### The New Way\n\nThe two main new keywords that enable ES6 modules are `import` and `export`. There's lots of nuance to the syntax, so let's take a deeper look.\n\n**Warning:** An important detail that's easy to overlook: both `import` and `export` must always appear in the top-level scope of their respective usage. For example, you cannot put either an `import` or `export` inside an `if` conditional; they must appear outside of all blocks and functions.\n\n#### `export`ing API Members\n\nThe `export` keyword is either put in front of a declaration, or used as an operator (of sorts) with a special list of bindings to export. Consider:\n\n```js\nexport function foo() {\n\t// ..\n}\n\nexport var awesome = 42;\n\nvar bar = [1,2,3];\nexport { bar };\n```\n\nAnother way of expressing the same exports:\n\n```js\nfunction foo() {\n\t// ..\n}\n\nvar awesome = 42;\nvar bar = [1,2,3];\n\nexport { foo, awesome, bar };\n```\n\nThese are all called *named exports*, as you are in effect exporting the name bindings of the variables/functions/etc.\n\nAnything you don't *label* with `export` stays private inside the scope of the module. That is, although something like `var bar = ..` looks like it's declaring at the top-level global scope, the top-level scope is actually the module itself; there is no global scope in modules.\n\n**Note:** Modules *do* still have access to `window` and all the \"globals\" that hang off it, just not as lexical top-level scope. However, you really should stay away from the globals in your modules if at all possible.\n\nYou can also \"rename\" (aka alias) a module member during named export:\n\n```js\nfunction foo() { .. }\n\nexport { foo as bar };\n```\n\nWhen this module is imported, only the `bar` member name is available to import; `foo` stays hidden inside the module.\n\nModule exports are not just normal assignments of values or references, as you're accustomed to with the `=` assignment operator. Actually, when you export something, you're exporting a binding (kinda like a pointer) to that thing (variable, etc.).\n\nWithin your module, if you change the value of a variable you already exported a binding to, even if it's already been imported (see the next section), the imported binding will resolve to the current (updated) value.\n\nConsider:\n\n```js\nvar awesome = 42;\nexport { awesome };\n\n// later\nawesome = 100;\n```\n\nWhen this module is imported, regardless of whether that's before or after the `awesome = 100` setting, once that assignment has happened, the imported binding resolves to the `100` value, not `42`.\n\nThat's because the binding is, in essence, a reference to, or a pointer to, the `awesome` variable itself, rather than a copy of its value. This is a mostly unprecedented concept for JS introduced with ES6 module bindings.\n\nThough you can clearly use `export` multiple times inside a module's definition, ES6 definitely prefers the approach that a module has a single export, which is known as a *default export*. In the words of some members of the TC39 committee, you're \"rewarded with simpler `import` syntax\" if you follow that pattern, and conversely \"penalized\" with more verbose syntax if you don't.\n\nA default export sets a particular exported binding to be the default when importing the module. The name of the binding is literally `default`. As you'll see later, when importing module bindings you can also rename them, as you commonly will with a default export.\n\nThere can only be one `default` per module definition. We'll cover `import` in the next section, and you'll see how the `import` syntax is more concise if the module has a default export.\n\nThere's a subtle nuance to default export syntax that you should pay close attention to. Compare these two snippets:\n\n```js\nfunction foo(..) {\n\t// ..\n}\n\nexport default foo;\n```\n\nAnd this one:\n\n```js\nfunction foo(..) {\n\t// ..\n}\n\nexport { foo as default };\n```\n\nIn the first snippet, you are exporting a binding to the function expression value at that moment, *not* to the identifier `foo`. In other words, `export default ..` takes an expression. If you later assign `foo` to a different value inside your module, the module import still reveals the function originally exported, not the new value.\n\nBy the way, the first snippet could also have been written as:\n\n```js\nexport default function foo(..) {\n\t// ..\n}\n```\n\n**Warning:** Although the `function foo..` part here is technically a function expression, for the purposes of the internal scope of the module, it's treated like a function declaration, in that the `foo` name is bound in the module's top-level scope (often called \"hoisting\"). The same is true for `export default class Foo..`. However, while you *can* do `export var foo = ..`, you currently cannot do `export default var foo = ..` (or `let` or `const`), in a frustrating case of inconsistency. At the time of this writing, there's already discussion of adding that capability in soon, post-ES6, for consistency sake.\n\nRecall the second snippet again:\n\n```js\nfunction foo(..) {\n\t// ..\n}\n\nexport { foo as default };\n```\n\nIn this version of the module export, the default export binding is actually to the `foo` identifier rather than its value, so you get the previously described binding behavior (i.e., if you later change `foo`'s value, the value seen on the import side will also be updated).\n\nBe very careful of this subtle gotcha in default export syntax, especially if your logic calls for export values to be updated. If you never plan to update a default export's value, `export default ..` is fine. If you do plan to update the value, you must use `export { .. as default }`. Either way, make sure to comment your code to explain your intent!\n\nBecause there can only be one `default` per module, you may be tempted to design your module with one default export of an object with all your API methods on it, such as:\n\n```js\nexport default {\n\tfoo() { .. },\n\tbar() { .. },\n\t..\n};\n```\n\nThat pattern seems to map closely to how a lot of developers have already structured their pre-ES6 modules, so it seems like a natural approach. Unfortunately, it has some downsides and is officially discouraged.\n\nIn particular, the JS engine cannot statically analyze the contents of a plain object, which means it cannot do some optimizations for static `import` performance. The advantage of having each member individually and explicitly exported is that the engine *can* do the static analysis and optimization.\n\nIf your API has more than one member already, it seems like these principles -- one default export per module, and all API members as named exports -- are in conflict, doesn't it? But you *can* have a single default export as well as other named exports; they are not mutually exclusive.\n\nSo, instead of this (discouraged) pattern:\n\n```js\nexport default function foo() { .. }\n\nfoo.bar = function() { .. };\nfoo.baz = function() { .. };\n```\n\nYou can do:\n\n```js\nexport default function foo() { .. }\n\nexport function bar() { .. }\nexport function baz() { .. }\n```\n\n**Note:** In this previous snippet, I used the name `foo` for the function that `default` labels. That `foo` name, however, is ignored for the purposes of export -- `default` is actually the exported name. When you import this default binding, you can give it whatever name you want, as you'll see in the next section.\n\nAlternatively, some will prefer:\n\n```js\nfunction foo() { .. }\nfunction bar() { .. }\nfunction baz() { .. }\n\nexport { foo as default, bar, baz, .. };\n```\n\nThe effects of mixing default and named exports will be more clear when we cover `import` shortly. But essentially it means that the most concise default import form would only retrieve the `foo()` function. The user could additionally manually list `bar` and `baz` as named imports, if they want them.\n\nYou can probably imagine how tedious that's going to be for consumers of your module if you have lots of named export bindings. There is a wildcard import form where you import all of a module's exports within a single namespace object, but there's no way to wildcard import to top-level bindings.\n\nAgain, the ES6 module mechanism is intentionally designed to discourage modules with lots of exports; relatively speaking, it's desired that such approaches be a little more difficult, as a sort of social engineering to encourage simple module design in favor of large/complex module design.\n\nI would probably recommend you not mix default export with named exports, especially if you have a large API and refactoring to separate modules isn't practical or desired. In that case, just use all named exports, and document that consumers of your module should probably use the `import * as ..` (namespace import, discussed in the next section) approach to bring the whole API in at once on a single namespace.\n\nWe mentioned this earlier, but let's come back to it in more detail. Other than the `export default ...` form that exports an expression value binding, all other export forms are exporting bindings to local identifiers. For those bindings, if you change the value of a variable inside a module after exporting, the external imported binding will access the updated value:\n\n```js\nvar foo = 42;\nexport { foo as default };\n\nexport var bar = \"hello world\";\n\nfoo = 10;\nbar = \"cool\";\n```\n\nWhen you import this module, the `default` and `bar` exports will be bound to the local variables `foo` and `bar`, meaning they will reveal the updated `10` and `\"cool\"` values. The values at time of export are irrelevant. The values at time of import are irrelevant. The bindings are live links, so all that matters is what the current value is when you access the binding.\n\n**Warning:** Two-way bindings are not allowed. If you import a `foo` from a module, and try to change the value of your imported `foo` variable, an error will be thrown! We'll revisit that in the next section.\n\nYou can also re-export another module's exports, such as:\n\n```js\nexport { foo, bar } from \"baz\";\nexport { foo as FOO, bar as BAR } from \"baz\";\nexport * from \"baz\";\n```\n\nThose forms are similar to just first importing from the `\"baz\"` module then listing its members explicitly for export from your module. However, in these forms, the members of the `\"baz\"` module are never imported to your module's local scope; they sort of pass through untouched.\n\n#### `import`ing API Members\n\nTo import a module, unsurprisingly you use the `import` statement. Just as `export` has several nuanced variations, so does `import`, so spend plenty of time considering the following issues and experimenting with your options.\n\nIf you want to import certain specific named members of a module's API into your top-level scope, you use this syntax:\n\n```js\nimport { foo, bar, baz } from \"foo\";\n```\n\n**Warning:** The `{ .. }` syntax here may look like an object literal, or even an object destructuring syntax. However, its form is special just for modules, so be careful not to confuse it with other `{ .. }` patterns elsewhere.\n\nThe `\"foo\"` string is called a *module specifier*. Because the whole goal is statically analyzable syntax, the module specifier must be a string literal; it cannot be a variable holding the string value.\n\nFrom the perspective of your ES6 code and the JS engine itself, the contents of this string literal are completely opaque and meaningless. The module loader will interpret this string as an instruction of where to find the desired module, either as a URL path or a local filesystem path.\n\nThe `foo`, `bar`, and `baz` identifiers listed must match named exports on the module's API (static analysis and error assertion apply). They are bound as top-level identifiers in your current scope:\n\n```js\nimport { foo } from \"foo\";\n\nfoo();\n```\n\nYou can rename the bound identifiers imported, as:\n\n```js\nimport { foo as theFooFunc } from \"foo\";\n\ntheFooFunc();\n```\n\nIf the module has just a default export that you want to import and bind to an identifier, you can opt to skip the `{ .. }` surrounding syntax for that binding. The `import` in this preferred case gets the nicest and most concise of the `import` syntax forms:\n\n```js\nimport foo from \"foo\";\n\n// or:\nimport { default as foo } from \"foo\";\n```\n\n**Note:** As explained in the previous section, the `default` keyword in a module's `export` specifies a named export where the name is actually `default`, as is illustrated by the second more verbose syntax option. The renaming from `default` to, in this case, `foo`, is explicit in the latter syntax and is identical yet implicit in the former syntax.\n\nYou can also import a default export along with other named exports, if the module has such a definition. Recall this module definition from earlier:\n\n```js\nexport default function foo() { .. }\n\nexport function bar() { .. }\nexport function baz() { .. }\n```\n\nTo import that module's default export and its two named exports:\n\n```js\nimport FOOFN, { bar, baz as BAZ } from \"foo\";\n\nFOOFN();\nbar();\nBAZ();\n```\n\nThe strongly suggested approach from ES6's module philosophy is that you only import the specific bindings from a module that you need. If a module provides 10 API methods, but you only need two of them, some believe it wasteful to bring in the entire set of API bindings.\n\nOne benefit, besides code being more explicit, is that narrow imports make static analysis and error detection (accidentally using the wrong binding name, for instance) more robust.\n\nOf course, that's just the standard position influenced by ES6 design philosophy; there's nothing that requires adherence to that approach.\n\nMany developers would be quick to point out that such approaches can be more tedious, requiring you to regularly revisit and update your `import` statement(s) each time you realize you need something else from a module. The trade-off is in exchange for convenience.\n\nIn that light, the preference might be to import everything from the module into a single namespace, rather than importing individual members, each directly into the scope. Fortunately, the `import` statement has a syntax variation that can support this style of module consumption, called *namespace import*.\n\nConsider a `\"foo\"` module exported as:\n\n```js\nexport function bar() { .. }\nexport var x = 42;\nexport function baz() { .. }\n```\n\nYou can import that entire API to a single module namespace binding:\n\n```js\nimport * as foo from \"foo\";\n\nfoo.bar();\nfoo.x;\t\t\t// 42\nfoo.baz();\n```\n\n**Note:** The `* as ..` clause requires the `*` wildcard. In other words, you cannot do something like `import { bar, x } as foo from \"foo\"` to bring in only part of the API but still bind to the `foo` namespace. I would have liked something like that, but for ES6 it's all or nothing with the namespace import.\n\nIf the module you're importing with `* as ..` has a default export, it is named `default` in the namespace specified. You can additionally name the default import outside of the namespace binding, as a top-level identifier. Consider a `\"world\"` module exported as:\n\n```js\nexport default function foo() { .. }\nexport function bar() { .. }\nexport function baz() { .. }\n```\n\nAnd this `import`:\n\n```js\nimport foofn, * as hello from \"world\";\n\nfoofn();\nhello.default();\nhello.bar();\nhello.baz();\n```\n\nWhile this syntax is valid, it can be rather confusing that one method of the module (the default export) is bound at the top-level of your scope, whereas the rest of the named exports (and one called `default`) are bound as properties on a differently named (`hello`) identifier namespace.\n\nAs I mentioned earlier, my suggestion would be to avoid designing your module exports in this way, to reduce the chances that your module's users will suffer these strange quirks.\n\nAll imported bindings are immutable and/or read-only. Consider the previous import; all of these subsequent assignment attempts will throw `TypeError`s:\n\n```js\nimport foofn, * as hello from \"world\";\n\nfoofn = 42;\t\t\t// (runtime) TypeError!\nhello.default = 42;\t// (runtime) TypeError!\nhello.bar = 42;\t\t// (runtime) TypeError!\nhello.baz = 42;\t\t// (runtime) TypeError!\n```\n\nRecall earlier in the \"`export`ing API Members\" section that we talked about how the `bar` and `baz` bindings are bound to the actual identifiers inside the `\"world\"` module. That means if the module changes those values, `hello.bar` and `hello.baz` now reference the updated values.\n\nBut the immutable/read-only nature of your local imported bindings enforces that you cannot change them from the imported bindings, hence the `TypeError`s. That's pretty important, because without those protections, your changes would end up affecting all other consumers of the module (remember: singleton), which could create some very surprising side effects!\n\nMoreover, though a module *can* change its API members from the inside, you should be very cautious of intentionally designing your modules in that fashion. ES6 modules are *intended* to be static, so deviations from that principle should be rare and should be carefully and verbosely documented.\n\n**Warning:** There are module design philosophies where you actually intend to let a consumer change the value of a property on your API, or module APIs are designed to be \"extended\" by having other \"plug-ins\" add to the API namespace. As we just asserted, ES6 module APIs should be thought of and designed as static and unchangeable, which strongly restricts and discourages these alternative module design patterns. You can get around these limitations by exporting a plain object, which of course can then be changed at will. But be careful and think twice before going down that road.\n\nDeclarations that occur as a result of an `import` are \"hoisted\" (see the *Scope & Closures* title of this series). Consider:\n\n```js\nfoo();\n\nimport { foo } from \"foo\";\n```\n\n`foo()` can run because not only did the static resolution of the `import ..` statement figure out what `foo` is during compilation, but it also \"hoisted\" the declaration to the top of the module's scope, thus making it available throughout the module.\n\nFinally, the most basic form of the `import` looks like this:\n\n```js\nimport \"foo\";\n```\n\nThis form does not actually import any of the module's bindings into your scope. It loads (if not already loaded), compiles (if not already compiled), and evaluates (if not already run) the `\"foo\"` module.\n\nIn general, that sort of import is probably not going to be terribly useful. There may be niche cases where a module's definition has side effects (such as assigning things to the `window`/global object). You could also envision using `import \"foo\"` as a sort of preload for a module that may be needed later.\n\n### Circular Module Dependency\n\nA imports B. B imports A. How does this actually work?\n\nI'll state off the bat that designing systems with intentional circular dependency is generally something I try to avoid. That having been said, I recognize there are reasons people do this and it can solve some sticky design situations.\n\nLet's consider how ES6 handles this. First, module `\"A\"`:\n\n```js\nimport bar from \"B\";\n\nexport default function foo(x) {\n\tif (x > 10) return bar( x - 1 );\n\treturn x * 2;\n}\n```\n\nNow, module `\"B\"`:\n\n```js\nimport foo from \"A\";\n\nexport default function bar(y) {\n\tif (y > 5) return foo( y / 2 );\n\treturn y * 3;\n}\n```\n\nThese two functions, `foo(..)` and `bar(..)`, would work as standard function declarations if they were in the same scope, because the declarations are \"hoisted\" to the whole scope and thus available to each other regardless of authoring order.\n\nWith modules, you have declarations in entirely different scopes, so ES6 has to do extra work to help make these circular references work.\n\nIn a rough conceptual sense, this is how circular `import` dependencies are validated and resolved:\n\n* If the `\"A\"` module is loaded first, the first step is to scan the file and analyze all the exports, so it can register all those bindings available for import. Then it processes the `import .. from \"B\"`, which signals that it needs to go fetch `\"B\"`.\n* Once the engine loads `\"B\"`, it does the same analysis of its export bindings. When it sees the `import .. from \"A\"`, it knows the API of `\"A\"` already, so it can verify the `import` is valid. Now that it knows the `\"B\"` API, it can also validate the `import .. from \"B\"` in the waiting `\"A\"` module.\n\nIn essence, the mutual imports, along with the static verification that's done to validate both `import` statements, virtually composes the two separate module scopes (via the bindings), such that `foo(..)` can call `bar(..)` and vice versa. This is symmetric to if they had originally been declared in the same scope.\n\nNow let's try using the two modules together. First, we'll try `foo(..)`:\n\n```js\nimport foo from \"foo\";\nfoo( 25 );\t\t\t\t// 11\n```\n\nOr we can try `bar(..)`:\n\n```js\nimport bar from \"bar\";\nbar( 25 );\t\t\t\t// 11.5\n```\n\nBy the time either the `foo(25)` or `bar(25)` calls are executed, all the analysis/compilation of all modules has completed. That means `foo(..)` internally knows directly about `bar(..)` and `bar(..)` internally knows directly about `foo(..)`.\n\nIf all we need is to interact with `foo(..)`, then we only need to import the `\"foo\"` module. Likewise with `bar(..)` and the `\"bar\"` module.\n\nOf course, we *can* import and use both of them if we want to:\n\n```js\nimport foo from \"foo\";\nimport bar from \"bar\";\n\nfoo( 25 );\t\t\t\t// 11\nbar( 25 );\t\t\t\t// 11.5\n```\n\nThe static loading semantics of the `import` statement mean that a `\"foo\"` and `\"bar\"` that mutually depend on each other via `import` will ensure that both are loaded, parsed, and compiled before either of them runs. So their circular dependency is statically resolved and this works as you'd expect.\n\n### Module Loading\n\nWe asserted at the beginning of this \"Modules\" section that the `import` statement uses a separate mechanism, provided by the hosting environment (browser, Node.js, etc.), to actually resolve the module specifier string into some useful instruction for finding and loading the desired module. That mechanism is the system *Module Loader*.\n\nThe default module loader provided by the environment will interpret a module specifier as a URL if in the browser, and (generally) as a local filesystem path if on a server such as Node.js. The default behavior is to assume the loaded file is authored in the ES6 standard module format.\n\nMoreover, you will be able to load a module into the browser via an HTML tag, similar to how current script programs are loaded. At the time of this writing, it's not fully clear if this tag will be `<script type=\"module\">` or `<module>`. ES6 doesn't control that decision, but discussions in the appropriate standards bodies are already well along in parallel of ES6.\n\nWhatever the tag looks like, you can be sure that under the covers it will use the default loader (or a customized one you've pre-specified, as we'll discuss in the next section).\n\nJust like the tag you'll use in markup, the module loader itself is not specified by ES6. It is a separate, parallel standard (http://whatwg.github.io/loader/) controlled currently by the WHATWG browser standards group.\n\nAt the time of this writing, the following discussions reflect an early pass at the API design, and things are likely to change.\n\n#### Loading Modules Outside of Modules\n\nOne use for interacting directly with the module loader is if a non-module needs to load a module. Consider:\n\n```js\n// normal script loaded in browser via `<script>`,\n// `import` is illegal here\n\nReflect.Loader.import( \"foo\" ) // returns a promise for `\"foo\"`\n.then( function(foo){\n\tfoo.bar();\n} );\n```\n\nThe `Reflect.Loader.import(..)` utility imports the entire module onto the named parameter (as a namespace), just like the `import * as foo ..` namespace import we discussed earlier.\n\n**Note:** The `Reflect.Loader.import(..)` utility returns a promise that is fulfilled once the module is ready. To import multiple modules, you can compose promises from multiple `Reflect.Loader.import(..)` calls using `Promise.all([ .. ])`. For more information about Promises, see \"Promises\" in Chapter 4.\n\nYou can also use `Reflect.Loader.import(..)` in a real module to dynamically/conditionally load a module, where `import` itself would not work. You might, for instance, choose to load a module containing a polyfill for some ES7+ feature if a feature test reveals it's not defined by the current engine.\n\nFor performance reasons, you'll want to avoid dynamic loading whenever possible, as it hampers the ability of the JS engine to fire off early fetches from its static analysis.\n\n#### Customized Loading\n\nAnother use for directly interacting with the module loader is if you want to customize its behavior through configuration or even redefinition.\n\nAt the time of this writing, there's a polyfill for the module loader API being developed (https://github.com/ModuleLoader/es6-module-loader). While details are scarce and highly subject to change, we can explore what possibilities may eventually land.\n\nThe `Reflect.Loader.import(..)` call may support a second argument for specifying various options to customize the import/load task. For example:\n\n```js\nReflect.Loader.import( \"foo\", { address: \"/path/to/foo.js\" } )\n.then( function(foo){\n\t// ..\n} )\n```\n\nIt's also expected that a customization will be provided (through some means) for hooking into the process of loading a module, where a translation/transpilation could occur after load but before the engine compiles the module.\n\nFor example, you could load something that's not already an ES6-compliant module format (e.g., CoffeeScript, TypeScript, CommonJS, AMD). Your translation step could then convert it to an ES6-compliant module for the engine to then process.\n\n## Classes\n\nFrom nearly the beginning of JavaScript, syntax and development patterns have all strived (read: struggled) to put on a facade of supporting class-oriented development. With things like `new` and `instanceof` and a `.constructor` property, who couldn't help but be teased that JS had classes hidden somewhere inside its prototype system?\n\nOf course, JS \"classes\" aren't nearly the same as classical classes. The differences are well documented, so I won't belabor that point any further here.\n\n**Note:** To learn more about the patterns used in JS to fake \"classes,\" and an alternative view of prototypes called \"delegation,\" see the second half of the *this & Object Prototypes* title of this series.\n\n### `class`\n\nAlthough JS's prototype mechanism doesn't work like traditional classes, that doesn't stop the strong tide of demand on the language to extend the syntactic sugar so that expressing \"classes\" looks more like real classes. Enter the ES6 `class` keyword and its associated mechanism.\n\nThis feature is the result of a highly contentious and drawn-out debate, and represents a smaller subset compromise from several strongly opposed views on how to approach JS classes. Most developers who want full classes in JS will find parts of the new syntax quite inviting, but will find important bits still missing. Don't worry, though. TC39 is already working on additional features to augment classes in the post-ES6 timeframe.\n\nAt the heart of the new ES6 class mechanism is the `class` keyword, which identifies a *block* where the contents define the members of a function's prototype. Consider:\n\n```js\nclass Foo {\n\tconstructor(a,b) {\n\t\tthis.x = a;\n\t\tthis.y = b;\n\t}\n\n\tgimmeXY() {\n\t\treturn this.x * this.y;\n\t}\n}\n```\n\nSome things to note:\n\n* `class Foo` implies creating a (special) function of the name `Foo`, much like you did pre-ES6.\n* `constructor(..)` identifies the signature of that `Foo(..)` function, as well as its body contents.\n* Class methods use the same \"concise method\" syntax available to object literals, as discussed in Chapter 2. This also includes the concise generator form as discussed earlier in this chapter, as well as the ES5 getter/setter syntax. However, class methods are non-enumerable whereas object methods are by default enumerable.\n* Unlike object literals, there are no commas separating members in a `class` body! In fact, they're not even allowed.\n\nThe `class` syntax definition in the previous snippet can be roughly thought of as this pre-ES6 equivalent, which probably will look fairly familiar to those who've done prototype-style coding before:\n\n```js\nfunction Foo(a,b) {\n\tthis.x = a;\n\tthis.y = b;\n}\n\nFoo.prototype.gimmeXY = function() {\n\treturn this.x * this.y;\n}\n```\n\nIn either the pre-ES6 form or the new ES6 `class` form, this \"class\" can now be instantiated and used just as you'd expect:\n\n```js\nvar f = new Foo( 5, 15 );\n\nf.x;\t\t\t\t\t\t// 5\nf.y;\t\t\t\t\t\t// 15\nf.gimmeXY();\t\t\t\t// 75\n```\n\nCaution! Though `class Foo` seems much like `function Foo()`, there are important differences:\n\n* A `Foo(..)` call of `class Foo` *must* be made with `new`, as the pre-ES6 option of `Foo.call( obj )` will *not* work.\n* While `function Foo` is \"hoisted\" (see the *Scope & Closures* title of this series), `class Foo` is not; the `extends ..` clause specifies an expression that cannot be \"hoisted.\" So, you must declare a `class` before you can instantiate it.\n* `class Foo` in the top global scope creates a lexical `Foo` identifier in that scope, but unlike `function Foo` does not create a global object property of that name.\n\nThe established `instanceof` operator still works with ES6 classes, because `class` just creates a constructor function of the same name. However, ES6 introduces a way to customize how `instanceof` works, using `Symbol.hasInstance` (see \"Well-Known Symbols\" in Chapter 7).\n\nAnother way of thinking about `class`, which I find more convenient, is as a *macro* that is used to automatically populate a `prototype` object. Optionally, it also wires up the `[[Prototype]]` relationship if using `extends` (see the next section).\n\nAn ES6 `class` isn't really an entity itself, but a meta concept that wraps around other concrete entities, such as functions and properties, and ties them together.\n\n**Tip:** In addition to the declaration form, a `class` can also be an expression, as in: `var x = class Y { .. }`. This is primarily useful for passing a class definition (technically, the constructor itself) as a function argument or assigning it to an object property.\n\n### `extends` and `super`\n\nES6 classes also have syntactic sugar for establishing the `[[Prototype]]` delegation link between two function prototypes -- commonly mislabeled \"inheritance\" or confusingly labeled \"prototype inheritance\" -- using the class-oriented familiar terminology `extends`:\n\n```js\nclass Bar extends Foo {\n\tconstructor(a,b,c) {\n\t\tsuper( a, b );\n\t\tthis.z = c;\n\t}\n\n\tgimmeXYZ() {\n\t\treturn super.gimmeXY() * this.z;\n\t}\n}\n\nvar b = new Bar( 5, 15, 25 );\n\nb.x;\t\t\t\t\t\t// 5\nb.y;\t\t\t\t\t\t// 15\nb.z;\t\t\t\t\t\t// 25\nb.gimmeXYZ();\t\t\t\t// 1875\n```\n\nA significant new addition is `super`, which is actually something not directly possible pre-ES6 (without some unfortunate hack trade-offs). In the constructor, `super` automatically refers to the \"parent constructor,\" which in the previous example is `Foo(..)`. In a method, it refers to the \"parent object,\" such that you can then make a property/method access off it, such as `super.gimmeXY()`.\n\n`Bar extends Foo` of course means to link the `[[Prototype]]` of `Bar.prototype` to `Foo.prototype`. So, `super` in a method like `gimmeXYZ()` specifically means `Foo.prototype`, whereas `super` means `Foo` when used in the `Bar` constructor.\n\n**Note:** `super` is not limited to `class` declarations. It also works in object literals, in much the same way we're discussing here. See \"Object `super`\" in Chapter 2 for more information.\n\n#### There Be `super` Dragons\n\nIt is not insignificant to note that `super` behaves differently depending on where it appears. In fairness, most of the time, that won't be a problem. But surprises await if you deviate from a narrow norm.\n\nThere may be cases where in the constructor you would want to reference the `Foo.prototype`, such as to directly access one of its properties/methods. However, `super` in the constructor cannot be used in that way; `super.prototype` will not work. `super(..)` means roughly to call `new Foo(..)`, but isn't actually a usable reference to `Foo` itself.\n\nSymmetrically, you may want to reference the `Foo(..)` function from inside a non-constructor method. `super.constructor` will point at `Foo(..)` the function, but beware that this function can *only* be invoked with `new`. `new super.constructor(..)` would be valid, but it wouldn't be terribly useful in most cases, because you can't make that call use or reference the current `this` object context, which is likely what you'd want.\n\nAlso, `super` looks like it might be driven by a function's context just like `this` -- that is, that they'd both be dynamically bound. However, `super` is not dynamic like `this` is. When a constructor or method makes a `super` reference inside it at declaration time (in the `class` body), that `super` is statically bound to that specific class hierarchy, and cannot be overridden (at least in ES6).\n\nWhat does that mean? It means that if you're in the habit of taking a method from one \"class\" and \"borrowing\" it for another class by overriding its `this`, say with `call(..)` or `apply(..)`, that may very well create surprises if the method you're borrowing has a `super` in it. Consider this class hierarchy:\n\n```js\nclass ParentA {\n\tconstructor() { this.id = \"a\"; }\n\tfoo() { console.log( \"ParentA:\", this.id ); }\n}\n\nclass ParentB {\n\tconstructor() { this.id = \"b\"; }\n\tfoo() { console.log( \"ParentB:\", this.id ); }\n}\n\nclass ChildA extends ParentA {\n\tfoo() {\n\t\tsuper.foo();\n\t\tconsole.log( \"ChildA:\", this.id );\n\t}\n}\n\nclass ChildB extends ParentB {\n\tfoo() {\n\t\tsuper.foo();\n\t\tconsole.log( \"ChildB:\", this.id );\n\t}\n}\n\nvar a = new ChildA();\na.foo();\t\t\t\t\t// ParentA: a\n\t\t\t\t\t\t\t// ChildA: a\nvar b = new ChildB();\t\t// ParentB: b\nb.foo();\t\t\t\t\t// ChildB: b\n```\n\nAll seems fairly natural and expected in this previous snippet. However, if you try to borrow `b.foo()` and use it in the context of `a` -- by virtue of dynamic `this` binding, such borrowing is quite common and used in many different ways, including mixins most notably -- you may find this result an ugly surprise:\n\n```js\n// borrow `b.foo()` to use in `a` context\nb.foo.call( a );\t\t\t// ParentB: a\n\t\t\t\t\t\t\t// ChildB: a\n```\n\nAs you can see, the `this.id` reference was dynamically rebound so that `: a` is reported in both cases instead of `: b`. But `b.foo()`'s `super.foo()` reference wasn't dynamically rebound, so it still reported `ParentB` instead of the expected `ParentA`.\n\nBecause `b.foo()` references `super`, it is statically bound to the `ChildB`/`ParentB` hierarchy and cannot be used against the `ChildA`/`ParentA` hierarchy. There is no ES6 solution to this limitation.\n\n`super` seems to work intuitively if you have a static class hierarchy with no cross-pollination. But in all fairness, one of the main benefits of doing `this`-aware coding is exactly that sort of flexibility. Simply, `class` + `super` requires you to avoid such techniques.\n\nThe choice boils down to narrowing your object design to these static hierarchies -- `class`, `extends`, and `super` will be quite nice -- or dropping all attempts to \"fake\" classes and instead embrace dynamic and flexible, classless objects and `[[Prototype]]` delegation (see the *this & Object Prototypes* title of this series).\n\n#### Subclass Constructor\n\nConstructors are not required for classes or subclasses; a default constructor is substituted in both cases if omitted. However, the default substituted constructor is different for a direct class versus an extended class.\n\nSpecifically, the default subclass constructor automatically calls the parent constructor, and passes along any arguments. In other words, you could think of the default subclass constructor sort of like this:\n\n```js\nconstructor(...args) {\n\tsuper(...args);\n}\n```\n\nThis is an important detail to note. Not all class languages have the subclass constructor automatically call the parent constructor. C++ does, but Java does not. But more importantly, in pre-ES6 classes, such automatic \"parent constructor\" calling does not happen. Be careful when converting to ES6 `class` if you've been relying on such calls *not* happening.\n\nAnother perhaps surprising deviation/limitation of ES6 subclass constructors: in a constructor of a subclass, you cannot access `this` until `super(..)` has been called. The reason is nuanced and complicated, but it boils down to the fact that the parent constructor is actually the one creating/initializing your instance's `this`. Pre-ES6, it works oppositely; the `this` object is created by the \"subclass constructor,\" and then you  call a \"parent constructor\" with the context of the \"subclass\" `this`.\n\nLet's illustrate. This works pre-ES6:\n\n```js\nfunction Foo() {\n\tthis.a = 1;\n}\n\nfunction Bar() {\n\tthis.b = 2;\n\tFoo.call( this );\n}\n\n// `Bar` \"extends\" `Foo`\nBar.prototype = Object.create( Foo.prototype );\n```\n\nBut this ES6 equivalent is not allowed:\n\n```js\nclass Foo {\n\tconstructor() { this.a = 1; }\n}\n\nclass Bar extends Foo {\n\tconstructor() {\n\t\tthis.b = 2;\t\t\t// not allowed before `super()`\n\t\tsuper();\t\t\t// to fix swap these two statements\n\t}\n}\n```\n\nIn this case, the fix is simple. Just swap the two statements in the subclass `Bar` constructor. However, if you've been relying pre-ES6 on being able to skip calling the \"parent constructor,\" beware because that won't be allowed anymore.\n\n#### `extend`ing Natives\n\nOne of the most heralded benefits to the new `class` and `extend` design is the ability to (finally!) subclass the built-in natives, like `Array`. Consider:\n\n```js\nclass MyCoolArray extends Array {\n\tfirst() { return this[0]; }\n\tlast() { return this[this.length - 1]; }\n}\n\nvar a = new MyCoolArray( 1, 2, 3 );\n\na.length;\t\t\t\t\t// 3\na;\t\t\t\t\t\t\t// [1,2,3]\n\na.first();\t\t\t\t\t// 1\na.last();\t\t\t\t\t// 3\n```\n\nPrior to ES6, a fake \"subclass\" of `Array` using manual object creation and linking to `Array.prototype` only partially worked. It missed out on the special behaviors of a real array, such as the automatically updating `length` property. ES6 subclasses should fully work with \"inherited\" and augmented behaviors as expected!\n\nAnother common pre-ES6 \"subclass\" limitation is with the `Error` object, in creating custom error \"subclasses.\" When genuine `Error` objects are created, they automatically capture special `stack` information, including the line number and file where the error is created. Pre-ES6 custom error \"subclasses\" have no such special behavior, which severely limits their usefulness.\n\nES6 to the rescue:\n\n```js\nclass Oops extends Error {\n\tconstructor(reason) {\n\t\tsuper(reason);\n\t\tthis.oops = reason;\n\t}\n}\n\n// later:\nvar ouch = new Oops( \"I messed up!\" );\nthrow ouch;\n```\n\nThe `ouch` custom error object in this previous snippet will behave like any other genuine error object, including capturing `stack`. That's a big improvement!\n\n### `new.target`\n\nES6 introduces a new concept called a *meta property* (see Chapter 7), in the form of `new.target`.\n\nIf that looks strange, it is; pairing a keyword with a `.` and a property name is definitely an out-of-the-ordinary pattern for JS.\n\n`new.target` is a new \"magical\" value available in all functions, though in normal functions it will always be `undefined`. In any constructor, `new.target` always points at the constructor that `new` actually directly invoked, even if the constructor is in a parent class and was delegated to by a `super(..)` call from a child constructor. Consider:\n\n```js\nclass Foo {\n\tconstructor() {\n\t\tconsole.log( \"Foo: \", new.target.name );\n\t}\n}\n\nclass Bar extends Foo {\n\tconstructor() {\n\t\tsuper();\n\t\tconsole.log( \"Bar: \", new.target.name );\n\t}\n\tbaz() {\n\t\tconsole.log( \"baz: \", new.target );\n\t}\n}\n\nvar a = new Foo();\n// Foo: Foo\n\nvar b = new Bar();\n// Foo: Bar   <-- respects the `new` call-site\n// Bar: Bar\n\nb.baz();\n// baz: undefined\n```\n\nThe `new.target` meta property doesn't have much purpose in class constructors, except accessing a static property/method (see the next section).\n\nIf `new.target` is `undefined`, you know the function was not called with `new`. You can then force a `new` invocation if that's necessary.\n\n### `static`\n\nWhen a subclass `Bar` extends a parent class `Foo`, we already observed that `Bar.prototype` is `[[Prototype]]`-linked to `Foo.prototype`. But additionally, `Bar()` is `[[Prototype]]`-linked to `Foo()`. That part may not have such an obvious reasoning.\n\nHowever, it's quite useful in the case where you declare `static` methods (not just properties) for a class, as these are added directly to that class's function object, not to the function object's `prototype` object. Consider:\n\n```js\nclass Foo {\n\tstatic cool() { console.log( \"cool\" ); }\n\twow() { console.log( \"wow\" ); }\n}\n\nclass Bar extends Foo {\n\tstatic awesome() {\n\t\tsuper.cool();\n\t\tconsole.log( \"awesome\" );\n\t}\n\tneat() {\n\t\tsuper.wow();\n\t\tconsole.log( \"neat\" );\n\t}\n}\n\nFoo.cool();\t\t\t\t\t// \"cool\"\nBar.cool();\t\t\t\t\t// \"cool\"\nBar.awesome();\t\t\t\t// \"cool\"\n\t\t\t\t\t\t\t// \"awesome\"\n\nvar b = new Bar();\nb.neat();\t\t\t\t\t// \"wow\"\n\t\t\t\t\t\t\t// \"neat\"\n\nb.awesome;\t\t\t\t\t// undefined\nb.cool;\t\t\t\t\t\t// undefined\n```\n\nBe careful not to get confused that `static` members are on the class's prototype chain. They're actually on the dual/parallel chain between the function constructors.\n\n#### `Symbol.species` Constructor Getter\n\nOne place where `static` can be useful is in setting the `Symbol.species` getter (known internally in the specification as `@@species`) for a derived (child) class. This capability allows a child class to signal to a parent class what constructor should be used -- when not intending the child class's constructor itself -- if any parent class method needs to vend a new instance.\n\nFor example, many methods on `Array` create and return a new `Array` instance. If you define a derived class from `Array`, but you want those methods to continue to vend actual `Array` instances instead of from your derived class, this works:\n\n```js\nclass MyCoolArray extends Array {\n\t// force `species` to be parent constructor\n\tstatic get [Symbol.species]() { return Array; }\n}\n\nvar a = new MyCoolArray( 1, 2, 3 ),\n\tb = a.map( function(v){ return v * 2; } );\n\nb instanceof MyCoolArray;\t// false\nb instanceof Array;\t\t\t// true\n```\n\nTo illustrate how a parent class method can use a child's species declaration somewhat like `Array#map(..)` is doing, consider:\n\n```js\nclass Foo {\n\t// defer `species` to derived constructor\n\tstatic get [Symbol.species]() { return this; }\n\tspawn() {\n\t\treturn new this.constructor[Symbol.species]();\n\t}\n}\n\nclass Bar extends Foo {\n\t// force `species` to be parent constructor\n\tstatic get [Symbol.species]() { return Foo; }\n}\n\nvar a = new Foo();\nvar b = a.spawn();\nb instanceof Foo;\t\t\t\t\t// true\n\nvar x = new Bar();\nvar y = x.spawn();\ny instanceof Bar;\t\t\t\t\t// false\ny instanceof Foo;\t\t\t\t\t// true\n```\n\nThe parent class `Symbol.species` does `return this` to defer to any derived class, as you'd normally expect. `Bar` then overrides to manually declare `Foo` to be used for such instance creation. Of course, a derived class can still vend instances of itself using `new this.constructor(..)`.\n\n## Review\n\nES6 introduces several new features that aid in code organization:\n\n* Iterators provide sequential access to data or operations. They can be consumed by new language features like `for..of` and `...`.\n* Generators are locally pause/resume capable functions controlled by an iterator. They can be used to programmatically (and interactively, through `yield`/`next(..)` message passing) *generate* values to be consumed via iteration.\n* Modules allow private encapsulation of implementation details with a publicly exported API. Module definitions are file-based, singleton instances, and statically resolved at compile time.\n* Classes provide cleaner syntax around prototype-based coding. The addition of `super` also solves tricky issues with relative references in the `[[Prototype]]` chain.\n\nThese new tools should be your first stop when trying to improve the architecture of your JS projects by embracing ES6.\n"
  },
  {
    "path": "es6 & beyond/ch4.md",
    "content": "# You Don't Know JS: ES6 & Beyond\n# Chapter 4: Async Flow Control\n\nIt's no secret if you've written any significant amount of JavaScript that asynchronous programming is a required skill. The primary mechanism for managing asynchrony has been the function callback.\n\nHowever, ES6 adds a new feature that helps address significant shortcomings in the callbacks-only approach to async: *Promises*. In addition, we can revisit generators (from the previous chapter) and see a pattern for combining the two that's a major step forward in async flow control programming in JavaScript.\n\n## Promises\n\nLet's clear up some misconceptions: Promises are not about replacing callbacks. Promises provide a trustable intermediary -- that is, between your calling code and the async code that will perform the task -- to manage callbacks.\n\nAnother way of thinking about a Promise is as an event listener, on which you can register to listen for an event that lets you know when a task has completed. It's an event that will only ever fire once, but it can be thought of as an event nonetheless.\n\nPromises can be chained together, which can sequence a series of asychronously completing steps. Together with higher-level abstractions like the `all(..)` method (in classic terms, a \"gate\") and the `race(..)` method (in classic terms, a \"latch\"), promise chains provide a mechanism for async flow control.\n\nYet another way of conceptualizing a Promise is that it's a *future value*, a time-independent container wrapped around a value. This container can be reasoned about identically whether the underlying value is final or not. Observing the resolution of a Promise extracts this value once available. In other words, a Promise is said to be the async version of a sync function's return value.\n\nA Promise can only have one of two possible resolution outcomes: fulfilled or rejected, with an optional single value. If a Promise is fulfilled, the final value is called a fulfillment. If it's rejected, the final value is called a reason (as in, a \"reason for rejection\"). Promises can only be resolved (fulfillment or rejection) *once*. Any further attempts to fulfill or reject are simply ignored. Thus, once a Promise is resolved, it's an immutable value that cannot be changed.\n\nClearly, there are several different ways to think about what a Promise is. No single perspective is fully sufficient, but each provides a separate aspect of the whole. The big takeaway is that they offer a significant improvement over callbacks-only async, namely that they provide order, predictability, and trustability.\n\n### Making and Using Promises\n\nTo construct a promise instance, use the `Promise(..)` constructor:\n\n```js\nvar p = new Promise( function pr(resolve,reject){\n\t// ..\n} );\n```\n\nThe `Promise(..)` constructor takes a single function (`pr(..)`), which is called immediately and receives two control functions as arguments, usually named `resolve(..)` and `reject(..)`. They are used as:\n\n* If you call `reject(..)`, the promise is rejected, and if any value is passed to `reject(..)`, it is set as the reason for rejection.\n* If you call `resolve(..)` with no value, or any non-promise value, the promise is fulfilled.\n* If you call `resolve(..)` and pass another promise, this promise simply adopts the state -- whether immediate or eventual -- of the passed promise (either fulfillment or rejection).\n\nHere's how you'd typically use a promise to refactor a callback-reliant function call. If you start out with an `ajax(..)` utility that expects to be able to call an error-first style callback:\n\n```js\nfunction ajax(url,cb) {\n\t// make request, eventually call `cb(..)`\n}\n\n// ..\n\najax( \"http://some.url.1\", function handler(err,contents){\n\tif (err) {\n\t\t// handle ajax error\n\t}\n\telse {\n\t\t// handle `contents` success\n\t}\n} );\n```\n\nYou can convert it to:\n\n```js\nfunction ajax(url) {\n\treturn new Promise( function pr(resolve,reject){\n\t\t// make request, eventually call\n\t\t// either `resolve(..)` or `reject(..)`\n\t} );\n}\n\n// ..\n\najax( \"http://some.url.1\" )\n.then(\n\tfunction fulfilled(contents){\n\t\t// handle `contents` success\n\t},\n\tfunction rejected(reason){\n\t\t// handle ajax error reason\n\t}\n);\n```\n\nPromises have a `then(..)` method that accepts one or two callback functions. The first function (if present) is treated as the handler to call if the promise is fulfilled successfully. The second function (if present) is treated as the handler to call if the promise is rejected explicitly, or if any error/exception is caught during resolution.\n\nIf one of the arguments is omitted or otherwise not a valid function -- typically you'll use `null` instead -- a default placeholder equivalent is used. The default success callback passes its fulfillment value along and the default error callback propagates its rejection reason along.\n\nThe shorthand for calling `then(null,handleRejection)` is `catch(handleRejection)`.\n\nBoth `then(..)` and `catch(..)` automatically construct and return another promise instance, which is wired to receive the resolution from whatever the return value is from the original promise's fulfillment or rejection handler (whichever is actually called). Consider:\n\n```js\najax( \"http://some.url.1\" )\n.then(\n\tfunction fulfilled(contents){\n\t\treturn contents.toUpperCase();\n\t},\n\tfunction rejected(reason){\n\t\treturn \"DEFAULT VALUE\";\n\t}\n)\n.then( function fulfilled(data){\n\t// handle data from original promise's\n\t// handlers\n} );\n```\n\nIn this snippet, we're returning an immediate value from either `fulfilled(..)` or `rejected(..)`, which then is received on the next event turn in the second `then(..)`'s `fulfilled(..)`. If we instead return a new promise, that new promise is subsumed and adopted as the resolution:\n\n```js\najax( \"http://some.url.1\" )\n.then(\n\tfunction fulfilled(contents){\n\t\treturn ajax(\n\t\t\t\"http://some.url.2?v=\" + contents\n\t\t);\n\t},\n\tfunction rejected(reason){\n\t\treturn ajax(\n\t\t\t\"http://backup.url.3?err=\" + reason\n\t\t);\n\t}\n)\n.then( function fulfilled(contents){\n\t// `contents` comes from the subsequent\n\t// `ajax(..)` call, whichever it was\n} );\n```\n\nIt's important to note that an exception (or rejected promise) in the first `fulfilled(..)` will *not* result in the first `rejected(..)` being called, as that handler only responds to the resolution of the first original promise. Instead, the second promise, which the second `then(..)` is called against, receives that rejection.\n\nIn this previous snippet, we are not listening for that rejection, which means it will be silently held onto for future observation. If you never observe it by calling a `then(..)` or `catch(..)`, then it will go unhandled. Some browser developer consoles may detect these unhandled rejections and report them, but this is not reliably guaranteed; you should always observe promise rejections.\n\n**Note:** This was just a brief overview of Promise theory and behavior. For a much more in-depth exploration, see Chapter 3 of the *Async & Performance* title of this series.\n\n### Thenables\n\nPromises are genuine instances of the `Promise(..)` constructor. However, there are promise-like objects called *thenables* that generally can interoperate with the Promise mechanisms.\n\nAny object (or function) with a `then(..)` function on it is assumed to be a thenable. Any place where the Promise mechanisms can accept and adopt the state of a genuine promise, they can also handle a thenable.\n\nThenables are basically a general label for any promise-like value that may have been created by some other system than the actual `Promise(..)` constructor. In that perspective, a thenable is generally less trustable than a genuine Promise. Consider this misbehaving thenable, for example:\n\n```js\nvar th = {\n\tthen: function thener( fulfilled ) {\n\t\t// call `fulfilled(..)` once every 100ms forever\n\t\tsetInterval( fulfilled, 100 );\n\t}\n};\n```\n\nIf you received that thenable and chained it with `th.then(..)`, you'd likely be surprised that your fulfillment handler is called repeatedly, when normal Promises are supposed to only ever be resolved once.\n\nGenerally, if you're receiving what purports to be a promise or thenable back from some other system, you shouldn't just trust it blindly. In the next section, we'll see a utility included with ES6 Promises that helps address this trust concern.\n\nBut to further understand the perils of this issue, consider that *any* object in *any* piece of code that's ever been defined to have a method on it called `then(..)` can be potentially confused as a thenable -- if used with Promises, of course -- regardless of if that thing was ever intended to even remotely be related to Promise-style async coding.\n\nPrior to ES6, there was never any special reservation made on methods called `then(..)`, and as you can imagine there's been at least a few cases where that method name has been chosen prior to Promises ever showing up on the radar screen. The most likely case of mistaken thenable will be async libraries that use `then(..)` but which are not strictly Promises-compliant -- there are several out in the wild.\n\nThe onus will be on you to guard against directly using values with the Promise mechanism that would be incorrectly assumed to be a thenable.\n\n### `Promise` API\n\nThe `Promise` API also provides some static methods for working with Promises.\n\n`Promise.resolve(..)` creates a promise resolved to the value passed in. Let's compare how it works to the more manual approach:\n\n```js\nvar p1 = Promise.resolve( 42 );\n\nvar p2 = new Promise( function pr(resolve){\n\tresolve( 42 );\n} );\n```\n\n`p1` and `p2` will have essentially identical behavior. The same goes for resolving with a promise:\n\n```js\nvar theP = ajax( .. );\n\nvar p1 = Promise.resolve( theP );\n\nvar p2 = new Promise( function pr(resolve){\n\tresolve( theP );\n} );\n```\n\n**Tip:** `Promise.resolve(..)` is the solution to the thenable trust issue raised in the previous section. Any value that you are not already certain is a trustable promise -- even if it could be an immediate value -- can be normalized by passing it to `Promise.resolve(..)`. If the value is already a recognizable promise or thenable, its state/resolution will simply be adopted, insulating you from misbehavior. If it's instead an immediate value, it will be \"wrapped\" in a genuine promise, thereby normalizing its behavior to be async.\n\n`Promise.reject(..)` creates an immediately rejected promise, the same as its `Promise(..)` constructor counterpart:\n\n```js\nvar p1 = Promise.reject( \"Oops\" );\n\nvar p2 = new Promise( function pr(resolve,reject){\n\treject( \"Oops\" );\n} );\n```\n\nWhile `resolve(..)` and `Promise.resolve(..)` can accept a promise and adopt its state/resolution, `reject(..)` and `Promise.reject(..)` do not differentiate what value they receive. So, if you reject with a promise or thenable, the promise/thenable itself will be set as the rejection reason, not its underlying value.\n\n`Promise.all([ .. ])` accepts an array of one or more values (e.g., immediate values, promises, thenables). It returns a promise back that will be fulfilled if all the values fulfill, or reject immediately once the first of any of them rejects.\n\nStarting with these values/promises:\n\n```js\nvar p1 = Promise.resolve( 42 );\nvar p2 = new Promise( function pr(resolve){\n\tsetTimeout( function(){\n\t\tresolve( 43 );\n\t}, 100 );\n} );\nvar v3 = 44;\nvar p4 = new Promise( function pr(resolve,reject){\n\tsetTimeout( function(){\n\t\treject( \"Oops\" );\n\t}, 10 );\n} );\n```\n\nLet's consider how `Promise.all([ .. ])` works with combinations of those values:\n\n```js\nPromise.all( [p1,p2,v3] )\n.then( function fulfilled(vals){\n\tconsole.log( vals );\t\t\t// [42,43,44]\n} );\n\nPromise.all( [p1,p2,v3,p4] )\n.then(\n\tfunction fulfilled(vals){\n\t\t// never gets here\n\t},\n\tfunction rejected(reason){\n\t\tconsole.log( reason );\t\t// Oops\n\t}\n);\n```\n\nWhile `Promise.all([ .. ])` waits for all fulfillments (or the first rejection), `Promise.race([ .. ])` waits only for either the first fulfillment or rejection. Consider:\n\n```js\n// NOTE: re-setup all test values to\n// avoid timing issues misleading you!\n\nPromise.race( [p2,p1,v3] )\n.then( function fulfilled(val){\n\tconsole.log( val );\t\t\t\t// 42\n} );\n\nPromise.race( [p2,p4] )\n.then(\n\tfunction fulfilled(val){\n\t\t// never gets here\n\t},\n\tfunction rejected(reason){\n\t\tconsole.log( reason );\t\t// Oops\n\t}\n);\n```\n\n**Warning:** While `Promise.all([])` will fulfill right away (with no values), `Promise.race([])` will hang forever. This is a strange inconsistency, and speaks to the suggestion that you should never use these methods with empty arrays.\n\n## Generators + Promises\n\nIt *is* possible to express a series of promises in a chain to represent the async flow control of your program. Consider:\n\n```js\nstep1()\n.then(\n\tstep2,\n\tstep1Failed\n)\n.then(\n\tfunction step3(msg) {\n\t\treturn Promise.all( [\n\t\t\tstep3a( msg ),\n\t\t\tstep3b( msg ),\n\t\t\tstep3c( msg )\n\t\t] )\n\t}\n)\n.then(step4);\n```\n\nHowever, there's a much better option for expressing async flow control, and it will probably be much more preferable in terms of coding style than long promise chains. We can use what we learned in Chapter 3 about generators to express our async flow control.\n\nThe important pattern to recognize: a generator can yield a promise, and that promise can then be wired to resume the generator with its fulfillment value.\n\nConsider the previous snippet's async flow control expressed with a generator:\n\n```js\nfunction *main() {\n\n\ttry {\n\t\tvar ret = yield step1();\n\t}\n\tcatch (err) {\n\t\tret = yield step1Failed( err );\n\t}\n\n\tret = yield step2( ret );\n\n\t// step 3\n\tret = yield Promise.all( [\n\t\tstep3a( ret ),\n\t\tstep3b( ret ),\n\t\tstep3c( ret )\n\t] );\n\n\tyield step4( ret );\n}\n```\n\nOn the surface, this snippet may seem more verbose than the promise chain equivalent in the earlier snippet. However, it offers a much more attractive -- and more importantly, a more understandable and reason-able -- synchronous-looking coding style (with `=` assignment of \"return\" values, etc.) That's especially true in that `try..catch` error handling can be used across those hidden async boundaries.\n\nWhy are we using Promises with the generator? It's certainly possible to do async generator coding without Promises.\n\nPromises are a trustable system that uninverts the inversion of control of normal callbacks or thunks (see the *Async & Performance* title of this series). So, combining the trustability of Promises and the synchronicity of code in generators effectively addresses all the major deficiencies of callbacks. Also, utilities like `Promise.all([ .. ])` are a nice, clean way to express concurrency at a generator's single `yield` step.\n\nSo how does this magic work? We're going to need a *runner* that can run our generator, receive a `yield`ed promise, and wire it up to resume the generator with either the fulfillment success value, or throw an error into the generator with the rejection reason.\n\nMany async-capable utilities/libraries have such a \"runner\"; for example, `Q.spawn(..)` and my asynquence's `runner(..)` plug-in. But here's a stand-alone runner to illustrate how the process works:\n\n```js\nfunction run(gen) {\n\tvar args = [].slice.call( arguments, 1), it;\n\n\tit = gen.apply( this, args );\n\n\treturn Promise.resolve()\n\t\t.then( function handleNext(value){\n\t\t\tvar next = it.next( value );\n\n\t\t\treturn (function handleResult(next){\n\t\t\t\tif (next.done) {\n\t\t\t\t\treturn next.value;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treturn Promise.resolve( next.value )\n\t\t\t\t\t\t.then(\n\t\t\t\t\t\t\thandleNext,\n\t\t\t\t\t\t\tfunction handleErr(err) {\n\t\t\t\t\t\t\t\treturn Promise.resolve(\n\t\t\t\t\t\t\t\t\tit.throw( err )\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t.then( handleResult );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t})( next );\n\t\t} );\n}\n```\n\n**Note:** For a more prolifically commented version of this utility, see the *Async & Performance* title of this series. Also, the run utilities provided with various async libraries are often more powerful/capable than what we've shown here. For example, asynquence's `runner(..)` can handle `yield`ed promises, sequences, thunks, and immediate (non-promise) values, giving you ultimate flexibility.\n\nSo now running `*main()` as listed in the earlier snippet is as easy as:\n\n```js\nrun( main )\n.then(\n\tfunction fulfilled(){\n\t\t// `*main()` completed successfully\n\t},\n\tfunction rejected(reason){\n\t\t// Oops, something went wrong\n\t}\n);\n```\n\nEssentially, anywhere that you have more than two asynchronous steps of flow control logic in your program, you can *and should* use a promise-yielding generator driven by a run utility to express the flow control in a synchronous fashion. This will make for much easier to understand and maintain code.\n\nThis yield-a-promise-resume-the-generator pattern is going to be so common and so powerful, the next version of JavaScript after ES6 is almost certainly going to introduce a new function type that will do it automatically without needing the run utility. We'll cover `async function`s (as they're expected to be called) in Chapter 8.\n\n## Review\n\nAs JavaScript continues to mature and grow in its widespread adoption, asynchronous programming is more and more of a central concern. Callbacks are not fully sufficient for these tasks, and totally fall down the more sophisticated the need.\n\nThankfully, ES6 adds Promises to address one of the major shortcomings of callbacks: lack of trust in predictable behavior. Promises represent the future completion value from a potentially async task, normalizing behavior across sync and async boundaries.\n\nBut it's the combination of Promises with generators that fully realizes the benefits of rearranging our async flow control code to de-emphasize and abstract away that ugly callback soup (aka \"hell\").\n\nRight now, we can manage these interactions with the aide of various async libraries' runners, but JavaScript is eventually going to support this interaction pattern with dedicated syntax alone!\n"
  },
  {
    "path": "es6 & beyond/ch5.md",
    "content": "# You Don't Know JS: ES6 & Beyond\n# Chapter 5: Collections\n\nStructured collection and access to data is a critical component of just about any JS program. From the beginning of the language up to this point, the array and the object have been our primary mechanism for creating data structures. Of course, many higher-level data structures have been built on top of these, as user-land libraries.\n\nAs of ES6, some of the most useful (and performance-optimizing!) data structure abstractions have been added as native components of the language.\n\nWe'll start this chapter first by looking at *TypedArrays*, technically contemporary to ES5 efforts several years ago, but only standardized as companions to WebGL and not JavaScript itself. As of ES6, these have been adopted directly by the language specification, which gives them first-class status.\n\nMaps are like objects (key/value pairs), but instead of just a string for the key, you can use any value -- even another object or map! Sets are similar to arrays (lists of values), but the values are unique; if you add a duplicate, it's ignored. There are also weak (in relation to memory/garbage collection) counterparts: WeakMap and WeakSet.\n\n## TypedArrays\n\nAs we cover in the *Types & Grammar* title of this series, JS does have a set of built-in types, like `number` and `string`. It'd be tempting to look at a feature named \"typed array\" and assume it means an array of a specific type of values, like an array of only strings.\n\nHowever, typed arrays are really more about providing structured access to binary data using array-like semantics (indexed access, etc.). The \"type\" in the name refers to a \"view\" layered on type of the bucket of bits, which is essentially a mapping of whether the bits should be viewed as an array of 8-bit signed integers, 16-bit signed integers, and so on.\n\nHow do you construct such a bit-bucket? It's called a \"buffer,\" and you construct it most directly with the `ArrayBuffer(..)` constructor:\n\n```js\nvar buf = new ArrayBuffer( 32 );\nbuf.byteLength;\t\t\t\t\t\t\t// 32\n```\n\n`buf` is now a binary buffer that is 32-bytes long (256-bits), that's pre-initialized to all `0`s. A buffer by itself doesn't really allow you any interaction exception for checking its `byteLength` property.\n\n**Tip:** Several web platform features use or return array buffers, such as `FileReader#readAsArrayBuffer(..)`, `XMLHttpRequest#send(..)`, and `ImageData` (canvas data).\n\nBut on top of this array buffer, you can then layer a \"view,\" which comes in the form of a typed array. Consider:\n\n```js\nvar arr = new Uint16Array( buf );\narr.length;\t\t\t\t\t\t\t// 16\n```\n\n`arr` is a typed array of 16-bit unsigned integers mapped over the 256-bit `buf` buffer, meaning you get 16 elements.\n\n### Endianness\n\nIt's very important to understand that the `arr` is mapped using the endian-setting (big-endian or little-endian) of the platform the JS is running on. This can be an issue if the binary data is created with one endianness but interpreted on a platform with the opposite endianness.\n\nEndian means if the low-order byte (collection of 8-bits) of a multi-byte number -- such as the 16-bit unsigned ints we created in the earlier snippet -- is on the right or the left of the number's bytes.\n\nFor example, let's imagine the base-10 number `3085`, which takes 16-bits to represent. If you have just one 16-bit number container, it'd be represented in binary as `0000110000001101` (hexadecimal `0c0d`) regardless of endianness.\n\nBut if `3085` was represented with two 8-bit numbers, the endianness would significantly affect its storage in memory:\n\n* `0000110000001101` / `0c0d` (big endian)\n* `0000110100001100` / `0d0c` (little endian)\n\nIf you received the bits of `3085` as `0000110100001100` from a little-endian system, but you layered a view on top of it in a big-endian system, you'd instead see value `3340` (base-10) and `0d0c` (base-16).\n\nLittle endian is the most common representation on the web these days, but there are definitely browsers where that's not true. It's important that you understand the endianness of both the producer and consumer of a chunk of binary data.\n\nFrom MDN, here's a quick way to test the endianness of your JavaScript:\n\n```js\nvar littleEndian = (function() {\n\tvar buffer = new ArrayBuffer( 2 );\n\tnew DataView( buffer ).setInt16( 0, 256, true );\n\treturn new Int16Array( buffer )[0] === 256;\n})();\n```\n\n`littleEndian` will be `true` or `false`; for most browsers, it should return `true`. This test uses `DataView(..)`, which allows more low-level, fine-grained control over accessing (setting/getting) the bits from the view you layer over the buffer. The third parameter of the `setInt16(..)` method in the previous snippet is for telling the `DataView` what endianness you're wanting it to use for that operation.\n\n**Warning:** Do not confuse endianness of underlying binary storage in array buffers with how a given number is represented when exposed in a JS program. For example, `(3085).toString(2)` returns `\"110000001101\"`, which with an assumed leading four `\"0\"`s appears to be the big-endian representation. In fact, this representation is based on a single 16-bit view, not a view of two 8-bit bytes. The `DataView` test above is the best way to determine endianness for your JS environment.\n\n### Multiple Views\n\nA single buffer can have multiple views attached to it, such as:\n\n```js\nvar buf = new ArrayBuffer( 2 );\n\nvar view8 = new Uint8Array( buf );\nvar view16 = new Uint16Array( buf );\n\nview16[0] = 3085;\nview8[0];\t\t\t\t\t\t// 13\nview8[1];\t\t\t\t\t\t// 12\n\nview8[0].toString( 16 );\t\t// \"d\"\nview8[1].toString( 16 );\t\t// \"c\"\n\n// swap (as if endian!)\nvar tmp = view8[0];\nview8[0] = view8[1];\nview8[1] = tmp;\n\nview16[0];\t\t\t\t\t\t// 3340\n```\n\nThe typed array constructors have multiple signature variations. We've shown so far only passing them an existing buffer. However, that form also takes two extra parameters: `byteOffset` and `length`. In other words, you can start the typed array view at a location other than `0` and you can make it span less than the full length of the buffer.\n\nIf the buffer of binary data includes data in non-uniform size/location, this technique can be quite useful.\n\nFor example, consider a binary buffer that has a 2-byte number (aka \"word\") at the beginning, followed by two 1-byte numbers, followed by a 32-bit floating point number. Here's how you can access that data with multiple views on the same buffer, offsets, and lengths:\n\n```js\nvar first = new Uint16Array( buf, 0, 2 )[0],\n\tsecond = new Uint8Array( buf, 2, 1 )[0],\n\tthird = new Uint8Array( buf, 3, 1 )[0],\n\tfourth = new Float32Array( buf, 4, 4 )[0];\n```\n\n### TypedArray Constructors\n\nIn addition to the `(buffer,[offset, [length]])` form examined in the previous section, typed array constructors also support these forms:\n\n* [constructor]`(length)`: Creates a new view over a new buffer of `length` bytes\n* [constructor]`(typedArr)`: Creates a new view and buffer, and copies the contents from the `typedArr` view\n* [constructor]`(obj)`: Creates a new view and buffer, and iterates over the array-like or object `obj` to copy its contents\n\nThe following typed array constructors are available as of ES6:\n\n* `Int8Array` (8-bit signed integers), `Uint8Array` (8-bit unsigned integers)\n\t- `Uint8ClampedArray` (8-bit unsigned integers, each value clamped on setting to the `0`-`255` range)\n* `Int16Array` (16-bit signed integers), `Uint16Array` (16-bit unsigned integers)\n* `Int32Array` (32-bit signed integers), `Uint32Array` (32-bit unsigned integers)\n* `Float32Array` (32-bit floating point, IEEE-754)\n* `Float64Array` (64-bit floating point, IEEE-754)\n\nInstances of typed array constructors are almost the same as regular native arrays. Some differences include having a fixed length and the values all being of the same \"type.\"\n\nHowever, they share most of the same `prototype` methods. As such, you likely will be able to use them as regular arrays without needing to convert.\n\nFor example:\n\n```js\nvar a = new Int32Array( 3 );\na[0] = 10;\na[1] = 20;\na[2] = 30;\n\na.map( function(v){\n\tconsole.log( v );\n} );\n// 10 20 30\n\na.join( \"-\" );\n// \"10-20-30\"\n```\n\n**Warning:** You can't use certain `Array.prototype` methods with TypedArrays that don't make sense, such as the mutators (`splice(..)`, `push(..)`, etc.) and `concat(..)`.\n\nBe aware that the elements in TypedArrays really are constrained to the declared bit sizes. If you have a `Uint8Array` and try to assign something larger than an 8-bit value into one of its elements, the value wraps around so as to stay within the bit length.\n\nThis could cause problems if you were trying to, for instance, square all the values in a TypedArray. Consider:\n\n```js\nvar a = new Uint8Array( 3 );\na[0] = 10;\na[1] = 20;\na[2] = 30;\n\nvar b = a.map( function(v){\n\treturn v * v;\n} );\n\nb;\t\t\t\t// [100, 144, 132]\n```\n\nThe `20` and `30` values, when squared, resulted in bit overflow. To get around such a limitation, you can use the `TypedArray#from(..)` function:\n\n```js\nvar a = new Uint8Array( 3 );\na[0] = 10;\na[1] = 20;\na[2] = 30;\n\nvar b = Uint16Array.from( a, function(v){\n\treturn v * v;\n} );\n\nb;\t\t\t\t// [100, 400, 900]\n```\n\nSee the \"`Array.from(..)` Static Function\" section in Chapter 6 for more information about the `Array.from(..)` that is shared with TypedArrays. Specifically, the \"Mapping\" section explains the mapping function accepted as its second argument.\n\nOne interesting behavior to consider is that TypedArrays have a `sort(..)` method much like regular arrays, but this one defaults to numeric sort comparisons instead of coercing values to strings for lexicographic comparison. For example:\n\n```js\nvar a = [ 10, 1, 2, ];\na.sort();\t\t\t\t\t\t\t\t// [1,10,2]\n\nvar b = new Uint8Array( [ 10, 1, 2 ] );\nb.sort();\t\t\t\t\t\t\t\t// [1,2,10]\n```\n\nThe `TypedArray#sort(..)` takes an optional compare function argument just like `Array#sort(..)`, which works in exactly the same way.\n\n## Maps\n\nIf you have a lot of JS experience, you know that objects are the primary mechanism for creating unordered key/value-pair data structures, otherwise known as maps. However, the major drawback with objects-as-maps is the inability to use a non-string value as the key.\n\nFor example, consider:\n\n```js\nvar m = {};\n\nvar x = { id: 1 },\n\ty = { id: 2 };\n\nm[x] = \"foo\";\nm[y] = \"bar\";\n\nm[x];\t\t\t\t\t\t\t// \"bar\"\nm[y];\t\t\t\t\t\t\t// \"bar\"\n```\n\nWhat's going on here? The two objects `x` and `y` both stringify to `\"[object Object]\"`, so only that one key is being set in `m`.\n\nSome have implemented fake maps by maintaining a parallel array of non-string keys alongside an array of the values, such as:\n\n```js\nvar keys = [], vals = [];\n\nvar x = { id: 1 },\n\ty = { id: 2 };\n\nkeys.push( x );\nvals.push( \"foo\" );\n\nkeys.push( y );\nvals.push( \"bar\" );\n\nkeys[0] === x;\t\t\t\t\t// true\nvals[0];\t\t\t\t\t\t// \"foo\"\n\nkeys[1] === y;\t\t\t\t\t// true\nvals[1];\t\t\t\t\t\t// \"bar\"\n```\n\nOf course, you wouldn't want to manage those parallel arrays yourself, so you could define a data structure with methods that automatically do the management under the covers. Besides having to do that work yourself, the main drawback is that access is no longer O(1) time-complexity, but instead is O(n).\n\nBut as of ES6, there's no longer any need to do this! Just use `Map(..)`:\n\n```js\nvar m = new Map();\n\nvar x = { id: 1 },\n\ty = { id: 2 };\n\nm.set( x, \"foo\" );\nm.set( y, \"bar\" );\n\nm.get( x );\t\t\t\t\t\t// \"foo\"\nm.get( y );\t\t\t\t\t\t// \"bar\"\n```\n\nThe only drawback is that you can't use the `[ ]` bracket access syntax for setting and retrieving values. But `get(..)` and `set(..)` work perfectly suitably instead.\n\nTo delete an element from a map, don't use the `delete` operator, but instead use the `delete(..)` method:\n\n```js\nm.set( x, \"foo\" );\nm.set( y, \"bar\" );\n\nm.delete( y );\n```\n\nYou can clear the entire map's contents with `clear()`. To get the length of a map (i.e., the number of keys), use the `size` property (not `length`):\n\n```js\nm.set( x, \"foo\" );\nm.set( y, \"bar\" );\nm.size;\t\t\t\t\t\t\t// 2\n\nm.clear();\nm.size;\t\t\t\t\t\t\t// 0\n```\n\nThe `Map(..)` constructor can also receive an iterable (see \"Iterators\" in Chapter 3), which must produce a list of arrays, where the first item in each array is the key and the second item is the value. This format for iteration is identical to that produced by the `entries()` method, explained in the next section. That makes it easy to make a copy of a map:\n\n```js\nvar m2 = new Map( m.entries() );\n\n// same as:\nvar m2 = new Map( m );\n```\n\nBecause a map instance is an iterable, and its default iterator is the same as `entries()`, the second shorter form is more preferable.\n\nOf course, you can just manually specify an *entries* list (array of key/value arrays) in the `Map(..)` constructor form:\n\n```js\nvar x = { id: 1 },\n\ty = { id: 2 };\n\nvar m = new Map( [\n\t[ x, \"foo\" ],\n\t[ y, \"bar\" ]\n] );\n\nm.get( x );\t\t\t\t\t\t// \"foo\"\nm.get( y );\t\t\t\t\t\t// \"bar\"\n```\n\n### Map Values\n\nTo get the list of values from a map, use `values(..)`, which returns an iterator. In Chapters 2 and 3, we covered various ways to process an iterator sequentially (like an array), such as the `...` spread operator and the `for..of` loop. Also, \"Arrays\" in Chapter 6 covers the `Array.from(..)` method in detail. Consider:\n\n```js\nvar m = new Map();\n\nvar x = { id: 1 },\n\ty = { id: 2 };\n\nm.set( x, \"foo\" );\nm.set( y, \"bar\" );\n\nvar vals = [ ...m.values() ];\n\nvals;\t\t\t\t\t\t\t// [\"foo\",\"bar\"]\nArray.from( m.values() );\t\t// [\"foo\",\"bar\"]\n```\n\nAs discussed in the previous section, you can iterate over a map's entries using `entries()` (or the default map iterator). Consider:\n\n```js\nvar m = new Map();\n\nvar x = { id: 1 },\n\ty = { id: 2 };\n\nm.set( x, \"foo\" );\nm.set( y, \"bar\" );\n\nvar vals = [ ...m.entries() ];\n\nvals[0][0] === x;\t\t\t\t// true\nvals[0][1];\t\t\t\t\t\t// \"foo\"\n\nvals[1][0] === y;\t\t\t\t// true\nvals[1][1];\t\t\t\t\t\t// \"bar\"\n```\n\n### Map Keys\n\nTo get the list of keys, use `keys()`, which returns an iterator over the keys in the map:\n\n```js\nvar m = new Map();\n\nvar x = { id: 1 },\n\ty = { id: 2 };\n\nm.set( x, \"foo\" );\nm.set( y, \"bar\" );\n\nvar keys = [ ...m.keys() ];\n\nkeys[0] === x;\t\t\t\t\t// true\nkeys[1] === y;\t\t\t\t\t// true\n```\n\nTo determine if a map has a given key, use `has(..)`:\n\n```js\nvar m = new Map();\n\nvar x = { id: 1 },\n\ty = { id: 2 };\n\nm.set( x, \"foo\" );\n\nm.has( x );\t\t\t\t\t\t// true\nm.has( y );\t\t\t\t\t\t// false\n```\n\nMaps essentially let you associate some extra piece of information (the value) with an object (the key) without actually putting that information on the object itself.\n\nWhile you can use any kind of value as a key for a map, you typically will use objects, as strings and other primitives are already eligible as keys of normal objects. In other words, you'll probably want to continue to use normal objects for maps unless some or all of the keys need to be objects, in which case map is more appropriate.\n\n**Warning:** If you use an object as a map key and that object is later discarded (all references unset) in attempt to have garbage collection (GC) reclaim its memory, the map itself will still retain its entry. You will need to remove the entry from the map for it to be GC-eligible. In the next section, we'll see WeakMaps as a better option for object keys and GC.\n\n## WeakMaps\n\nWeakMaps are a variation on maps, which has most of the same external behavior but differs underneath in how the memory allocation (specifically its GC) works.\n\nWeakMaps take (only) objects as keys. Those objects are held *weakly*, which means if the object itself is GC'd, the entry in the WeakMap is also removed. This isn't observable behavior, though, as the only way an object can be GC'd is if there's no more references to it -- once there are no more references to it, you have no object reference to check if it exists in the WeakMap.\n\nOtherwise, the API for WeakMap is similar, though more limited:\n\n```js\nvar m = new WeakMap();\n\nvar x = { id: 1 },\n\ty = { id: 2 };\n\nm.set( x, \"foo\" );\n\nm.has( x );\t\t\t\t\t\t// true\nm.has( y );\t\t\t\t\t\t// false\n```\n\nWeakMaps do not have a `size` property or `clear()` method, nor do they expose any iterators over their keys, values, or entries. So even if you unset the `x` reference, which will remove its entry from `m` upon GC, there is no way to tell. You'll just have to take JavaScript's word for it!\n\nJust like Maps, WeakMaps let you soft-associate information with an object. But they are particularly useful if the object is not one you completely control, such as a DOM element. If the object you're using as a map key can be deleted and should be GC-eligible when it is, then a WeakMap is a more appropriate option.\n\nIt's important to note that a WeakMap only holds its *keys* weakly, not its values. Consider:\n\n```js\nvar m = new WeakMap();\n\nvar x = { id: 1 },\n\ty = { id: 2 },\n\tz = { id: 3 },\n\tw = { id: 4 };\n\nm.set( x, y );\n\nx = null;\t\t\t\t\t\t// { id: 1 } is GC-eligible\ny = null;\t\t\t\t\t\t// { id: 2 } is GC-eligible\n\t\t\t\t\t\t\t\t// only because { id: 1 } is\n\nm.set( z, w );\n\nw = null;\t\t\t\t\t\t// { id: 4 } is not GC-eligible\n```\n\nFor this reason, WeakMaps are in my opinion better named \"WeakKeyMaps.\"\n\n## Sets\n\nA set is a collection of unique values (duplicates are ignored).\n\nThe API for a set is similar to map. The `add(..)` method takes the place of the `set(..)` method (somewhat ironically), and there is no `get(..)` method.\n\nConsider:\n\n```js\nvar s = new Set();\n\nvar x = { id: 1 },\n\ty = { id: 2 };\n\ns.add( x );\ns.add( y );\ns.add( x );\n\ns.size;\t\t\t\t\t\t\t// 2\n\ns.delete( y );\ns.size;\t\t\t\t\t\t\t// 1\n\ns.clear();\ns.size;\t\t\t\t\t\t\t// 0\n```\n\nThe `Set(..)` constructor form is similar to `Map(..)`, in that it can receive an iterable, like another set or simply an array of values. However, unlike how `Map(..)` expects *entries* list (array of key/value arrays), `Set(..)` expects a *values* list (array of values):\n\n```js\nvar x = { id: 1 },\n\ty = { id: 2 };\n\nvar s = new Set( [x,y] );\n```\n\nA set doesn't need a `get(..)` because you don't retrieve a value from a set, but rather test if it is present or not, using `has(..)`:\n\n```js\nvar s = new Set();\n\nvar x = { id: 1 },\n\ty = { id: 2 };\n\ns.add( x );\n\ns.has( x );\t\t\t\t\t\t// true\ns.has( y );\t\t\t\t\t\t// false\n```\n\n**Note:** The comparison algorithm in `has(..)` is almost identical to `Object.is(..)` (see Chapter 6), except that `-0` and `0` are treated as the same rather than distinct.\n\n### Set Iterators\n\nSets have the same iterator methods as maps. Their behavior is different for sets, but symmetric with the behavior of map iterators. Consider:\n\n```js\nvar s = new Set();\n\nvar x = { id: 1 },\n\ty = { id: 2 };\n\ns.add( x ).add( y );\n\nvar keys = [ ...s.keys() ],\n\tvals = [ ...s.values() ],\n\tentries = [ ...s.entries() ];\n\nkeys[0] === x;\nkeys[1] === y;\n\nvals[0] === x;\nvals[1] === y;\n\nentries[0][0] === x;\nentries[0][1] === x;\nentries[1][0] === y;\nentries[1][1] === y;\n```\n\nThe `keys()` and `values()` iterators both yield a list of the unique values in the set. The `entries()` iterator yields a list of entry arrays, where both items of the array are the unique set value. The default iterator for a set is its `values()` iterator.\n\nThe inherent uniqueness of a set is its most useful trait. For example:\n\n```js\nvar s = new Set( [1,2,3,4,\"1\",2,4,\"5\"] ),\n\tuniques = [ ...s ];\n\nuniques;\t\t\t\t\t\t// [1,2,3,4,\"1\",\"5\"]\n```\n\nSet uniqueness does not allow coercion, so `1` and `\"1\"` are considered distinct values.\n\n## WeakSets\n\nWhereas a WeakMap holds its keys weakly (but its values strongly), a WeakSet holds its values weakly (there aren't really keys).\n\n```js\nvar s = new WeakSet();\n\nvar x = { id: 1 },\n\ty = { id: 2 };\n\ns.add( x );\ns.add( y );\n\nx = null;\t\t\t\t\t\t// `x` is GC-eligible\ny = null;\t\t\t\t\t\t// `y` is GC-eligible\n```\n\n**Warning:** WeakSet values must be objects, not primitive values as is allowed with sets.\n\n## Review\n\nES6 defines a number of useful collections that make working with data in structured ways more efficient and effective.\n\nTypedArrays provide \"view\"s of binary data buffers that align with various integer types, like 8-bit unsigned integers and 32-bit floats. The array access to binary data makes operations much easier to express and maintain, which enables you to more easily work with complex data like video, audio, canvas data, and so on.\n\nMaps are key-value pairs where the key can be an object instead of just a string/primitive. Sets are unique lists of values (of any type).\n\nWeakMaps are maps where the key (object) is weakly held, so that GC is free to collect the entry if it's the last reference to an object. WeakSets are sets where the value is weakly held, again so that GC can remove the entry if it's the last reference to that object.\n"
  },
  {
    "path": "es6 & beyond/ch6.md",
    "content": "# You Don't Know JS: ES6 & Beyond\n# Chapter 6: API Additions\n\nFrom conversions of values to mathematic calculations, ES6 adds many static properties and methods to various built-in natives and objects to help with common tasks. In addition, instances of some of the natives have new capabilities via various new prototype methods.\n\n**Note:** Most of these features can be faithfully polyfilled. We will not dive into such details here, but check out \"ES6 Shim\" (https://github.com/paulmillr/es6-shim/) for standards-compliant shims/polyfills.\n\n## `Array`\n\nOne of the most commonly extended features in JS by various user libraries is the Array type. It should be no surprise that ES6 adds a number of helpers to Array, both static and prototype (instance).\n\n### `Array.of(..)` Static Function\n\nThere's a well known gotcha with the `Array(..)` constructor, which is that if there's only one argument passed, and that argument is a number, instead of making an array of one element with that number value in it, it constructs an empty array with a `length` property equal to the number. This action produces the unfortunate and quirky \"empty slots\" behavior that's reviled about JS arrays.\n\n`Array.of(..)` replaces `Array(..)` as the preferred function-form constructor for arrays, because `Array.of(..)` does not have that special single-number-argument case. Consider:\n\n```js\nvar a = Array( 3 );\na.length;\t\t\t\t\t\t// 3\na[0];\t\t\t\t\t\t\t// undefined\n\nvar b = Array.of( 3 );\nb.length;\t\t\t\t\t\t// 1\nb[0];\t\t\t\t\t\t\t// 3\n\nvar c = Array.of( 1, 2, 3 );\nc.length;\t\t\t\t\t\t// 3\nc;\t\t\t\t\t\t\t\t// [1,2,3]\n```\n\nUnder what circumstances would you want to use `Array.of(..)` instead of just creating an array with literal syntax, like `c = [1,2,3]`? There's two possible cases.\n\nIf you have a callback that's supposed to wrap argument(s) passed to it in an array, `Array.of(..)` fits the bill perfectly. That's probably not terribly common, but it may scratch an itch for you.\n\nThe other scenario is if you subclass `Array` (see \"Classes\" in Chapter 3) and want to be able to create and initialize elements in an instance of your subclass, such as:\n\n```js\nclass MyCoolArray extends Array {\n\tsum() {\n\t\treturn this.reduce( function reducer(acc,curr){\n\t\t\treturn acc + curr;\n\t\t}, 0 );\n\t}\n}\n\nvar x = new MyCoolArray( 3 );\nx.length;\t\t\t\t\t\t// 3 -- oops!\nx.sum();\t\t\t\t\t\t// 0 -- oops!\n\nvar y = [3];\t\t\t\t\t// Array, not MyCoolArray\ny.length;\t\t\t\t\t\t// 1\ny.sum();\t\t\t\t\t\t// `sum` is not a function\n\nvar z = MyCoolArray.of( 3 );\nz.length;\t\t\t\t\t\t// 1\nz.sum();\t\t\t\t\t\t// 3\n```\n\nYou can't just (easily) create a constructor for `MyCoolArray` that overrides the behavior of the `Array` parent constructor, because that constructor is necessary to actually create a well-behaving array value (initializing the `this`). The \"inherited\" static `of(..)` method on the `MyCoolArray` subclass provides a nice solution.\n\n### `Array.from(..)` Static Function\n\nAn \"array-like object\" in JavaScript is an object that has a `length` property on it, specifically with an integer value of zero or higher.\n\nThese values have been notoriously frustrating to work with in JS; it's been quite common to need to transform them into an actual array, so that the various `Array.prototype` methods (`map(..)`, `indexOf(..)` etc.) are available to use with it. That process usually looks like:\n\n```js\n// array-like object\nvar arrLike = {\n\tlength: 3,\n\t0: \"foo\",\n\t1: \"bar\"\n};\n\nvar arr = Array.prototype.slice.call( arrLike );\n```\n\nAnother common task where `slice(..)` is often used is in duplicating a real array:\n\n```js\nvar arr2 = arr.slice();\n```\n\nIn both cases, the new ES6 `Array.from(..)` method can be a more understandable and graceful -- if also less verbose -- approach:\n\n```js\nvar arr = Array.from( arrLike );\n\nvar arrCopy = Array.from( arr );\n```\n\n`Array.from(..)` looks to see if the first argument is an iterable (see \"Iterators\" in Chapter 3), and if so, it uses the iterator to produce values to \"copy\" into the returned array. Because real arrays have an iterator for those values, that iterator is automatically used.\n\nBut if you pass an array-like object as the first argument to `Array.from(..)`, it behaves basically the same as `slice()` (no arguments!) or `apply(..)` does, which is that it simply loops over the value, accessing numerically named properties from `0` up to whatever the value of `length` is.\n\nConsider:\n\n```js\nvar arrLike = {\n\tlength: 4,\n\t2: \"foo\"\n};\n\nArray.from( arrLike );\n// [ undefined, undefined, \"foo\", undefined ]\n```\n\nBecause positions `0`, `1`, and `3` didn't exist on `arrLike`, the result was the `undefined` value for each of those slots.\n\nYou could produce a similar outcome like this:\n\n```js\nvar emptySlotsArr = [];\nemptySlotsArr.length = 4;\nemptySlotsArr[2] = \"foo\";\n\nArray.from( emptySlotsArr );\n// [ undefined, undefined, \"foo\", undefined ]\n```\n\n#### Avoiding Empty Slots\n\nThere's a subtle but important difference in the previous snippet between the `emptySlotsArr` and the result of the `Array.from(..)` call. `Array.from(..)` never produces empty slots.\n\nPrior to ES6, if you wanted to produce an array initialized to a certain length with actual `undefined` values in each slot (no empty slots!), you had to do extra work:\n\n```js\nvar a = Array( 4 );\t\t\t\t\t\t\t\t// four empty slots!\n\nvar b = Array.apply( null, { length: 4 } );\t\t// four `undefined` values\n```\n\nBut `Array.from(..)` now makes this easier:\n\n```js\nvar c = Array.from( { length: 4 } );\t\t\t// four `undefined` values\n```\n\n**Warning:** Using an empty slot array like `a` in the previous snippets would work with some array functions, but others ignore empty slots (like `map(..)`, etc.). You should never intentionally work with empty slots, as it will almost certainly lead to strange/unpredictable behavior in your programs.\n\n#### Mapping\n\nThe `Array.from(..)` utility has another helpful trick up its sleeve. The second argument, if provided, is a mapping callback (almost the same as the regular `Array#map(..)` expects) which is called to map/transform each value from the source to the returned target. Consider:\n\n```js\nvar arrLike = {\n\tlength: 4,\n\t2: \"foo\"\n};\n\nArray.from( arrLike, function mapper(val,idx){\n\tif (typeof val == \"string\") {\n\t\treturn val.toUpperCase();\n\t}\n\telse {\n\t\treturn idx;\n\t}\n} );\n// [ 0, 1, \"FOO\", 3 ]\n```\n\n**Note:** As with other array methods that take callbacks, `Array.from(..)` takes an optional third argument that if set will specify the `this` binding for the callback passed as the second argument. Otherwise, `this` will be `undefined`.\n\nSee \"TypedArrays\" in Chapter 5 for an example of using `Array.from(..)` in translating values from an array of 8-bit values to an array of 16-bit values.\n\n### Creating Arrays and Subtypes\n\nIn the last couple of sections, we've discussed `Array.of(..)` and `Array.from(..)`, both of which create a new array in a similar way to a constructor. But what do they do in subclasses? Do they create instances of the base `Array` or the derived subclass?\n\n```js\nclass MyCoolArray extends Array {\n\t..\n}\n\nMyCoolArray.from( [1, 2] ) instanceof MyCoolArray;\t// true\n\nArray.from(\n\tMyCoolArray.from( [1, 2] )\n) instanceof MyCoolArray;\t\t\t\t\t\t\t// false\n```\n\nBoth `of(..)` and `from(..)` use the constructor that they're accessed from to construct the array. So if you use the base `Array.of(..)` you'll get an `Array` instance, but if you use `MyCoolArray.of(..)`, you'll get a `MyCoolArray` instance.\n\nIn \"Classes\" in Chapter 3, we covered the `@@species` setting which all the built-in classes (like `Array`) have defined, which is used by any prototype methods if they create a new instance. `slice(..)` is a great example:\n\n```js\nvar x = new MyCoolArray( 1, 2, 3 );\n\nx.slice( 1 ) instanceof MyCoolArray;\t\t\t\t// true\n```\n\nGenerally, that default behavior will probably be desired, but as we discussed in Chapter 3, you *can* override if you want:\n\n```js\nclass MyCoolArray extends Array {\n\t// force `species` to be parent constructor\n\tstatic get [Symbol.species]() { return Array; }\n}\n\nvar x = new MyCoolArray( 1, 2, 3 );\n\nx.slice( 1 ) instanceof MyCoolArray;\t\t\t\t// false\nx.slice( 1 ) instanceof Array;\t\t\t\t\t\t// true\n```\n\nIt's important to note that the `@@species` setting is only used for the prototype methods, like `slice(..)`. It's not used by `of(..)` and `from(..)`; they both just use the `this` binding (whatever constructor is used to make the reference). Consider:\n\n```js\nclass MyCoolArray extends Array {\n\t// force `species` to be parent constructor\n\tstatic get [Symbol.species]() { return Array; }\n}\n\nvar x = new MyCoolArray( 1, 2, 3 );\n\nMyCoolArray.from( x ) instanceof MyCoolArray;\t\t// true\nMyCoolArray.of( [2, 3] ) instanceof MyCoolArray;\t// true\n```\n\n### `copyWithin(..)` Prototype Method\n\n`Array#copyWithin(..)` is a new mutator method available to all arrays (including Typed Arrays; see Chapter 5). `copyWithin(..)` copies a portion of an array to another location in the same array, overwriting whatever was there before.\n\nThe arguments are *target* (the index to copy to), *start* (the inclusive index to start the copying from), and optionally *end* (the exclusive index to stop copying). If any of the arguments are negative, they're taken to be relative from the end of the array.\n\nConsider:\n\n```js\n[1,2,3,4,5].copyWithin( 3, 0 );\t\t\t// [1,2,3,1,2]\n\n[1,2,3,4,5].copyWithin( 3, 0, 1 );\t\t// [1,2,3,1,5]\n\n[1,2,3,4,5].copyWithin( 0, -2 );\t\t// [4,5,3,4,5]\n\n[1,2,3,4,5].copyWithin( 0, -2, -1 );\t// [4,2,3,4,5]\n```\n\nThe `copyWithin(..)` method does not extend the array's length, as the first example in the previous snippet shows. Copying simply stops when the end of the array is reached.\n\nContrary to what you might think, the copying doesn't always go in left-to-right (ascending index) order. It's possible this would result in repeatedly copying an already copied value if the from and target ranges overlap, which is presumably not desired behavior.\n\nSo internally, the algorithm avoids this case by copying in reverse order to avoid that gotcha. Consider:\n\n```js\n[1,2,3,4,5].copyWithin( 2, 1 );\t\t// ???\n```\n\nIf the algorithm was strictly moving left to right, then the `2` should be copied to overwrite the `3`, then *that* copied `2` should be copied to overwrite `4`, then *that* copied `2` should be copied to overwrite `5`, and you'd end up with `[1,2,2,2,2]`.\n\nInstead, the copying algorithm reverses direction and copies `4` to overwrite `5`, then copies `3` to overwrite `4`, then copies `2` to overwrite `3`, and the final result is `[1,2,2,3,4]`. That's probably more \"correct\" in terms of expectation, but it can be confusing if you're only thinking about the copying algorithm in a naive left-to-right fashion.\n\n### `fill(..)` Prototype Method\n\nFilling an existing array entirely (or partially) with a specified value is natively supported as of ES6 with the `Array#fill(..)` method:\n\n```js\nvar a = Array( 4 ).fill( undefined );\na;\n// [undefined,undefined,undefined,undefined]\n```\n\n`fill(..)` optionally takes *start* and *end* parameters, which indicate a subset portion of the array to fill, such as:\n\n```js\nvar a = [ null, null, null, null ].fill( 42, 1, 3 );\n\na;\t\t\t\t\t\t\t\t\t// [null,42,42,null]\n```\n\n### `find(..)` Prototype Method\n\nThe most common way to search for a value in an array has generally been the `indexOf(..)` method, which returns the index the value is found at or `-1` if not found:\n\n```js\nvar a = [1,2,3,4,5];\n\n(a.indexOf( 3 ) != -1);\t\t\t\t// true\n(a.indexOf( 7 ) != -1);\t\t\t\t// false\n\n(a.indexOf( \"2\" ) != -1);\t\t\t// false\n```\n\nThe `indexOf(..)` comparison requires a strict `===` match, so a search for `\"2\"` fails to find a value of `2`, and vice versa. There's no way to override the matching algorithm for `indexOf(..)`. It's also unfortunate/ungraceful to have to make the manual comparison to the `-1` value.\n\n**Tip:** See the *Types & Grammar* title of this series for an interesting (and controversially confusing) technique to work around the `-1` ugliness with the `~` operator.\n\nSince ES5, the most common workaround to have control over the matching logic has been the `some(..)` method. It works by calling a function callback for each element, until one of those calls returns a `true`/truthy value, and then it stops. Because you get to define the callback function, you have full control over how a match is made:\n\n```js\nvar a = [1,2,3,4,5];\n\na.some( function matcher(v){\n\treturn v == \"2\";\n} );\t\t\t\t\t\t\t\t// true\n\na.some( function matcher(v){\n\treturn v == 7;\n} );\t\t\t\t\t\t\t\t// false\n```\n\nBut the downside to this approach is that you only get the `true`/`false` indicating if a suitably matched value was found, but not what the actual matched value was.\n\nES6's `find(..)` addresses this. It works basically the same as `some(..)`, except that once the callback returns a `true`/truthy value, the actual array value is returned:\n\n```js\nvar a = [1,2,3,4,5];\n\na.find( function matcher(v){\n\treturn v == \"2\";\n} );\t\t\t\t\t\t\t\t// 2\n\na.find( function matcher(v){\n\treturn v == 7;\t\t\t\t\t// undefined\n});\n```\n\nUsing a custom `matcher(..)` function also lets you match against complex values like objects:\n\n```js\nvar points = [\n\t{ x: 10, y: 20 },\n\t{ x: 20, y: 30 },\n\t{ x: 30, y: 40 },\n\t{ x: 40, y: 50 },\n\t{ x: 50, y: 60 }\n];\n\npoints.find( function matcher(point) {\n\treturn (\n\t\tpoint.x % 3 == 0 &&\n\t\tpoint.y % 4 == 0\n\t);\n} );\t\t\t\t\t\t\t\t// { x: 30, y: 40 }\n```\n\n**Note:** As with other array methods that take callbacks, `find(..)` takes an optional second argument that if set will specify the `this` binding for the callback passed as the first argument. Otherwise, `this` will be `undefined`.\n\n### `findIndex(..)` Prototype Method\n\nWhile the previous section illustrates how `some(..)` yields a boolean result for a search of an array, and `find(..)` yields the matched value itself from the array search, there's also a need for finding the positional index of the matched value.\n\n`indexOf(..)` does that, but there's no control over its matching logic; it always uses `===` strict equality. So ES6's `findIndex(..)` is the answer:\n\n```js\nvar points = [\n\t{ x: 10, y: 20 },\n\t{ x: 20, y: 30 },\n\t{ x: 30, y: 40 },\n\t{ x: 40, y: 50 },\n\t{ x: 50, y: 60 }\n];\n\npoints.findIndex( function matcher(point) {\n\treturn (\n\t\tpoint.x % 3 == 0 &&\n\t\tpoint.y % 4 == 0\n\t);\n} );\t\t\t\t\t\t\t\t// 2\n\npoints.findIndex( function matcher(point) {\n\treturn (\n\t\tpoint.x % 6 == 0 &&\n\t\tpoint.y % 7 == 0\n\t);\n} );\t\t\t\t\t\t\t\t// -1\n```\n\nDon't use `findIndex(..) != -1` (the way it's always been done with `indexOf(..)`) to get a boolean from the search, because `some(..)` already yields the `true`/`false` you want. And don't do `a[ a.findIndex(..) ]` to get the matched value, because that's what `find(..)` accomplishes. And finally, use `indexOf(..)` if you need the index of a strict match, or `findIndex(..)` if you need the index of a more customized match.\n\n**Note:** As with other array methods that take callbacks, `findIndex(..)` takes an optional second argument that if set will specify the `this` binding for the callback passed as the first argument. Otherwise, `this` will be `undefined`.\n\n### `entries()`, `values()`, `keys()` Prototype Methods\n\nIn Chapter 3, we illustrated how data structures can provide a patterned item-by-item enumeration of their values, via an iterator. We then expounded on this approach in Chapter 5, as we explored how the new ES6 collections (Map, Set, etc.) provide several methods for producing different kinds of iterations.\n\nBecause it's not new to ES6, `Array` might not be thought of traditionally as a \"collection,\" but it is one in the sense that it provides these same iterator methods: `entries()`, `values()`, and `keys()`. Consider:\n\n```js\nvar a = [1,2,3];\n\n[...a.values()];\t\t\t\t\t// [1,2,3]\n[...a.keys()];\t\t\t\t\t\t// [0,1,2]\n[...a.entries()];\t\t\t\t\t// [ [0,1], [1,2], [2,3] ]\n\n[...a[Symbol.iterator]()];\t\t\t// [1,2,3]\n```\n\nJust like with `Set`, the default `Array` iterator is the same as what `values()` returns.\n\nIn \"Avoiding Empty Slots\" earlier in this chapter, we illustrated how `Array.from(..)` treats empty slots in an array as just being present slots with `undefined` in them. That's actually because under the covers, the array iterators behave that way:\n\n```js\nvar a = [];\na.length = 3;\na[1] = 2;\n\n[...a.values()];\t\t// [undefined,2,undefined]\n[...a.keys()];\t\t\t// [0,1,2]\n[...a.entries()];\t\t// [ [0,undefined], [1,2], [2,undefined] ]\n```\n\n## `Object`\n\nA few additional static helpers have been added to `Object`. Traditionally, functions of this sort have been seen as focused on the behaviors/capabilities of object values.\n\nHowever, starting with ES6, `Object` static functions will also be for general-purpose global APIs of any sort that don't already belong more naturally in some other location (i.e., `Array.from(..)`).\n\n### `Object.is(..)` Static Function\n\nThe `Object.is(..)` static function makes value comparisons in an even more strict fashion than the `===` comparison.\n\n`Object.is(..)` invokes the underlying `SameValue` algorithm (ES6 spec, section 7.2.9). The `SameValue` algorithm is basically the same as the `===` Strict Equality Comparison Algorithm (ES6 spec, section 7.2.13), with two important exceptions.\n\nConsider:\n\n```js\nvar x = NaN, y = 0, z = -0;\n\nx === x;\t\t\t\t\t\t\t// false\ny === z;\t\t\t\t\t\t\t// true\n\nObject.is( x, x );\t\t\t\t\t// true\nObject.is( y, z );\t\t\t\t\t// false\n```\n\nYou should continue to use `===` for strict equality comparisons; `Object.is(..)` shouldn't be thought of as a replacement for the operator. However, in cases where you're trying to strictly identify a `NaN` or `-0` value, `Object.is(..)` is now the preferred option.\n\n**Note:** ES6 also adds a `Number.isNaN(..)` utility (discussed later in this chapter) which may be a slightly more convenient test; you may prefer `Number.isNaN(x)` over `Object.is(x,NaN)`. You *can* accurately test for `-0` with a clumsy `x == 0 && 1 / x === -Infinity`, but in this case `Object.is(x,-0)` is much better.\n\n### `Object.getOwnPropertySymbols(..)` Static Function\n\nThe \"Symbols\" section in Chapter 2 discusses the new Symbol primitive value type in ES6.\n\nSymbols are likely going to be mostly used as special (meta) properties on objects. So the `Object.getOwnPropertySymbols(..)` utility was introduced, which retrieves only the symbol properties directly on an object:\n\n```js\nvar o = {\n\tfoo: 42,\n\t[ Symbol( \"bar\" ) ]: \"hello world\",\n\tbaz: true\n};\n\nObject.getOwnPropertySymbols( o );\t// [ Symbol(bar) ]\n```\n\n### `Object.setPrototypeOf(..)` Static Function\n\nAlso in Chapter 2, we mentioned the `Object.setPrototypeOf(..)` utility, which (unsurprisingly) sets the `[[Prototype]]` of an object for the purposes of *behavior delegation* (see the *this & Object Prototypes* title of this series). Consider:\n\n```js\nvar o1 = {\n\tfoo() { console.log( \"foo\" ); }\n};\nvar o2 = {\n\t// .. o2's definition ..\n};\n\nObject.setPrototypeOf( o2, o1 );\n\n// delegates to `o1.foo()`\no2.foo();\t\t\t\t\t\t\t// foo\n```\n\nAlternatively:\n\n```js\nvar o1 = {\n\tfoo() { console.log( \"foo\" ); }\n};\n\nvar o2 = Object.setPrototypeOf( {\n\t// .. o2's definition ..\n}, o1 );\n\n// delegates to `o1.foo()`\no2.foo();\t\t\t\t\t\t\t// foo\n```\n\nIn both previous snippets, the relationship between `o2` and `o1` appears at the end of the `o2` definition. More commonly, the relationship between an `o2` and `o1` is specified at the top of the `o2` definition, as it is with classes, and also with `__proto__` in object literals (see \"Setting `[[Prototype]]`\" in Chapter 2).\n\n**Warning:** Setting a `[[Prototype]]` right after object creation is reasonable, as shown. But changing it much later is generally not a good idea and will usually lead to more confusion than clarity.\n\n### `Object.assign(..)` Static Function\n\nMany JavaScript libraries/frameworks provide utilities for copying/mixing one object's properties into another (e.g., jQuery's `extend(..)`). There are various nuanced differences between these different utilities, such as whether a property with value `undefined` is ignored or not.\n\nES6 adds `Object.assign(..)`, which is a simplified version of these algorithms. The first argument is the *target*, and any other arguments passed are the *sources*, which will be processed in listed order. For each source, its enumerable and own (e.g., not \"inherited\") keys, including symbols, are copied as if by plain `=` assignment. `Object.assign(..)` returns the target object.\n\nConsider this object setup:\n\n```js\nvar target = {},\n\to1 = { a: 1 }, o2 = { b: 2 },\n\to3 = { c: 3 }, o4 = { d: 4 };\n\n// setup read-only property\nObject.defineProperty( o3, \"e\", {\n\tvalue: 5,\n\tenumerable: true,\n\twritable: false,\n\tconfigurable: false\n} );\n\n// setup non-enumerable property\nObject.defineProperty( o3, \"f\", {\n\tvalue: 6,\n\tenumerable: false\n} );\n\no3[ Symbol( \"g\" ) ] = 7;\n\n// setup non-enumerable symbol\nObject.defineProperty( o3, Symbol( \"h\" ), {\n\tvalue: 8,\n\tenumerable: false\n} );\n\nObject.setPrototypeOf( o3, o4 );\n```\n\nOnly the properties `a`, `b`, `c`, `e`, and `Symbol(\"g\")` will be copied to `target`:\n\n```js\nObject.assign( target, o1, o2, o3 );\n\ntarget.a;\t\t\t\t\t\t\t// 1\ntarget.b;\t\t\t\t\t\t\t// 2\ntarget.c;\t\t\t\t\t\t\t// 3\n\nObject.getOwnPropertyDescriptor( target, \"e\" );\n// { value: 5, writable: true, enumerable: true,\n//   configurable: true }\n\nObject.getOwnPropertySymbols( target );\n// [Symbol(\"g\")]\n```\n\nThe `d`, `f`, and `Symbol(\"h\")` properties are omitted from copying; non-enumerable properties and non-owned properties are all excluded from the assignment. Also, `e` is copied as a normal property assignment, not duplicated as a read-only property.\n\nIn an earlier section, we showed using `setPrototypeOf(..)` to set up a `[[Prototype]]` relationship between an `o2` and `o1` object. There's another form that leverages `Object.assign(..)`:\n\n```js\nvar o1 = {\n\tfoo() { console.log( \"foo\" ); }\n};\n\nvar o2 = Object.assign(\n\tObject.create( o1 ),\n\t{\n\t\t// .. o2's definition ..\n\t}\n);\n\n// delegates to `o1.foo()`\no2.foo();\t\t\t\t\t\t\t// foo\n```\n\n**Note:** `Object.create(..)` is the ES5 standard utility that creates an empty object that is `[[Prototype]]`-linked. See the *this & Object Prototypes* title of this series for more information.\n\n## `Math`\n\nES6 adds several new mathematic utilities that fill in holes or aid with common operations. All of these can be manually calculated, but most of them are now defined natively so that in some cases the JS engine can either more optimally perform the calculations, or perform them with better decimal precision than their manual counterparts.\n\nIt's likely that asm.js/transpiled JS code (see the *Async & Performance* title of this series) is the more likely consumer of many of these utilities rather than direct developers.\n\nTrigonometry:\n\n* `cosh(..)` - Hyperbolic cosine\n* `acosh(..)` - Hyperbolic arccosine\n* `sinh(..)` - Hyperbolic sine\n* `asinh(..)` - Hyperbolic arcsine\n* `tanh(..)` - Hyperbolic tangent\n* `atanh(..)` - Hyperbolic arctangent\n* `hypot(..)` - The squareroot of the sum of the squares (i.e., the generalized Pythagorean theorem)\n\nArithmetic:\n\n* `cbrt(..)` - Cube root\n* `clz32(..)` - Count leading zeros in 32-bit binary representation\n* `expm1(..)` - The same as `exp(x) - 1`\n* `log2(..)` - Binary logarithm (log base 2)\n* `log10(..)` - Log base 10\n* `log1p(..)` - The same as `log(x + 1)`\n* `imul(..)` - 32-bit integer multiplication of two numbers\n\nMeta:\n\n* `sign(..)` - Returns the sign of the number\n* `trunc(..)` - Returns only the integer part of a number\n* `fround(..)` - Rounds to nearest 32-bit (single precision) floating-point value\n\n## `Number`\n\nImportantly, for your program to properly work, it must accurately handle numbers. ES6 adds some additional properties and functions to assist with common numeric operations.\n\nTwo additions to `Number` are just references to the preexisting globals: `Number.parseInt(..)` and `Number.parseFloat(..)`.\n\n### Static Properties\n\nES6 adds some helpful numeric constants as static properties:\n\n* `Number.EPSILON` - The minimum value between any two numbers: `2^-52` (see Chapter 2 of the *Types & Grammar* title of this series regarding using this value as a tolerance for imprecision in floating-point arithmetic)\n* `Number.MAX_SAFE_INTEGER` - The highest integer that can \"safely\" be represented unambiguously in a JS number value: `2^53 - 1`\n* `Number.MIN_SAFE_INTEGER` - The lowest integer that can \"safely\" be represented unambiguously in a JS number value: `-(2^53 - 1)` or `(-2)^53 + 1`.\n\n**Note:** See Chapter 2 of the *Types & Grammar* title of this series for more information about \"safe\" integers.\n\n### `Number.isNaN(..)` Static Function\n\nThe standard global `isNaN(..)` utility has been broken since its inception, in that it returns `true` for things that are not numbers, not just for the actual `NaN` value, because it coerces the argument to a number type (which can falsely result in a NaN). ES6 adds a fixed utility `Number.isNaN(..)` that works as it should:\n\n```js\nvar a = NaN, b = \"NaN\", c = 42;\n\nisNaN( a );\t\t\t\t\t\t\t// true\nisNaN( b );\t\t\t\t\t\t\t// true -- oops!\nisNaN( c );\t\t\t\t\t\t\t// false\n\nNumber.isNaN( a );\t\t\t\t\t// true\nNumber.isNaN( b );\t\t\t\t\t// false -- fixed!\nNumber.isNaN( c );\t\t\t\t\t// false\n```\n\n### `Number.isFinite(..)` Static Function\n\nThere's a temptation to look at a function name like `isFinite(..)` and assume it's simply \"not infinite\". That's not quite correct, though. There's more nuance to this new ES6 utility. Consider:\n\n```js\nvar a = NaN, b = Infinity, c = 42;\n\nNumber.isFinite( a );\t\t\t\t// false\nNumber.isFinite( b );\t\t\t\t// false\n\nNumber.isFinite( c );\t\t\t\t// true\n```\n\nThe standard global `isFinite(..)` coerces its argument, but `Number.isFinite(..)` omits the coercive behavior:\n\n```js\nvar a = \"42\";\n\nisFinite( a );\t\t\t\t\t\t// true\nNumber.isFinite( a );\t\t\t\t// false\n```\n\nYou may still prefer the coercion, in which case using the global `isFinite(..)` is a valid choice. Alternatively, and perhaps more sensibly, you can use `Number.isFinite(+x)`, which explicitly coerces `x` to a number before passing it in (see Chapter 4 of the *Types & Grammar* title of this series).\n\n### Integer-Related Static Functions\n\nJavaScript number values are always floating point (IEEE-754). So the notion of determining if a number is an \"integer\" is not about checking its type, because JS makes no such distinction.\n\nInstead, you need to check if there's any non-zero decimal portion of the value. The easiest way to do that has commonly been:\n\n```js\nx === Math.floor( x );\n```\n\nES6 adds a `Number.isInteger(..)` helper utility that potentially can determine this quality slightly more efficiently:\n\n```js\nNumber.isInteger( 4 );\t\t\t\t// true\nNumber.isInteger( 4.2 );\t\t\t// false\n```\n\n**Note:** In JavaScript, there's no difference between `4`, `4.`, `4.0`, or `4.0000`. All of these would be considered an \"integer\", and would thus yield `true` from `Number.isInteger(..)`.\n\nIn addition, `Number.isInteger(..)` filters out some clearly not-integer values that `x === Math.floor(x)` could potentially mix up:\n\n```js\nNumber.isInteger( NaN );\t\t\t// false\nNumber.isInteger( Infinity );\t\t// false\n```\n\nWorking with \"integers\" is sometimes an important bit of information, as it can simplify certain kinds of algorithms. JS code by itself will not run faster just from filtering for only integers, but there are optimization techniques the engine can take (e.g., asm.js) when only integers are being used.\n\nBecause of `Number.isInteger(..)`'s handling of `NaN` and `Infinity` values, defining a `isFloat(..)` utility would not be just as simple as `!Number.isInteger(..)`. You'd need to do something like:\n\n```js\nfunction isFloat(x) {\n\treturn Number.isFinite( x ) && !Number.isInteger( x );\n}\n\nisFloat( 4.2 );\t\t\t\t\t\t// true\nisFloat( 4 );\t\t\t\t\t\t// false\n\nisFloat( NaN );\t\t\t\t\t\t// false\nisFloat( Infinity );\t\t\t\t// false\n```\n\n**Note:** It may seem strange, but Infinity should neither be considered an integer nor a float.\n\nES6 also defines a `Number.isSafeInteger(..)` utility, which checks to make sure the value is both an integer and within the range of `Number.MIN_SAFE_INTEGER`-`Number.MAX_SAFE_INTEGER` (inclusive).\n\n```js\nvar x = Math.pow( 2, 53 ),\n\ty = Math.pow( -2, 53 );\n\nNumber.isSafeInteger( x - 1 );\t\t// true\nNumber.isSafeInteger( y + 1 );\t\t// true\n\nNumber.isSafeInteger( x );\t\t\t// false\nNumber.isSafeInteger( y );\t\t\t// false\n```\n\n## `String`\n\nStrings already have quite a few helpers prior to ES6, but even more have been added to the mix.\n\n### Unicode Functions\n\n\"Unicode-Aware String Operations\" in Chapter 2 discusses `String.fromCodePoint(..)`, `String#codePointAt(..)`, and `String#normalize(..)` in detail. They have been added to improve Unicode support in JS string values.\n\n```js\nString.fromCodePoint( 0x1d49e );\t\t\t// \"𝒞\"\n\n\"ab𝒞d\".codePointAt( 2 ).toString( 16 );\t\t// \"1d49e\"\n```\n\nThe `normalize(..)` string prototype method is used to perform Unicode normalizations that either combine characters with adjacent \"combining marks\" or decompose combined characters.\n\nGenerally, the normalization won't create a visible effect on the contents of the string, but will change the contents of the string, which can affect how things like the `length` property are reported, as well as how character access by position behave:\n\n```js\nvar s1 = \"e\\u0301\";\ns1.length;\t\t\t\t\t\t\t// 2\n\nvar s2 = s1.normalize();\ns2.length;\t\t\t\t\t\t\t// 1\ns2 === \"\\xE9\";\t\t\t\t\t\t// true\n```\n\n`normalize(..)` takes an optional argument that specifies the normalization form to use. This argument must be one of the following four values: `\"NFC\"` (default), `\"NFD\"`, `\"NFKC\"`, or `\"NFKD\"`.\n\n**Note:** Normalization forms and their effects on strings is well beyond the scope of what we'll discuss here. See \"Unicode Normalization Forms\" (http://www.unicode.org/reports/tr15/) for more information.\n\n### `String.raw(..)` Static Function\n\nThe `String.raw(..)` utility is provided as a built-in tag function to use with template string literals (see Chapter 2) for obtaining the raw string value without any processing of escape sequences.\n\nThis function will almost never be called manually, but will be used with tagged template literals:\n\n```js\nvar str = \"bc\";\n\nString.raw`\\ta${str}d\\xE9`;\n// \"\\tabcd\\xE9\", not \"\tabcdé\"\n```\n\nIn the resultant string, `\\` and `t` are separate raw characters, not the one escape sequence character `\\t`. The same is true with the Unicode escape sequence.\n\n### `repeat(..)` Prototype Function\n\nIn languages like Python and Ruby, you can repeat a string as:\n\n```js\n\"foo\" * 3;\t\t\t\t\t\t\t// \"foofoofoo\"\n```\n\nThat doesn't work in JS, because `*` multiplication is only defined for numbers, and thus `\"foo\"` coerces to the `NaN` number.\n\nHowever, ES6 defines a string prototype method `repeat(..)` to accomplish the task:\n\n```js\n\"foo\".repeat( 3 );\t\t\t\t\t// \"foofoofoo\"\n```\n\n### String Inspection Functions\n\nIn addition to `String#indexOf(..)` and `String#lastIndexOf(..)` from prior to ES6, three new methods for searching/inspection have been added: `startsWith(..)`, `endsWidth(..)`, and `includes(..)`.\n\n```js\nvar palindrome = \"step on no pets\";\n\npalindrome.startsWith( \"step on\" );\t// true\npalindrome.startsWith( \"on\", 5 );\t// true\n\npalindrome.endsWith( \"no pets\" );\t// true\npalindrome.endsWith( \"no\", 10 );\t// true\n\npalindrome.includes( \"on\" );\t\t// true\npalindrome.includes( \"on\", 6 );\t\t// false\n```\n\nFor all the string search/inspection methods, if you look for an empty string `\"\"`, it will either be found at the beginning or the end of the string.\n\n**Warning:** These methods will not by default accept a regular expression for the search string. See \"Regular Expression Symbols\" in Chapter 7 for information about disabling the `isRegExp` check that is performed on this first argument.\n\n## Review\n\nES6 adds many extra API helpers on the various built-in native objects:\n\n* `Array` adds `of(..)` and `from(..)` static functions, as well as prototype functions like `copyWithin(..)` and `fill(..)`.\n* `Object` adds static functions like `is(..)` and `assign(..)`.\n* `Math` adds static functions like `acosh(..)` and `clz32(..)`.\n* `Number` adds static properties like `Number.EPSILON`, as well as static functions like `Number.isFinite(..)`.\n* `String` adds static functions like `String.fromCodePoint(..)` and `String.raw(..)`, as well as prototype functions like `repeat(..)` and `includes(..)`.\n\nMost of these additions can be polyfilled (see ES6 Shim), and were inspired by utilities in common JS libraries/frameworks.\n"
  },
  {
    "path": "es6 & beyond/ch7.md",
    "content": "# You Don't Know JS: ES6 & Beyond\n# Chapter 7: Meta Programming\n\nMeta programming is programming where the operation targets the behavior of the program itself. In other words, it's programming the programming of your program. Yeah, a mouthful, huh?\n\nFor example, if you probe the relationship between one object `a` and another `b` -- are they `[[Prototype]]` linked? -- using `a.isPrototype(b)`, this is commonly referred to as introspection, a form of meta programming. Macros (which don't exist in JS, yet) --  where the code modifies itself at compile time -- are another obvious example of meta programming. Enumerating the keys of an object with a `for..in` loop, or checking if an object is an *instance of* a \"class constructor\", are other common meta programming tasks.\n\nMeta programming focuses on one or more of the following: code inspecting itself, code modifying itself, or code modifying default language behavior so other code is affected.\n\nThe goal of meta programming is to leverage the language's own intrinsic capabilities to make the rest of your code more descriptive, expressive, and/or flexible. Because of the *meta* nature of meta programming, it's somewhat difficult to put a more precise definition on it than that. The best way to understand meta programming is to see it through examples.\n\nES6 adds several new forms/features for meta programming on top of what JS already had.\n\n## Function Names\n\nThere are cases where your code may want to introspect on itself and ask what the name of some function is. If you ask what a function's name is, the answer is surprisingly somewhat ambiguous. Consider:\n\n```js\nfunction daz() {\n\t// ..\n}\n\nvar obj = {\n\tfoo: function() {\n\t\t// ..\n\t},\n\tbar: function baz() {\n\t\t// ..\n\t},\n\tbam: daz,\n\tzim() {\n\t\t// ..\n\t}\n};\n```\n\nIn this previous snippet, \"what is the name of `obj.foo()`\" is slightly nuanced. Is it `\"foo\"`, `\"\"`, or `undefined`? And what about `obj.bar()` -- is it named `\"bar\"` or `\"baz\"`? Is `obj.bam()` named `\"bam\"` or `\"daz\"`? What about `obj.zim()`?\n\nMoreover, what about functions which are passed as callbacks, like:\n\n```js\nfunction foo(cb) {\n\t// what is the name of `cb()` here?\n}\n\nfoo( function(){\n\t// I'm anonymous!\n} );\n```\n\nThere are quite a few ways that functions can be expressed in programs, and it's not always clear and unambiguous what the \"name\" of that function should be.\n\nMore importantly, we need to distinguish whether the \"name\" of a function refers to its `name` property -- yes, functions have a property called `name` -- or whether it refers to the lexical binding name, such as `bar` in `function bar() { .. }`.\n\nThe lexical binding name is what you use for things like recursion:\n\n```js\nfunction foo(i) {\n\tif (i < 10) return foo( i * 2 );\n\treturn i;\n}\n```\n\nThe `name` property is what you'd use for meta programming purposes, so that's what we'll focus on in this discussion.\n\nThe confusion comes because by default, the lexical name a function has (if any) is also set as its `name` property. Actually there was no official requirement for that behavior by the ES5 (and prior) specifications. The setting of the `name` property was nonstandard but still fairly reliable. As of ES6, it has been standardized.\n\n**Tip:** If a function has a `name` value assigned, that's typically the name used in stack traces in developer tools.\n\n### Inferences\n\nBut what happens to the `name` property if a function has no lexical name?\n\nAs of ES6, there are now inference rules which can determine a sensible `name` property value to assign a function even if that function doesn't have a lexical name to use.\n\nConsider:\n\n```js\nvar abc = function() {\n\t// ..\n};\n\nabc.name;\t\t\t\t// \"abc\"\n```\n\nHad we given the function a lexical name like `abc = function def() { .. }`, the `name` property would of course be `\"def\"`. But in the absence of the lexical name, intuitively the `\"abc\"` name seems appropriate.\n\nHere are other forms that will infer a name (or not) in ES6:\n\n```js\n(function(){ .. });\t\t\t\t\t// name:\n(function*(){ .. });\t\t\t\t// name:\nwindow.foo = function(){ .. };\t\t// name:\n\nclass Awesome {\n\tconstructor() { .. }\t\t\t// name: Awesome\n\tfunny() { .. }\t\t\t\t\t// name: funny\n}\n\nvar c = class Awesome { .. };\t\t// name: Awesome\n\nvar o = {\n\tfoo() { .. },\t\t\t\t\t// name: foo\n\t*bar() { .. },\t\t\t\t\t// name: bar\n\tbaz: () => { .. },\t\t\t\t// name: baz\n\tbam: function(){ .. },\t\t\t// name: bam\n\tget qux() { .. },\t\t\t\t// name: get qux\n\tset fuz() { .. },\t\t\t\t// name: set fuz\n\t[\"b\" + \"iz\"]:\n\t\tfunction(){ .. },\t\t\t// name: biz\n\t[Symbol( \"buz\" )]:\n\t\tfunction(){ .. }\t\t\t// name: [buz]\n};\n\nvar x = o.foo.bind( o );\t\t\t// name: bound foo\n(function(){ .. }).bind( o );\t\t// name: bound\n\nexport default function() { .. }\t// name: default\n\nvar y = new Function();\t\t\t\t// name: anonymous\nvar GeneratorFunction =\n\tfunction*(){}.__proto__.constructor;\nvar z = new GeneratorFunction();\t// name: anonymous\n```\n\nThe `name` property is not writable by default, but it is configurable, meaning you can use `Object.defineProperty(..)` to manually change it if so desired.\n\n## Meta Properties\n\nIn the \"`new.target`\" section of Chapter 3, we introduced a concept new to JS in ES6: the meta property. As the name suggests, meta properties are intended to provide special meta information in the form of a property access that would otherwise not have been possible.\n\nIn the case of `new.target`, the keyword `new` serves as the context for a property access. Clearly `new` is itself not an object, which makes this capability special. However, when `new.target` is used inside a constructor call (a function/method invoked with `new`), `new` becomes a virtual context, so that `new.target` can refer to the target constructor that `new` invoked.\n\nThis is a clear example of a meta programming operation, as the intent is to determine from inside a constructor call what the original `new` target was, generally for the purposes of introspection (examining typing/structure) or static property access.\n\nFor example, you may want to have different behavior in a constructor depending on if it's directly invoked or invoked via a child class:\n\n```js\nclass Parent {\n\tconstructor() {\n\t\tif (new.target === Parent) {\n\t\t\tconsole.log( \"Parent instantiated\" );\n\t\t}\n\t\telse {\n\t\t\tconsole.log( \"A child instantiated\" );\n\t\t}\n\t}\n}\n\nclass Child extends Parent {}\n\nvar a = new Parent();\n// Parent instantiated\n\nvar b = new Child();\n// A child instantiated\n```\n\nThere's a slight nuance here, which is that the `constructor()` inside the `Parent` class definition is actually given the lexical name of the class (`Parent`), even though the syntax implies that the class is a separate entity from the constructor.\n\n**Warning:** As with all meta programming techniques, be careful of creating code that's too clever for your future self or others maintaining your code to understand. Use these tricks with caution.\n\n## Well Known Symbols\n\nIn the \"Symbols\" section of Chapter 2, we covered the new ES6 primitive type `symbol`. In addition to symbols you can define in your own program, JS predefines a number of built-in symbols, referred to as *Well Known Symbols* (WKS).\n\nThese symbol values are defined primarily to expose special meta properties that are being exposed to your JS programs to give you more control over JS's behavior.\n\nWe'll briefly introduce each and discuss their purpose.\n\n### `Symbol.iterator`\n\nIn Chapters 2 and 3, we introduced and used the `@@iterator` symbol, automatically used by `...` spreads and `for..of` loops. We also saw `@@iterator` as defined on the new ES6 collections as defined in Chapter 5.\n\n`Symbol.iterator` represents the special location (property) on any object where the language mechanisms automatically look to find a method that will construct an iterator instance for consuming that object's values. Many objects come with a default one defined.\n\nHowever, we can define our own iterator logic for any object value by setting the `Symbol.iterator` property, even if that's overriding the default iterator. The meta programming aspect is that we are defining behavior which other parts of JS (namely, operators and looping constructs) use when processing an object value we define.\n\nConsider:\n\n```js\nvar arr = [4,5,6,7,8,9];\n\nfor (var v of arr) {\n\tconsole.log( v );\n}\n// 4 5 6 7 8 9\n\n// define iterator that only produces values\n// from odd indexes\narr[Symbol.iterator] = function*() {\n\tvar idx = 1;\n\tdo {\n\t\tyield this[idx];\n\t} while ((idx += 2) < this.length);\n};\n\nfor (var v of arr) {\n\tconsole.log( v );\n}\n// 5 7 9\n```\n\n### `Symbol.toStringTag` and `Symbol.hasInstance`\n\nOne of the most common meta programming tasks is to introspect on a value to find out what *kind* it is, usually to decide what operations are appropriate to perform on it. With objects, the two most common inspection techniques are `toString()` and `instanceof`.\n\nConsider:\n\n```js\nfunction Foo() {}\n\nvar a = new Foo();\n\na.toString();\t\t\t\t// [object Object]\na instanceof Foo;\t\t\t// true\n```\n\nAs of ES6, you can control the behavior of these operations:\n\n```js\nfunction Foo(greeting) {\n\tthis.greeting = greeting;\n}\n\nFoo.prototype[Symbol.toStringTag] = \"Foo\";\n\nObject.defineProperty( Foo, Symbol.hasInstance, {\n\tvalue: function(inst) {\n\t\treturn inst.greeting == \"hello\";\n\t}\n} );\n\nvar a = new Foo( \"hello\" ),\n\tb = new Foo( \"world\" );\n\nb[Symbol.toStringTag] = \"cool\";\n\na.toString();\t\t\t\t// [object Foo]\nString( b );\t\t\t\t// [object cool]\n\na instanceof Foo;\t\t\t// true\nb instanceof Foo;\t\t\t// false\n```\n\nThe `@@toStringTag` symbol on the prototype (or instance itself) specifies a string value to use in the `[object ___]` stringification.\n\nThe `@@hasInstance` symbol is a method on the constructor function which receives the instance object value and lets you decide by returning `true` or `false` if the value should be considered an instance or not.\n\n**Note:** To set `@@hasInstance` on a function, you must use `Object.defineProperty(..)`, as the default one on `Function.prototype` is `writable: false`. See the *this & Object Prototypes* title of this series for more information.\n\n### `Symbol.species`\n\nIn \"Classes\" in Chapter 3, we introduced the `@@species` symbol, which controls which constructor is used by built-in methods of a class that needs to spawn new instances.\n\nThe most common example is when subclassing `Array` and wanting to define which constructor (`Array(..)` or your subclass) inherited methods like `slice(..)` should use. By default, `slice(..)` called on an instance of a subclass of `Array` would produce a new instance of that subclass, which is frankly what you'll likely often want.\n\nHowever, you can meta program by overriding a class's default `@@species` definition:\n\n```js\nclass Cool {\n\t// defer `@@species` to derived constructor\n\tstatic get [Symbol.species]() { return this; }\n\n\tagain() {\n\t\treturn new this.constructor[Symbol.species]();\n\t}\n}\n\nclass Fun extends Cool {}\n\nclass Awesome extends Cool {\n\t// force `@@species` to be parent constructor\n\tstatic get [Symbol.species]() { return Cool; }\n}\n\nvar a = new Fun(),\n\tb = new Awesome(),\n\tc = a.again(),\n\td = b.again();\n\nc instanceof Fun;\t\t\t// true\nd instanceof Awesome;\t\t// false\nd instanceof Cool;\t\t\t// true\n```\n\nThe `Symbol.species` setting defaults on the built-in native constructors to the `return this` behavior as illustrated in the previous snippet in the `Cool` definition. It has no default on user classes, but as shown that behavior is easy to emulate.\n\nIf you need to define methods that generate new instances, use the meta programming of the `new this.constructor[Symbol.species](..)` pattern instead of the hard-wiring of `new this.constructor(..)` or `new XYZ(..)`. Derived classes will then be able to customize `Symbol.species` to control which constructor vends those instances.\n\n### `Symbol.toPrimitive`\n\nIn the *Types & Grammar* title of this series, we discussed the `ToPrimitive` abstract coercion operation, which is used when an object must be coerced to a primitive value for some operation (such as `==` comparison or `+` addition). Prior to ES6, there was no way to control this behavior.\n\nAs of ES6, the `@@toPrimitive` symbol as a property on any object value can customize that `ToPrimitive` coercion by specifying a method.\n\nConsider:\n\n```js\nvar arr = [1,2,3,4,5];\n\narr + 10;\t\t\t\t// 1,2,3,4,510\n\narr[Symbol.toPrimitive] = function(hint) {\n\tif (hint == \"default\" || hint == \"number\") {\n\t\t// sum all numbers\n\t\treturn this.reduce( function(acc,curr){\n\t\t\treturn acc + curr;\n\t\t}, 0 );\n\t}\n};\n\narr + 10;\t\t\t\t// 25\n```\n\nThe `Symbol.toPrimitive` method will be provided with a *hint* of `\"string\"`, `\"number\"`, or `\"default\"` (which should be interpreted as `\"number\"`), depending on what type the operation invoking `ToPrimitive` is expecting. In the previous snippet, the additive `+` operation has no hint (`\"default\"` is passed). A multiplicative `*` operation would hint `\"number\"` and a `String(arr)` would hint `\"string\"`.\n\n**Warning:** The `==` operator will invoke the `ToPrimitive` operation with no hint -- the `@@toPrimitive` method, if any is called with hint `\"default\"` -- on an object if the other value being compared is not an object. However, if both comparison values are objects, the behavior of `==` is identical to `===`, which is that the references themselves are directly compared. In this case, `@@toPrimitive` is not invoked at all. See the *Types & Grammar* title of this series for more information about coercion and the abstract operations.\n\n### Regular Expression Symbols\n\nThere are four well known symbols that can be overridden for regular expression objects, which control how those regular expressions are used by the four corresponding `String.prototype` functions of the same name:\n\n* `@@match`: The `Symbol.match` value of a regular expression is the method used to match all or part of a string value with the given regular expression. It's used by `String.prototype.match(..)` if you pass it a regular expression for the pattern matching.\n\n   The default algorithm for matching is laid out in section 21.2.5.6 of the ES6 specification (https://people.mozilla.org/~jorendorff/es6-draft.html#sec-regexp.prototype-@@match). You could override this default algorithm and provide extra regex features, such as look-behind assertions.\n\n   `Symbol.match` is also used by the `isRegExp` abstract operation (see the note in \"String Inspection Functions\" in Chapter 6) to determine if an object is intended to be used as a regular expression. To force this check to fail for an object so it's not treated as a regular expression, set the `Symbol.match` value to `false` (or something falsy).\n* `@@replace`: The `Symbol.replace` value of a regular expression is the method used by `String.prototype.replace(..)` to replace within a string one or all occurrences of character sequences that match the given regular expression pattern.\n\n   The default algorithm for replacing is laid out in section 21.2.5.8 of the ES6 specification (https://people.mozilla.org/~jorendorff/es6-draft.html#sec-regexp.prototype-@@replace).\n\n   One cool use for overriding the default algorithm is to provide additional `replacer` argument options, such as supporting `\"abaca\".replace(/a/g,[1,2,3])` producing `\"1b2c3\"` by consuming the iterable for successive replacement values.\n* `@@search`: The `Symbol.search` value of a regular expression is the method used by `String.prototype.search(..)` to search for a sub-string within another string as matched by the given regular expression.\n\n   The default algorithm for searching is laid out in section 21.2.5.9 of the ES6 specification (https://people.mozilla.org/~jorendorff/es6-draft.html#sec-regexp.prototype-@@search).\n* `@@split`: The `Symbol.split` value of a regular expression is the method used by `String.prototype.split(..)` to split a string into sub-strings at the location(s) of the delimiter as matched by the given regular expression.\n\n   The default algorithm for splitting is laid out in section 21.2.5.11 of the ES6 specification (https://people.mozilla.org/~jorendorff/es6-draft.html#sec-regexp.prototype-@@split).\n\nOverriding the built-in regular expression algorithms is not for the faint of heart! JS ships with a highly optimized regular expression engine, so your own user code will likely be a lot slower. This kind of meta programming is neat and powerful, but it should only be used in cases where it's really necessary or beneficial.\n\n### `Symbol.isConcatSpreadable`\n\nThe `@@isConcatSpreadable` symbol can be defined as a boolean property (`Symbol.isConcatSpreadable`) on any object (like an array or other iterable) to indicate if it should be *spread out* if passed to an array `concat(..)`.\n\nConsider:\n\n```js\nvar a = [1,2,3],\n\tb = [4,5,6];\n\nb[Symbol.isConcatSpreadable] = false;\n\n[].concat( a, b );\t\t// [1,2,3,[4,5,6]]\n```\n\n### `Symbol.unscopables`\n\nThe `@@unscopables` symbol can be defined as an object property (`Symbol.unscopables`) on any object to indicate which properties can and cannot be exposed as lexical variables in a `with` statement.\n\nConsider:\n\n```js\nvar o = { a:1, b:2, c:3 },\n\ta = 10, b = 20, c = 30;\n\no[Symbol.unscopables] = {\n\ta: false,\n\tb: true,\n\tc: false\n};\n\nwith (o) {\n\tconsole.log( a, b, c );\t\t// 1 20 3\n}\n```\n\nA `true` in the `@@unscopables` object indicates the property should be *unscopable*, and thus filtered out from the lexical scope variables. `false` means it's OK to be included in the lexical scope variables.\n\n**Warning:** The `with` statement is disallowed entirely in `strict` mode, and as such should be considered deprecated from the language. Don't use it. See the *Scope & Closures* title of this series for more information. Because `with` should be avoided, the `@@unscopables` symbol is also moot.\n\n## Proxies\n\nOne of the most obviously meta programming features added to ES6 is the `Proxy` feature.\n\nA proxy is a special kind of object you create that \"wraps\" -- or sits in front of -- another normal object. You can register special handlers (aka *traps*) on the proxy object which are called when various operations are performed against the proxy. These handlers have the opportunity to perform extra logic in addition to *forwarding* the operations on to the original target/wrapped object.\n\nOne example of the kind of *trap* handler you can define on a proxy is `get` that intercepts the `[[Get]]` operation -- performed when you try to access a property on an object. Consider:\n\n```js\nvar obj = { a: 1 },\n\thandlers = {\n\t\tget(target,key,context) {\n\t\t\t// note: target === obj,\n\t\t\t// context === pobj\n\t\t\tconsole.log( \"accessing: \", key );\n\t\t\treturn Reflect.get(\n\t\t\t\ttarget, key, context\n\t\t\t);\n\t\t}\n\t},\n\tpobj = new Proxy( obj, handlers );\n\nobj.a;\n// 1\n\npobj.a;\n// accessing: a\n// 1\n```\n\nWe declare a `get(..)` handler as a named method on the *handler* object (second argument to `Proxy(..)`), which receives a reference to the *target* object (`obj`), the *key* property name (`\"a\"`), and the `self`/receiver/proxy (`pobj`).\n\nAfter the `console.log(..)` tracing statement, we \"forward\" the operation onto `obj` via `Reflect.get(..)`. We will cover the `Reflect` API in the next section, but note that each available proxy trap has a corresponding `Reflect` function of the same name.\n\nThese mappings are symmetric on purpose. The proxy handlers each intercept when a respective meta programming task is performed, and the `Reflect` utilities each perform the respective meta programming task on an object. Each proxy handler has a default definition that automatically calls the corresponding `Reflect` utility. You will almost certainly use both `Proxy` and `Reflect` in tandem.\n\nHere's a list of handlers you can define on a proxy for a *target* object/function, and how/when they are triggered:\n\n* `get(..)`: via `[[Get]]`, a property is accessed on the proxy (`Reflect.get(..)`, `.` property operator, or `[ .. ]` property operator)\n* `set(..)`: via `[[Set]]`, a property value is set on the proxy (`Reflect.set(..)`, the `=` assignment operator, or destructuring assignment if it targets an object property)\n* `deleteProperty(..)`: via `[[Delete]]`, a property is deleted from the proxy (`Reflect.deleteProperty(..)` or `delete`)\n* `apply(..)` (if *target* is a function): via `[[Call]]`, the proxy is invoked as a normal function/method (`Reflect.apply(..)`, `call(..)`, `apply(..)`, or the `(..)` call operator)\n* `construct(..)` (if *target* is a constructor function): via `[[Construct]]`, the proxy is invoked as a constructor function (`Reflect.construct(..)` or `new`)\n* `getOwnPropertyDescriptor(..)`: via `[[GetOwnProperty]]`, a property descriptor is retrieved from the proxy (`Object.getOwnPropertyDescriptor(..)` or `Reflect.getOwnPropertyDescriptor(..)`)\n* `defineProperty(..)`: via `[[DefineOwnProperty]]`, a property descriptor is set on the proxy (`Object.defineProperty(..)` or `Reflect.defineProperty(..)`)\n* `getPrototypeOf(..)`: via `[[GetPrototypeOf]]`, the `[[Prototype]]` of the proxy is retrieved (`Object.getPrototypeOf(..)`, `Reflect.getPrototypeOf(..)`, `__proto__`, `Object#isPrototypeOf(..)`, or `instanceof`)\n* `setPrototypeOf(..)`: via `[[SetPrototypeOf]]`, the `[[Prototype]]` of the proxy is set (`Object.setPrototypeOf(..)`, `Reflect.setPrototypeOf(..)`, or `__proto__`)\n* `preventExtensions(..)`: via `[[PreventExtensions]]`, the proxy is made non-extensible (`Object.preventExtensions(..)` or `Reflect.preventExtensions(..)`)\n* `isExtensible(..)`: via `[[IsExtensible]]`, the extensibility of the proxy is probed (`Object.isExtensible(..)` or `Reflect.isExtensible(..)`)\n* `ownKeys(..)`: via `[[OwnPropertyKeys]]`, the set of owned properties and/or owned symbol properties of the proxy is retrieved (`Object.keys(..)`, `Object.getOwnPropertyNames(..)`, `Object.getOwnSymbolProperties(..)`, `Reflect.ownKeys(..)`, or `JSON.stringify(..)`)\n* `enumerate(..)`: via `[[Enumerate]]`, an iterator is requested for the proxy's enumerable owned and \"inherited\" properties (`Reflect.enumerate(..)` or `for..in`)\n* `has(..)`: via `[[HasProperty]]`, the proxy is probed to see if it has an owned or \"inherited\" property (`Reflect.has(..)`, `Object#hasOwnProperty(..)`, or `\"prop\" in obj`)\n\n**Tip:** For more information about each of these meta programming tasks, see the \"`Reflect` API\" section later in this chapter.\n\nIn addition to the notations in the preceding list about actions that will trigger the various traps, some traps are triggered indirectly by the default actions of another trap. For example:\n\n```js\nvar handlers = {\n\t\tgetOwnPropertyDescriptor(target,prop) {\n\t\t\tconsole.log(\n\t\t\t\t\"getOwnPropertyDescriptor\"\n\t\t\t);\n\t\t\treturn Object.getOwnPropertyDescriptor(\n\t\t\t\ttarget, prop\n\t\t\t);\n\t\t},\n\t\tdefineProperty(target,prop,desc){\n\t\t\tconsole.log( \"defineProperty\" );\n\t\t\treturn Object.defineProperty(\n\t\t\t\ttarget, prop, desc\n\t\t\t);\n\t\t}\n\t},\n\tproxy = new Proxy( {}, handlers );\n\nproxy.a = 2;\n// getOwnPropertyDescriptor\n// defineProperty\n```\n\nThe `getOwnPropertyDescriptor(..)` and `defineProperty(..)` handlers are triggered by the default `set(..)` handler's steps when setting a property value (whether newly adding or updating). If you also define your own `set(..)` handler, you may or may not make the corresponding calls against `context` (not `target`!) which would trigger these proxy traps.\n\n### Proxy Limitations\n\nThese meta programming handlers trap a wide array of fundamental operations you can perform against an object. However, there are some operations which are not (yet, at least) available to intercept.\n\nFor example, none of these operations are trapped and forwarded from `pobj` proxy to `obj` target:\n\n```js\nvar obj = { a:1, b:2 },\n\thandlers = { .. },\n\tpobj = new Proxy( obj, handlers );\n\ntypeof obj;\nString( obj );\nobj + \"\";\nobj == pobj;\nobj === pobj\n```\n\nPerhaps in the future, more of these underlying fundamental operations in the language will be interceptable, giving us even more power to extend JavaScript from within itself.\n\n**Warning:** There are certain *invariants* -- behaviors which cannot be overridden -- that apply to the use of proxy handlers. For example, the result from the `isExtensible(..)` handler is always coerced to a `boolean`. These invariants restrict some of your ability to customize behaviors with proxies, but they do so only to prevent you from creating strange and unusual (or inconsistent) behavior. The conditions for these invariants are complicated so we won't fully go into them here, but this post (http://www.2ality.com/2014/12/es6-proxies.html#invariants) does a great job of covering them.\n\n### Revocable Proxies\n\nA regular proxy always traps for the target object, and cannot be modified after creation -- as long as a reference is kept to the proxy, proxying remains possible. However, there may be cases where you want to create a proxy that can be disabled when you want to stop allowing it to proxy. The solution is to create a *revocable proxy*:\n\n```js\nvar obj = { a: 1 },\n\thandlers = {\n\t\tget(target,key,context) {\n\t\t\t// note: target === obj,\n\t\t\t// context === pobj\n\t\t\tconsole.log( \"accessing: \", key );\n\t\t\treturn target[key];\n\t\t}\n\t},\n\t{ proxy: pobj, revoke: prevoke } =\n\t\tProxy.revocable( obj, handlers );\n\npobj.a;\n// accessing: a\n// 1\n\n// later:\nprevoke();\n\npobj.a;\n// TypeError\n```\n\nA revocable proxy is created with `Proxy.revocable(..)`, which is a regular function, not a constructor like `Proxy(..)`. Otherwise, it takes the same two arguments: *target* and *handlers*.\n\nThe return value of `Proxy.revocable(..)` is not the proxy itself as with `new Proxy(..)`. Instead, it's an object with two properties: *proxy* and *revoke* -- we used object destructuring (see \"Destructuring\" in Chapter 2) to assign these properties to `pobj` and `prevoke()` variables, respectively.\n\nOnce a revocable proxy is revoked, any attempts to access it (trigger any of its traps) will throw a `TypeError`.\n\nAn example of using a revocable proxy might be handing out a proxy to another party in your application that manages data in your model, instead of giving them a reference to the real model object itself. If your model object changes or is replaced, you want to invalidate the proxy you handed out so the other party knows (via the errors!) to request an updated reference to the model.\n\n### Using Proxies\n\nThe meta programming benefits of these Proxy handlers should be obvious. We can almost fully intercept (and thus override) the behavior of objects, meaning we can extend object behavior beyond core JS in some very powerful ways. We'll look at a few example patterns to explore the possibilities.\n\n#### Proxy First, Proxy Last\n\nAs we mentioned earlier, you typically think of a proxy as \"wrapping\" the target object. In that sense, the proxy becomes the primary object that the code interfaces with, and the actual target object remains hidden/protected.\n\nYou might do this because you want to pass the object somewhere that can't be fully \"trusted,\" and so you need to enforce special rules around its access rather than passing the object itself.\n\nConsider:\n\n```js\nvar messages = [],\n\thandlers = {\n\t\tget(target,key) {\n\t\t\t// string value?\n\t\t\tif (typeof target[key] == \"string\") {\n\t\t\t\t// filter out punctuation\n\t\t\t\treturn target[key]\n\t\t\t\t\t.replace( /[^\\w]/g, \"\" );\n\t\t\t}\n\n\t\t\t// pass everything else through\n\t\t\treturn target[key];\n\t\t},\n\t\tset(target,key,val) {\n\t\t\t// only set unique strings, lowercased\n\t\t\tif (typeof val == \"string\") {\n\t\t\t\tval = val.toLowerCase();\n\t\t\t\tif (target.indexOf( val ) == -1) {\n\t\t\t\t\ttarget.push(val);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\t},\n\tmessages_proxy =\n\t\tnew Proxy( messages, handlers );\n\n// elsewhere:\nmessages_proxy.push(\n\t\"heLLo...\", 42, \"wOrlD!!\", \"WoRld!!\"\n);\n\nmessages_proxy.forEach( function(val){\n\tconsole.log(val);\n} );\n// hello world\n\nmessages.forEach( function(val){\n\tconsole.log(val);\n} );\n// hello... world!!\n```\n\nI call this *proxy first* design, as we interact first (primarily, entirely) with the proxy.\n\nWe enforce some special rules on interacting with `messages_proxy` that aren't enforced for `messages` itself. We only add elements if the value is a string and is also unique; we also lowercase the value. When retrieving values from `messages_proxy`, we filter out any punctuation in the strings.\n\nAlternatively, we can completely invert this pattern, where the target interacts with the proxy instead of the proxy interacting with the target. Thus, code really only interacts with the main object. The easiest way to accomplish this fallback is to have the proxy object in the `[[Prototype]]` chain of the main object.\n\nConsider:\n\n```js\nvar handlers = {\n\t\tget(target,key,context) {\n\t\t\treturn function() {\n\t\t\t\tcontext.speak(key + \"!\");\n\t\t\t};\n\t\t}\n\t},\n\tcatchall = new Proxy( {}, handlers ),\n\tgreeter = {\n\t\tspeak(who = \"someone\") {\n\t\t\tconsole.log( \"hello\", who );\n\t\t}\n\t};\n\n// setup `greeter` to fall back to `catchall`\nObject.setPrototypeOf( greeter, catchall );\n\ngreeter.speak();\t\t\t\t// hello someone\ngreeter.speak( \"world\" );\t\t// hello world\n\ngreeter.everyone();\t\t\t\t// hello everyone!\n```\n\nWe interact directly with `greeter` instead of `catchall`. When we call `speak(..)`, it's found on `greeter` and used directly. But when we try to access a method like `everyone()`, that function doesn't exist on `greeter`.\n\nThe default object property behavior is to check up the `[[Prototype]]` chain (see the *this & Object Prototypes* title of this series), so `catchall` is consulted for an `everyone` property. The proxy `get()` handler then kicks in and returns a function that calls `speak(..)` with the name of the property being accessed (`\"everyone\"`).\n\nI call this pattern *proxy last*, as the proxy is used only as a last resort.\n\n#### \"No Such Property/Method\"\n\nA common complaint about JS is that objects aren't by default very defensive in the situation where you try to access or set a property that doesn't already exist. You may wish to predefine all the properties/methods for an object, and have an error thrown if a nonexistent property name is subsequently used.\n\nWe can accomplish this with a proxy, either in *proxy first* or *proxy last* design. Let's consider both.\n\n```js\nvar obj = {\n\t\ta: 1,\n\t\tfoo() {\n\t\t\tconsole.log( \"a:\", this.a );\n\t\t}\n\t},\n\thandlers = {\n\t\tget(target,key,context) {\n\t\t\tif (Reflect.has( target, key )) {\n\t\t\t\treturn Reflect.get(\n\t\t\t\t\ttarget, key, context\n\t\t\t\t);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow \"No such property/method!\";\n\t\t\t}\n\t\t},\n\t\tset(target,key,val,context) {\n\t\t\tif (Reflect.has( target, key )) {\n\t\t\t\treturn Reflect.set(\n\t\t\t\t\ttarget, key, val, context\n\t\t\t\t);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow \"No such property/method!\";\n\t\t\t}\n\t\t}\n\t},\n\tpobj = new Proxy( obj, handlers );\n\npobj.a = 3;\npobj.foo();\t\t\t// a: 3\n\npobj.b = 4;\t\t\t// Error: No such property/method!\npobj.bar();\t\t\t// Error: No such property/method!\n```\n\nFor both `get(..)` and `set(..)`, we only forward the operation if the target object's property already exists; error thrown otherwise. The proxy object (`pobj`) is the main object code should interact with, as it intercepts these actions to provide the protections.\n\nNow, let's consider inverting with *proxy last* design:\n\n```js\nvar handlers = {\n\t\tget() {\n\t\t\tthrow \"No such property/method!\";\n\t\t},\n\t\tset() {\n\t\t\tthrow \"No such property/method!\";\n\t\t}\n\t},\n\tpobj = new Proxy( {}, handlers ),\n\tobj = {\n\t\ta: 1,\n\t\tfoo() {\n\t\t\tconsole.log( \"a:\", this.a );\n\t\t}\n\t};\n\n// setup `obj` to fall back to `pobj`\nObject.setPrototypeOf( obj, pobj );\n\nobj.a = 3;\nobj.foo();\t\t\t// a: 3\n\nobj.b = 4;\t\t\t// Error: No such property/method!\nobj.bar();\t\t\t// Error: No such property/method!\n```\n\nThe *proxy last* design here is a fair bit simpler with respect to how the handlers are defined. Instead of needing to intercept the `[[Get]]` and `[[Set]]` operations and only forward them if the target property exists, we instead rely on the fact that if either `[[Get]]` or `[[Set]]` get to our `pobj` fallback, the action has already traversed the whole `[[Prototype]]` chain and not found a matching property. We are free at that point to unconditionally throw the error. Cool, huh?\n\n#### Proxy Hacking the `[[Prototype]]` Chain\n\nThe `[[Get]]` operation is the primary channel by which the `[[Prototype]]` mechanism is invoked. When a property is not found on the immediate object, `[[Get]]` automatically hands off the operation to the `[[Prototype]]` object.\n\nThat means you can use the `get(..)` trap of a proxy to emulate or extend the notion of this `[[Prototype]]` mechanism.\n\nThe first hack we'll consider is creating two objects which are circularly linked via `[[Prototype]]` (or, at least it appears that way!). You cannot actually create a real circular `[[Prototype]]` chain, as the engine will throw an error. But a proxy can fake it!\n\nConsider:\n\n```js\nvar handlers = {\n\t\tget(target,key,context) {\n\t\t\tif (Reflect.has( target, key )) {\n\t\t\t\treturn Reflect.get(\n\t\t\t\t\ttarget, key, context\n\t\t\t\t);\n\t\t\t}\n\t\t\t// fake circular `[[Prototype]]`\n\t\t\telse {\n\t\t\t\treturn Reflect.get(\n\t\t\t\t\ttarget[\n\t\t\t\t\t\tSymbol.for( \"[[Prototype]]\" )\n\t\t\t\t\t],\n\t\t\t\t\tkey,\n\t\t\t\t\tcontext\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t},\n\tobj1 = new Proxy(\n\t\t{\n\t\t\tname: \"obj-1\",\n\t\t\tfoo() {\n\t\t\t\tconsole.log( \"foo:\", this.name );\n\t\t\t}\n\t\t},\n\t\thandlers\n\t),\n\tobj2 = Object.assign(\n\t\tObject.create( obj1 ),\n\t\t{\n\t\t\tname: \"obj-2\",\n\t\t\tbar() {\n\t\t\t\tconsole.log( \"bar:\", this.name );\n\t\t\t\tthis.foo();\n\t\t\t}\n\t\t}\n\t);\n\n// fake circular `[[Prototype]]` link\nobj1[ Symbol.for( \"[[Prototype]]\" ) ] = obj2;\n\nobj1.bar();\n// bar: obj-1 <-- through proxy faking [[Prototype]]\n// foo: obj-1 <-- `this` context still preserved\n\nobj2.foo();\n// foo: obj-2 <-- through [[Prototype]]\n```\n\n**Note:** We didn't need to proxy/forward `[[Set]]` in this example, so we kept things simpler. To be fully `[[Prototype]]` emulation compliant, you'd want to implement a `set(..)` handler that searches the `[[Prototype]]` chain for a matching property and respects its descriptor behavior (e.g., set, writable). See the *this & Object Prototypes* title of this series.\n\nIn the previous snippet, `obj2` is `[[Prototype]]` linked to `obj1` by virtue of the `Object.create(..)` statement. But to create the reverse (circular) linkage, we create property on `obj1` at the symbol location `Symbol.for(\"[[Prototype]]\")` (see \"Symbols\" in Chapter 2). This symbol may look sort of special/magical, but it isn't. It just allows me a conveniently named hook that semantically appears related to the task I'm performing.\n\nThen, the proxy's `get(..)` handler looks first to see if a requested `key` is on the proxy. If not, the operation is manually handed off to the object reference stored in the `Symbol.for(\"[[Prototype]]\")` location of `target`.\n\nOne important advantage of this pattern is that the definitions of `obj1` and `obj2` are mostly not intruded by the setting up of this circular relationship between them. Although the previous snippet has all the steps intertwined for brevity's sake, if you look closely, the proxy handler logic is entirely generic (doesn't know about `obj1` or `obj2` specifically). So, that logic could be pulled out into a simple helper that wires them up, like a `setCircularPrototypeOf(..)` for example. We'll leave that as an exercise for the reader.\n\nNow that we've seen how we can use `get(..)` to emulate a `[[Prototype]]` link, let's push the hackery a bit further. Instead of a circular `[[Prototype]]`, what about multiple `[[Prototype]]` linkages (aka \"multiple inheritance\")? This turns out to be fairly straightforward:\n\n```js\nvar obj1 = {\n\t\tname: \"obj-1\",\n\t\tfoo() {\n\t\t\tconsole.log( \"obj1.foo:\", this.name );\n\t\t},\n\t},\n\tobj2 = {\n\t\tname: \"obj-2\",\n\t\tfoo() {\n\t\t\tconsole.log( \"obj2.foo:\", this.name );\n\t\t},\n\t\tbar() {\n\t\t\tconsole.log( \"obj2.bar:\", this.name );\n\t\t}\n\t},\n\thandlers = {\n\t\tget(target,key,context) {\n\t\t\tif (Reflect.has( target, key )) {\n\t\t\t\treturn Reflect.get(\n\t\t\t\t\ttarget, key, context\n\t\t\t\t);\n\t\t\t}\n\t\t\t// fake multiple `[[Prototype]]`\n\t\t\telse {\n\t\t\t\tfor (var P of target[\n\t\t\t\t\tSymbol.for( \"[[Prototype]]\" )\n\t\t\t\t]) {\n\t\t\t\t\tif (Reflect.has( P, key )) {\n\t\t\t\t\t\treturn Reflect.get(\n\t\t\t\t\t\t\tP, key, context\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\tobj3 = new Proxy(\n\t\t{\n\t\t\tname: \"obj-3\",\n\t\t\tbaz() {\n\t\t\t\tthis.foo();\n\t\t\t\tthis.bar();\n\t\t\t}\n\t\t},\n\t\thandlers\n\t);\n\n// fake multiple `[[Prototype]]` links\nobj3[ Symbol.for( \"[[Prototype]]\" ) ] = [\n\tobj1, obj2\n];\n\nobj3.baz();\n// obj1.foo: obj-3\n// obj2.bar: obj-3\n```\n\n**Note:** As mentioned in the note after the earlier circular `[[Prototype]]` example, we didn't implement the `set(..)` handler, but it would be necessary for a complete solution that emulates `[[Set]]` actions as normal `[[Prototype]]`s behave.\n\n`obj3` is set up to multiple-delegate to both `obj1` and `obj2`. In `obj3.baz()`, the `this.foo()` call ends up pulling `foo()` from `obj1` (first-come, first-served, even though there's also a `foo()` on `obj2`). If we reordered the linkage as `obj2, obj1`, the `obj2.foo()` would have been found and used.\n\nBut as is, the `this.bar()` call doesn't find a `bar()` on `obj1`, so it falls over to check `obj2`, where it finds a match.\n\n`obj1` and `obj2` represent two parallel `[[Prototype]]` chains of `obj3`. `obj1` and/or `obj2` could themselves have normal `[[Prototype]]` delegation to other objects, or either could themself be a proxy (like `obj3` is) that can multiple-delegate.\n\nJust as with the circular `[[Prototype]]` example earlier, the definitions of `obj1`, `obj2`, and `obj3` are almost entirely separate from the generic proxy logic that handles the multiple-delegation. It would be trivial to define a utility like `setPrototypesOf(..)` (notice the \"s\"!) that takes a main object and a list of objects to fake the multiple `[[Prototype]]` linkage to. Again, we'll leave that as an exercise for the reader.\n\nHopefully the power of proxies is now becoming clearer after these various examples. There are many other powerful meta programming tasks that proxies enable.\n\n## `Reflect` API\n\nThe `Reflect` object is a plain object (like `Math`), not a function/constructor like the other built-in natives.\n\nIt holds static functions which correspond to various meta programming tasks that you can control. These functions correspond one-to-one with the handler methods (*traps*) that Proxies can define.\n\nSome of the functions will look familiar as functions of the same names on `Object`:\n\n* `Reflect.getOwnPropertyDescriptor(..)`\n* `Reflect.defineProperty(..)`\n* `Reflect.getPrototypeOf(..)`\n* `Reflect.setPrototypeOf(..)`\n* `Reflect.preventExtensions(..)`\n* `Reflect.isExtensible(..)`\n\nThese utilities in general behave the same as their `Object.*` counterparts. However, one difference is that the `Object.*` counterparts attempt to coerce their first argument (the target object) to an object if it's not already one. The `Reflect.*` methods simply throw an error in that case.\n\nAn object's keys can be accessed/inspected using these utilities:\n\n* `Reflect.ownKeys(..)`: Returns the list of all owned keys (not \"inherited\"), as returned by both `Object.getOwnPropertyNames(..)` and `Object.getOwnPropertySymbols(..)`. See the \"Property Enumeration Order\" section for information about the order of keys.\n* `Reflect.enumerate(..)`: Returns an iterator that produces the set of all non-symbol keys (owned and \"inherited\") that are *enumerable* (see the *this & Object Prototypes* title of this series). Essentially, this set of keys is the same as those processed by a `for..in` loop. See the \"Property Enumeration Order\" section for information about the order of keys.\n* `Reflect.has(..)`: Essentially the same as the `in` operator for checking if a property is on an object or its `[[Prototype]]` chain. For example, `Reflect.has(o,\"foo\")` essentially performs `\"foo\" in o`.\n\nFunction calls and constructor invocations can be performed manually, separate of the normal syntax (e.g., `(..)` and `new`) using these utilities:\n\n* `Reflect.apply(..)`: For example, `Reflect.apply(foo,thisObj,[42,\"bar\"])` calls the `foo(..)` function with `thisObj` as its `this`, and passes in the `42` and `\"bar\"` arguments.\n* `Reflect.construct(..)`: For example, `Reflect.construct(foo,[42,\"bar\"])` essentially calls `new foo(42,\"bar\")`.\n\nObject property access, setting, and deletion can be performed manually using these utilities:\n\n* `Reflect.get(..)`: For example, `Reflect.get(o,\"foo\")` retrieves `o.foo`.\n* `Reflect.set(..)`: For example, `Reflect.set(o,\"foo\",42)` essentially performs `o.foo = 42`.\n* `Reflect.deleteProperty(..)`: For example, `Reflect.deleteProperty(o,\"foo\")` essentially performs `delete o.foo`.\n\nThe meta programming capabilities of `Reflect` give you programmatic equivalents to emulate various syntactic features, exposing previously hidden-only abstract operations. For example, you can use these capabilities to extend features and APIs for *domain specific languages* (DSLs).\n\n### Property Ordering\n\nPrior to ES6, the order used to list an object's keys/properties was implementation dependent and undefined by the specification. Generally, most engines have enumerated them in creation order, though developers have been strongly encouraged not to ever rely on this ordering.\n\nAs of ES6, the order for listing owned properties is now defined (ES6 specification, section 9.1.12) by the `[[OwnPropertyKeys]]` algorithm, which produces all owned properties (strings or symbols), regardless of enumerability. This ordering is only guaranteed for `Reflect.ownKeys(..)` (and by extension, `Object.getOwnPropertyNames(..)` and `Object.getOwnPropertySymbols(..)`).\n\nThe ordering is:\n\n1. First, enumerate any owned properties that are integer indexes, in ascending numeric order.\n2. Next, enumerate the rest of the owned string property names in creation order.\n3. Finally, enumerate owned symbol properties in creation order.\n\nConsider:\n\n```js\nvar o = {};\n\no[Symbol(\"c\")] = \"yay\";\no[2] = true;\no[1] = true;\no.b = \"awesome\";\no.a = \"cool\";\n\nReflect.ownKeys( o );\t\t\t\t// [1,2,\"b\",\"a\",Symbol(c)]\nObject.getOwnPropertyNames( o );\t// [1,2,\"b\",\"a\"]\nObject.getOwnPropertySymbols( o );\t// [Symbol(c)]\n```\n\nOn the other hand, the `[[Enumerate]]` algorithm (ES6 specification, section 9.1.11) produces only enumerable properties, from the target object as well as its `[[Prototype]]` chain. It is used by both `Reflect.enumerate(..)` and `for..in`. The observable ordering is implementation dependent and not controlled by the specification.\n\nBy contrast, `Object.keys(..)` invokes the `[[OwnPropertyKeys]]` algorithm to get a list of all owned keys. However, it filters out non-enumerable properties and then reorders the list to match legacy implementation-dependent behavior, specifically with `JSON.stringify(..)` and `for..in`. So, by extension the ordering *also* matches that of `Reflect.enumerate(..)`.\n\nIn other words, all four mechanisms (`Reflect.enumerate(..)`, `Object.keys(..)`, `for..in`, and `JSON.stringify(..)`) will  match with the same implementation-dependent ordering, though they technically get there in different ways.\n\nImplementations are allowed to match these four to the ordering of `[[OwnPropertyKeys]]`, but are not required to. Nevertheless, you will likely observe the following ordering behavior from them:\n\n```js\nvar o = { a: 1, b: 2 };\nvar p = Object.create( o );\np.c = 3;\np.d = 4;\n\nfor (var prop of Reflect.enumerate( p )) {\n\tconsole.log( prop );\n}\n// c d a b\n\nfor (var prop in p) {\n\tconsole.log( prop );\n}\n// c d a b\n\nJSON.stringify( p );\n// {\"c\":3,\"d\":4}\n\nObject.keys( p );\n// [\"c\",\"d\"]\n```\n\nBoiling this all down: as of ES6, `Reflect.ownKeys(..)`, `Object.getOwnPropertyNames(..)`, and `Object.getOwnPropertySymbols(..)` all have predictable and reliable ordering guaranteed by the specification. So it's safe to build code that relies on this ordering.\n\n`Reflect.enumerate(..)`, `Object.keys(..)`, and `for..in` (as well as `JSON.stringify(..)` by extension) continue to share an observable ordering with each other, as they always have. But that ordering will not necessarily be the same as that of `Reflect.ownKeys(..)`. Care should still be taken in relying on their implementation-dependent ordering.\n\n## Feature Testing\n\nWhat is a feature test? It's a test that you run to determine if a feature is available or not. Sometimes, the test is not just for existence, but for conformance to specified behavior -- features can exist but be buggy.\n\nThis is a meta programming technique, to test the environment your program runs in to then determine how your program should behave.\n\nThe most common use of feature tests in JS is checking for the existence of an API and if it's not present, defining a polyfill (see Chapter 1). For example:\n\n```js\nif (!Number.isNaN) {\n\tNumber.isNaN = function(x) {\n\t\treturn x !== x;\n\t};\n}\n```\n\nThe `if` statement in this snippet is meta programming: we're probing our program and its runtime environment to determine if and how we should proceed.\n\nBut what about testing for features that involve new syntax?\n\nYou might try something like:\n\n```js\ntry {\n\ta = () => {};\n\tARROW_FUNCS_ENABLED = true;\n}\ncatch (err) {\n\tARROW_FUNCS_ENABLED = false;\n}\n```\n\nUnfortunately, this doesn't work, because our JS programs are compiled. Thus, the engine will choke on the `() => {}` syntax if it is not already supporting ES6 arrow functions. Having a syntax error in your program prevents it from running, which prevents your program from subsequently responding differently if the feature is supported or not.\n\nTo meta program with feature tests around syntax-related features, we need a way to insulate the test from the initial compile step our program runs through. For instance, if we could store the code for the test in a string, then the JS engine wouldn't by default try to compile the contents of that string, until we asked it to.\n\nDid your mind just jump to using `eval(..)`?\n\nNot so fast. See the *Scope & Closures* title of this series for why `eval(..)` is a bad idea. But there's another option with less downsides: the `Function(..)` constructor.\n\nConsider:\n\n```js\ntry {\n\tnew Function( \"( () => {} )\" );\n\tARROW_FUNCS_ENABLED = true;\n}\ncatch (err) {\n\tARROW_FUNCS_ENABLED = false;\n}\n```\n\nOK, so now we're meta programming by determining if a feature like arrow functions *can* compile in the current engine or not. You might then wonder, what would we do with this information?\n\nWith existence checks for APIs, and defining fallback API polyfills, there's a clear path for what to do with either test success or failure. But what can we do with the information that we get from `ARROW_FUNCS_ENABLED` being `true` or `false`?\n\nBecause the syntax can't appear in a file if the engine doesn't support that feature, you can't just have different functions defined in the file with and without the syntax in question.\n\nWhat you can do is use the test to determine which of a set of JS files you should load. For example, if you had a set of these feature tests in a bootstrapper for your JS application, it could then test the environment to determine if your ES6 code can be loaded and run directly, or if you need to load a transpiled version of your code (see Chapter 1).\n\nThis technique is called *split delivery*.\n\nIt recognizes the reality that your ES6 authored JS programs will sometimes be able to entirely run \"natively\" in ES6+ browsers, but other times need transpilation to run in pre-ES6 browsers. If you always load and use the transpiled code, even in the new ES6-compliant environments, you're running suboptimal code at least some of the time. This is not ideal.\n\nSplit delivery is more complicated and sophisticated, but it represents a more mature and robust approach to bridging the gap between the code you write and the feature support in browsers your programs must run in.\n\n### FeatureTests.io\n\nDefining feature tests for all of the ES6+ syntax, as well as the semantic behaviors, is a daunting task you probably don't want to tackle yourself. Because these tests require dynamic compilation (`new Function(..)`), there's some unfortunate performance cost.\n\nMoreover, running these tests every single time your app runs is probably wasteful, as on average a user's browser only updates once in a several week period at most, and even then, new features aren't necessarily showing up with every update.\n\nFinally, managing the list of feature tests that apply to your specific code base -- rarely will your programs use the entirety of ES6 -- is unruly and error-prone.\n\nThe \"https://featuretests.io\" feature-tests-as-a-service offers solutions to these frustrations.\n\nYou can load the service's library into your page, and it loads the latest test definitions and runs all the feature tests. It does so using background processing with Web Workers, if possible, to reduce the performance overhead. It also uses LocalStorage persistence to cache the results in a way that can be shared across all sites you visit which use the service, which drastically reduces how often the tests need to run on each browser instance.\n\nYou get runtime feature tests in each of your users' browsers, and you can use those tests results dynamically to serve users the most appropriate code (no more, no less) for their environments.\n\nMoreover, the service provides tools and APIs to scan your files to determine what features you need, so you can fully automate your split delivery build processes.\n\nFeatureTests.io makes it practical to use feature tests for all parts of ES6 and beyond to make sure that only the best code is ever loaded and run for any given environment.\n\n## Tail Call Optimization (TCO)\n\nNormally, when a function call is made from inside another function, a second *stack frame* is allocated to separately manage the variables/state of that other function invocation. Not only does this allocation cost some processing time, but it also takes up some extra memory.\n\nA call stack chain typically has at most 10-15 jumps from one function to another and another. In those scenarios, the memory usage is not likely any kind of practical problem.\n\nHowever, when you consider recursive programming (a function calling itself repeatedly) -- or mutual recursion with two or more functions calling each other -- the call stack could easily be hundreds, thousands, or more levels deep. You can probably see the problems that could cause, if memory usage grows unbounded.\n\nJavaScript engines have to set an arbitrary limit to prevent such programming techniques from crashing by running the browser and device out of memory. That's why we get the frustrating \"RangeError: Maximum call stack size exceeded\" thrown if the limit is hit.\n\n**Warning:** The limit of call stack depth is not controlled by the specification. It's implementation dependent, and will vary between browsers and devices. You should never code with strong assumptions of exact observable limits, as they may very well change from release to release.\n\nCertain patterns of function calls, called *tail calls*, can be optimized in a way to avoid the extra allocation of stack frames. If the extra allocation can be avoided, there's no reason to arbitrarily limit the call stack depth, so the engines can let them run unbounded.\n\nA tail call is a `return` statement with a function call, where nothing has to happen after the call except returning its value.\n\nThis optimization can only be applied in `strict` mode. Yet another reason to always be writing all your code as `strict`!\n\nHere's a function call that is *not* in tail position:\n\n```js\n\"use strict\";\n\nfunction foo(x) {\n\treturn x * 2;\n}\n\nfunction bar(x) {\n\t// not a tail call\n\treturn 1 + foo( x );\n}\n\nbar( 10 );\t\t\t\t// 21\n```\n\n`1 + ..` has to be performed after the `foo(x)` call completes, so the state of that `bar(..)` invocation needs to be preserved.\n\nBut the following snippet demonstrates calls to `foo(..)` and `bar(..)` where both *are* in tail position, as they're the last thing to happen in their code path (other than the `return`):\n\n```js\n\"use strict\";\n\nfunction foo(x) {\n\treturn x * 2;\n}\n\nfunction bar(x) {\n\tx = x + 1;\n\tif (x > 10) {\n\t\treturn foo( x );\n\t}\n\telse {\n\t\treturn bar( x + 1 );\n\t}\n}\n\nbar( 5 );\t\t\t\t// 24\nbar( 15 );\t\t\t\t// 32\n```\n\nIn this program, `bar(..)` is clearly recursive, but `foo(..)` is just a regular function call. In both cases, the function calls are in *proper tail position*. The `x + 1` is evaluated before the `bar(..)` call, and whenever that call finishes, all that happens is the `return`.\n\nProper Tail Calls (PTC) of these forms can be optimized -- called tail call optimization (TCO) -- so that the extra stack frame allocation is unnecessary. Instead of creating a new stack frame for the next function call, the engine just reuses the existing stack frame. That works because a function doesn't need to preserve any of the current state, as nothing happens with that state after the PTC.\n\nTCO means there's practically no limit to how deep the call stack can be. That trick slightly improves regular function calls in normal programs, but more importantly opens the door to using recursion for program expression even if the call stack could be tens of thousands of calls deep.\n\nWe're no longer relegated to simply theorizing about recursion for problem solving, but can actually use it in real JavaScript programs!\n\nAs of ES6, all PTC should be optimizable in this way, recursion or not.\n\n### Tail Call Rewrite\n\nThe hitch, however, is that only PTC can be optimized; non-PTC will still work of course, but will cause stack frame allocation as they always did. You'll have to be careful about structuring your functions with PTC if you expect the optimizations to kick in.\n\nIf you have a function that's not written with PTC, you may find the need to manually rearrange your code to be eligible for TCO.\n\nConsider:\n\n```js\n\"use strict\";\n\nfunction foo(x) {\n\tif (x <= 1) return 1;\n\treturn (x / 2) + foo( x - 1 );\n}\n\nfoo( 123456 );\t\t\t// RangeError\n```\n\nThe call to `foo(x-1)` isn't a PTC because its result has to be added to `(x / 2)` before `return`ing.\n\nHowever, to make this code eligible for TCO in an ES6 engine, we can rewrite it as follows:\n\n```js\n\"use strict\";\n\nvar foo = (function(){\n\tfunction _foo(acc,x) {\n\t\tif (x <= 1) return acc;\n\t\treturn _foo( (x / 2) + acc, x - 1 );\n\t}\n\n\treturn function(x) {\n\t\treturn _foo( 1, x );\n\t};\n})();\n\nfoo( 123456 );\t\t\t// 3810376848.5\n```\n\nIf you run the previous snippet in an ES6 engine that implements TCO, you'll get the `3810376848.5` answer as shown. However, it'll still fail with a `RangeError` in non-TCO engines.\n\n### Non-TCO Optimizations\n\nThere are other techniques to rewrite the code so that the call stack isn't growing with each call.\n\nOne such technique is called *trampolining*, which amounts to having each partial result represented as a function that either returns another partial result function or the final result. Then you can simply loop until you stop getting a function, and you'll have the result. Consider:\n\n```js\n\"use strict\";\n\nfunction trampoline( res ) {\n\twhile (typeof res == \"function\") {\n\t\tres = res();\n\t}\n\treturn res;\n}\n\nvar foo = (function(){\n\tfunction _foo(acc,x) {\n\t\tif (x <= 1) return acc;\n\t\treturn function partial(){\n\t\t\treturn _foo( (x / 2) + acc, x - 1 );\n\t\t};\n\t}\n\n\treturn function(x) {\n\t\treturn trampoline( _foo( 1, x ) );\n\t};\n})();\n\nfoo( 123456 );\t\t\t// 3810376848.5\n```\n\nThis reworking required minimal changes to factor out the recursion into the loop in `trampoline(..)`:\n\n1. First, we wrapped the `return _foo ..` line in the `return partial() { ..` function expression.\n2. Then we wrapped the `_foo(1,x)` call in the `trampoline(..)` call.\n\nThe reason this technique doesn't suffer the call stack limitation is that each of those inner `partial(..)` functions is just returned back to the `while` loop in `trampoline(..)`, which runs it and then loop iterates again. In other words, `partial(..)` doesn't recursively call itself, it just returns another function. The stack depth remains constant, so it can run as long as it needs to.\n\nTrampolining expressed in this way uses the closure that the inner `partial()` function has over the `x` and `acc` variables to keep the state from iteration to iteration. The advantage is that the looping logic is pulled out into a reusable `trampoline(..)` utility function, which many libraries provide versions of. You can reuse `trampoline(..)` multiple times in your program with different trampolined algorithms.\n\nOf course, if you really wanted to deeply optimize (and the reusability wasn't a concern), you could discard the closure state and inline the state tracking of `acc` into just one function's scope along with a loop. This technique is generally called *recursion unrolling*:\n\n```js\n\"use strict\";\n\nfunction foo(x) {\n\tvar acc = 1;\n\twhile (x > 1) {\n\t\tacc = (x / 2) + acc;\n\t\tx = x - 1;\n\t}\n\treturn acc;\n}\n\nfoo( 123456 );\t\t\t// 3810376848.5\n```\n\nThis expression of the algorithm is simpler to read, and will likely perform the best (strictly speaking) of the various forms we've explored. That may seem like a clear winner, and you may wonder why you would ever try the other approaches.\n\nThere are some reasons why you might not want to always manually unroll your recursions:\n\n* Instead of factoring out the trampolining (loop) logic for reusability, we've inlined it. This works great when there's only one example to consider, but as soon as you have a half dozen or more of these in your program, there's a good chance you'll want some reusability to keep things shorter and more manageable.\n* The example here is deliberately simple enough to illustrate the different forms. In practice, there are many more complications in recursion algorithms, such as mutual recursion (more than just one function calling itself).\n\n   The farther you go down this rabbit hole, the more manual and intricate the *unrolling* optimizations are. You'll quickly lose all the perceived value of readability. The primary advantage of recursion, even in the PTC form, is that it preserves the algorithm readability, and offloads the performance optimization to the engine.\n\nIf you write your algorithms with PTC, the ES6 engine will apply TCO to let your code run in constant stack depth (by reusing stack frames). You get the readability of recursion with most of the performance benefits and no limitations of run length.\n\n### Meta?\n\nWhat does TCO have to do with meta programming?\n\nAs we covered in the \"Feature Testing\" section earlier, you can determine at runtime what features an engine supports. This includes TCO, though determining it is quite brute force. Consider:\n\n```js\n\"use strict\";\n\ntry {\n\t(function foo(x){\n\t\tif (x < 5E5) return foo( x + 1 );\n\t})( 1 );\n\n\tTCO_ENABLED = true;\n}\ncatch (err) {\n\tTCO_ENABLED = false;\n}\n```\n\nIn a non-TCO engine, the recursive loop will fail out eventually, throwing an exception caught by the `try..catch`. Otherwise, the loop completes easily thanks to TCO.\n\nYuck, right?\n\nBut how could meta programming around the TCO feature (or rather, the lack thereof) benefit our code? The simple answer is that you could use such a feature test to decide to load a version of your application's code that uses recursion, or an alternative one that's been converted/transpiled to not need recursion.\n\n#### Self-Adjusting Code\n\nBut here's another way of looking at the problem:\n\n```js\n\"use strict\";\n\nfunction foo(x) {\n\tfunction _foo() {\n\t\tif (x > 1) {\n\t\t\tacc = acc + (x / 2);\n\t\t\tx = x - 1;\n\t\t\treturn _foo();\n\t\t}\n\t}\n\n\tvar acc = 1;\n\n\twhile (x > 1) {\n\t\ttry {\n\t\t\t_foo();\n\t\t}\n\t\tcatch (err) { }\n\t}\n\n\treturn acc;\n}\n\nfoo( 123456 );\t\t\t// 3810376848.5\n```\n\nThis algorithm works by attempting to do as much of the work with recursion as possible, but keeping track of the progress via scoped variables `x` and `acc`. If the entire problem can be solved with recursion without an error, great. If the engine kills the recursion at some point, we simply catch that with the `try..catch` and then try again, picking up where we left off.\n\nI consider this a form of meta programming in that you are probing during runtime the ability of the engine to fully (recursively) finish the task, and working around any (non-TCO) engine limitations that may restrict you.\n\nAt first (or even second!) glance, my bet is this code seems much uglier to you compared to some of the earlier versions. It also runs a fair bit slower (on larger runs in a non-TCO environment).\n\nThe primary advantage, other than it being able to complete any size task even in non-TCO engines, is that this \"solution\" to the recursion stack limitation is much more flexible than the trampolining or manual unrolling techniques shown previously.\n\nEssentially, `_foo()` in this case is a sort of stand-in for practically any recursive task, even mutual recursion. The rest is the boilerplate that should work for just about any algorithm.\n\nThe only \"catch\" is that to be able to resume in the event of a recursion limit being hit, the state of the recursion must be in scoped variables that exist outside the recursive function(s). We did that by leaving `x` and `acc` outside of the `_foo()` function, instead of passing them as arguments to `_foo()` as earlier.\n\nAlmost any recursive algorithm can be adapted to work this way. That means it's the most widely applicable way of leveraging TCO with recursion in your programs, with minimal rewriting.\n\nThis approach still uses a PTC, meaning that this code will *progressively enhance* from running using the loop many times (recursion batches) in an older browser to fully leveraging TCO'd recursion in an ES6+ environment. I think that's pretty cool!\n\n## Review\n\nMeta programming is when you turn the logic of your program to focus on itself (or its runtime environment), either to inspect its own structure or to modify it. The primary value of meta programming is to extend the normal mechanisms of the language to provide additional capabilities.\n\nPrior to ES6, JavaScript already had quite a bit of meta programming capability, but ES6 significantly ramps that up with several new features.\n\nFrom function name inferences for anonymous functions to meta properties that give you information about things like how a constructor was invoked, you can inspect the program structure while it runs more than ever before. Well Known Symbols let you override intrinsic behaviors, such as coercion of an object to a primitive value. Proxies can intercept and customize various low-level operations on objects, and `Reflect` provides utilities to emulate them.\n\nFeature testing, even for subtle semantic behaviors like Tail Call Optimization, shifts the meta programming focus from your program to the JS engine capabilities itself. By knowing more about what the environment can do, your programs can adjust themselves to the best fit as they run.\n\nShould you meta program? My advice is: first focus on learning how the core mechanics of the language really work. But once you fully know what JS itself can do, it's time to start leveraging these powerful meta programming capabilities to push the language further!\n"
  },
  {
    "path": "es6 & beyond/ch8.md",
    "content": "# You Don't Know JS: ES6 & Beyond\n# Chapter 8: Beyond ES6\n\nAt the time of this writing, the final draft of ES6 (*ECMAScript 2015*) is shortly headed toward its final official vote of approval by ECMA. But even as ES6 is being finalized, the TC39 committee is already hard at work at on features for ES7/2016 and beyond.\n\nAs we discussed in Chapter 1, it's expected that the cadence of progress for JS is going to accelerate from updating once every several years to having an official version update once per year (hence the year-based naming). That alone is going to radically change how JS developers learn about and keep up with the language.\n\nBut even more importantly, the committee is actually going to work feature by feature. As soon as a feature is spec-complete and has its kinks worked out through implementation experiments in a few browsers, that feature will be considered stable enough to start using. We're all strongly encouraged to adopt features once they're ready instead of waiting for some official standards vote. If you haven't already learned ES6, the time is *past due* to get on board!\n\nAs the time of this writing, a list of future proposals and their status can be seen here (https://github.com/tc39/ecma262#current-proposals).\n\nTranspilers and polyfills are how we'll bridge to these new features even before all browsers we support have implemented them. Babel, Traceur, and several other major transpilers already have support for some of the post-ES6 features that are most likely to stabilize.\n\nWith that in mind, it's already time for us to look at some of them. Let's jump in!\n\n**Warning:** These features are all in various stages of development. While they're likely to land, and probably will look similar, take the contents of this chapter with more than a few grains of salt. This chapter will evolve in future editions of this title as these (and other!) features finalize.\n\n## `async function`s\n\nIn \"Generators + Promises\" in Chapter 4, we mentioned that there's a proposal for direct syntactic support for the pattern of generators `yield`ing promises to a runner-like utility that will resume it on promise completion. Let's take a brief look at that proposed feature, called `async function`.\n\nRecall this generator example from Chapter 4:\n\n```js\nrun( function *main() {\n\tvar ret = yield step1();\n\n\ttry {\n\t\tret = yield step2( ret );\n\t}\n\tcatch (err) {\n\t\tret = yield step2Failed( err );\n\t}\n\n\tret = yield Promise.all([\n\t\tstep3a( ret ),\n\t\tstep3b( ret ),\n\t\tstep3c( ret )\n\t]);\n\n\tyield step4( ret );\n} )\n.then(\n\tfunction fulfilled(){\n\t\t// `*main()` completed successfully\n\t},\n\tfunction rejected(reason){\n\t\t// Oops, something went wrong\n\t}\n);\n```\n\nThe proposed `async function` syntax can express this same flow control logic without needing the `run(..)` utility, because JS will automatically know how to look for promises to wait and resume. Consider:\n\n```js\nasync function main() {\n\tvar ret = await step1();\n\n\ttry {\n\t\tret = await step2( ret );\n\t}\n\tcatch (err) {\n\t\tret = await step2Failed( err );\n\t}\n\n\tret = await Promise.all( [\n\t\tstep3a( ret ),\n\t\tstep3b( ret ),\n\t\tstep3c( ret )\n\t] );\n\n\tawait step4( ret );\n}\n\nmain()\n.then(\n\tfunction fulfilled(){\n\t\t// `main()` completed successfully\n\t},\n\tfunction rejected(reason){\n\t\t// Oops, something went wrong\n\t}\n);\n```\n\nInstead of the `function *main() { ..` declaration, we declare with the `async function main() { ..` form. And instead of `yield`ing a promise, we `await` the promise. The call to run the function `main()` actually returns a promise that we can directly observe. That's the equivalent to the promise that we get back from a `run(main)` call.\n\nDo you see the symmetry? `async function` is essentially syntactic sugar for the generators + promises + `run(..)` pattern; under the covers, it operates the same!\n\nIf you're a C# developer and this `async`/`await` looks familiar, it's because this feature is directly inspired by C#'s feature. It's nice to see language precedence informing convergence!\n\nBabel, Traceur and other transpilers already have early support for the current status of `async function`s, so you can start using them already. However, in the next section \"Caveats\", we'll see why you perhaps shouldn't jump on that ship quite yet.\n\n**Note:** There's also a proposal for `async function*`, which would be called an \"async generator.\" You can both `yield` and `await` in the same code, and even combine those operations in the same statement: `x = await yield y`. The \"async generator\" proposal seems to be more in flux -- namely, its return value is not fully worked out yet. Some feel it should be an *observable*, which is kind of like the combination of an iterator and a promise. For now, we won't go further into that topic, but stay tuned as it evolves.\n\n### Caveats\n\nOne unresolved point of contention with `async function` is that because it only returns a promise, there's no way from the outside to *cancel* an `async function` instance that's currently running. This can be a problem if the async operation is resource intensive, and you want to free up the resources as soon as you're sure the result won't be needed.\n\nFor example:\n\n```js\nasync function request(url) {\n\tvar resp = await (\n\t\tnew Promise( function(resolve,reject){\n\t\t\tvar xhr = new XMLHttpRequest();\n\t\t\txhr.open( \"GET\", url );\n\t\t\txhr.onreadystatechange = function(){\n\t\t\t\tif (xhr.readyState == 4) {\n\t\t\t\t\tif (xhr.status == 200) {\n\t\t\t\t\t\tresolve( xhr );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\treject( xhr.statusText );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\t\t\txhr.send();\n\t\t} )\n\t);\n\n\treturn resp.responseText;\n}\n\nvar pr = request( \"http://some.url.1\" );\n\npr.then(\n\tfunction fulfilled(responseText){\n\t\t// ajax success\n\t},\n\tfunction rejected(reason){\n\t\t// Oops, something went wrong\n\t}\n);\n```\n\nThis `request(..)` that I've conceived is somewhat like the `fetch(..)` utility that's recently been proposed for inclusion into the web platform. So the concern is, what happens if you want to use the `pr` value to somehow indicate that you want to cancel a long-running Ajax request, for example?\n\nPromises are not cancelable (at the time of writing, anyway). In my opinion, as well as many others, they never should be (see the *Async & Performance* title of this series). And even if a promise did have a `cancel()` method on it, does that necessarily mean that calling `pr.cancel()` should actually propagate a cancelation signal all the way back up the promise chain to the `async function`?\n\nSeveral possible resolutions to this debate have surfaced:\n\n* `async function`s won't be cancelable at all (status quo)\n* A \"cancel token\" can be passed to an async function at call time\n* Return value changes to a cancelable-promise type that's added\n* Return value changes to something else non-promise (e.g., observable, or control token with promise and cancel capabilities)\n\nAt the time of this writing, `async function`s return regular promises, so it's less likely that the return value will entirely change. But it's too early to tell where things will land. Keep an eye on this discussion.\n\n## `Object.observe(..)`\n\nOne of the holy grails of front-end web development is data binding -- listening for updates to a data object and syncing the DOM representation of that data. Most JS frameworks provide some mechanism for these sorts of operations.\n\nIt appears likely that post ES6, we'll see support added directly to the language, via a utility called `Object.observe(..)`. Essentially, the idea is that you can set up a listener to observe an object's changes, and have a callback called any time a change occurs. You can then update the DOM accordingly, for instance.\n\nThere are six types of changes that you can observe:\n\n* add\n* update\n* delete\n* reconfigure\n* setPrototype\n* preventExtensions\n\nBy default, you'll be notified of all these change types, but you can filter down to only the ones you care about.\n\nConsider:\n\n```js\nvar obj = { a: 1, b: 2 };\n\nObject.observe(\n\tobj,\n\tfunction(changes){\n\t\tfor (var change of changes) {\n\t\t\tconsole.log( change );\n\t\t}\n\t},\n\t[ \"add\", \"update\", \"delete\" ]\n);\n\nobj.c = 3;\n// { name: \"c\", object: obj, type: \"add\" }\n\nobj.a = 42;\n// { name: \"a\", object: obj, type: \"update\", oldValue: 1 }\n\ndelete obj.b;\n// { name: \"b\", object: obj, type: \"delete\", oldValue: 2 }\n```\n\nIn addition to the main `\"add\"`, `\"update\"`, and `\"delete\"` change types:\n\n* The `\"reconfigure\"` change event is fired if one of the object's properties is reconfigured with `Object.defineProperty(..)`, such as changing its `writable` attribute. See the *this & Object Prototypes* title of this series for more information.\n* The `\"preventExtensions\"` change event is fired if the object is made non-extensible via `Object.preventExtensions(..)`.\n\n   Because both `Object.seal(..)` and `Object.freeze(..)` also imply `Object.preventExtensions(..)`, they'll also fire its corresponding change event. In addition, `\"reconfigure\"` change events will also be fired for each property on the object.\n* The `\"setPrototype\"` change event is fired if the `[[Prototype]]` of an object is changed, either by setting it with the `__proto__` setter, or using `Object.setPrototypeOf(..)`.\n\nNotice that these change events are notified immediately after said change. Don't confuse this with proxies (see Chapter 7) where you can intercept the actions before they occur. Object observation lets you respond after a change (or set of changes) occurs.\n\n### Custom Change Events\n\nIn addition to the six built-in change event types, you can also listen for and fire custom change events.\n\nConsider:\n\n```js\nfunction observer(changes){\n\tfor (var change of changes) {\n\t\tif (change.type == \"recalc\") {\n\t\t\tchange.object.c =\n\t\t\t\tchange.object.oldValue +\n\t\t\t\tchange.object.a +\n\t\t\t\tchange.object.b;\n\t\t}\n\t}\n}\n\nfunction changeObj(a,b) {\n\tvar notifier = Object.getNotifier( obj );\n\n\tobj.a = a * 2;\n\tobj.b = b * 3;\n\n\t// queue up change events into a set\n\tnotifier.notify( {\n\t\ttype: \"recalc\",\n\t\tname: \"c\",\n\t\toldValue: obj.c\n\t} );\n}\n\nvar obj = { a: 1, b: 2, c: 3 };\n\nObject.observe(\n\tobj,\n\tobserver,\n\t[\"recalc\"]\n);\n\nchangeObj( 3, 11 );\n\nobj.a;\t\t\t// 12\nobj.b;\t\t\t// 30\nobj.c;\t\t\t// 3\n```\n\nThe change set (`\"recalc\"` custom event) has been queued for delivery to the observer, but not delivered yet, which is why `obj.c` is still `3`.\n\nThe changes are by default delivered at the end of the current event loop (see the *Async & Performance* title of this series). If you want to deliver them immediately, use `Object.deliverChangeRecords(observer)`. Once the change events are delivered, you can observe `obj.c` updated as expected:\n\n```js\nobj.c;\t\t\t// 42\n```\n\nIn the previous example, we called `notifier.notify(..)` with the complete change event record. An alternative form for queuing change records is to use `performChange(..)`, which separates specifying the type of the event from the rest of event record's properties (via a function callback). Consider:\n\n```js\nnotifier.performChange( \"recalc\", function(){\n\treturn {\n\t\tname: \"c\",\n\t\t// `this` is the object under observation\n\t\toldValue: this.c\n\t};\n} );\n```\n\nIn certain circumstances, this separation of concerns may map more cleanly to your usage pattern.\n\n### Ending Observation\n\nJust like with normal event listeners, you may wish to stop observing an object's change events. For that, you use `Object.unobserve(..)`.\n\nFor example:\n\n```js\nvar obj = { a: 1, b: 2 };\n\nObject.observe( obj, function observer(changes) {\n\tfor (var change of changes) {\n\t\tif (change.type == \"setPrototype\") {\n\t\t\tObject.unobserve(\n\t\t\t\tchange.object, observer\n\t\t\t);\n\t\t\tbreak;\n\t\t}\n\t}\n} );\n```\n\nIn this trivial example, we listen for change events until we see the `\"setPrototype\"` event come through, at which time we stop observing any more change events.\n\n## Exponentiation Operator\n\nAn operator has been proposed for JavaScript to perform exponentiation in the same way that `Math.pow(..)` does. Consider:\n\n```js\nvar a = 2;\n\na ** 4;\t\t\t// Math.pow( a, 4 ) == 16\n\na **= 3;\t\t// a = Math.pow( a, 3 )\na;\t\t\t\t// 8\n```\n\n**Note:** `**` is essentially the same as it appears in Python, Ruby, Perl, and others.\n\n## Objects Properties and `...`\n\nAs we saw in the \"Too Many, Too Few, Just Enough\" section of Chapter 2, the `...` operator is pretty obvious in how it relates to spreading or gathering arrays. But what about objects?\n\nSuch a feature was considered for ES6, but was deferred to be considered after ES6 (aka \"ES7\" or \"ES2016\" or ...). Here's how it might work in that \"beyond ES6\" timeframe:\n\n```js\nvar o1 = { a: 1, b: 2 },\n\to2 = { c: 3 },\n\to3 = { ...o1, ...o2, d: 4 };\n\nconsole.log( o3.a, o3.b, o3.c, o3.d );\n// 1 2 3 4\n```\n\nThe `...` operator might also be used to gather an object's destructured properties back into an object:\n\n```js\nvar o1 = { b: 2, c: 3, d: 4 };\nvar { b, ...o2 } = o1;\n\nconsole.log( b, o2.c, o2.d );\t\t// 2 3 4\n```\n\nHere, the `...o2` re-gathers the destructured `c` and `d` properties back into an `o2` object (`o2` does not have a `b` property like `o1` does).\n\nAgain, these are just proposals under consideration beyond ES6. But it'll be cool if they do land.\n\n## `Array#includes(..)`\n\nOne extremely common task JS developers need to perform is searching for a value inside an array of values. The way this has always been done is:\n\n```js\nvar vals = [ \"foo\", \"bar\", 42, \"baz\" ];\n\nif (vals.indexOf( 42 ) >= 0) {\n\t// found it!\n}\n```\n\nThe reason for the `>= 0` check is because `indexOf(..)` returns a numeric value of `0` or greater if found, or `-1` if not found. In other words, we're using an index-returning function in a boolean context. But because `-1` is truthy instead of falsy, we have to be more manual with our checks.\n\nIn the *Types & Grammar* title of this series, I explored another pattern that I slightly prefer:\n\n```js\nvar vals = [ \"foo\", \"bar\", 42, \"baz\" ];\n\nif (~vals.indexOf( 42 )) {\n\t// found it!\n}\n```\n\nThe `~` operator here conforms the return value of `indexOf(..)` to a value range that is suitably boolean coercible. That is, `-1` produces `0` (falsy), and anything else produces a non-zero (truthy) value, which is what we for deciding if we found the value or not.\n\nWhile I think that's an improvement, others strongly disagree. However, no one can argue that `indexOf(..)`'s searching logic is perfect. It fails to find `NaN` values in the array, for example.\n\nSo a proposal has surfaced and gained a lot of support for adding a real boolean-returning array search method, called `includes(..)`:\n\n```js\nvar vals = [ \"foo\", \"bar\", 42, \"baz\" ];\n\nif (vals.includes( 42 )) {\n\t// found it!\n}\n```\n\n**Note:** `Array#includes(..)` uses matching logic that will find `NaN` values, but will not distinguish between `-0` and `0` (see the *Types & Grammar* title of this series). If you don't care about `-0` values in your programs, this will likely be exactly what you're hoping for. If you *do* care about `-0`, you'll need to do your own searching logic, likely using the `Object.is(..)` utility (see Chapter 6).\n\n## SIMD\n\nWe cover Single Instruction, Multiple Data (SIMD) in more detail in the *Async & Performance* title of this series, but it bears a brief mention here, as it's one of the next likely features to land in a future JS.\n\nThe SIMD API exposes various low-level (CPU) instructions that can operate on more than a single number value at a time. For example, you'll be able to specify two *vectors* of 4 or 8 numbers each, and multiply the respective elements all at once (data parallelism!).\n\nConsider:\n\n```js\nvar v1 = SIMD.float32x4( 3.14159, 21.0, 32.3, 55.55 );\nvar v2 = SIMD.float32x4( 2.1, 3.2, 4.3, 5.4 );\n\nSIMD.float32x4.mul( v1, v2 );\n// [ 6.597339, 67.2, 138.89, 299.97 ]\n```\n\nSIMD will include several other operations besides `mul(..)` (multiplication), such as `sub()`, `div()`, `abs()`, `neg()`, `sqrt()`, and many more.\n\nParallel math operations are critical for the next generations of high performance JS applications.\n\n## WebAssembly (WASM)\n\nBrendan Eich made a late breaking announcement near the completion of the first edition of this title that has the potential to significantly impact the future path of JavaScript: WebAssembly (WASM). We will not be able to cover WASM in detail here, as it's extremely early at the time of this writing. But this title would be incomplete without at least a brief mention of it.\n\nOne of the strongest pressures on the recent (and near future) design changes of the JS language has been the desire that it become a more suitable target for transpilation/cross-compilation from other languages (like C/C++, ClojureScript, etc.). Obviously, performance of code running as JavaScript has been a primary concern.\n\nAs discussed in the *Async & Performance* title of this series, a few years ago a group of developers at Mozilla introduced an idea to JavaScript called ASM.js. ASM.js is a subset of valid JS that most significantly restricts certain actions that make code hard for the JS engine to optimize. The result is that ASM.js compatible code running in an ASM-aware engine can run remarkably faster, nearly on par with native optimized C equivalents. Many viewed ASM.js as the most likely backbone on which performance-hungry applications would ride in JavaScript.\n\nIn other words, all roads to running code in the browser *lead through JavaScript*.\n\nThat is, until the WASM announcement. WASM provides an alternate path for other languages to target the browser's runtime environment without having to first pass through JavaScript. Essentially, if WASM takes off, JS engines will grow an extra capability to execute a binary format of code that can be seen as somewhat similar to a bytecode (like that which runs on the JVM).\n\nWASM proposes a format for a binary representation of a highly compressed AST (syntax tree) of code, which can then give instructions directly to the JS engine and its underpinnings, without having to be parsed by JS, or even behave by the rules of JS. Languages like C or C++ can be compiled directly to the WASM format instead of ASM.js, and gain an extra speed advantage by skipping the JS parsing.\n\nThe near term for WASM is to have parity with ASM.js and indeed JS. But eventually, it's expected that WASM would grow new capabilities that surpass anything JS could do. For example, the pressure for JS to evolve radical features like threads -- a change that would certainly send major shockwaves through the JS ecosystem -- has a more hopeful future as a future WASM extension, relieving the pressure to change JS.\n\nIn fact, this new roadmap opens up many new roads for many languages to target the web runtime. That's an exciting new future path for the web platform!\n\nWhat does it mean for JS? Will JS become irrelevant or \"die\"? Absolutely not. ASM.js will likely not see much of a future beyond the next couple of years, but the majority of JS is quite safely anchored in the web platform story.\n\nProponents of WASM suggest its success will mean that the design of JS will be protected from pressures that would have eventually stretched it beyond assumed breaking points of reasonability. It is projected that WASM will become the preferred target for high-performance parts of applications, as authored in any of a myriad of different languages.\n\nInterestingly, JavaScript is one of the lesser likely languages to target WASM in the future. There may be future changes that carve out subsets of JS that might be tenable for such targeting, but that path doesn't seem high on the priority list.\n\nWhile JS likely won't be much of a WASM funnel, JS code and WASM code will be able to interoperate in the most significant ways, just as naturally as current module interactions. You can imagine calling a JS function like `foo()` and having that actually invoke a WASM function of that name with the power to run well outside the constraints of the rest of your JS.\n\nThings which are currently written in JS will probably continue to always be written in JS, at least for the foreseeable future. Things which are transpiled to JS will probably eventually at least consider targeting WASM instead. For things which need the utmost in performance with minimal tolerance for layers of abstraction, the likely choice will be to find a suitable non-JS language to author in, then targeting WASM.\n\nThere's a good chance this shift will be slow, and will be years in the making. WASM landing in all the major browser platforms is probably a few years out at best. In the meantime, the WASM project (https://github.com/WebAssembly) has an early polyfill to demonstrate proof-of-concept for its basic tenets.\n\nBut as time goes on, and as WASM learns new non-JS tricks, it's not too much a stretch of imagination to see some currently-JS things being refactored to a WASM-targetable language. For example, the performance sensitive parts of frameworks, game engines, and other heavily used tools might very well benefit from such a shift. Developers using these tools in their web applications likely won't notice much difference in usage or integration, but will just automatically take advantage of the performance and capabilities.\n\nWhat's certain is that the more real WASM becomes over time, the more it means to the trajectory and design of JavaScript. It's perhaps one of the most important \"beyond ES6\" topics developers should keep an eye on.\n\n## Review\n\nIf all the other books in this series essentially propose this challenge, \"you (may) not know JS (as much as you thought),\" this book has instead suggested, \"you don't know JS anymore.\" The book has covered a ton of new stuff added to the language in ES6. It's an exciting collection of new language features and paradigms that will forever improve our JS programs.\n\nBut JS is not done with ES6! Not even close. There's already quite a few features in various stages of development for the \"beyond ES6\" timeframe. In this chapter, we briefly looked at some of the most likely candidates to land in JS very soon.\n\n`async function`s are powerful syntactic sugar on top of the generators + promises pattern (see Chapter 4). `Object.observe(..)` adds direct native support for observing object change events, which is critical for implementing data binding. The `**` exponentiation operator, `...` for object properties, and `Array#includes(..)` are all simple but helpful improvements to existing mechanisms. Finally, SIMD ushers in a new era in the evolution of high performance JS.\n\nCliché as it sounds, the future of JS is really bright! The challenge of this series, and indeed of this book, is incumbent on every reader now. What are you waiting for? It's time to get learning and exploring!\n"
  },
  {
    "path": "es6 & beyond/foreword.md",
    "content": "# You Don't Know JS: ES6 & Beyond\n# Foreword\n\nKyle Simpson is a thorough pragmatist.\n\nI can't think of higher praise than this. To me, these are two of the most important qualities that a software developer must have. That's right: *must*, not *should*. Kyle's keen ability to tease apart layers of the JavaScript programming language and present them in understandable and meaningful portions is second to none.\n\n*ES6 & Beyond* will be familiar to readers of the *You Don't Know JS* series:  they can expect to be deeply immersed in everything from the obvious, to the very subtle -- revealing semantics that were either taken for granted or never even considered. Until now, the *You Don't Know JS* book series has covered material that has at least some degree of familiarity to its readers. They have either seen or heard about the subject matter; they may even have experience with it. This volume covers material that only a very small portion of the JavaScript developer community has been exposed to: the  evolutionary changes to the language introduced in the ECMAScript 2015 Language Specification.\n\nOver the last couple years, I've witnessed Kyle's tireless efforts to familiarize himself with this material to a level of expertise that is rivaled by only a handful of his professional peers. That's quite a feat, considering that at the time of this writing, the language specification document hasn't been formally published! But what I've said is true, and I've read every word that Kyle's written for this book. I've followed every change, and each time, the content only gets better and provides yet a deeper level of understanding.\n\nThis book is about shaking up your sense of understanding by exposing you to the new and unknown. The intention is to evolve your knowledge in step with your tools by bestowing you with new capabilities. It exists to give you the confidence to fully embrace the next major era of JavaScript programming.\n\nRick Waldron<br>\n[@rwaldron](http://twitter.com/rwaldron)<br>\nOpen Web Engineer at Bocoup<br>\nEcma/TC39 Representative for jQuery\n"
  },
  {
    "path": "es6 & beyond/toc.md",
    "content": "# You Don't Know JS: ES6 & Beyond\n\n## Table of Contents\n\n* Предисловие\n* Введение\n* Глава 1: ES? Настоящее и Будущее\n\t* Версионирование\n\t* Транспиляция\n* Глава 2: Синтаксис\n\t* Блочная область видимости\n\t* Spread / Rest операторы\n\t* Параметры со значениями по умолчанию\n\t* Деструктуризация\n\t* Расширения объектных литералов\n\t* Шаблонные литералы\n\t* Стрелочные функции\n\t* Цикл `for..of`\n\t* Расширения регулярных выражений\n\t* Расширения числовых литералов\n\t* Юникод\n\t* Тип данных Symbol\n* Глава 3: Организация кода\n\t* Итераторы\n\t* Генераторы\n\t* Модули\n\t* Классы\n* Глава 4: Асинхронный поток исполнения\n\t* Промисы\n\t* Генераторы + Промисы\n* Глава 5: Коллекции\n\t* Типизированные массивы\n\t* Объекты Map\n\t* Объекты WeakMap\n\t* Объекты Set\n\t* Объекты WeakSet\n* Глава 6: Нововведения API\n\t* `Array`\n\t* `Object`\n\t* `Math`\n\t* `Number`\n\t* `String`\n* Глава 7: Метапрограммирование\n\t* Имена функций\n\t* Метасвойства\n\t* Уже знакомые символы (`Symbol`)\n\t* Объекты Proxy\n\t* `Reflect` API\n\t* Тестирование\n\t* Оптимизация хвостовой рекурсии (Tail Call Optimization - TCO)\n* Глава 8: За пределами ES6\n\t* Функции `async`\n\t* `Object.observe(..)`\n\t* Оператор возведения в степень\n\t* Свойства объектов и `...`\n\t* `Array#includes(..)`\n\t* SIMD\n* Appendix A: Acknowledgments\n"
  },
  {
    "path": "preface.md",
    "content": "# Вы не знаете JS\n# Предисловие\n\nЯ уверен, что вы заметили, но «JS» в названии серии книг — это не аббревиатура для слов, используемых для проклятий в адрес JavaScript, хотя проклинание причуд языка — это то, на чём, вероятно, мы все можем поймать себя!\n\nС самых ранних дней Интернета JavaScript был основополагающей технологией, управляющей интерактивным взаимодействием с контентом, который мы потребляем. И хотя мерцающие шлейфы за курсором мыши и раздражающие всплывающие окна — это то, с чего JavaScript начинался, почти 2 десятилетия спустя технология и возможности JavaScript выросли на несколько порядков, и мало кто подвергает сомнению его роль в основе самой широко доступной программной платформы в мире: в вебе.\n\nНо как язык он постоянно был объектом критики, отчасти благодаря своему наследию, но даже в большей степени — из-за философии своего устройства. Даже название напоминает, как сказал однажды Брендан Айк, о статусе «тупого младшего брата», по сравнению с более зрелым старшим братом «Java». Но это название — просто случайность, политический и маркетинговый ход. Эти два языка во многом отличаются друг от друга. «JavaScript» так же связан с «Java», как «вал» с «карнавалом».\n\nПоскольку JavaScript заимствует концепции и синтаксические идиомы из нескольких языков, включая как гордые процедурные корни в стиле C, так и тонкие, менее очевидные функциональные корни в стиле Scheme / Lisp, он чрезвычайно доступен для широкой аудитории разработчиков, даже тех, у кого мало или совсем нет опыта программирования. \"Hello World\" на JavaScript настолько прост, что язык выглядит привлекательным и доступным на первых порах.\n\nХотя JavaScript — это, возможно, один из самых простых языков в начале работы с ним, его эксцентричность делает твёрдое владение им гораздо менее обычным явлением, чем во многих других языках. Там, где для написания полноценной программы требуется довольно глубокое знание языка, как в C или C++, полноценная программа на JavaScript может почти не проникать под поверхность того, на что способен язык.\n\nСложные концепции, которые глубоко укоренились в языке, стремятся вместо этого выглядеть *внешне* простыми, как передача функций в качестве обратных вызовов, что побуждает JavaScript-разработчика просто использовать язык как есть и не слишком беспокоиться о том, что происходит под капотом.\n\nЭто одновременно и простой, лёгкий в использовании язык, имеющий широкое обращение, и сложный, полный нюансов набор языковых механик, который без тщательного изучения ускользнёт от *истинного понимания* даже для самых опытных JavaScript-разработчиков.\n\nВ этом парадокс JavaScript, ахиллесова пята языка, проблема, к которой мы сейчас обращаемся. Поскольку JavaScript *можно* использовать без понимания, это понимание зачастую никогда не достигается.\n\n## Миссия\n\nЕсли каждый раз, когда вы сталкиваетесь с какой-то неожиданностью или разочарованием в JavaScript, ваша реакция — добавить это в чёрный список, как некоторые привыкли делать, то вскоре от всего богатства JavaScript у вас останется только оболочка.\n\nХотя это подмножество известно под названием «Сильные стороны», умоляю вас, дорогой читатель, вместо этого считать его «Лёгкими сторонами», «Безопасными сторонами» или даже «Неполными сторонами».\n\nСерия *Вы не знаете JavaScript* предлагает противоположный вызов: учиться и глубоко понимать *весь* JavaScript, включая (в особенности) «Тяжёлые стороны».\n\nЗдесь мы обращаемся к стремлению JS-разработчиков выучить «достаточно», чтобы обходиться этим, даже не заставляя себя в точности выяснить, как и почему язык ведёт себя так, как он это делает. Кроме того, мы избегаем общего совета *отдыхать*, когда путь становится тяжёлым.\n\nЯ недоволен, и вы не должны быть довольны, останавливаясь каждый раз, когда что-то *просто работает*, без полного понимания, *почему*. Я вежливо призываю вас отправиться по этой ухабистой непроторенной дороге и охватить всё, чем JavaScript является и на что он способен. С этими знаниями ни одна технология, фреймворк, или другой популярный тренд недели не останется за пределами вашего понимания.\n\nКаждая из этих книг берёт конкретные ключевые части языка, которые чаще всего неправильно понимаются или недооцениваются, и погружается в них глубоко и исчерпывающе. Вам стоит отбросить твёрдую уверенность в своём понимании не только теоретических, но и практических составляющих.\n\nJavaScript, который вы знаете *прямо сейчас* — вероятно, *стороны*, переданные вам другими, кто перегорел от неполного понимания. *Этот* JavaScript — всего лишь тень истинного языка. Вы не знаете JavaScript *по-настоящему*, *пока что*, но если вы вникнете в эту серию, вы *будете*. Продолжайте читать, друзья. JavaScript ждёт вас.\n\n## Резюме\n\nJavaScript потрясающий. Он легко учится частично, и гораздо труднее учится полностью (или хотя бы *достаточно*). Когда разработчики сталкиваются с затруднениями, они обычно обвиняют язык вместо нехватки собственных знаний о нём. Цель этих книг — исправить это, вдохновляя на высокую оценку языка, который вы можете сейчас и *должны* глубоко *знать*.\n\nПримечание. Многие примеры в этой книге предполагают использование современных (и будущих) JavaScript-сред, таких как ES6. Какой-то код может не работать так, как описано, если он запускается на старых (до ES6) платформах.\n"
  },
  {
    "path": "scope & closures/README.md",
    "content": "# Вы не знаете JS: Область видимости и замыкания\n\n<img src=\"cover.jpg\" width=\"300\">\n\n-----\n\n**[Купить цифровую или печатную книгу от издательства O'Reilly (англ.)](http://shop.oreilly.com/product/0636920026327.do)**\n\n-----\n\n[Оглавление](toc.md)\n\n* [Введение](https://shanehudson.net/2014/06/03/foreword-dont-know-js/) (by [Shane Hudson](https://github.com/shanehudson))\n* [Предисловие](../preface.md)\n* [Глава 1: Что такое область видимости?](ch1.md)\n* [Глава 2: Лексическая область видимости](ch2.md)\n* [Глава 3: Область видимости: функции против блоков](ch3.md)\n* [Глава 4: Поднятие переменных (Hoisting)](ch4.md)\n* [Глава 5: Замыкание области видимости](ch5.md)\n* [Приложение A: Динамическая область видимости](apA.md)\n* [Приложение B: Полифиллинг блочной области видимости](apB.md)\n* [Приложение C: Лексический this](apC.md)\n* [Приложение D: Благодарности!](apD.md)\n"
  },
  {
    "path": "scope & closures/apA.md",
    "content": "# Вы не знаете JS: Область видимости и замыкания\n# Приложение A: Динамическая область видимости\n\nВ главе 2 мы говорили о \"динамической области видимости\" как о противопоставлении модели \"лексической области видимости\", которая и есть то, как работает область видимости в JavaScript (а по факту и во многих других языках).\n\nМы кратко рассмотрим динамическую область видимости, чтобы крепко усвоить  разницу. Но, важнее то, что динамическая область видимости — ближайшая родственница другого механизма (`this`) в JavaScript, который мы рассмотрели в книге \"*this и прототипы объектов*\".\n\nКак мы уже отметили в главе 2, лексическая область видимости — это набор правил о том, как именно *Движок* может искать переменную и как он ее может найти. Ключевая характеристика лексической области видимости — она определяется на этапе написания кода (предполагая, что вы не жульничаете с помощью `eval()` или `with`).\n\nДинамическая область видимости похоже означает, и не зря, что есть модель, при помощи которой область видимости можно определить динамически во время выполнения, вместо статического определения при написании кода. То, что нам нужно. Давайте отразим это в коде:\n\n```js\nfunction foo() {\n\tconsole.log( a ); // 2\n}\n\nfunction bar() {\n\tvar a = 3;\n\tfoo();\n}\n\nvar a = 2;\n\nbar();\n```\n\nЛексическая область видимости хранит информацию о том, что RHS-ссылка на `a` в `foo()` будет разрешена в глобальную переменную `a`, что приведет к тому, что будет выведено значение `2`.\n\nДинамическая область видимости, напротив, не интересуется тем как и где были объявлены функции и области видимости, а скорее интересуется тем **откуда они будут вызываться**. Иными словами, здесь цепочка областей видимости основана на стеке вызовов, а не на вложенности областей видимости в коде.\n\nИтак, если бы в JavaScript была динамическая область видимости, то когда  выполнилась бы `foo()`, **теоретически** нижеприведенный код привел бы к выводу `3`.\n\n```js\nfunction foo() {\n\tconsole.log( a ); // 3  (not 2!)\n}\n\nfunction bar() {\n\tvar a = 3;\n\tfoo();\n}\n\nvar a = 2;\n\nbar();\n```\n\nКак такое может быть? А всё потому, что когда `foo()` не может разрешить ссылку на переменную `a`, вместо поднятия по цепочке вложенных лексических областей видимости, она взбирается вверх по стеку вызовов, чтобы найти откуда `foo()` была *вызвана*. Поскольку `foo()` вызывалась из `bar()`, она проверяет переменные в области видимости `bar()` и находит там `a` со значением `3`.\n\nСтранно? Возможно вы так и подумали, на какой-то момент.\n\nНо это всего лишь потому, что вы возможно работали только с (или по меньшей мере глубоко изучили) кодом, который работает c лексической областью видимости. Поэтому то динамическая область видимости и кажется чужой. Если бы вы писали код на языке с динамической областью видимости, для вас всё это показалось бы естественным, а лексическая область видимости показалось бы чудаковатой.\n\nЧтобы внести ясность, в JavaScript **нет, на самом деле, динамической области видимости**. В нем есть лексическая область видимости. Проще некуда. Но механизм работы `this` немного похож на динамическую область видимости.\n\nКлючевое сравнение: **лексическая область видимости определяется временем написания кода, тогда как динамическая область видимости (и `this`!) определяется во время выполнения**. Лексическую область видимости интересует *где функция была объявлена*, а динамическую — *откуда была вызвана* функция.\n\nИ наконец: `this` интересует *как была вызвана функция*, что показывает как близко связаны механизм `this` с идеей динамической области видимости. Чтобы изучить во всех подробностях `this`, прочтите книгу \"*this и прототипы объектов*\".\n"
  },
  {
    "path": "scope & closures/apB.md",
    "content": "# Вы не знаете JS: Область видимости и замыкания\n# Приложение B: Полифиллинг блочной области видимости\n\nВ главе 3 мы исследовали блочную область видимости. Мы отметили, что операторы `with` и `catch` оба являются крошечными примерами блочной области видимости, которые существуют в JavaScript с тех пор как появился ES3.\n\nНо в ES6 был представлен `let`, который окончательно дал полные, неограниченные возможности применять блочную область видимости в нашем коде. Есть много впечатляющих вещей, как функциональных, так и стилистических, которые появились благодаря блочной области видимости.\n\nНо что если мы хотим использовать блочную область видимости в пред-ES6 окружении?\n\nПредставим такой код:\n\n```js\n{\n\tlet a = 2;\n\tconsole.log( a ); // 2\n}\n\nconsole.log( a ); // ReferenceError\n```\n\nОн отлично работает в ES6 окружении. Но можем ли мы также сделать в пред-ES6? `catch` — вот ответ.\n\n```js\ntry{throw 2}catch(a){\n\tconsole.log( a ); // 2\n}\n\nconsole.log( a ); // ReferenceError\n```\n\nОго! Какой это уродливый, странновыглядящий код. Тут `try/catch`, которые используются, чтобы принудительно вызвать ошибку, но эта \"ошибка\" — всего лишь значение `2`, а затем объявление переменной, которая получает это значение в блоке `catch(a)`. Мозг: взорван!\n\nВсе правильно, в блоке `catch` есть блочная область видимости, которая похоже может использоваться как полифиллинг для блочной области видимости в пред-ES6 окружении.\n\n\"Но...\", - скажете вы. \"...никто не хочет писать ужасный код подобный этому!\" Это правда. Никто не пишет такой код, который выдает компилятор CoffeeScript. Но суть не в этом.\n\nСуть в том, что утилиты могут транспилировать код на ES6, чтобы он мог работать в пред-ES6 окружении. Можно писать код с блочными областями видимости и извлекать преимущества из такой функциональности и дать возможность утилите во время сборки проекта позаботиться о том, чтобы сгенерировать код, который действительно будет *работать* после публикации.\n\nЭто и в самом деле предпочтительный путь миграции для всего (кхм, большей части) ES6: использовать транспилятор кода чтобы брать код на ES6 и выдать ES5-совместимый код на период перехода от пред-ES6 к ES6.\n\n## Traceur\n\nГугл поддерживает проект, называемый \"Traceur\", единственной задачей которого является транспиляция возможностей ES6 в пред-ES6 (в основном ES5, но не только!) для повседневного использования. Комитет TC39 полагается на этот инструмент (и другие), чтобы проверять на практике семантику тех возможностей, которые он выпускает.\n\nВо что же превратит Traceur наш код? Вы угадали!\n\n```js\n{\n\ttry {\n\t\tthrow undefined;\n\t} catch (a) {\n\t\ta = 2;\n\t\tconsole.log( a );\n\t}\n}\n\nconsole.log( a );\n```\n\nТак что с использованием таких утилит мы можем получать все преимущества блочной области видимости независимо от того, будет ли это работать только в  ES6 или нет, потому что `try/catch` используется (и работает именно так) со времен ES3.\n\n## Блоки: неявные против явных\n\nВ главе 3 мы обозначили некоторые потенциальные проблемы с обслуживаемостью/рефакторингом когда представили блочную область видимости. А есть ли другой путь получить преимущества блочной области видимости, но уменьшив эти недостатки?\n\nРассмотрим еще одну альтернативную форму `let`, называемую \"let-блок\" или \"оператор let\" (в противоположность \"объявлениям let\", рассмотренным ранее).\n\n```js\nlet (a = 2) {\n\tconsole.log( a ); // 2\n}\n\nconsole.log( a ); // ReferenceError\n```\n\nВместо неявного \"угона\" существующего блока let-оператор создает явный блок со своей собственной областью видимости. Но явный блок выделяется не только этим и возможно более удобным рефакторингом кода, с ним код получается чище  грамматически, с помощью принудительного переноса всех определений наверх блока. Это облегчает понимание любого блока, а также того, что попадает в область его видимости, а что — нет.\n\nКак шаблон, он отражает подход, когда многие люди используют область видимости функции и они вручную перемещают/поднимают все свои объявления `var` вверх функции. let-оператор помещает их в начало блока намеренно и если вы не используете объявления `let`, разбросанные повсюду как попало, то объявления в блочной области видимости немного легче находить и управлять ими.\n\nНо есть проблема! let в форме оператора не включен в ES6. И официальный компилятор Traceur также не принимает такую форму кода как корректную.\n\nУ нас есть два варианта. Можно отформатировать код используя ES6-совместимый синтаксис и добавить немного дисциплины в коде:\n\n```js\n/*let*/ { let a = 2;\n\tconsole.log( a );\n}\n\nconsole.log( a ); // ReferenceError\n```\n\nНо инструменты призваны решать наши проблемы. Поэтому вторым вариантом будет  писать явно блоки оператора let и позволить утилите сконвертировать их в корректный, работающий код.\n\nПоэтому, я создал утилиту, названную \"let-er\" для решения этой единственной проблемы. *let-er* — транспилятор кода на этапе сборки, но его единственной задачей является находить let-операторы и транспилировать их. Она оставит в целости и сохранности весь остальной ваш код, включая любые let-объявления. Вы можете безопасно пользоваться *let-er* как первым звеном транспиляции ES6, а затем передать код во что-то подобное Traceur если надо.\n\nБолее того, в *let-er* есть опция настройки `--es6`, при включении которой (по умолчанию выключена), меняется получаемый код. Вместо полифильного хака `try/catch` из ES3, *let-er* возьмет наш код и выдаст полностью ES6-совместимый, без всяких хаков:\n\n```js\n{\n\tlet a = 2;\n\tconsole.log( a );\n}\n\nconsole.log( a ); // ReferenceError\n```\n\nТак что вы можете начать пользоваться *let-er* прямо сейчас и выпускать код под все пред-ES6 среды, а когда вам требуется только ES6, можно добавить опцию и сразу же получать только ES6-код.\n\nИ что более важно, **вы можете использовать более предпочтительную и более явную форму let-оператора** даже не смотря на то, что он не является официальной частью какой-либо версии ES (пока что).\n\n## Производительность\n\nПозвольте мне напоследок добавить пару слов о производительности `try/catch` и/или чтобы рассмотреть вопрос: \"почему бы просто не использовать IIFE для создания области видимости?\"\n\nВо-первых, производительность `try/catch` *ниже*, но нет ни одного разумного предположения, что в этом случае так и *есть*, или даже что *так будет всегда* в таких случаях. Поскольку официальный подтвержденный TC39 ES6-транспилятор использует `try/catch`, команда Traceur попросила Chrome улучшить производительность `try/catch` и у них конечно же есть мотивация так и сделать.\n\nВо-вторых, IIFE — нельзя равноценно сравнивать с `try/catch`, поскольку функция, обернутая вокруг любого обычного кода, меняет значение внутри этого кода у операторов `this`, `return`, `break` и `continue`. IIFE - не замена в повседневных задачах. Ее можно использовать вручную только в особых случаях.\n\nВ итоге, вопрос превращается в такой: нужна ли вам блочная область видимости или нет. Если нужна, эти утилиты дадут вам такую возможность. Если нет, продолжайте использовать `var` и кодировать!\n\n[Google Traceur](https://google.github.io/traceur-compiler/demo/repl.html)\n\n[let-er](https://github.com/getify/let-er)\n"
  },
  {
    "path": "scope & closures/apC.md",
    "content": "# Вы не знаете JS: Область видимости и замыкания\n# Приложение C: Лексический this\n\nХотя эта книга и не рассматривает механизм `this` во всех деталях, есть одна тема в ES6, которая связывает `this` с лексической областью видимости существенным образом, по которому мы быстро пробежимся.\n\nES6 добавляет особую синтаксическую форму объявления функции, названную \"стрелочная функция\". Она выглядит примерно так:\n\n```js\nvar foo = a => {\n\tconsole.log( a );\n};\n\nfoo( 2 ); // 2\n```\n\nТак называемая \"жирная стрелка\" часто упоминается как сокращение для *утомительно длинного* (сарказм) ключевого слова `function`.\n\nНо есть кое-что более важное в стрелочных функциях, что не имеет ничего общего с экономией символов в вашем коде.\n\nВ двух словах, этот код страдает от одной проблемы:\n\n```js\n\nvar obj = {\n\tid: \"awesome\",\n\tcool: function coolFn() {\n\t\tconsole.log( this.id );\n\t}\n};\n\nvar id = \"not awesome\";\n\nobj.cool(); // awesome\n\nsetTimeout( obj.cool, 100 ); // not awesome\n```\n\nПроблема заключается в потере привязки `this` в функции `cool()`. Есть разные пути решения этой проблемы, но наиболее частое решение — `var self = this;`.\n\nВыглядит это примерно так:\n\n```js\nvar obj = {\n\tcount: 0,\n\tcool: function coolFn() {\n\t\tvar self = this;\n\n\t\tif (self.count < 1) {\n\t\t\tsetTimeout( function timer(){\n\t\t\t\tself.count++;\n\t\t\t\tconsole.log( \"красиво?\" );\n\t\t\t}, 100 );\n\t\t}\n\t}\n};\n\nobj.cool(); // красиво?\n```\n\nЧтобы не слишком углубляться в подробности, \"решение \"`var self = this` всего лишь избавляется целиком от всей проблемы понимания и правильного использования привязки `this`, а взамен возвращается к чему-то более удобному для нас: лексической области видимости. `self` становится всего лишь идентификатором, который может быть определен с помощью лексической области видимости и замыкания, и не заботится о том, что случится с привязкой `this` по пути.\n\nЛюди не любят писать подробно особенно то, что делают снова и снова. Таким образом, мотивацией ES6 является помощь в облегчении таких сценариев и разумеется в *устранении* общих проблем идиом, таких как эта.\n\nРешение в ES6, стрелочная функция, вводит поведение, называемое \"лексический  this\".\n\n```js\nvar obj = {\n\tcount: 0,\n\tcool: function coolFn() {\n\t\tif (this.count < 1) {\n\t\t\tsetTimeout( () => { // стрелочная функция, выигрышный вариант?\n\t\t\t\tthis.count++;\n\t\t\t\tconsole.log( \"красиво?\" );\n\t\t\t}, 100 );\n\t\t}\n\t}\n};\n\nobj.cool(); // красиво?\n```\n\nВкратце, стрелочные функции ведут себя совсем не как обычные функции в том, что касается их привязки к `this`. Они отбрасывают все обычные правила для привязки `this`, а взамен берут значение `this` из их непосредственной окружающей области видимости, неважно из какой.\n\nТак что в этом примере кода стрелочная функция не получает свой `this` непривязанным каким-то непредсказуемым путем, она всего лишь \"наследует\" привязку `this` функции `cool()` (что правильно, если мы вызываем ее так, как показано выше!).\n\nНесмотря на то, что это делает код короче, моя точка зрения в том, что  стрелочные функции — всего лишь на самом деле закодированная в синтаксис языка распространенная *ошибка* разработчиков, которая приводит к тому, чтобы запутать и соединить правила \"привязки this\" с правилами \"лексической области видимости\".\n\nДругими словами: зачем искать неприятности и ударяться в словоблудие используя парадигму кодирования стиля `this`, всего лишь чтобы подрезать ему крылья смешивая его с лексическими ссылками. Кажется естественным принять тот или иной подход для любой конкретной части кода, а не смешивать их в одном и том же месте.\n\n**Примечание:** еще один недостаток стрелочных функций в том, что они анонимны, не именованы. Загляните в главу 3, чтобы ознакомиться с причинами почему анонимные функции менее предпочтительны, чем именованные.\n\nБолее подходящий подход, с моей точки зрения, к этой \"проблеме\", использовать  и рассматривать механизм `this` правильно.\n\n```js\nvar obj = {\n\tcount: 0,\n\tcool: function coolFn() {\n\t\tif (this.count < 1) {\n\t\t\tsetTimeout( function timer(){\n\t\t\t\tthis.count++; // `this` безопасен из-за `bind(..)`\n\t\t\t\tconsole.log( \"еще красивее\" );\n\t\t\t}.bind( this ), 100 ); // смотри, `bind()`!\n\t\t}\n\t}\n};\n\nobj.cool(); // еще красивее\n```\n\nЧто бы вы ни предпочли: новое поведение лексического this стрелочных функций или испытанный и верный `bind()`, важно отметить, что стрелочные функции —  **не только** сокращение написания \"function\".\n\nУ них есть *намеренная разница в поведении*, которую необходимо изучить и понимать, и если мы их выбираем, то использовать по максимуму их возможности.\n\nТеперь, когда мы полностью понимаем образование лексической области видимости (и замыкания!), понять лексический this будет проще простого!\n"
  },
  {
    "path": "scope & closures/apD.md",
    "content": "# Вы не знаете JS: Область видимости и замыкания\n# Приложение D: Благодарности\n\nЕсть множество людей, которых нужно поблагодарить за то, что появилась на свет эта книга и вся серия.\n\nВо-первых, я должен поблагодарить мою жену Кристен Симпсон (Christen Simpson) и двух моих детей Итана (Ethan) и Эмили (Emily), за то, что мирились с тем, что их папу вечно надо было отрывать от компьютера. Даже когда я не писал книги, моя одержимость JavaScript приклеивала мой взгляд к экрану больше, чем следовало. То время, которое я занял у моей семьи, и есть причина, по которой  эти книги могут так глубоко и полностью объяснить JavaScript для вас, читатель. Я в большом долгу перед своей семьей.\n\nХочу поблагодарить моих редакторов в O'Reilly, а именно Simon St.Laurent и Brian MacDonald, как и остальных в команде редакторов и маркетинга. Работать с ними — одно удовольствие, и хочется особенно поблагодарить их за создание подходящих условий во время этого эксперимента с написанием \"open source\"-книги, за редактирование и выпуск.\n\nСпасибо всем тем, кто участвовал в улучшении этой серии книг присылая предложения по редактированию и корректировке, включая Shelley Powers, Tim Ferro, Evan Borden, Forrest L. Norvell, Jennifer Davis, Jesse Harlin и многих других. Большое спасибо Shane Hudson за написание предисловия к этой серии книг.\n\nСпасибо бесчисленным участникам сообщества, включая членов комитета TC39, кто поделился столько многим с нами и особенно за терпеливое отношение к моим бесконечным вопросам и изысканиям. John-David Dalton, Juriy \"kangax\" Zaytsev, Mathias Bynens, Axel Rauschmayer, Nicholas Zakas, Angus Croll, Reginald Braithwaite, Dave Herman, Brendan Eich, Allen Wirfs-Brock, Bradley Meck, Domenic Denicola, David Walsh, Tim Disney, Peter van der Zee, Andrea Giammarchi, Kit Cambridge, Eric Elliott и многие другие, я упомянул лишь малую часть.\n\nСерия книг *Вы не знаете JS* родилась на Kickstarter, поэтому я также хочу поблагодарить всех моих (почти) 500 щедрых инвесторов, без которых эта серия книг не появилась бы:\n\n> Jan Szpila, nokiko, Murali Krishnamoorthy, Ryan Joy, Craig Patchett, pdqtrader, Dale Fukami, ray hatfield, R0drigo Perez [Mx], Dan Petitt, Jack Franklin, Andrew Berry, Brian Grinstead, Rob Sutherland, Sergi Meseguer, Phillip Gourley, Mark Watson, Jeff Carouth, Alfredo Sumaran, Martin Sachse, Marcio Barrios, Dan, AimelyneM, Matt Sullivan, Delnatte Pierre-Antoine, Jake Smith, Eugen Tudorancea, Iris, David Trinh, simonstl, Ray Daly, Uros Gruber, Justin Myers, Shai Zonis, Mom & Dad, Devin Clark, Dennis Palmer, Brian Panahi Johnson, Josh Marshall, Marshall, Dennis Kerr, Matt Steele, Erik Slagter, Sacah, Justin Rainbow, Christian Nilsson, Delapouite, D.Pereira, Nicolas Hoizey, George V. Reilly, Dan Reeves, Bruno Laturner, Chad Jennings, Shane King, Jeremiah Lee Cohick, od3n, Stan Yamane, Marko Vucinic, Jim B, Stephen Collins, Ægir Þorsteinsson, Eric Pederson, Owain, Nathan Smith, Jeanetteurphy, Alexandre ELISÉ, Chris Peterson, Rik Watson, Luke Matthews, Justin Lowery, Morten Nielsen, Vernon Kesner, Chetan Shenoy, Paul Tregoing, Marc Grabanski, Dion Almaer, Andrew Sullivan, Keith Elsass, Tom Burke, Brian Ashenfelter, David Stuart, Karl Swedberg, Graeme, Brandon Hays, John Christopher, Gior, manoj reddy, Chad Smith, Jared Harbour, Minoru TODA, Chris Wigley, Daniel Mee, Mike, Handyface, Alex Jahraus, Carl Furrow, Rob Foulkrod, Max Shishkin, Leigh Penny Jr., Robert Ferguson, Mike van Hoenselaar, Hasse Schougaard, rajan venkataguru, Jeff Adams, Trae Robbins, Rolf Langenhuijzen, Jorge Antunes, Alex Koloskov, Hugh Greenish, Tim Jones, Jose Ochoa, Michael Brennan-White, Naga Harish Muvva, Barkóczi Dávid, Kitt Hodsden, Paul McGraw, Sascha Goldhofer, Andrew Metcalf, Markus Krogh, Michael Mathews, Matt Jared, Juanfran, Georgie Kirschner, Kenny Lee, Ted Zhang, Amit Pahwa, Inbal Sinai, Dan Raine, Schabse Laks, Michael Tervoort, Alexandre Abreu, Alan Joseph Williams, NicolasD, Cindy Wong, Reg Braithwaite, LocalPCGuy, Jon Friskics, Chris Merriman, John Pena, Jacob Katz, Sue Lockwood, Magnus Johansson, Jeremy Crapsey, Grzegorz Pawłowski, nico nuzzaci, Christine Wilks, Hans Bergren, charles montgomery, Ariel בר-לבב Fogel, Ivan Kolev, Daniel Campos, Hugh Wood, Christian Bradford, Frédéric Harper, Ionuţ Dan Popa, Jeff Trimble, Rupert Wood, Trey Carrico, Pancho Lopez, Joël kuijten, Tom A Marra, Jeff Jewiss, Jacob Rios, Paolo Di Stefano, Soledad Penades, Chris Gerber, Andrey Dolganov, Wil Moore III, Thomas Martineau, Kareem, Ben Thouret, Udi Nir, Morgan Laupies, jory carson-burson, Nathan L Smith, Eric Damon Walters, Derry Lozano-Hoyland, Geoffrey Wiseman, mkeehner, KatieK, Scott MacFarlane, Brian LaShomb, Adrien Mas, christopher ross, Ian Littman, Dan Atkinson, Elliot Jobe, Nick Dozier, Peter Wooley, John Hoover, dan, Martin A. Jackson, Héctor Fernando Hurtado, andy ennamorato, Paul Seltmann, Melissa Gore, Dave Pollard, Jack Smith, Philip Da Silva, Guy Israeli, @megalithic, Damian Crawford, Felix Gliesche, April Carter Grant, Heidi, jim tierney, Andrea Giammarchi, Nico Vignola, Don Jones, Chris Hartjes, Alex Howes, john gibbon, David J. Groom, BBox, Yu 'Dilys' Sun, Nate Steiner, Brandon Satrom, Brian Wyant, Wesley Hales, Ian Pouncey, Timothy Kevin Oxley, George Terezakis, sanjay raj, Jordan Harband, Marko McLion, Wolfgang Kaufmann, Pascal Peuckert, Dave Nugent, Markus Liebelt, Welling Guzman, Nick Cooley, Daniel Mesquita, Robert Syvarth, Chris Coyier, Rémy Bach, Adam Dougal, Alistair Duggin, David Loidolt, Ed Richer, Brian Chenault, GoldFire Studios, Carles Andrés, Carlos Cabo, Yuya Saito, roberto ricardo, Barnett Klane, Mike Moore, Kevin Marx, Justin Love, Joe Taylor, Paul Dijou, Michael Kohler, Rob Cassie, Mike Tierney, Cody Leroy Lindley, tofuji, Shimon Schwartz, Raymond, Luc De Brouwer, David Hayes, Rhys Brett-Bowen, Dmitry, Aziz Khoury, Dean, Scott Tolinski - Level Up, Clement Boirie, Djordje Lukic, Anton Kotenko, Rafael Corral, Philip Hurwitz, Jonathan Pidgeon, Jason Campbell, Joseph C., SwiftOne, Jan Hohner, Derick Bailey, getify, Daniel Cousineau, Chris Charlton, Eric Turner, David Turner, Joël Galeran, Dharma Vagabond, adam, Dirk van Bergen, dave ♥♫★ furf, Vedran Zakanj, Ryan McAllen, Natalie Patrice Tucker, Eric J. Bivona, Adam Spooner, Aaron Cavano, Kelly Packer, Eric J, Martin Drenovac, Emilis, Michael Pelikan, Scott F. Walter, Josh Freeman, Brandon Hudgeons, vijay chennupati, Bill Glennon, Robin R., Troy Forster, otaku_coder, Brad, Scott, Frederick Ostrander, Adam Brill, Seb Flippence, Michael Anderson, Jacob, Adam Randlett, Standard, Joshua Clanton, Sebastian Kouba, Chris Deck, SwordFire, Hannes Papenberg, Richard Woeber, hnzz, Rob Crowther, Jedidiah Broadbent, Sergey Chernyshev, Jay-Ar Jamon, Ben Combee, luciano bonachela, Mark Tomlinson, Kit Cambridge, Michael Melgares, Jacob Adams, Adrian Bruinhout, Bev Wieber, Scott Puleo, Thomas Herzog, April Leone, Daniel Mizieliński, Kees van Ginkel, Jon Abrams, Erwin Heiser, Avi Laviad, David newell, Jean-Francois Turcot, Niko Roberts, Erik Dana, Charles Neill, Aaron Holmes, Grzegorz Ziółkowski, Nathan Youngman, Timothy, Jacob Mather, Michael Allan, Mohit Seth, Ryan Ewing, Benjamin Van Treese, Marcelo Santos, Denis Wolf, Phil Keys, Chris Yung, Timo Tijhof, Martin Lekvall, Agendine, Greg Whitworth, Helen Humphrey, Dougal Campbell, Johannes Harth, Bruno Girin, Brian Hough, Darren Newton, Craig McPheat, Olivier Tille, Dennis Roethig, Mathias Bynens, Brendan Stromberger, sundeep, John Meyer, Ron Male, John F Croston III, gigante, Carl Bergenhem, B.J. May, Rebekah Tyler, Ted Foxberry, Jordan Reese, Terry Suitor, afeliz, Tom Kiefer, Darragh Duffy, Kevin Vanderbeken, Andy Pearson, Simon Mac Donald, Abid Din, Chris Joel, Tomas Theunissen, David Dick, Paul Grock, Brandon Wood, John Weis, dgrebb, Nick Jenkins, Chuck Lane, Johnny Megahan, marzsman, Tatu Tamminen, Geoffrey Knauth, Alexander Tarmolov, Jeremy Tymes, Chad Auld, Sean Parmelee, Rob Staenke, Dan Bender, Yannick derwa, Joshua Jones, Geert Plaisier, Tom LeZotte, Christen Simpson, Stefan Bruvik, Justin Falcone, Carlos Santana, Michael Weiss, Pablo Villoslada, Peter deHaan, Dimitris Iliopoulos, seyDoggy, Adam Jordens, Noah Kantrowitz, Amol M, Matthew Winnard, Dirk Ginader, Phinam Bui, David Rapson, Andrew Baxter, Florian Bougel, Michael George, Alban Escalier, Daniel Sellers, Sasha Rudan, John Green, Robert Kowalski, David I. Teixeira (@ditma, Charles Carpenter, Justin Yost, Sam S, Denis Ciccale, Kevin Sheurs, Yannick Croissant, Pau Fracés, Stephen McGowan, Shawn Searcy, Chris Ruppel, Kevin Lamping, Jessica Campbell, Christopher Schmitt, Sablons, Jonathan Reisdorf, Bunni Gek, Teddy Huff, Michael Mullany, Michael Fürstenberg, Carl Henderson, Rick Yoesting, Scott Nichols, Hernán Ciudad, Andrew Maier, Mike Stapp, Jesse Shawl, Sérgio Lopes, jsulak, Shawn Price, Joel Clermont, Chris Ridmann, Sean Timm, Jason Finch, Aiden Montgomery, Elijah Manor, Derek Gathright, Jesse Harlin, Dillon Curry, Courtney Myers, Diego Cadenas, Arne de Bree, João Paulo Dubas, James Taylor, Philipp Kraeutli, Mihai Păun, Sam Gharegozlou, joshjs, Matt Murchison, Eric Windham, Timo Behrmann, Andrew Hall, joshua price, Théophile Villard\n\nЭта серия книг выпускается в стиле \"open source\", включая редактирование и выпуск. Мы отдаем дань благодарности GitHub за предоставление такой возможности для сообщества!\n\nЕще раз спасибо всем бесчисленным людям, которых я не перечислил по имени, но кого я тем не менее должен поблагодарить. Пусть эта серия книг будет \"принадлежать\" всем нам и служить вкладом в увеличение информированности и понимании языка JavaScript, на благо всех нынешних и будущих вкладчиков в общее дело сообщества.\n"
  },
  {
    "path": "scope & closures/ch1.md",
    "content": "# Вы не знаете JS: Область видимости и замыкания\n# Глава 1: Что такое область видимости?\n\nОдна из самых фундаментальных парадигм почти всех языков программирования — возможность сохранять значения в переменных, а позже извлекать или менять эти значения. Собственно, возможность хранить значения и извлекать значения из переменных — это то, что дает программе *состояние*.\n\nБез такого концепта программа могла бы выполнять некоторые задачи, но они были бы весьма ограничены и не были бы очень уж интересны.\n\nНо включение переменных в нашу программу порождает самые интересные вопросы, которые мы теперь зададим: где эти переменные *живут*? Другими словами, где они хранятся? И, что более важно, как наша программа их находит, когда нуждается в них?\n\nЭти вопросы говорят о необходимости четкого набора правил для хранения переменных в некотором месте и для обнаружения этих переменных позднее. Мы назовем этот набор правил — *Область видимости*.\n\nНо где и как правила этих *областей видимости* устанавливаются?\n\n## Теория компиляторов\n\nСамо собой разумеется, хотя это может удивить в зависимости от вашего уровня взаимодействия с различными языками, но несмотря на тот факт, что JavaScript попадает под общую категорию \"динамических\" или \"интерпретируемых\" языков, на самом деле он язык компилируемый. Он *не* компилируется заранее, как многие традиционно компилируемые языки, и результаты компиляции не являются переносимыми среди различных распределенных систем.\n\nТем не менее, среда исполнения JavaScript выполняет много тех шагов, что и любой другой традиционный компилятор языка. Хоть и более сложными способами, чем мы обычно можем себе представить.\n\nВ традиционном процессе языковой компиляции, часть кода вашей программы обычно проходит три шага *до* того, как будет выполнена, в общих чертах называемых \"компиляцией\":\n\n1. **Разбиение на лексемы (Tokenizing/Lexing)**: разбиение строки символов  на имеющие смысл (для языка) части, называемые лексемами. Например, представьте программу: `var a = 2;`. Эта программа вероятнее всего будет разбита на следующие лексемы: `var`, `a`, `=`, `2` и `;`. Пробел может быть сохранен или не сохранен как лексема, в зависимости от того, имеет он смысл или нет.\n\n    **Примечание:** Разница между *tokenizing* и *lexing* — едва различима и теоретическая, но она сосредотачивается на том, идентифицируются ли эти лексемы как *без состояния* или *с состоянием*. Проще говоря, если токенизатор используется для того, чтобы вызывать правила парсинга с сохранением состояния чтобы выяснить, следует ли считать `a`  отдельной лексемой или только частью другой лексемы, то *это* будет **lexing**.\n\n2. **Парсинг:** берет поток (массив) лексем и превращает его в дерево вложенных элементов, которые сообща представляют грамматическую структуру программы. Это дерево называется \"AST\" (<b>A</b>bstract <b>S</b>yntax <b>T</b>ree, дерево абстрактного синтаксиса).\n\n    Такое дерево для `var a = 2;` может начинаться с узла верхнего уровня с названием `VariableDeclaration`, с дочерним узлом `Identifier` (чье значение равно `a`) и еще одним дочерним узлом `AssignmentExpression`, у которого тоже есть дочерний узел `NumericLiteral` (чье значение равно `2`).\n\n3. **Генерация кода:** процесс взятия AST и превращения его в исполняемый код. Эта часть сильно зависит от языка, платформы назначения и т.п..\n\n    Итак, вместо того, чтобы увязать в деталях, мы просто опустим их и скажем, что есть способ взять наше вышеописанное AST для `var a = 2;` и превратить его в набор машинных инструкций, чтобы в действительности *создать* переменную с именем `a` (включая выделение памяти и т.д.), а затем сохранить значение в `a`.\n\n    **Примечание:** подробности того, как движок управляет системными ресурсами, глубже, чем мы будем \"копать\". Поэтому мы всего лишь примем на веру, что движок умеет создавать и сохранять переменные когда это необходимо.\n\nДвижок JavaScript гораздо сложнее, чем *просто* эти три шага, как и большинство других языковых компиляторов. Например, в процессе синтаксического анализа и генерации кода безусловно существуют шаги по оптимизации быстродействия выполнения, включая сокращение избыточных элементов и т.п..\n\nТак что здесь я лишь очерчиваю границы. Но я думаю, что вскоре вы поймете, почему эти детали, которые мы *сейчас* освещаем, даже на высоком уровне, актуальны. \n\nПрежде всего, JavaScript‐движки не могут позволить себе роскошь (как и другие языковые компиляторы) иметь массу времени на оптимизацию. Потому что компиляция JavaScript не происходит заблаговременно на этапе сборки, как это происходит в других языках.\n\nДля JavaScript, компиляция во многих случаях происходит всего лишь за микросекунды (или меньше!) перед выполнением кода. Чтобы гарантировать высочайшее быстродействие, движки JS используют все виды уловок (такие как JIT, который компилирует лениво и даже перекомпилирует на ходу), которые вне \"области\" нашего обсуждения тут.\n\nДавайте скажем, простоты ради, что любой фрагмент JavaScript-кода должен быть скомпилирован до (обычно *прямо* перед этим!) его выполнения. Таким образом, компилятор JS *сперва* возьмет программу `var a = 2;` и скомпилирует ее, а затем будет готов выполнить ее. Обычно сразу же.\n\n## Понимание области видимости\n\nМы будем подходить к изучению темы области видимости таким образом, чтобы думать об этом процессе в терминах диалога. Но *кто* же ведет этот диалог?\n\n### Действующие лица\n\nДавайте познакомимся с действующими лицами, которые взаимодействуют при обработке программы `var a = 2;`, для того чтобы понимать их разговоры, которые мы вскоре услышим:\n\n1. *Движок* отвечает за компиляцию от начала и до конца, а также за выполнение нашей JavaScript программы;\n\n2. *Компилятор* — один из друзей *Движка*, выполняет всю грязную работу по синтаксическому анализу и генерации кода (см. предыдущий раздел);\n\n3. *Область видимости* — еще один друг *Движка*, собирает и обслуживает список поиска всех объявленных идентификаторов (переменных) и следит за исполнением строгого набора правил относительно того, каким образом эти идентификаторы доступны для текущего выполняемого кода.\n\nДля *полного понимания* как работает JavaScript, вам необходимо начать *думать* как *Движок* (и его друзья) думают, задавать вопросы как они задают и отвечать на них точно так же.\n\n### Туда и обратно\n\nКогда вы видите программу `var a = 2;`, вы вероятнее всего подумаете о ней как об одном операторе. Но наш новый друг *Движок* видит это не так. На самом деле, *Движок* видит два отдельных оператора: один, который *Компилятор* обработает во время компиляции, а другой, который *Движок* обработает во время выполнения.\n\nТак давайте же разберем по полочкам, как *Движок* и его друзья поступят с программой `var a = 2;`.\n\nПервое, что сделает *Компилятор* с этой программой, — это разобъет ее на лексемы, которые затем распарсит в дерево. Но когда *Компилятор* доберется до генерации кода, он будет интерпретировать программу несколько по-иному нежели предполагалось.\n\nРазумным предположением могло бы быть то, что *Компилятор* будет производить код, который можно кратко представить следующим псевдокодом: \"Выделить память для переменной, пометить ее как `a`, затем поместить значение `2` в эту переменную.\" К сожалению, это не совсем точно.\n\n*Компилятор* вместо этого сделает следующее:\n\n1. Встретив `var a`, *Компилятор* попросит *Область видимости* проверить, существует ли уже переменная `a` в коллекции указанной области видимости. Если да, то *Компилятор* проигнорирует это объявление переменной и двинется дальше. В противном случае, *Компилятор* попросит *Область видимости* объявить новую переменную `a` в коллекции указанной области видимости.\n\n2. Затем *Компилятор* сгенерирует код для *Движка* для последующего выполнения, чтобы обработать присваивание `a = 2`. Код, который *Движок* запускает, сначала спросит *Область видимости* есть ли переменная с именем `a`, доступная в коллекции текущей области видимости. Если есть, то *Движок* будет использовать эту переменную. Если нет, то *Движок* будет искать *в другом месте* (см. раздел *Вложенная область видимости* ниже).\n\nЕсли *Движок* в итоге найдет переменную, он присвоит ей значение `2`. Если нет, то *Движок* вскинет руки и выкрикнет: \"Ошибка!\".\n\nПодводя итог, чтобы присвоить значение переменной, выполняются два различных действия: во-первых, *Компилятор* объявляет переменную (если она не была объявлена ранее) в текущей области видимости, а во-вторых, при выполнении кода, *Движок* ищет эту переменную в *Области видимости* и, если находит, присваивает ей значение.\n\n### Компилятор расскажет\n\nНам нужно еще немного компиляторной терминологии, перед тем как двинуться дальше.\n\nКогда *Движок* выполняет код, который *Компилятор* генерирует на шаге (2), он должен найти переменную `a`, чтобы увидеть, была ли она объявлена. И этот поиск принимает во внимание *Область видимости*. Но тип поиска, который выполняет *Движок*, влияет на результат поиска.\n\nВ нашем случае говорят, что *Движок* будет выполнять \"LHS\"-поиск переменной `a`. Другой тип поиска называется \"RHS\".\n\nДержу пари, что вы можете угадать что означают \"L\" и \"R\". Эти термины означают \"Left-hand Side\" (левая сторона) и \"Right-hand Side\" (правая сторона).\n\nСторона... чего? *Операции присваивания.*\n\nИными словами, LHS-поиск выполняется, когда переменная появляется с левой стороны операции присваивания, а RHS-поиск выполняется, когда переменная появляется с правой стороны операции присваивания.\n\nНа самом деле, давайте будем немного точнее. RHS-поиск, для наших целей, неотличим от простого поиска значения некоторой переменной. Тогда как LHS-поиск пытается найти сам контейнер переменной, чтобы он мог присвоить значение. Таким образом, RHS по существу *не обязательно* означает \"правая сторона присваивания\", он просто более точно означает \"не левая сторона\".\n\nСтав на мгновение легкомысленным, вы могли бы подумать, что RHS вместо этого означает \"извлеки его/ее исходное значение\", подразумевая, что RHS — это \"иди и получи значение из...\".\n\nДавайте копнем немного глубже в этом направлении.\n\nКогда я говорю:\n\n```js\nconsole.log( a );\n```\n\nСсылка на `a` — это RHS-ссылка, потому что здесь ничего не присваивается в  `a`. Напротив, мы выполняем поиск, чтобы извлечь значение `a`, для того, чтобы передать значение в `console.log(..)`.\n\nДля сравнения:\n\n```js\na = 2;\n```\n\nСсылка на `a` здесь — это LHS-ссылка, так как мы не заботимся здесь о том, каково текущее значение, мы просто хотим найти эту переменную  как цель для операции присваивания `= 2`.\n\n**Примечание:** LHS и RHS, означающие \"левая/правая сторона присваивания\", не обязательно буквально означают \"левая/правая сторона операции присваивания `=`\". Есть еще несколько способов, которыми производится присваивание, и поэтому лучше концептуально думать о нем как: \"кто является целью присваивания (LHS)\" и \"кто источник присваивания (RHS)\".\n\nПредставьте такую программу, в которой есть обе ссылки LHS и RHS:\n\n```js\nfunction foo(a) {\n\tconsole.log( a ); // 2\n}\n\nfoo( 2 );\n```\n\nПоследняя строка, которая активизирует `foo(..)` как вызов функции, требует RHS-ссылку на `foo`, что значит, \"сходи и найди значение `foo` и дай его мне\". Более того, `(..)` означает, что значение `foo` должно быть выполнено, поэтому это скорее всего функция!\n\nЗдесь есть едва уловимое, но важное присваивание. **Вы обнаружили его?**\n\nВы наверное упустили неявное `a = 2` в этом коде. Это происходит, когда значение `2` передается как аргумент в функцию `foo(..)`, в этом случае значение `2` **присваивается** параметру `a`. Чтобы (неявно) присвоить значение параметру `a`, выполняется LHS-поиск.\n\nТакже есть и RHS-ссылка на значение `a` и это результирующее значение передается в `console.log(..)`. `console.log(..)` нужна ссылка для выполнения. Для объекта `console` это RHS-поиск, затем происходит разрешение имени свойства чтобы убедиться существует ли метод, называемый `log`.\n\nНаконец, мы можем осмыслить, что есть LHS/RHS-обмен передаваемым значением `2` (путем RHS-поиска переменной `a`) в `log(..)`. Внутри родной реализации  `log(..)`, мы можем предположить, что у нее есть параметры, у первого из которых (возможно называющегося `arg1`) есть поиск LHS-ссылки, до присваивания ему `2`.\n\n**Примечание:** У вас может появиться соблазн представлять объявление функции `function foo(a) {...` как обычное объявление переменной и присваивание, такое как `var foo` и `foo = function(a){...`. Делая так, будет соблазн думать об объявлении этой функции как подразумевающей LHS-поиск.\n\nОднако, едва заметная, но важная разница есть в том, что *Компилятор* обрабатывает как объявление, так и определение значения во время генерации кода, благодаря чему, когда *Движок* выполняет код, не требуется никакой обработки чтобы \"присвоить\" значение функции в `foo`. Следовательно, неуместно думать об объявлении функции как о присваивании с помощью LHS-поиска тем способом, который мы здесь обсуждаем.\n\n### Беседа Движка и Области видимости\n\n```js\nfunction foo(a) {\n\tconsole.log( a ); // 2\n}\n\nfoo( 2 );\n```\n\nДавайте представим вышеуказанный обмен между ними (который обрабатывает этот код) как беседу. Беседа может пойти примерно так:\n\n> ***Движок***: Эй, *Область видимости*, у меня есть RHS-ссылка на `foo`. Когда-нибудь слышала о такой?\n\n> ***Область видимости***: Ну разумеется, слышала. *Компилятор* объявил ее всего секунду назад. Это функция. Пожалуйста!\n\n> ***Движок***: Отлично, спасибо! Хорошо, я выполняю `foo`.\n\n> ***Движок***: Эй, *Область видимости*, у меня есть LHS-ссылка на `a`, слышала что-нибудь о ней?\n\n> ***Область видимости***: Ну разумеется, слышала. *Компилятор* объявил ее как формальный параметр в `foo` только что. Пожалуйста!\n\n> ***Движок***: Отзывчива как всегда, *Область видимости*. Снова спасибо. А теперь присвоим `2` в `a`.\n\n> ***Движок***: Эй, *Область видимости*, извини, что беспокою тебя снова. Мне нужен RHS-поиск `console`. Когда-нибудь слышала о таком имени?\n\n> ***Область видимости***: Нет проблем, *Движок*, это то, чем я весь день и занимаюсь. Да, у меня есть `console`. Она встроенная. Пожалуйста!\n\n> ***Движок***: Идеально. Ищу `log(..)`. Превосходно, это функция.\n\n> ***Движок***: Эй, *Область видимости*. Можешь помочь мне с RHS-ссылкой на `a`? Думаю, я ее помню, но просто хочу лишний раз проверить.\n\n> ***Область видимости***: Ты прав, *Движок*. Та же ссылка, не изменилась. Пожалуйста!\n\n> ***Движок***: Круто! Передаю значение `a`, которое равно `2`, в `log(..)`.\n\n> ...\n\n### Тест\n\nПроверьте ваше понимание на настоящий момент. Обязательно сыграйте роль *Движка* и поучаствуйте в \"беседе\" с *Областью видимости*:\n\n```js\nfunction foo(a) {\n\tvar b = a;\n\treturn a + b;\n}\n\nvar c = foo( 2 );\n```\n\n1. Определите все LHS-поиски (их 3!).\n\n2. Определите все RHS-поиски (их 4!).\n\n**Примечание:** См. обзор этой главы, чтобы узнать ответы на тест!\n\n## Вложенная область видимости\n\nМы говорили, что *Область видимости* — это набор правил поиска переменных по их идентификатору. Однако, обычно бывает более одной *Области видимости*.\n\nТакже как блок или функция вкладывается внутрь другого блока или функции, области видимости вкладываются внутрь других областей. Поэтому, если переменную не найти в ближайшей области видимости, *Движок* заглядывает в следующую внешнюю по отношению к этой область видимости, продолжая так до тех пор, пока не найдет или пока не достигнет самой внешней (т.е. глобальной) области.\n\nПример:\n\n```js\nfunction foo(a) {\n\tconsole.log( a + b );\n}\n\nvar b = 2;\n\nfoo( 2 ); // 4\n```\n\nRHS-ссылка на `b` не может быть разрешена внутри функции `foo`, но она может быть разрешена в *Области видимости*, окружающей ее (в этом случае, глобальной).\n\nПоэтому, еще раз пересмотрев беседы между *Движком* и *Областью видимости*, мы возможно услышим:\n\n> ***Движок***: \"Эй, *Область видимости* `foo`, что-нибудь слышала о `b`? У меня есть RHS-ссылка на нее\".\n\n> ***Область видимости***: \"Не-а, никогда не слышала о такой. Попробуй что-нибудь другое!\"\n\n> ***Движок***: \"Эй, *Область видимости* снаружи `foo`! О, ты еще и глобальная *Область видимости*, круто. Когда-нибудь слышала о `b`? У меня есть RHS-ссылка на нее.\"\n\n> ***Область видимости***: \"Да-да, конечно есть. Пожалуйста!\"\n\nПростые правила просмотра вложенных *Областей видимости*: *Движок* начинает в текущей выполняемой *Области видимости*, ищет в ней переменную, затем если не находит, продолжает поиск уровнем выше и так далее. Если достигнута самая внешняя глобальная область видимости, поиск останавливается, независимо от того, нашел он переменную или нет.\n\n### Берем за основу метафоры\n\nДля визуализации процесса разрешения во вложенных *Областях видимости*, я хочу, чтобы вы подумали об этом высоком здании.\n\n<img src=\"fig1.png\" width=\"250\">\n\nЗдание символизирует набор правил вложенных *Областей видимости* нашей программы. Первый этаж здания представляет вашу текущую выполняемую *Область видимости*, где бы вы ни были. Верхний уровень здания — это глобальная *Область видимости*.\n\nВы разрешаете LHS- и RHS-ссылки ища на вашем текущем этаже, а если вы не нашли что искали, поднимаетесь на лифте на следующий этаж, ища там, затем на следующий и так далее. Как только вы попадаете на верхний этаж(глобальная *Область видимости*), вы либо находите то, что искали, либо не находите. Но в любом случае вы должны остановиться.\n\n## Ошибки\n\nПочему имеет значение называть поиск LHS или RHS?\n\nПотому что эти два типа поиска ведут себя по-разному в обстановке, когда переменная еще не была объявлена (не была найдена ни в одной просмотренной *Области видимости*).\n\nПредставьте:\n\n```js\nfunction foo(a) {\n\tconsole.log( a + b );\n\tb = a;\n}\n\nfoo( 2 );\n```\n\nКогда происходит RHS-поиск `b` первый раз, она не будет найдена. Это как бы  \"необъявленная\" переменная, так как она не была найдена в этой области видимости.\n\nЕсли RHS-поиск не сможет когда-либо найти переменную, в любой из вложенных *Областей видимости*, это приведет к возврату *Движком* ошибки `ReferenceError`. Важно отметить, что эта ошибка имеет тип `ReferenceError`.\n\nНапротив, если *Движок* выполняет LHS-поиск и достигает верхнего этажа (глобальной *Области видимости*) и не находит ничего, и если программа не запущена в \"строгом режиме\", то затем глобальная *Область видимости* создаст новую переменную с таким именем **в глобальной области видимости** и передаст ее обратно *Движку*.\n\n*\"Нет, до этого не было ни одной и я любезно создала ее для тебя.\"*\n\n\"Строгий режим\", который был добавлен в ES5, имеет ряд разных отличий от обычного/нестрогого/ленивого режима. Одно такое отличие — это то, что он запрещает автоматическое/неявное создание глобальных переменных. В этом случае, не было бы никакой переменной в глобальной *Области видимости*, чтобы передать обратно от LHS-поиска, и *Движок* выбросит `ReferenceError` аналогично случаю с RHS.\n\nТеперь, если переменная найдена в ходе RHS-поиска, но вы пытаетесь сделать что-то с ее значением, что невозможно, например, пытаетесь выполнить как функцию не-функциональное значение или ссылаетесь на свойство значения `null` или `undefined`, то *Движок* выдаст другой вид ошибки, называемый `TypeError`.\n\n`ReferenceError` — это сбой разрешения имени, связанный с *Областью видимости*, тогда как `TypeError` подразумевает, что разрешение имени в *Области видимости* было успешным, но была попытка выполнения нелегального/невозможного действия с результатом.\n\n## Обзор\n\nОбласть видимости — это набор правил, которые определяют где и как переменная (идентификатор) могут быть найдены. Этот поиск может осуществляться для целей присваивания значения переменной, которая является LHS (left-hand-side) ссылкой, или может осуществляться для целей извлечения ее значения, которое является RHS (right-hand-side) ссылкой.\n\nLHS-ссылки являются результатом операции присваивания. Присваивания, связанные с *Областью видимости*, могут происходить либо с помощью операции `=`, либо передачей аргументов (присваиванием) параметрам функции.\n\nJavaScript *Движок* перед выполнением сначала компилирует код, и пока он это делает, он разбивает операторы, подобные `var a = 2;` на два отдельных шага:\n\n1. Первый, `var a`, чтобы объявить ее в *Область видимости*. Это выполняется в самом начале, до исполнения кода.\n\n2. Позже, `a = 2` ищет переменную (LHS-ссылку) и присваивает ей значение, если находит.\n\nОба поиска ссылок LHS и RHS начинаются в текущей выполняющейся *Области видимости* и если нужно (т.е. они не нашли что искали в ней), они работают с их более высокими вложенными *Областями видимости*, с одной областью (этажом) за раз, ища идентификатор, пока не доберутся до глобальной (верхний этаж) и не остановятся, вне зависимости от результата поиска.\n\nНевыполненные RHS-ссылки приводят к выбросу `ReferenceError`. Невыполненные LHS-ссылки приводят к автоматической, неявно созданной переменной с таким именем (если не включен \"Строгий режим\"), либо к `ReferenceError` (если включен \"Строгий режим\").\n\n### Ответы к тесту\n\n```js\nfunction foo(a) {\n\tvar b = a;\n\treturn a + b;\n}\n\nvar c = foo( 2 );\n```\n\n1. Определите все LHS-поиски (их 3!).\n\n\t**`c = ..`, `a = 2` (неявное присваивание параметру) и `b = ..`**\n\n2. Определите все RHS-поиски (их 4!).\n\n    **`foo(2..`, `= a;`, `a + ..` и `.. + b`**\n\n\nПро \"Строгий режим\" [см. здесь](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/Strict_mode)\n"
  },
  {
    "path": "scope & closures/ch2.md",
    "content": "# Вы не знаете JS: Область видимости и замыкания\n# Глава 2: Лексическая область видимости\n\nВ главе 1, мы определили \"область видимости\" как набор правил, которые регулируют как *Движок* может искать переменную по ее имени идентификатора и найти ее либо в текущей *Области видимости*, либо в любой из *вложенных Областей видимости*, в которой она содержится.\n\nЕсть две преобладающих модели того, как работает область видимости. Первая из них, безусловно самая распространенная, используется необъятным большинством языков программирования. Она называется **Лексическая область видимости** и мы изучим ее в деталях. Другая модель, которая все еще используется некоторыми языками (такими как скриптовый Bash, некоторые режимы в Perl и т.д.), называется **Динамическая область видимости**.\n\nДинамическая область видимости рассматривается в приложении A. Я упоминаю ее здесь только чтобы показать контраст с лексической областью действия, которая является моделью области видимости, используемой в JavaScript.\n\n## Время разбора на лексемы\n\nКак мы уже обсудили в главе 1, первая традиционная фаза работы стандартного компилятора языка называется разбиение на лексемы (lexing или tokenizing). Если вы припомните, то процесс разбиения на лексемы анализирует символы строки исходного кода и дает семантическое значение лексемам как результат некоторого парсинга с состоянием.\n\nЭто и есть та концепция, которая предоставляет основу понимания что такое лексическая область видимости и откуда происходит ее название.\n\nОпределяя ее отчасти через саму себя, лексическая область видимости — это область видимости, которая определена во время разбора на лексемы. Иными словами, лексическая область видимости основана на том, где переменные и блоки области видимости были созданы вами во время написания и таким образом (в основном) навечно зафиксированы на момент, когда лексический анализатор обрабатывал ваш код.\n\n**Примечание:** Совсем скоро мы увидим, что есть некоторые способы обмануть лексическую область действия, тем самым меняя ее после того, как лексический анализатор уже прошелся по ней, но к ним относятся неодобрительно. Считается лучшей практикой обращаться с лексической областью видимости как, по сути дела с чисто лексической и следовательно полностью относящейся к моменту написания кода по своей природе.\n\nДавайте рассмотрим этот код:\n\n```js\nfunction foo(a) {\n\n\tvar b = a * 2;\n\n\tfunction bar(c) {\n\t\tconsole.log( a, b, c );\n\t}\n\n\tbar(b * 3);\n}\n\nfoo( 2 ); // 2 4 12\n```\n\nВ этом примере кода есть три вложенных области видимости. Удобно представлять эти области видимости как зоны одна внутри другой.\n\n<img src=\"fig2.png\" width=\"500\">\n\n**Зона 1** заключает в себе глобальную область видимости, у которой есть всего один идентификатор: `foo`.\n\n**Зона 2** заключает в себе область видимости `foo`, которая включает в себя три идентификатора: `a`, `bar` и `b`.\n\n**Зона 3** заключает в себе область видимости `bar` и она включает в себя всего один идентификатор: `c`.\n\nЗоны областей видимости определяются тем, где написаны блоки области видимости, которые последовательно вложены друг в друга. В следующей главе, мы обсудим различные единицы области видимости, а сейчас давайте просто допустим, что каждая функция создает новую зону области видимости.\n\nЗона для `bar` полностью содержится в зоне для `foo`, потому что (и только поэтому) это то место, которое мы выбрали для создания функции `bar`.\n\nЗаметьте, что эти вложенные зоны вложены однозначно и четко. Мы не говорим сейчас о круговых диаграммах Эйлера—Венна, где зоны могут пересекать границы. Иными словами, ни одна зона для функции не может одновременно существовать (частично) внутри двух других зон внешних областей видимости, как и ни одна функция не может частично быть внутри каждой из двух родительских функций.\n\n### Поиски\n\nСтруктура и относительное положение этих зон областей видимости полностью объясняет *Движку* все места, в которые ему нужно заглянуть, чтобы найти идентификатор.\n\nВ вышеприведенном коде, *Движок* выполняет оператор `console.log(..)` и идет искать три переменных `a`, `b`, и `c`, на которые есть ссылки. Сначала он начинает с самой внутренней зоны области видимости, области видимости функции `bar(..)`. Он не найдет там `a`, поэтому пойдет на уровень выше, наружу к следующей ближайшей зоне области видимости, области видимости `foo(..)`. Там он наконец найдет `a`, и поэтому использует эту `a`. То же самое и для `b`. А вот `c` он найдет внутри `bar(..)`.\n\nЕсли бы `c` была и внутри `bar(..)`, и внутри `foo(..)`, то оператор `console.log(..)` нашел и использовал ту, что в `bar(..)`, никогда не трогая такую же из `foo(..)`.\n\n**Поиск в области видимости прекращается как только он находит первое совпадение**. Одно и то же имя идентификатора может быть указано в нескольких слоях вложенных областей видимости, что называется \"затенение (shadowing)\" (внутренний идентификатор \"затеняет (shadows)\" внешний). Независимо от затенения, поиск в области видимости всегда начинается с самой внутренней области видимости, исполняющейся в данный момент и работает таким путем по направлению наружу/вверх пока не найдется первое совпадение и тогда останавливается.\n\n**Примечание:** Глобальные переменные также автоматически являются свойствами глобального объекта (`window` в браузерах и т.п.), поэтому *можно* ссылаться на глобальную переменную не прямо по ее лексическому имени, а вместо этого  косвенно использовать ссылку на свойство глобального объекта.\n\n```js\nwindow.a\n```\n\nЭта техника дает доступ к глобальной переменной, которая в противном случае была бы недоступна из-за затенения. Однако, неглобальные затененные переменные не могут быть доступны.\n\nНе важно *откуда* вызывается функция или даже *как* она вызывается, ее лексическая область видимости определена **только** тем, где функция была объявлена.\n\nПроцесс поиска в лексической области видимости применяется *только* к идентификаторам первого класса, таким как `a`, `b` и `c`. Если у вас есть ссылка на `foo.bar.baz` в строке кода, поиск в лексической области будет применен чтобы найти идентификатор `foo`, но как только он находит эту переменную, ему на смену приходят правила доступа к свойствам объекта, чтобы разрешить имена свойств `bar` и `baz`, соответственно.\n\n## Обманываем лексическую область видимости\n\nЕсли лексическая область видимости определяется только тем, где объявлена функция, что целиком во власти момента написания кода, какой может быть возможный путь \"изменить\" (т.е. обмануть) лексическую область во время выполнения?\n\nВ JavaScript есть два таких механизма. К ним обоим одинаково неодобрительно относятся в широком сообществе как к плохим практикам использования кода. Но типичные аргументы против них обычно не видят самого главного: **обман лексической области видимости ведет к более худшей производительности.**\n\nПеред тем как я объясню проблему с производительностью, всё же, давайте взглянем на то, как работают эти два механизма.\n\n### `eval`\n\nФункция `eval(..)` в JavaScript берет строку как аргумент и интерпретирует содержимое строки как если бы это был код, написанный в этой точке программы. Другими словами, вы можете программно генерировать код внутри вашего собственного кода и запускать сгенерированный код как если бы он был там во время написания кода.\n\nПри вычислении `eval(..)` в таком свете, должно быть ясно как `eval(..)` позволяет модифицировать окружение лексической области видимости, обманывая и притворяясь, что этот код был тут всё время.\n\nНа последующих строках кода после того, как выполнена `eval(..)`, *Движок* не \"узнает\" или не \"позаботится\" о том, что предыдущий код, о котором идет речь,  был динамически интерпретирован и таким образом изменил окружение лексической области видимости. *Движок* просто выполнит свои поиски по лексической области видимости как он обычно это делает.\n\nПредставьте следующий код:\n\n```js\nfunction foo(str, a) {\n\teval( str ); // обман!\n\tconsole.log( a, b );\n}\n\nvar b = 2;\n\nfoo( \"var b = 3;\", 1 ); // 1, 3\n```\n\nСтрока `\"var b = 3;\"` интерпретируется в точке вызова `eval(..)`, как будто этот код был тут всегда. Поскольку этот код объявляет новую переменную `b`, он изменяет существующую лексическую область `foo(..)`. Фактически, как было указано выше, этот код на самом деле создает переменную `b` внутри `foo(..)`, которая затеняет `b`, которая была объявлена во внешней (глобальной) области видимости.\n\nКогда происходит вызов `console.log(..)`, он находит и `a`, и `b` в области видимости `foo(..)`, но никогда не найдет внешнюю `b`. По этой причине, мы напечатаем \"1, 3\" вместо \"1, 2\" как это было бы в обычном случае.\n\n**Примечание:** В этом примере для простоты строка \"кода\", которую мы передали, была фиксированным литералом. Но она легко может быть создана программно соединением символов вместе на основе логики вашей программы. `eval(..)` обычно используется для динамически созданного кода, поскольку динамическое вычисление по существу статического кода из строкового литерала не дает никакого реального преимущества перед простым написанием этого кода напрямую.\n\nПо умолчанию, если строка кода, которую выполняет `eval(..)`, содержит одно или более объявлений (переменных или функций), тогда это действие меняет существующую лексическую область видимости, в которой располагается `eval(..)`. Технически, `eval(..)` может быть вызвана \"неявно\", путем различных трюков (вне нашего обсуждения здесь), которые приводят к тому, что она вместо этого запускается в контексте глобальной области видимости, таким образом меняя ее. Но в любом случае, `eval(..)` может во время исполнения менять лексическую область видимости, определенную на момент написания кода.\n\n**Примечание:** Когда `eval(..)` используется в программе, работающей в строгом режиме, она работает со своей собственной лексической областью видимости, что означает, что объявления, сделанные внутри `eval()`, не поменяют окружающую область видимости.\n\n```js\nfunction foo(str) {\n   \"use strict\";\n   eval( str );\n   console.log( a ); // ReferenceError: a is not defined\n}\n\nfoo( \"var a = 2\" );\n```\n\nЕсть другие средства в JavaScript, которые почти равносильны по эффекту вызовам `eval(..)`. `setTimeout(..)` и `setInterval(..)`, которые *могут* принимать строку как свой первый аргумент, содержимое которой `вычисляется` как код динамически сгенерированной функции. Это старая, унаследованная функциональность и давным-давно устаревшая. Не делайте так!\n\nКонструктор функции `new Function(..)` аналогично принимает строку кода  в своем **последнем** аргументе, чтобы превратить ее в динамически сгенерированную функцию (первые аргументы, если указаны, являются именованными параметрами для новой функции). Такой синтаксис конструктора функции немного безопаснее, чем `eval(..)`, но его также следует избегать в вашем коде.\n\nВарианты использования динамически сгенерированного кода внутри вашей программы крайне редки, поскольку снижение производительности почти никогда не стоит такой возможности.\n\n### `with`\n\nЕще одна возможность в JavaScript, к которой неодобрительно относятся (и которая сейчас устарела!), которая обманывает лексическую область видимости, это ключевое слово `with`. Есть много подходящих путей, чтобы объяснить что такое `with`, но я выберу объяснение с точки зрения того, как оно взаимодействует и влияет на лексическую область видимости.\n\n`with` обычно описывают как сокращение для выполнения множественных ссылок на свойства объекта *без* повторения каждый раз ссылки на сам объект.\n\nНапример:\n\n```js\nvar obj = {\n\ta: 1,\n\tb: 2,\n\tc: 3\n};\n\n// более \"скучно\" повторять \"obj\"\nobj.a = 2;\nobj.b = 3;\nobj.c = 4;\n\n// \"легкое\" сокращение\nwith (obj) {\n\ta = 3;\n\tb = 4;\n\tc = 5;\n}\n```\n\nОднако, здесь происходит нечто большее, чем просто удобное сокращение для доступа к свойствам объекта. Представьте:\n\n```js\nfunction foo(obj) {\n\twith (obj) {\n\t\ta = 2;\n\t}\n}\n\nvar o1 = {\n\ta: 3\n};\n\nvar o2 = {\n\tb: 3\n};\n\nfoo( o1 );\nconsole.log( o1.a ); // 2\n\nfoo( o2 );\nconsole.log( o2.a ); // undefined\nconsole.log( a ); // 2 — Упс, утекшая глобальная переменная!\n```\n\nВ этом примере кода, создаются два объекта `o1` и `o2`. У одного есть свойство `a`, а у другого — нет. Функция `foo(..)` берет ссылку на объект `obj` как аргумент, а затем вызывает `with (obj) { .. }` с этой ссылкой. Внутри блока `with` мы делаем, как нам представляется, обычную лексическую ссылку на `a`, на самом деле LHS-ссылку (см. главу 1), чтобы присвоить ей значение `2`.\n\nКогда мы передаем `o1`, присвоение `a = 2` находит свойство `o1.a` и присваивает ему значение `2`, что нашло свое отражение в последующем операторе `console.log(o1.a)`. Однако, когда мы передаем `o2`, поскольку у него нет свойства `a`, это свойство не создается, а `o2.a` остается `undefined`.\n\nНо затем мы замечаем своеобразный побочный эффект, факт того, что присвоение `a = 2` создало глобальную переменную `a`. Как такое может быть?\n\nОператор `with` берет объект, у которого есть ноль или более свойств, и **трактует этот объект как если бы *он* являлся целиком отдельной лексической областью видимости**, и таким образом свойства объекта воспринимаются как лексически определенные идентификаторы в этой \"области видимости\".\n\n**Примечание:** Даже если блок `with` трактует объект как лексическую область видимости, обычное объявление `var` внутри этого блока `with` не будет входить в область этого блока `with`, а вместо этого будет в области видимости функции, содержащей этот блок.\n\nВ то время как функция `eval(..)` может менять существующую лексическую область видимости, если она принимает строку кода с одним или более объявлениями в ней, то оператор `with` на самом деле создает **полностью новую лексическую область действия** на ровном месте из объекта, который вы ему передаете.\n\nТаким образом мы поняли, что \"область видимости\", объявленная оператором `with`  когда мы передали `o1`, была `o1` и что у этой \"области видимости\" есть \"идентификатор\", который соответствует свойству `o1.a`. Но когда мы  использовали `o2` как \"область видимости\", у нее не было такого \"идентификатора\" `a` и поэтому сработали обычные правила поиска LHS-идентификатора (см. главу 1).\n\nНи \"область видимости\" `o2`, ни область видимости `foo(..)`, ни даже глобальная область видимости не нашли у себя идентификатор `a`, поэтому когда выполняется `a = 2`, это приводит к созданию автоматической глобальной переменной (поскольку мы в нестрогом режиме).\n\nЭто незнакомая и отчасти ошеломляющая мысль увидеть как `with` превращает, во время выполнения, объект и его свойства в \"область видимости\" *с* \"идентификаторами\". Но это — самое понятное объяснение, которое я могу дать результатам, которые мы видели.\n\n**Примечание:** В дополнение к тому, что является плохой идеей их использовать, как `eval(..)`, так и `with` подвергаются воздействию (ограничиваются) строгим режимом. `with` полностью запрещено, в то время как различные формы скрытых или небезопасных `eval(..)` запрещены при сохранении базовой функциональности.\n\n### Быстродействие\n\nОба `eval(..)` и `with` обманывают в той или иной форме лексическую область видимости, определенную на этапе кодирования, изменением или созданием новой лексической области видимости во время выполнения.\n\nИтак, что тут такого, спросите вы? Если они предлагают улучшенную функциональность и гибкость кодирования, разве это не *хорошие* возможности? **Нет.**\n\nВ  *Движке* JavaScript есть много оптимизаций быстродействия, которые он выполняет во время фазы компиляции. Некоторые из этих оптимизаций сводятся к возможности по сути статически анализировать код, как только он разбирается на лексемы, и заранее определять где находятся все переменные и функции, для того чтобы понадобилось меньше усилий для разрешения имен идентификаторов во время выполнения.\n\nНо если *Движок* находит в коде `eval(..)` или `with`, он фактически должен *предположить*, что все его знание о местонахождении идентификаторов может быть неправильным, потому что он не знает точно во время написания кода какой код вы можете передать в `eval(..)`, чтобы поменять лексическую область видимости или какое содержимое объекта вы можете передать в `with`, чтобы создать новую лексическую область видимости, чтобы быть в курсе.\n\nИными словами, с точки зрения пессимистического здравого смысла, большинство таких оптимизаций, которые он *мог бы* сделать, бессмысленны, если есть `eval(..)` или `with`, поэтому он просто не выполняет *никаких* оптимизаций.\n\nВаш код почти определенно будет стремиться работать медленнее просто из-за того факта, что вы включили `eval(..)` или `with` где-либо в вашем коде. Не важно насколько умным может быть *Движок* пытаясь ограничить побочные эффекты этих пессимистических предположений, но **нельзя обойти тот факт, что без оптимизаций код работает медленнее.**\n\n## Обзор\n\nЛексическая область видимости означает, что область видимости определена решениями о том, где объявляются функции на стадии написания кода. Фаза разбиения на лексемы при компиляции фактически способна узнать где и как объявлены все идентификаторы, и таким образом предсказать как их будут искать во время выполнения.\n\nДва механизма в JavaScript могут \"обмануть\" лексическую область видимости: `eval(..)` и `with`. Первый может менять существующую лексическую область видимости (во время выполнения) исполняя строку \"кода\", в которой есть одно или несколько объявлений. Второй по сути создает целую новую лексическую область видимости (снова во время выполнения) интерпретируя ссылку на объект *как* \"область видимости\", а свойства этого объекта как идентификаторы этой области.\n\nНедостаток этих механизмов в том, что они лишают смысла возможность *Движка*  выполнять оптимизации во время компиляции, принимающие во внимание поиск в области видимости, так как *Движок* должен пессимистически предположить, что такие оптимизации будут неправильными. Код *будет* выполняться медленнее в результате использования любой из этих возможностей. **Не используйте их!**\n"
  },
  {
    "path": "scope & closures/ch3.md",
    "content": "# Вы не знаете JS: Область видимости и замыкания\n# Глава 3: Область видимости: функции против блоков\n\nКак мы уже исследовали в главе 2, область видимости состоит из серии \"зон\", каждая из которых действует как контейнер или корзина, в которой объявляются идентификаторы (переменные, функции). Эти зоны четко вкладываются друг в друга и это вложение определяется во время написания кода.\n\nНо что именно конкретно создает новую зону? Только функция? Могут ли другие структуры в JavaScript создавать зоны областей видимости?\n\n## Область видимости из функций\n\nСамый общий ответ на эти вопросы такой — в JavaScript есть области видимости в функциях. То есть, каждая функция, которую вы объявляете, создает зону для себя, но больше ни одна структура не создает свою собственную зону области видимости. Как мы скоро увидим, это не совсем правда.\n\nНо сначала, давайте исследуем область видимости функции и ее применения.\n\nПредставьте такой код:\n\n```js\nfunction foo(a) {\n\tvar b = 2;\n\n\t// некоторый код\n\n\tfunction bar() {\n\t\t// ...\n\t}\n\n\t// еще код\n\n\tvar c = 3;\n}\n```\n\nВ этом коде зона области видимости для `foo(..)` включает в себя идентификаторы `a`, `b`, `c` и `bar`. **Не важно** *где* в области видимости появится объявление, переменная или функция принадлежит к содержащей их зоне области видимости, вне зависимости от места объявления. Мы исследуем в следующей главе как *это* в точности работает.\n\nУ `bar(..)` есть своя собственная зона области видимости. Также и у глобальной области видимости, у которой есть всего один идентификатор: `foo`.\n\nТак как `a`, `b`, `c` и `bar` все принадлежат к зоне области видимости `foo(..)`, они недоступны вне `foo(..)`. То есть, нижеприведенный код весь целиком приведет к ошибкам `ReferenceError`, так как идентификаторы недоступны в глобальной области видимости:\n\n```js\nbar(); // ошибка\n\nconsole.log( a, b, c ); // все 3 вызовут ошибку\n```\n\nОднако, все эти идентификаторы (`a`, `b`, `c`, `foo` и `bar`) доступны *внутри* `foo(..)` и конечно также доступны внутри `bar(..)` (предполагаем, что нет ни одного объявления затеняющих идентификаторов внутри `bar(..)`).\n\nОбласть видимости функции поощряет идею, что все переменные принадлежат функции и могут быть использованы и переиспользованы на всем протяжении функции (и более того, доступны даже во вложенных областях видимости). Этот подход к дизайну может быть довольно полезен и несомненно может использовать в полном объеме \"динамическую\" природу переменных JavaScript, чтобы иметь дело со значениями разных типов при необходимости.\n\nС другой стороны, если вы не принимаете меры предосторожности, переменные, существующие на всей протяженности области видимости, могут привести к неожиданным ошибкам.\n\n## Прячемся на виду у всей области видимости\n\nТрадиционный путь рассуждений о функциях таков: вы определяете функцию, а затем добавляете код внутрь нее. Но обратное рассуждение столь же обоснованно и удобно: взять любую произвольную часть кода, которую вы написали, и обернуть ее в объявление функции, что в сущности \"прячет\" код.\n\nПрактическим результатом является создание зоны области видимости вокруг кода, о котором идет речь, а это значит, что любые объявления (переменной или функции) в этом коде будут ограничены областью видимости новой оборачивающей код функции, вместо ранее охватывающей области видимости. Иными словами, вы можете \"спрятать\" переменные и функции заключив их в область видимости функции.\n\nПочему же \"прятать\" переменные и функции — полезная техника?\n\nЕсть множество причин, мотивирующих на это сокрытие, основанное на области видимости. Они имеют тенденцию проистекать из принципа дизайна ПО \"Принцип наименьших привилегий\", также иногда называемый \"Наименьшие полномочия\" или \"Наименьшая открытость\". Этот принцип заявляет, что в дизайне ПО, таком как API для модуля/объекта, вам следует выставлять наружу только то, что минимально необходимо и \"прятать\" всё остальное.\n\nЭтот принцип распространяется и на выбор того, какая область видимости будет содержать переменные и функции. Если все переменные и функции были бы в глобальной области видимости, они были бы, конечно, доступны любой вложенной области видимости. Но это нарушает принцип \"Наименьшей...\" в том, что вы  (видимо) открываете многие переменные или функции, которые вам следовало в противном случае держать приватными, коль скоро правильное использование кода будет препятствовать доступу к этим переменным/функциям.\n\nНапример:\n\n```js\nfunction doSomething(a) {\n\tb = a + doSomethingElse( a * 2 );\n\n\tconsole.log( b * 3 );\n}\n\nfunction doSomethingElse(a) {\n\treturn a - 1;\n}\n\nvar b;\n\ndoSomething( 2 ); // 15\n```\n\nВ этом коде, переменная `b` и функция `doSomethingElse(..)` — похоже \"частные\" детали того, как `doSomething(..)` выполняет свою работу. Предоставление  окружающей области видимости \"доступа\" к `b` и `doSomethingElse(..)` не только не необходимо, но также возможно и \"опасно\" тем, что их могут нечаянно использовать, намеренно или нет, и это может нарушить предварительные соглашения в `doSomething(..)`.\n\nБолее \"правильный\" дизайн скрыл бы эти частные детали внутри области видимости `doSomething(..)`, например как тут:\n\n```js\nfunction doSomething(a) {\n\tfunction doSomethingElse(a) {\n\t\treturn a - 1;\n\t}\n\n\tvar b;\n\n\tb = a + doSomethingElse( a * 2 );\n\n\tconsole.log( (b * 3) );\n}\n\ndoSomething( 2 ); // 15\n```\n\nТеперь, `b` и `doSomethingElse(..)` недоступны для любого внешнего воздействия, а взамен управляются только в `doSomething(..)`. Функциональность и конечный результат оказались не затронуты, а дизайн хранит частные детали частными, что обычно считается лучшим ПО.\n\n### Предотвращение коллизий\n\nЕще одно преимущество \"скрытия\" переменных и функций внутри области действия — чтобы избежать неумышленных коллизий между двумя идентификаторами с одним и тем же именем, но с разным целевым использованием. Коллизии часто приводят к неумышленной перезаписи значений.\n\nНапример:\n\n```js\nfunction foo() {\n\tfunction bar(a) {\n\t\ti = 3; // меняем `i` в окружающей области видимости цикла for-loop\n\t\tconsole.log( a + i );\n\t}\n\n\tfor (var i=0; i<10; i++) {\n\t\tbar( i * 2 ); // упс, впереди бесконечный цикл!\n\t}\n}\n\nfoo();\n```\n\nПрисваивание `i = 3` внутри `bar(..)` неожиданно перезаписывает `i`, которая была объявлена в `foo(..)` внутри цикла for-loop. В этом случае, это приведет к бесконечному циклу, так как `i` установлена в фиксированное значение `3` и она всегда будет оставаться `< 10`.\n\nПрисваиванию внутри `bar(..)` нужно объявить локальную переменную для своих нужд, независимо от того, какое имя идентификатора выбрано. `var i = 3;` исправило бы эту проблему (и создало бы ранее упоминавшееся объявление \"затененной переменной\" `i`). *Дополнительная*, не альтернативная возможность — выбрать совсем другое имя идентификатора, такое как `var j = 3;`. Но дизайн вашего ПО естественно может подразумевать использование одного и того же имени идентификатора, поэтому использование области видимости, чтобы \"скрыть\" ваше внутреннее объявление — это ваша лучшая/единственная возможность в этом случае.\n\n#### Глобальные \"Пространства имен\"\n\nОсобенно яркий пример (наверное) коллизии переменных возникает в глобальной области видимости. Многие библиотеки, загружаемые в вашу программу, могут без всякого труда вступить в коллизию друг с другом, если они не спрячут должным образом свои внутренние/приватные функции и переменные.\n\nТакие библиотеки, как правило, создают единственное объявление переменной, часто объекта, с достаточно уникальным именем в глобальной области видимости. Этот объект затем используется как \"пространство имен\" для этой библиотеки, где вся открываемая характерная функциональность делается как свойства этого объекта (пространства имен), вместо того, чтобы выставлять свои идентификаторы в области видимости на самом верхнем уровне.\n\nНапример:\n\n```js\nvar MyReallyCoolLibrary = {\n\tawesome: \"stuff\",\n\tdoSomething: function() {\n\t\t// ...\n\t},\n\tdoAnotherThing: function() {\n\t\t// ...\n\t}\n};\n```\n\n#### Управление модулями\n\nЕще одна возможность избежать коллизии — более современный \"модульный\" подход, используя любой из множества диспетчеров внедрения зависимостей. Используя эти инструменты, ни одна библиотека никогда не добавит ни одного идентификатора в глобальную область видимости, но взамен требуется явно импортировать их идентификатор в другую особую область видимости используя различные механизмы диспетчера внедрения зависимостей.\n\nСледует отметить, что эти инструменты не обладают \"волшебной\" функциональностью, которая свободна от правил лексической области видимости. Они просто используют правила области видимости, о которых уже рассказывалось здесь, чтобы управлять тем, что ни один идентификатор не будет пущен ни в одну общую область видимости, а взамен идентификаторы будут храниться в приватных, не подверженных коллизиям областях видимости, которые предотвратят любые случайные коллизии областей видимости.\n\nСобственно, вы можете кодировать осторожно и добиться таких же результатов как диспетчеры внедрения зависимостей без реальной необходимости их использования, если таков будет ваш выбор. Детальная информация о модульном шаблоне есть в главе 5.\n\n## Функции как области видимости\n\nМы уже видели, что можно взять любой кусок кода и обернуть его в функцию, и это эффективно \"скроет\" любые вложенные определения переменных или функций от внешней области видимости во внутренней области видимости этой функции.\n\nНапример:\n\n```js\nvar a = 2;\n\nfunction foo() { // <-- вставляем это\n\n\tvar a = 3;\n\tconsole.log( a ); // 3\n\n} // <-- и это\nfoo(); // <-- и это\n\nconsole.log( a ); // 2\n```\n\nНесмотря на то, что эта техника \"работает\", она не обязательно очень идеальна. Она привносит некоторые проблемы. Первая, это то, что мы должны объявить именованную функцию `foo()`, которая означает, что само имя идентификатора `foo` \"засоряет\" окружающую область видимости (в данном случае глобальную). Мы также должны явно вызвать функцию по имени (`foo()`) для того ,чтобы обернутый код выполнился на самом деле.\n\nБыло бы идеально, если бы функции не было нужно имя (или точнее, чтобы это имя не загрязняло окружающую область видимости) и если бы функция могла бы автоматически выполняться.\n\nК счастью, JavaScript предлагает решение обеих проблем.\n\n```js\nvar a = 2;\n\n(function foo(){ // <-- вставляем это\n\n\tvar a = 3;\n\tconsole.log( a ); // 3\n\n})(); // <-- и это\n\nconsole.log( a ); // 2\n```\n\nДавайте разберем в деталях что же тут происходит.\n\nСперва, заметьте, что оператор окружающей функции начинается с `(function...` в противоположность простому `function...`. Хоть это и может показаться несущественной деталью, это на самом деле огромное изменение. Вместо того, чтобы трактовать функцию как стандартное объявление, функция трактуется как функциональное выражение.\n\n**Примечание:** Самый легкий путь отличить объявление от выражения — позиция слова \"function\" в операторе (не только строка, но и отдельный оператор). Если \"function\" — самое первое, что стоит в операторе, то это объявление функции. Иначе, это функциональное выражение.\n\nКлючевое отличие между объявлением функции и функциональным выражением, которое мы можем заметить тут, связано с тем, где его имя связывается с идентификатором.\n\nСравните два предыдущих кода. В первом, имя `foo` связано с окружающей областью видимости и мы вызываем его напрямую через `foo()`. Во втором коде, имя `foo` не связано с окружающей областью видимости, а взамен связано только со своей собственной функцией.\n\nИными словами, `(function foo(){ .. })` как выражение означает, что идентификатор `foo` может быть найден *только* в области видимости, которая обозначена `..`, но не во внешней области видимости. Скрывание имени `foo` внутри себя означает, что оно не будет неоправданно загрязнять окружающую область видимости.\n\n### Анонимный против названного\n\nВозможно, вы лучше всего знакомы с функциональными выражениями как с параметрами функций обратного вызова, например:\n\n```js\nsetTimeout( function(){\n\tconsole.log(\"I waited 1 second!\");\n}, 1000 );\n```\n\nЭто называется \"анонимное функциональное выражение\", так как у `function()...` нет именованного идентификатора. Функциональные выражения могут быть анонимными, но объявления функций не могут опускать имя — это было бы невалидным синтаксисом JS.\n\nАнонимные функциональные выражения быстро и легко вводить и многие библиотеки и утилиты проявляют тенденцию к поощрению этого идиоматического стиля кода. Однако, у них есть несколько недостатков о которых нужно упомянуть:\n\n1. У анонимных функций нет удобного имени для отображения в стектрейсах (stacktrace), что может затруднить отладку.\n\n2. Если функции без имени будет нужно сослаться на себя же, для рекурсии или чего-то подобного, к сожалению требуется **устаревшая** ссылка `arguments.callee`. Еще один пример необходимости в ссылке на себя, когда функция обработчика события хочет отписать себя от события после выполнения.\n\n3. Анонимные функции опускают имя, что часто удобно для обеспечения большей читаемости/понятности кода. Наглядное же имя помогает самодокументировать рассматриваемый код.\n\n**Встраиваемые функциональные выражения** — мощные и полезные инструменты, выбор между анонимными и именованными не умаляет их достоинств. Именование вашего функционального выражения достаточно эффективно решает все перечисленные недостатки, и при этом не имеет ощутимых минусов. Лучшая практика — это всегда именовать ваши функциональные выражения:\n\n```js\nsetTimeout( function timeoutHandler(){ // <-- Смотри, у меня есть имя!\n\tconsole.log( \"I waited 1 second!\" );\n}, 1000 );\n```\n\n### Вызов функциональных выражений по месту\n\n```js\nvar a = 2;\n\n(function foo(){\n\n\tvar a = 3;\n\tconsole.log( a ); // 3\n\n})();\n\nconsole.log( a ); // 2\n```\n\nТеперь, когда у нас есть функция как выражение благодаря обертыванию ее в пару `( )`, мы можем вызвать эту функцию добавив еще одни `()` в конце, как тут `(function foo(){ .. })()`. Первая окружающая пара `( )` делает функцию выражением, а вторая `()` выполняет функцию.\n\nЭтот шаблон настолько в ходу, что несколько лет назад сообщество условилось о термине для него: **IIFE**, что означает **I**mmediately (немедленно) **I**nvoked (вызываемое) **F**unction (функциональное) **E**xpression (выражение).\n\nКонечно, IIFE не обязательно нужны имена, самая распространенная форма IIFE — использование анонимного функционального выражения. Несмотря на то, что определенно менее используемое, именование IIFE имеет все вышеперечисленные преимущества над анонимными функциональными выражениями, поэтому взять его на вооружение — хорошая практика.\n\n```js\nvar a = 2;\n\n(function IIFE(){\n\n\tvar a = 3;\n\tconsole.log( a ); // 3\n\n})();\n\nconsole.log( a ); // 2\n```\n\nЕсть легкая вариация формы традиционной IIFE, которую предпочитают некоторые: `(function(){ .. }())`. Посмотрим ближе, чтобы увидеть разницу. В первой форме функциональное выражение обернуто в `( )`, а затем пара вызывающих ее `()` снаружи прямо за ними. Во второй форме, вызывающая пара `()` переместилась внутрь внешней окружающей пары `( )`.\n\nЭти две формы идентичны по функциональности. **Какую из них предпочесть — всего лишь ваш стилистический выбор**.\n\nЕще одна вариация IIFE, которая широко распространена, это использование того факта, что они, на самом деле, просто вызовы функций, и передача им аргумента(ов).\n\nНапример:\n\n```js\nvar a = 2;\n\n(function IIFE( global ){\n\n\tvar a = 3;\n\tconsole.log( a ); // 3\n\tconsole.log( global.a ); // 2\n\n})( window );\n\nconsole.log( a ); // 2\n```\n\nМы передаем ссылку на объект `window`, но параметр мы назвали `global`, так что у нас есть ясное стилистическое разграничение для глобальных и неглобальных ссылок. Конечно, вы можете передать внутрь что-то из окружающей области видимости, если хотите, и можете назвать параметр(ы) так, как удобно вам. Это в основном всего лишь стилистический выбор.\n\nЕще одно применение этого шаблона решает (узкоспециализированную) проблему, что значение идентификатора по умолчанию `undefined` может быть некорректно перезаписано, приведя к неожиданным результатам. Давая параметру имя `undefined`, но не передавая никакого значения для этого аргумента, мы можем гарантировать, что идентификатор `undefined` фактически имеет незаданное значение в этом блоке кода:\n\n```js\nundefined = true; // устанавливаем мину для другого кода! остерегайтесь!\n\n(function IIFE( undefined ){\n\n\tvar a;\n\tif (a === undefined) {\n\t\tconsole.log( \"Undefined is safe here!\" );\n\t}\n\n})();\n```\n\nЕще одна вариация IIFE меняет порядок вещей на обратный, где вызываемая функция идет второй, *после* вызова и параметров, которые в нее передаются. Этот шаблон используется в проекте UMD (Universal Module Definition). Некоторые люди находят его более ясным для понимания, хотя он немного более многословный.\n\n```js\nvar a = 2;\n\n(function IIFE( def ){\n\tdef( window );\n})(function def( global ){\n\n\tvar a = 3;\n\tconsole.log( a ); // 3\n\tconsole.log( global.a ); // 2\n\n});\n```\n\nФункциональное выражение `def` определяется во второй половине кода, а затем передается как параметр (также названный `def`) в функцию `IIFE`, определенную в первой половине кода. Наконец, параметр `def` (функция) вызывается, передавая `window` в нее как параметр `global`.\n\n## Блоки как области видимости\n\nВ то время как функции являются самыми распространенными единицами области видимости и определенно самые распространенные подходы к разработке в большей части JS, есть и другие единицы области видимости, и использование этих единиц области видимости может привести к даже более лучшему, более чистому управлению кодом.\n\nМногие языки, отличные от JavaScript, поддерживают блочную область видимости и поэтому разработчики из этих языков привыкли к такому мышлению, в свою очередь те, кто изначально работали в JavaScript могут найти эту концепцию немного чуждой.\n\nНо даже если вы никогда не писали ни строчки кода в стиле блочной области видимости, вы возможно все-таки знакомы с этой чрезвычайно общей идиомой в JavaScript:\n\n```js\nfor (var i=0; i<10; i++) {\n\tconsole.log( i );\n}\n```\n\nМы объявляем переменную `i` прямо внутри заголовка цикла for-loop, скорее всего потому, что наше *намерение* — использовать `i` только в контексте этого цикла for-loop и в основном игнорировать факт того, что переменная на самом деле заключает себя в окружающую область видимости (функции или глобальную).\n\nВот это и есть самое важное в блочной области видимости. Объявление переменных как можно ближе и как можно локальней к тому месту, где они будут использоваться. Еще один пример:\n\n```js\nvar foo = true;\n\nif (foo) {\n\tvar bar = foo * 2;\n\tbar = something( bar );\n\tconsole.log( bar );\n}\n```\n\nМы используем переменную `bar` только в контексте оператора if, поэтому вполне разумно, что мы объявили ее внутри блока if. Однако, место, где мы объявляем переменные не имеет значения при использовании `var`, так как они всегда принадлежат окружающей области видимости. Этот код по существу \"поддельная\" блочная область видимости, только для целей стилистики, и полагается на самообязательство не использовать случайно `bar` в другом месте этой области видимости.\n\nБлочная область видимости — это инструмент для расширения ранее упоминаемого \"Принципа наименьш~~их~~ей ~~привилегий~~ открытости\" с сокрытия информации в функциях на сокрытие информации в блоках вашего кода.\n\nДавайте еще раз посмотрим пример с for-loop:\n\n```js\nfor (var i=0; i<10; i++) {\n\tconsole.log( i );\n}\n```\n\nЗачем загрязнять всю область видимости функции переменной `i`, которая будет использоваться (или только *следует*, по меньшей мере) в цикле for-loop?\n\nНо более важно, что разработчики могут предпочесть *проверить* себя на предмет случайного (пере)использования переменных снаружи от их предполагаемой области действия, как например получить ошибку о неизвестной переменной, если вы пытаетесь использовать ее не в том месте. Блочная область видимости (если бы она была возможна) для переменной `i` сделала бы `i` доступной только для цикла for-loop, приводя к ошибке, если к `i` осуществляется доступ в другом месте функции. Это помогает убедиться, что переменные не будут переиспользованы в нечетких или труднообслуживаемых сценариях.\n\nНо, печальная реальность состоит в том, что, на первый взгляд, в JavaScript нет возможности блочной области видимости.\n\nИли, если точнее, пока вы не копнете немного глубже.\n\n### `with`\n\nМы изучали `with` в главе 2. Несмотря на то, что к нему относятся с неодобрением с момента его появления, оно *является* примером (формой) блочной области видимости, поскольку область видимости, которая создается из объекта, существует только в течение жизненного цикла этого оператора `with`, а не окружающей области видимости.\n\n### `try/catch`\n\n*Очень* малоизвестным фактом является то, что JavaScript в ES3 специфицирует объявление переменной в блоке `catch` оператора `try/catch` как принадлежащее блочной области видимости блока `catch`.\n\nНапример:\n\n```js\ntry {\n\tundefined(); // нелегальная операция, чтобы вызвать исключение!\n}\ncatch (err) {\n\tconsole.log( err ); // работает!\n}\n\nconsole.log( err ); // ReferenceError: `err` not found\n```\n\nКак видите, `err` существует только в блоке `catch` и выбрасывает ошибку когда вы пытаетесь сослаться на нее где-либо в другом месте.\n\n**Примечание:** Несмотря на то, что такое поведение было определено и истинно практически во всех стандартных средах JS (за исключением разве что старого IE), многие линтеры (средства контроля качества кода) похоже до сих пор  жалуются, если у вас есть два или более блоков `catch` в одной и той же области видимости, каждый из которых объявляет свою переменную ошибки с одинаковым именем идентификатора. В действительности это не переопределение, поскольку переменные безопасно обернуты в блочные области видимости, но линтеры похоже до сих пор раздражающе жалуются на этот факт.\n\nЧтобы избежать таких ненужных предупреждений, некоторые разработчики именуют свои переменные в `catch` как `err1`, `err2` и т.д.. Другие разработчики просто выключают проверку линтера на повторяющиеся имена переменных.\n\nПрирода блочной области видимости `catch` может казаться бесполезным академическим фактом, но лучше загляните в приложение B, чтобы получить детальную информацию о том насколько полезна она может быть.\n\n### `let`\n\nДо сих пор мы видели, что в JavaScript есть только несколько странных нишевых возможностей, которые предлагают функциональность блочной области видимости. Если бы это было всё, что у нас есть, а так и *было* на протяжении многих, многих лет, то блочная область видимости не была бы столь полезна для разработчика на JavaScript.\n\nК счастью, ES6 поменял ситуацию и представляет новое ключевое слово `let`, которое соседствует с `var` как еще один путь объявления переменных.\n\nКлючевое слово `let` присоединяет объявление переменной к области видимости того блока (обычно пара `{ .. }`), в котором оно содержится. Иными словами, `let` неявно похищает у любой блочной области видимости ее объявления переменных.\n\n```js\nvar foo = true;\n\nif (foo) {\n\tlet bar = foo * 2;\n\tbar = something( bar );\n\tconsole.log( bar );\n}\n\nconsole.log( bar ); // ReferenceError\n```\n\nИспользование `let` для присоединения переменной к существующему блоку в некоторой степени неявно. Оно может ввести в заблуждение, если вы не оказываете пристальное внимание на то, в каких блоках есть переменные, принадлежащие к их области видимости, и на привычку перемещать блоки, оборачивать их в другие блоки, и т.п., по мере того, как вы разрабатываете и развиваете код.\n\nСоздание явных блоков для блочной области видимости может решить некоторые из этих вопросов, делая более очевидным то, куда присоединены переменные, а куда — нет. Обычно, явный код предпочтительней неявного или едва заметного. Такой явный стиль блочной области видимости легко получить и он более естественно походит на то, как в других языках работает блочная область видимости:\n\n```js\nvar foo = true;\n\nif (foo) {\n\t{ // <-- явный блок\n\t\tlet bar = foo * 2;\n\t\tbar = something( bar );\n\t\tconsole.log( bar );\n\t}\n}\n\nconsole.log( bar ); // ReferenceError\n```\n\nМожно создать обычный блок для использования `let` просто включая пару `{ .. }` в любом месте, где этот оператор является валидным синтаксисом. В этом случае, мы сделали явный блок *внутри*  оператора if, который потом будет легче перемещать как целый блок при рефакторинге, без изменения позиции и семантики окружающего оператора if.\n\n**Примечание:** Еще один путь объявить явные блочные области видимости есть в приложении B.\n\nВ главе 4 мы рассмотрим поднятие переменных (hoisting), которая расскажет об объявлениях, которые воспринимаются как существующие для всей области видимости, в которой они появляются.\n\nОднако, объявления, сделанные с помощью `let`, *не* поднимаются во всей области видимости блока, в котором они появляются. Такие объявления очевидно не будут \"существовать\" в блоке до оператора объявления.\n\n```js\n{\n   console.log( bar ); // ReferenceError!\n   let bar = 2;\n}\n```\n\n#### Сборка мусора\n\nЕще одна причина полезности блочной области видимости связана с замыканиями и сборкой мусора, чтобы освободить память. Мы кратко проиллюстрируем это здесь, но детально механизм замыканий будет рассматриваться в главе 5.\n\nПример:\n\n```js\nfunction process(data) {\n\t// делаем что-то интересное\n}\n\nvar someReallyBigData = { .. };\n\nprocess( someReallyBigData );\n\nvar btn = document.getElementById( \"my_button\" );\n\nbtn.addEventListener( \"click\", function click(evt){\n\tconsole.log(\"button clicked\");\n}, /*capturingPhase=*/false );\n```\n\nОбратный вызов обработчика щелчка `click` совсем не *требует* переменную `someReallyBigData`. Это значит, теоретически, что после выполнения `process(..)`, большая памятезатратная структура данных может быть собрана сборщиком мусора. Однако, весьма вероятно (хотя зависит от реализации), что движок JS все еще должен будет оставить структуру в памяти, поскольку у функции `click` есть замыкание, действующее во всей области видимости.\n\nБлочная область видимости может устранить этот недостаток, делая более явным для движка то, что ему не нужна `someReallyBigData`:\n\n```js\nfunction process(data) {\n\t// делаем что-то интересное\n}\n\n// всё, что объявлено внутри этого блока, может исчезнуть после него!\n{\n\tlet someReallyBigData = { .. };\n\n\tprocess( someReallyBigData );\n}\n\nvar btn = document.getElementById( \"my_button\" );\n\nbtn.addEventListener( \"click\", function click(evt){\n\tconsole.log(\"button clicked\");\n}, /*capturingPhase=*/false );\n```\n\nОбъявление явных блоков для переменных, чтобы локально привязать их к блокам   — мощный инструмент, который вы можете добавить в свой арсенал.\n\n#### `let` в циклах\n\nОсобый случай, в котором `let` показывает себя с лучшей стороны — в случае с циклом for, как мы уже обсуждали ранее.\n\n```js\nfor (let i=0; i<10; i++) {\n\tconsole.log( i );\n}\n\nconsole.log( i ); // ReferenceError\n```\n\n`let` в заголовке цикла for не только привязывает `i` к телу цикла, но фактически, он **перепривязывает ее** в каждой *итерации* цикла, обязательно  переприсваивая ей значение с окончания предыдущей итерации.\n\nВот еще один способ показать режим пред-итеративной привязки:\n\n```js\n{\n\tlet j;\n\tfor (j=0; j<10; j++) {\n\t\tlet i = j; // перепривязка в каждой итерации!\n\t\tconsole.log( i );\n\t}\n}\n```\n\nПричина, по которой эта пред-итеративная привязка интересна, станет ясна в главе 5, когда мы обсудим замыкания.\n\nТак как объявления `let` присоединяются к обычным блокам вместо присоединения к окружающей области видимости функции (или глобальной), могут быть ошибки в программе, когда у существующего кода есть скрытая надежда на объявления `var`, действующие в рамках области видимости функции, и замена `var` на `let` может потребовать дополнительного внимания при рефакторинге кода.\n\nПример:\n\n```js\nvar foo = true, baz = 10;\n\nif (foo) {\n\tvar bar = 3;\n\n\tif (baz > bar) {\n\t\tconsole.log( baz );\n\t}\n\n\t// ...\n}\n```\n\nЭтот код довольно легко отрефакторить в такой:\n\n```js\nvar foo = true, baz = 10;\n\nif (foo) {\n\tvar bar = 3;\n\n\t// ...\n}\n\nif (baz > bar) {\n\tconsole.log( baz );\n}\n```\n\nНо, остерегайтесь таких изменений, когда используете переменные блочной области видимости:\n\n```js\nvar foo = true, baz = 10;\n\nif (foo) {\n\tlet bar = 3;\n\n\tif (baz > bar) { // <-- не забудьте про `bar`, если будете перемещать этот блок!\n\t\tconsole.log( baz );\n\t}\n}\n```\n\nСм. приложение B, чтобы узнать об альтернативном (более явном) стиле организации блочной области видимости, который может дать более простое обслуживание/рефакторинг кода, что более разумно для этих сценариев.\n\n### `const`\n\nВ дополнение к `let`, ES6 представляет ключевое слово `const`, которое также создает переменную блочной области видимости, но чье значение фиксированно (константа). Любая попытка изменить это значение позже приведет к ошибке.\n\n```js\nvar foo = true;\n\nif (foo) {\n\tvar a = 2;\n\tconst b = 3; // в блочной области видимости содержащего ее `if`\n\n\ta = 3; // просто отлично!\n\tb = 4; // ошибка!\n}\n\nconsole.log( a ); // 3\nconsole.log( b ); // ReferenceError!\n```\n\n## Обзор\n\nФункции — самые распространенные единицы области видимости в JavaScript. Переменные и функции, которые объявляются внутри другой функции, по существу \"скрыты\" от любой из окружающих \"областей видимости\", что является намеренным принципом разработки хорошего ПО.\n\nНо функции — отнюдь не только единицы области видимости. Блочная область видимости ссылается на идею, что переменные и функции могут принадлежать произвольному блоку (обычно, любой паре `{ .. }`) кода, нежели только окружающей функции.\n\nНачиная с ES3, в структуре `try/catch` есть блочная область видимости в выражении `catch`.\n\nВ ES6 представлено ключевое слово `let` (родственница ключевого слова `var`), чтобы позволить объявления переменных в любом произвольном блоке кода. `if (..) { let a = 2; }` объявит переменную `a`, которая фактически похитит область видимости блока `{ .. }` в `if` и присоединит себя к ней.\n\nХоть некоторые похоже и верят в это, но блочную область видимости не следует использовать как полную замену функциональной области видимости `var`. Обе функциональности сосуществуют вместе, а разработчики могут и должны использовать обе техники области видимости: функциональную и блочную, в соответствующих местах, чтобы создавать лучший, более читаемый/обслуживаемый код.\n\n[Принцип наименьших привилегий](http://en.wikipedia.org/wiki/Principle_of_least_privilege)\n"
  },
  {
    "path": "scope & closures/ch4.md",
    "content": "# Вы не знаете JS: Область видимости и замыкания\n# Глава 4: Поднятие переменных (Hoisting)\n\nТеперь вы должно быть вполне уверенно разбираетесь в идее области видимости, и в том, как переменные присоединяются к различным уровням области видимости в зависимости от того, где и как они объявлены. Обе области видимости, как функции, так и блока работают по одинаковым правилам в таком виде: любая переменная, объявленная в области видимости, присоединяется к этой области видимости.\n\nНо есть маленький нюанс в том, как работает присоединение к области видимости с объявлениями, которые появляются в различных местах области видимости, и это именно тот нюанс, который мы тут и исследуем.\n\n## Курица или яйцо?\n\nЕсть искушение подумать, что весь код, который вы видите в программе на JavaScript, интерпретируется строка за строкой. Несмотря на то, что по сути это правда, есть одна часть этого предположения, которая может привести к  некорректному пониманию вашей программы.\n\nПредставьте такой код:\n\n```js\na = 2;\n\nvar a;\n\nconsole.log( a );\n```\n\nЧто вы ожидаете увидеть в выводе оператора `console.log(..)`?\n\nМногие разработчики ожидают увидеть `undefined`, поскольку оператор `var a` идет после `a = 2`, и было бы естественным предположить, что переменная переопределена и потому ей присвоено значение по умолчанию `undefined`. Однако, результат будет `2`.\n\nПредставьте еще один код:\n\n```js\nconsole.log( a );\n\nvar a = 2;\n```\n\nВы можете склониться к предположению, что поскольку в предыдущем показанном коде есть некоторое поведение в стиле \"немного с ног на голову\", то возможно в этом коде также будет выведено `2`. Другие могут подумать, что поскольку переменная `a` используется раньше, чем объявлена, то это приведет к выбросу `ReferenceError`.\n\nК сожалению, оба предположения неверны. Будет выведено `undefined`.\n\n**Так что же здесь происходит?** Похоже тут вопрос сродни \"что раньше: курица или яйцо?\". Что идет первым: объявление (\"яйцо\") или присваивание (\"курица\")?\n\n## Компилятор снова наносит удар\n\nЧтобы ответить на этот вопрос, нам нужно вернуться в главу 1 и нашу дискуссию о компиляторах. Вспомните, что *Движок* на самом деле скомпилирует ваш код JavaScript до того, как начнет интерпретировать его. Частью фазы компиляции является нахождение и ассоциация всех объявлений с их соответствующими областями видимости. Глава 2 показала нам, что это и есть сердце лексической области видимости.\n\nПоэтому, лучший путь думать об этих вещах — что все объявления как переменных, так и функций, обрабатываются в первую очередь, до того как будет выполнена любая часть вашего кода.\n\nКогда видите `var a = 2;`, вы наверное думаете о нем как об одном операторе. Но JavaScript на самом деле думает о нем как о двух операторах: `var a;` и `a = 2;`. Первый оператор, объявление, обрабатывается во время фазы компиляции. Второй оператор, присваивание, остается **на своем месте** в фазе исполнения.\n\nСледовательно о нашем первом коде следует думать как об обрабатываемом следующим образом:\n\n```js\nvar a;\n```\n```js\na = 2;\n\nconsole.log( a );\n```\n\n...где первая часть — компиляция, а вторая — выполнение.\n\nАналогично, наш второй код в действительности будет обработан так:\n\n```js\nvar a;\n```\n```js\nconsole.log( a );\n\na = 2;\n```\n\nПолучается, один из путей представить это, в какой-то степени образно, что эти объявления переменной и функции \"переехали\" с того места, где они появились в коде в начало кода. Это дало начало названию \"Поднятие (Hoisting)\".\n\nДругими словами, **яйцо (объявление) появилось до курицы (присваивания)**.\n\n**Примечание:** Поднимаются только сами объявления, тогда как любые присваивания или другая логика выполнения остается *на месте*. Если поднятие намеренно используется, чтобы перестроить логику выполнения вашего кода, то это может вызвать хаос.\n\n```js\nfoo();\n\nfunction foo() {\n\tconsole.log( a ); // undefined\n\n\tvar a = 2;\n}\n```\n\nОбъявление функции `foo` (которое в этом случае *включает в себя* соответствующее значение как актуальную функцию) поднимается, благодаря чему ее вызов в первой строке может быть выполнен.\n\nТакже важно отметить, что каждое поднятие соотносится **с областью видимости**. Поэтому несмотря на то, что наши предыдущие примеры кода были упрощенными в том, что были включены только в глобальную область видимости, функция `foo(..)`, которую мы сейчас изучаем, показывает, что `var a` поднимается наверх `foo(..)` (а не, очевидно, наверх всей программы). Так что программу можно было бы прочесть более точно как:\n\n```js\nfunction foo() {\n\tvar a;\n\n\tconsole.log( a ); // undefined\n\n\ta = 2;\n}\n\nfoo();\n```\n\nОбъявления функций поднимаются, как мы только что видели. А функциональные выражения — нет.\n\n```js\nfoo(); // не ReferenceError, но TypeError!\n\nvar foo = function bar() {\n\t// ...\n};\n```\n\nИдентификатор переменной `foo` поднимается и присоединяется к включающей его области видимости (глобальной) этой программы, поэтому `foo()` не вызовет ошибки `ReferenceError`. Но в `foo` пока еще нет значения (как если бы это было объявление обычной функции вместо выражения). Поэтому, `foo()` пытается вызвать значение `undefined`, которое является неправильной операцией с вызовом ошибки `TypeError`.\n\nТакже помните, что даже если это именованное функциональное выражение, идентификатор имени недоступен в окружающей области видимости:\n\n```js\nfoo(); // TypeError\nbar(); // ReferenceError\n\nvar foo = function bar() {\n\t// ...\n};\n```\n\nЭтот код более точно интерпретируется (с учетом поднятия) как:\n\n```js\nvar foo;\n\nfoo(); // TypeError\nbar(); // ReferenceError\n\nfoo = function() {\n\tvar bar = ...self...\n\t// ...\n}\n```\n\n## Сначала функции\n\nКак объявления функций, так и переменных поднимаются. Но тонкость (которая *поможет* объяснить множественные объявления \"дубликатов\" в коде) в том, что сперва поднимаются функции, а затем уже переменные.\n\nПредставим:\n\n```js\nfoo(); // 1\n\nvar foo;\n\nfunction foo() {\n\tconsole.log( 1 );\n}\n\nfoo = function() {\n\tconsole.log( 2 );\n};\n```\n\n`1` выводится вместо `2`! Этот код интерпретируется *Движком* так:\n\n```js\nfunction foo() {\n\tconsole.log( 1 );\n}\n\nfoo(); // 1\n\nfoo = function() {\n\tconsole.log( 2 );\n};\n```\n\nОбратите внимание, что `var foo` является дублем объявления (и поэтому игнорируется), даже несмотря на то, что идет до объявления `function foo()...`, потому что объявления функций поднимаются до обычных переменных.\n\nВ то время как множественные/дублирующие объявления `var` фактически игнорируются, последовательные объявления функции *перекрывают* предыдущие.\n\n```js\nfoo(); // 3\n\nfunction foo() {\n\tconsole.log( 1 );\n}\n\nvar foo = function() {\n\tconsole.log( 2 );\n};\n\nfunction foo() {\n\tconsole.log( 3 );\n}\n```\n\nНесмотря на то, что всё это может прозвучать как не более чем любопытный академический факт, это привлекает тем, что дубли определений в одной и той же области видимости — в самом деле плохая идея и часто приводит к странным результатам.\n\nОбъявления функций, которые появляются внутри обычных блоков, обычно поднимаются в окружающей области видимости, вместо того чтобы быть условными как показывает код ниже:\n\n```js\nfoo(); // \"b\"\n\nvar a = true;\nif (a) {\n   function foo() { console.log( \"a\" ); }\n}\nelse {\n   function foo() { console.log( \"b\" ); }\n}\n```\n\nОднако, важно отметить, что такое поведение небезопасно и может измениться в будущих версиях JavaScript, поэтому лучше избегать объявления функций в блоках.\n\n## Обзор\n\nУ нас есть соблазн смотреть на `var a = 2;` как на один оператор, но  *Движок* JavaScript видит это по-другому. Он видит `var a` и `a = 2` как два отдельных оператора, первый — как задачу фазы компиляции, а второй — как задачу фазы выполнения.\n\nЭто приводит к тому, что все объявления в области видимости, независимо от того где они появляются, обрабатываются *первыми*, до того, как сам код будет выполнен. Можно мысленно представить себе это как объявления (переменных и функций), \"переезжающие\" в начало их соответствующих областей видимости, что мы называем \"поднятие (hoisting)\".\n\nСами объявления поднимаются, а присваивания, даже присваивания функциональных выражений, *не* поднимаются.\n\nОстерегайтесь дублей объявлений, особенно смешанных обычных объявлений var и объявлений функций — вас будут поджидать неприятности!"
  },
  {
    "path": "scope & closures/ch5.md",
    "content": "# Вы не знаете JS: Область видимости и замыкания\n# Глава 5: Замыкание области видимости\n\nМы добрались до этого места, как я надеюсь, с очень здравым, цельным пониманием того, как работает область видимости.\n\nМы сосредоточимся на крайне важной, но постоянно ускользающей, *почти мифологичной* части языка: **замыканиях**. Если вы следили за нашей дискуссией о лексической области видимости до этого момента, ее развязка заключается в том, что замыкание будет чрезвычайно, разочаровывающе, практически самоочевидным. *За ширмой фокусника есть человек и мы вот-вот его увидим*. Нет, его зовут не Крокфорд (Crockford) (прим. переводчика: постоянный участник развития языка JavaScript, создатель текстового формата обмена данными JSON)!\n\nЕсли у вас всё еще есть изводящие вас вопросы о лексической области видимости, то тогда самое время вернуться и просмотреть еще раз главу 2 перед тем как продолжить читать далее.\n\n## Прозрение\n\nДля тех, кто уже мало-мальски получил опыт в JavaScript, но кто, пожалуй, никогда не ухватывал суть замыканий, *понимание замыкания* может выглядеть как особая нирвана и чтобы достичь ее он должен бороться и идти на жертвы.\n\nЯ помню, что несколько лет назад у меня были навыки владения JavaScript, но не было представления о том, что такое замыкания. Подсказка о том, что была *та самая другая сторона* языка, та, которая обещала даже больше возможностей чем те, которыми я обладал, дразнила и манила меня. Я помню как читал исходный код ранних фреймворков пытаясь понять как именно они работают. Я помню тот первый раз, когда что-то подобное \"шаблону модуля\" начало возникать в моих мыслях. Я очень живо помню эти \"*ага!*\".\n\nЧего я не знал в те времена и что потребовало от меня годы, чтобы понять, и что я надеюсь передать вам теперь — это вот этот секрет: **замыкание повсюду окружает вас в JavaScript, вы всего лишь должны распознать его и воспользоваться им.** Замыкания — это не особый инструмент, для которого вы должны изучить новый синтаксис и шаблоны. Нет, замыкания — это даже не оружие, которые вы должны изучить, чтобы уметь обращаться и подчинять его себе как Люк обучался Силе.\n\nЗамыкания получаются в результате написания кода, который исходит из лексической области видимости. Они просто возникают. Вам и в самом деле не нужно намеренно создавать замыкания, чтобы получить их преимущества. Замыкания создаются и используются вами на протяжении всего вашего кода.\n Что вы *упускаете*, так это то, что должен быть подходящий мысленный контекст, чтобы распознавать, пользоваться и получать выигрыш от замыканий по вашему собственному желанию.\n\nМомент просветления будет выглядеть примерно так: **О, замыкания уже встречаются везде в моем коде, теперь я их наконец-то *вижу*.** Понимание замыкания похоже на то, когда Нео впервые увидел Матрицу.\n\n## Суть дела\n\nХорошо, достаточно гипербол и бесстыдных ссылок на кино.\n\nВот откровенное определение того, что вам нужно знать, чтобы понимать и распознавать замыкания:\n\n> Замыкание — это когда функция умеет запоминать и имеет доступ к лексической области видимости даже тогда, когда эта функция выполняется вне своей лексической области видимости.\n\nДавайте рассмотрим небольшой код, чтобы проиллюстрировать это определение.\n\n```js\nfunction foo() {\n\tvar a = 2;\n\n\tfunction bar() {\n\t\tconsole.log( a ); // 2\n\t}\n\n\tbar();\n}\n\nfoo();\n```\n\nЭтот код выглядит знакомым, напоминая о наших обсуждениях вложенных областей видимости. У функции `bar()` есть *доступ* к переменной `a` во внешней окружающей области видимости на основании правил поиска лексической области видимости (в этом случае это поиск ссылок RHS).\n\nЭто \"замыкание\"?\n\nНу, технически... *возможно*. Но согласно нашему же определению \"что вам нужно знать о замыканиях\" выше... *не совсем так*. Думаю, что самым точным образом объяснить ссылку в `bar()` на `a` будет с помощью правил поиска в лексической области видимости и эти правила — *единственная* (важная!) **часть** того, что такое замыкание.\n\nС чисто академической точки зрения, про вышеуказанный код можно сказать, что у функции `bar()` есть *замыкание* на область `foo()` (и разумеется, даже на остальные области видимости, к которым у нее есть доступ, такие как глобальная область видимости в нашем случае). Немного другими словами, говорят, что `bar()` перекрывает область видимости `foo()`. Почему? Потому что `bar()` вложен внутри `foo()`. Ясно и просто.\n\nНо, замыкание, определенное подобным путем, не является ни совсем уж *характерным*, ни выглядящим *проверяемым* в этом коде. Мы ясно видим лексическую область видимости, но замыкание остается какой-то мистической двигающейся тенью за кодом.\n\nТогда давайте посмотрим на код, который представит замыкание во всей красе:\n\n```js\nfunction foo() {\n\tvar a = 2;\n\n\tfunction bar() {\n\t\tconsole.log( a );\n\t}\n\n\treturn bar;\n}\n\nvar baz = foo();\n\nbaz(); // 2 -- Ого, замыкание только что было раскрыто, мужики!\n```\n\nУ функции `bar()` есть доступ в лексической области видимости к внутренней области видимости `foo()`. Но в то же время, мы берем `bar()`, саму функцию, и передаем ее *как* значение. В этом случае мы `возвращаем` сам объект функции, на который ссылается `bar`.\n\nПосле выполнения `foo()` мы присвоим значение, которое она возвращает (нашу внутреннюю функцию `bar()`) в переменную `baz`, а затем мы фактически вызовем `baz()`, который конечно вызовет нашу внутреннюю функцию `bar()`, просто с помощью другой ссылки в идентификаторе.\n\nЕстественно `bar()` выполнится. Но в этом случае, она выполняется *снаружи* относительно своей объявленной лексической области видимости.\n\nПосле выполнения `foo()`, обычно мы ожидаем, что вся внутренняя область видимости `foo()` целиком будет удалена, поскольку мы знаем что *Движок* использует *сборщик мусора*, который исследует и освобождает память, которая больше не используется. Поскольку видно, что содержимое `foo()` больше не используется, кажется естественным, что оно должно быть *удалено* сборщиком.\n\nНо \"магия\" замыканий не даст этому произойти. Эта внутренняя область видимости на самом деле *все еще* \"используется\", а потому не будет удалена. Кто ее использует? **Сама функция `bar()`**.\n\nБлагодаря тому, где она была объявлена, у `bar()` есть замыкание лексической области видимости на внутренную область видимости `foo()`, которая удерживает область видимости для `bar()`, чтобы ссылаться на нее позднее.\n\n**`bar()` все еще содержит ссылку на эту область видимости и эта ссылка называется замыканием.**\n\nТаким образом, несколькими микросекундами позже, когда переменная `baz` вызывается (вызывая внутреннюю функцию, которую мы изначально пометили как `bar`), у нее как и полагается есть *доступ* к лексической области видимости, определенной на этапе разработки, поэтому у нее есть доступ к переменной `a` как мы и ожидали.\n\nФункция вызывается корректно вне ее лексической области видимости, определенной на этапе разработки. **Замыкание** дает функции возможность продлить доступ к лексической области видимости, которая была определена на этапе разработки.\n\nКонечно, любой из различных путей, которыми можно эти функции *передавать* как значения, а следовательно вызывать в других местах, является примером контролирующего замыкания.\n\n```js\nfunction foo() {\n\tvar a = 2;\n\n\tfunction baz() {\n\t\tconsole.log( a ); // 2\n\t}\n\n\tbar( baz );\n}\n\nfunction bar(fn) {\n\tfn(); // смотри мам, я видел замыкание!\n}\n```\n\nМы передаем внутреннюю функцию `baz` в `bar` и вызываем ее (теперь как `fn`), и когда мы это делаем, ее замыкание на внутреннюю область видимости `foo()` соблюдается посредством доступа к `a`.\n\nТакие передачи функций могут быть также и непрямыми.\n\n```js\nvar fn;\n\nfunction foo() {\n\tvar a = 2;\n\n\tfunction baz() {\n\t\tconsole.log( a );\n\t}\n\n\tfn = baz; // присваиваем `baz` глобальной переменной\n}\n\nfunction bar() {\n\tfn(); // смотри мам, я видел замыкание!\n}\n\nfoo();\n\nbar(); // 2\n```\n\nКакую бы возможность мы ни использовали, чтобы *передать* внутреннюю функцию вне ее лексической области видимости, эта возможность будет помогать удерживать ссылку на область видимости там, где она была объявлена изначально и когда бы мы ни выполняли ее это замыкание будет соблюдаться.\n\n## Теперь я вижу\n\nРанее приводимые части кода были немного академичны и искусственно сконструированы, чтобы проиллюстрировать *использование замыкания*. Но я обещал вам что-то большее, нежели просто новую крутую игрушку. Я обещал, что замыкание будет чем-то, что окружает вас повсюду в вашем коде. Давайте теперь  *взглянем* на эту правду.\n\n```js\nfunction wait(message) {\n\n\tsetTimeout( function timer(){\n\t\tconsole.log( message );\n\t}, 1000 );\n\n}\n\nwait( \"Привет, замыкание!\" );\n```\n\nМы берем внутреннюю функцию (с именем `timer`) и передаем ее в `setTimeout(..)`. Но у `timer` есть замыкание области видимости на область `wait(..)`, разумеется с хранением и использованием ссылки на переменную `message`.\n\nЧерез тысячу миллисекунд после того, как мы выполнили `wait(..)` и ее внутренняя область видимости, которой в ином случае следовало исчезнуть, у внутренней функции `timer` все еще есть замыкание на ту область видимости.\n\nГлубоко во внутренностях *Движка*, встроенная функция `setTimeout(..)` держит ссылку на некоторый параметр, возможно названный `fn` или `func`, или как-то похоже. *Движок* выполняет эту функцию, которая вызывает нашу внутреннюю функцию `timer`, а ссылка на лексическую область видимости все еще остается целой.\n\n**Замыкание.**\n\nИли если вы из лагеря jQuery (или любого другого похожего JS фреймворка):\n\n```js\nfunction setupBot(name,selector) {\n\t$( selector ).click( function activator(){\n\t\tconsole.log( \"Активирую: \" + name );\n\t} );\n}\n\nsetupBot( \"Closure Bot 1\", \"#bot_1\" );\nsetupBot( \"Closure Bot 2\", \"#bot_2\" );\n```\n\nЯ не знаю какой код пишете вы, но я регулярно пишу код, который ответственен за управление всей глобальной армией ботов замыканий, так что это абсолютно правдоподобно!\n\nЕсли серьезно, фактически *когда бы* и *где бы* вы ни обращались с функциями  (у которой есть доступ к их собственным лексическим областям видимости) как со значениями первого класса и ни передавали их повсюду, вы скорее всего увидите, что эти функции образуют замыкание. Будь это таймеры, обработчики событий, Ajax-запросы, кросс-оконные сообщения, вэб-воркеры или любые другие асинхронные (или синхронные!) задачи, когда вы передаете *колбэк-функцию*, приготовьтесь разбрасывать вокруг замыкания!\n\n**Примечание:** Глава 3 рассказывала о шаблоне IIFE. Несмотря на то, что часто говорят, что IIFE (отдельно) — пример явного замыкания, я немного не соглашусь, исходя из нашего определения, данного выше.\n\n```js\nvar a = 2;\n\n(function IIFE(){\n\tconsole.log( a );\n})();\n```\n\nЭтот код \"работает\", но не выглядит как точная демонстрация замыкания. Почему? Потому что функция (которую мы назвали тут \"IIFE\") — не выполняется вне своей лексической области видимости. Она все еще вызывается прямо в той же области видимости, в которой была объявлена (окружающая/глобальная область видимости, которая хранит `a`). `a` обнаруживается через обычный поиск в лексической области видимости, а не через замыкание.\n\nНесмотря на то, что замыкание может технически получаться во время объявления переменных, оно *не* обязательно наблюдаемо явно, а потому, как говорят, *это как звук падающего дерева в лесу, когда рядом никого нет.*\n\nХотя IIFE *сама по себе* не является примером замыкания, она несомненно создает область видимости, и это один из самых распространенных инструментов,   который мы используем для создания области видимости, которая может быть замкнута. Таким образом, IIFE, разумеется, тесно связана с замыканием, даже несмотря на то, что не производит самих замыканий.\n\nОтложи сейчас эту книгу, дорогой читатель. У меня есть для тебя задача. Открой какой-нибудь свой недавний JavaScript-код. Поищи функции как значения и определи где ты уже используешь замыкания, где ты возможно их раньше не замечал.\n\nЯ подожду.\n\nТеперь... ты видишь!\n\n## Циклы + замыкание\n\nСамый распространенный канонический пример, используемый для иллюстрации замыкания, приводят с использованием скромного цикла for.\n\n```js\nfor (var i=1; i<=5; i++) {\n\tsetTimeout( function timer(){\n\t\tconsole.log( i );\n\t}, i*1000 );\n}\n```\n\n**Примечание:** Линтеры частенько ругаются на то, что вы помещаете функции внутрь циклов, так как ошибки непонимания замыкания — **настолько типичны среди разработчиков**. Мы объясним, как в данном случае сделать правильно, раскрыв всю мощь замыкания. Но эта тонкость часто ускользает от линтеров и они ругаются в любом случае, предполагая что вы *на самом деле* не знаете, что делаете.\n\nСущность этого кусочка кода в том, что мы обычно *ожидаем* такого поведения, что в итоге будут распечатаны числа \"1\", \"2\", .. \"5\", по одному за раз, по одному в секунду соответственно.\n\nНа самом деле, если вы запустите этот код, вы получите вывод числа \"6\" 5 раз подряд, через односекундные интервалы.\n\n**Да?**\n\nВо-первых, позвольте объяснить откуда взялась цифра `6`. Условие окончания цикла — когда `i`  *не* `<=5`. Первый раз это происходит, когда `i` равно 6. Таким образом, вывод результата отражает конечное значение `i` после завершения цикла.\n\nНа самом деле это кажется очевидным при повторном взгляде. Все функции обратного вызова функции timeout запускаются прямо после завершения цикла. Фактически, пока тикают таймеры, даже если это был вызов `setTimeout(.., 0)` в каждой итерации цикла, все эти функции обратного вызова все равно будут запущены строго после выполнения цикла, и как следствие напечатают `6` каждый раз.\n\nНо здесь есть более глубокий вопрос на повестке дня. Чего *не хватает* в нашем коде чтобы в самом деле вести себя так как мы себе это семантически представляли?\n\nА не хватает того, что мы пытаемся *предполагать*, что каждая итерация цикла \"захватывает\" свою собственную копию `i` во время выполнения итерации. Но, тем путем, которым работает область видимости, все 5 этих функций, хотя они и определяются отдельно в каждой итерации цикла, все они **замыкаются на одну и ту же глобальную разделяемую область видимости**, в которой, фактически, только одна переменная `i`.\n\nВ таком свете, *конечно*, все функции разделяют ссылку на одну и ту же `i`. Кое-что в структуре циклов как правило смущает нас мыслями о том, что есть еще что-то сложное в их работе. Это не так. Нет никакой разницы по сравнению с тем, как если бы мы объявили каждый вызов timeout из 5 друг за другом вообще без всякого цикла.\n\nХорошо, итак вернемся обратно к нашему животрепещущему вопросу. Чего же не хватает? Нам нужна ~~больше колокольчиков на шее у коровы~~ более изолированная область видимости. Точнее говоря, нам нужна новая изолированная область видимости для каждой итерации цикла.\n\nМы изучили в главе 3, что IIFE создает область видимости объявляя и сразу выполняя функцию.\n\nДавайте попробуем:\n\n```js\nfor (var i=1; i<=5; i++) {\n\t(function(){\n\t\tsetTimeout( function timer(){\n\t\t\tconsole.log( i );\n\t\t}, i*1000 );\n\t})();\n}\n```\n\nЭто сработает? Попробуйте. Я снова жду.\n\nЯ не буду и дальше интриговать вас. **А вот и нет!** Но почему? Теперь у нас очевидно есть еще одна лексическая область видимости. Каждая функция обратного вызова для timeout, разумеется, замкнута на свою собственную область видимости на итерацию, создаваемую явно каждым вызовом IIFE.\n\nНедостаточно иметь изолированную область видимости **если эта область пуста**. Взгляните поближе. Наша IIFE — всего лишь пустая ничего не делающая область видимости. Нужно *что-то* внутри нее, чтобы она стала полезной для нас.\n\nЕй нужна ее собственная переменная, с копией значения `i` в каждой итерации.\n\n```js\nfor (var i=1; i<=5; i++) {\n\t(function(){\n\t\tvar j = i;\n\t\tsetTimeout( function timer(){\n\t\t\tconsole.log( j );\n\t\t}, j*1000 );\n\t})();\n}\n```\n\n**Эврика! Работает!**\n\nНебольшая вариация на тему, которую некоторые предпочтут вышеуказанной:\n\n```js\nfor (var i=1; i<=5; i++) {\n\t(function(j){\n\t\tsetTimeout( function timer(){\n\t\t\tconsole.log( j );\n\t\t}, j*1000 );\n\t})( i );\n}\n```\n\nКонечно, поскольку эти IIFE — всего лишь функции, мы можем передать в них `i` и мы можем назвать передаваемый параметр `j`, если хотим, или даже можем снова назвать его `i`. В любом случае код теперь работает.\n\nИспользование IIFE внутри каждой итерации создало новую область видимости для каждой итерации, что дало обратным вызовам функции при вызове timeout  возможность захватывать новую область видимости в каждой итерации, в каждой из которых есть переменная с правильным итерационным значением в ней.\n\nПроблема решена!\n\n### И вновь рассмотрим блочную область видимости\n\nВнимательно изучите наш анализ предыдущего решения. Мы использовали IIFE, чтобы создать новую область видимости на каждую итерацию. Иными словами, нам фактически *необходима* **блочная область видимости** для каждой итерации. Глава 3 открыла для нас объявление через `let`, которая \"похищает\" блок и объявляет переменную прямо в нем.\n\n**Фактически она превратила блок в область видимости, которую мы можем охватить.** Таким образом, следующий прекрасный код \"просто работает\":\n\n```js\nfor (var i=1; i<=5; i++) {\n\tlet j = i; // да-да, блочная область видимости для замыкания!\n\tsetTimeout( function timer(){\n\t\tconsole.log( j );\n\t}, j*1000 );\n}\n```\n\n*Но и это еще не всё!* (голосом Якубовича). Есть особое поведение для объявлений `let` в заголовке цикла for. Это поведение определяет, что переменная будет объявлена не один раз для всего цикла, **а для каждой итерации**. И, она, конечно же, будет инициализирована в каждой последующей итерации значением с окончания предыдущей итерации.\n\n```js\nfor (let i=1; i<=5; i++) {\n\tsetTimeout( function timer(){\n\t\tconsole.log( i );\n\t}, i*1000 );\n}\n```\n\nНасколько это круто? Блочная область видимости и замыкание работают рука об руку, решая все мировые проблемы. Не знаю насчет вас, но меня это делает счастливым JavaScript-ером.\n\n## Модули\n\nЕсть еще паттерны программирования, которые эффективно используют мощь замыканий, но которые внешне не особенно похожи на функции обратного вызова. Давайте рассмотрим самый мощный из них: *модуль*.\n\n```js\nfunction foo() {\n\tvar something = \"cool\";\n\tvar another = [1, 2, 3];\n\n\tfunction doSomething() {\n\t\tconsole.log( something );\n\t}\n\n\tfunction doAnother() {\n\t\tconsole.log( another.join( \" ! \" ) );\n\t}\n}\n```\n\nКак видно из этого кода, здесь нет никакого явного замыкания. У нас просто есть некоторые приватные переменные `something` и `another`, а также парочка внутренних функций `doSomething()` и `doAnother()`, у обеих из которых есть лексическая область видимости (а потому и замыкание!) над внутренней областью `foo()`.\n\nА теперь смотрите:\n\n```js\nfunction CoolModule() {\n\tvar something = \"cool\";\n\tvar another = [1, 2, 3];\n\n\tfunction doSomething() {\n\t\tconsole.log( something );\n\t}\n\n\tfunction doAnother() {\n\t\tconsole.log( another.join( \" ! \" ) );\n\t}\n\n\treturn {\n\t\tdoSomething: doSomething,\n\t\tdoAnother: doAnother\n\t};\n}\n\nvar foo = CoolModule();\n\nfoo.doSomething(); // cool\nfoo.doAnother(); // 1 ! 2 ! 3\n```\n\nЭтот шаблон в JavaScript мы называем *модуль*. Самый распространенный путь реализации шаблона модуля часто называют \"Действенный модуль\" и это тот вариант, который мы тут и представили.\n\nДавайте изучим некоторые факты об этом коде.\n\nВо-первых, `CoolModule()` — просто функция, но ее *надлежит вызвать* для создания объекта модуля. Без выполнения внешней функции не случится ни создание внутренней области видимости, ни создание замыканий.\n\nВо-вторых, функция `CoolModule()` возвращает объект, выполненный в синтаксисе объектного литерала `{ key: value, ... }`. У объекта, который мы возвращаем, есть ссылки на наши внутренние функции, но *не* на наши внутренние переменные. Мы храним их скрытыми и приватными. Правильнее всего будет думать о возвращаемом значении в виде объекта, как по существу о **публичном API для нашего модуля**.\n\nЭто объектное возвращаемое значение в итоге присваивается внешней переменной `foo`, а затем мы можем получить доступ к этим методам в API, например к `foo.doSomething()`.\n\n**Примечание:** Не обязательно возвращать настоящий объект из нашего модуля. Мы могли бы просто вернуть напрямую внутреннюю функцию. jQuery как раз является хорошим тому примером. Идентификаторы `jQuery` и `$` — это публичное API для \"модуля\" jQuery, но они сами по сути просто функции  (которые сами по себе могут иметь свойства, поскольку все функции являются объектами).\n\nУ функций `doSomething()` и `doAnother()` есть замыкание на внутреннюю область видимости \"экземпляра\" модуля (полученного на самом деле вызовом `CoolModule()`). Когда мы передаем эти функции вне лексической области видимости путем ссылок на свойства объекта, который мы возвращаем, то мы в этот момент фактически получаем условия, при которых замыкание может появиться и выполниться.\n\nИзлагая проще, есть два \"требования\", которые должны выполняться для шаблона модуля:\n\n1. Должна быть внешняя окружающая функция и она должна быть вызвана хотя бы раз (каждый раз создается новый экземпляр модуля).\n\n2. Окружающая функция должна возвращать хотя бы одну внутреннюю функцию, для того, чтобы у этой внутренней функции было замыкание на приватную область видимости и был доступ и/или возможность изменения ее внутреннего состояния.\n\nОбъект со свойством-функцией сам по себе *на самом деле* не модуль. Объект, возвращаемый вызовом функции, у которого есть только свойства-данные и ни одной замыкающей функции *фактически* не является модулем, с точки зрения здравого смысла.\n\nВышеприведенный код показывает автономный конструктор модуля с названием `CoolModule()`, который можно вызвать любое количество раз, каждый раз создавая новый экземпляр модуля. Небольшая вариация этого шаблона — это когда вы заботитесь о том, чтобы был только один экземпляр, что-то вроде  \"синглтона\":\n\n```js\nvar foo = (function CoolModule() {\n\tvar something = \"cool\";\n\tvar another = [1, 2, 3];\n\n\tfunction doSomething() {\n\t\tconsole.log( something );\n\t}\n\n\tfunction doAnother() {\n\t\tconsole.log( another.join( \" ! \" ) );\n\t}\n\n\treturn {\n\t\tdoSomething: doSomething,\n\t\tdoAnother: doAnother\n\t};\n})();\n\nfoo.doSomething(); // cool\nfoo.doAnother(); // 1 ! 2 ! 3\n```\n\nТут мы превратили нашу модульную функцию в IIFE (см. главу 3), *сразу же* вызвали ее и присвоили возвращаемое ею значение прямо нашему единственному идентификатору `foo`.\n\nМодули — это всего лишь функции, поэтому они могут принимать параметры:\n\n```js\nfunction CoolModule(id) {\n\tfunction identify() {\n\t\tconsole.log( id );\n\t}\n\n\treturn {\n\t\tidentify: identify\n\t};\n}\n\nvar foo1 = CoolModule( \"foo 1\" );\nvar foo2 = CoolModule( \"foo 2\" );\n\nfoo1.identify(); // \"foo 1\"\nfoo2.identify(); // \"foo 2\"\n```\n\nЕще одна небольшая, но полнофункциональная вариация модульного шаблона — дать имя объекту, который вы возвращаете как публичное API:\n\n```js\nvar foo = (function CoolModule(id) {\n\tfunction change() {\n\t\t// modifying the public API\n\t\tpublicAPI.identify = identify2;\n\t}\n\n\tfunction identify1() {\n\t\tconsole.log( id );\n\t}\n\n\tfunction identify2() {\n\t\tconsole.log( id.toUpperCase() );\n\t}\n\n\tvar publicAPI = {\n\t\tchange: change,\n\t\tidentify: identify1\n\t};\n\n\treturn publicAPI;\n})( \"foo module\" );\n\nfoo.identify(); // foo module\nfoo.change();\nfoo.identify(); // FOO MODULE\n```\n\nСохраняя внутреннюю ссылку на объект публичного API внутри экземпляра модуля вы можете менять эту ссылку на модуль **изнутри**, включая добавление и удаление методов, свойств *и* изменение их значений.\n\n### Современные модули\n\nРазличные загрузчики/менеджеры модульных зависимостей фактически упаковывают это определение модульного шаблона в дружественное API. Прежде чем начать изучать любую отдельную библиотеку, позвольте мне показать *очень простой* экспериментальный вариант **только в иллюстративных целях**:\n\n```js\nvar MyModules = (function Manager() {\n\tvar modules = {};\n\n\tfunction define(name, deps, impl) {\n\t\tfor (var i=0; i<deps.length; i++) {\n\t\t\tdeps[i] = modules[deps[i]];\n\t\t}\n\t\tmodules[name] = impl.apply( impl, deps );\n\t}\n\n\tfunction get(name) {\n\t\treturn modules[name];\n\t}\n\n\treturn {\n\t\tdefine: define,\n\t\tget: get\n\t};\n})();\n```\n\nКлючевая часть этого кода — `modules[name] = impl.apply(impl, deps)`. Это вызов функции-обертки определения для модуля (с передачей внутрь любых зависимостей) и сохранение возвращаемого значения, API модуля, во внутренний список модулей со ссылкой по имени.\n\nИ вот как именно я мог бы его использовать для определения нескольких модулей:\n\n```js\nMyModules.define( \"bar\", [], function(){\n\tfunction hello(who) {\n\t\treturn \"Let me introduce: \" + who;\n\t}\n\n\treturn {\n\t\thello: hello\n\t};\n} );\n\nMyModules.define( \"foo\", [\"bar\"], function(bar){\n\tvar hungry = \"hippo\";\n\n\tfunction awesome() {\n\t\tconsole.log( bar.hello( hungry ).toUpperCase() );\n\t}\n\n\treturn {\n\t\tawesome: awesome\n\t};\n} );\n\nvar bar = MyModules.get( \"bar\" );\nvar foo = MyModules.get( \"foo\" );\n\nconsole.log(\n\tbar.hello( \"hippo\" )\n); // Let me introduce: hippo\n\nfoo.awesome(); // LET ME INTRODUCE: HIPPO\n```\n\nОба модуля \"foo\" и \"bar\" объявлены с функцией, которая возвращает публичное API. \"foo\" даже получает экземпляр \"bar\" как параметр-зависимость и может его использовать соответствующим образом.\n\nПотратьте немного времени на изучение этих примеров кода, чтобы полностью осознать всю мощь замыканий и потом воспользоваться ими в собственных целях. Ключевой вывод тут в том, что нет никакого особого \"волшебства\" в модульных менеджерах. Они соответствуют обеим характеристикам шаблона модулей, которые я перечислил выше: вызов обертки определения функции и хранение возвращаемого значения в качестве API для этого модуля.\n\nИными словами, модули — это просто модули, даже если вы делаете ставку на хорошо знакомый вам инструмент для этого.\n\n### Будущие модули\n\nES6 добавляет синтаксическую поддержку первого класса для концепции модулей. При загрузке через модульную систему, ES6 обрабатывает файл как отдельный модуль. Каждый модуль может как импортировать другие модули или отдельные члены из API, так и экспортировать свои собственные публичные члены API.\n\n**Примечание:** Модули, основанные на функциях — не статически распознаваемый шаблон (о котором знает компилятор), поэтому их семантика API не учитывается до момента времени выполнения. То есть, вы фактически можете менять API модуля в процессе выполнения кода (см. ранее обсуждение `публичного API`).\n\nВ противоположность этому, модульное API ES6 — статическое (API не меняется во время выполнения). Поскольку компилятор *это* знает, он может (и делает!)  проверить во время (загрузки файла и) компиляции, что ссылка на член API импортируемого модуля *действительно существует*. Если ссылка на API не существует, компилятор выдаст \"заблаговременную\" ошибку на этапе компиляции, вместо того, чтобы  ждать традиционного динамического разрешения ссылок во время выполнения (и ошибок, если есть).\n\nУ модулей ES6 **нет** \"встраиваемого\" формата, они должны определяться в отдельных файлах (по одному на модуль). У браузеров/движков есть \"загрузчик модулей\" по умолчанию (который может быть переопределен, но это уже далеко за пределами нашего здесь обсуждения), который синхронно загружает файл модуля, когда он импортируется.\n\nРассмотрим код:\n\n**bar.js**\n```js\nfunction hello(who) {\n\treturn \"Let me introduce: \" + who;\n}\n\nexport hello;\n```\n\n**foo.js**\n```js\n// импортирует только `hello()` из модуля \"bar\"\nimport hello from \"bar\";\n\nvar hungry = \"hippo\";\n\nfunction awesome() {\n\tconsole.log(\n\t\thello( hungry ).toUpperCase()\n\t);\n}\n\nexport awesome;\n```\n\n```js\n// импортирует модули \"foo\" и \"bar\" целиком\nmodule foo from \"foo\";\nmodule bar from \"bar\";\n\nconsole.log(\n\tbar.hello( \"rhino\" )\n); // Let me introduce: rhino\n\nfoo.awesome(); // LET ME INTRODUCE: HIPPO\n```\n\n**Примечание:** Необходимо создать отдельные файлы **\"foo.js\"** и **\"bar.js\"**, с указанным выше содержимым. Затем ваша программа загрузит/импортирует эти модули, чтобы использовать их как показано в третьем фрагменте кода.\n\n`import` импортирует один или более членов API модуля в текущую область видимости, каждый в свою переменную (`hello` в нашем случае). `module` импортирует API модуля целиком в указанную переменную (`foo`, `bar` в нашем случае). `export` экспортирует идентификатор (переменную, функцию) в публичное API текущего модуля. Эти операторы можно использовать в определении модуля столько раз, сколько потребуется.\n\nСодержимое внутри *файла модуля* обрабатывается как если бы оно было заключено в замыкание области видимости, также как и у модулей с функцией-замыканием, рассмотренных ранее.\n\n## Итог\n\nПохоже, что знания о замыкании полны предрассудков и суеверий как загадочный мир, стоящий особняком внутри JavaScript, который могут познать только самые храбрые души. Но на самом деле — это всего лишь стандартный и почти очевидный факт о том, как писать код в среде лексической области видимости, где функции являются значениями и могут свободно передаваться куда угодно.\n\n**Замыкание — это когда функция может запомнить и иметь доступ к своей лексической области видимости даже тогда, когда она вызывается вне своей лексической области видимости.**\n\nЗамыкания могут сбить нас с толку, например в циклах, если мы не озаботимся тем, чтобы распознавать их и то как они работают. Но они еще и являются весьма мощным инструментом, дающим доступ к шаблонам, таким как *модули* в их различных формах.\n\nМодули требуют две ключевых характеристики: 1) внешнюю функцию-обертку, которую будут вызывать, чтобы создать закрытую область видимости 2) возвращаемое значение функции-обертки должно включать в себя ссылку на не менее чем одну внутреннюю функцию, у которой потом будет замыкание на внутреннюю область видимости обертки.\n\nТеперь вы сможете заметить замыкания повсюду в своем существующем коде и у нас теперь есть возможность обнаруживать и использовать все их преимущества!\n"
  },
  {
    "path": "scope & closures/toc.md",
    "content": "# Вы не знаете JS: Область видимости и замыкания\n\n## Содержание\n\n* Предисловие\n* Введение\n* Глава 1: Что такое область видимости?\n\t* Теория компиляторов\n\t* Понимание области видимости\n\t* Вложенная область видимости\n\t* Ошибки\n* Глава 2: Лексическая область видимости\n\t* Время разбора на лексемы\n\t* Обманываем лексическую область видимости\n* Глава 3: Область видимости: функции против блоков\n\t* Область видимости из функций\n\t* Прячемся на виду у всей области видимости\n\t* Функции как области видимости\n\t* Блоки как области видимости\n* Глава 4: Поднятие переменных (Hoisting)\n\t* Курица или яйцо?\n\t* Компилятор снова наносит удар\n\t* Сначала функции\n* Глава 5: Замыкание области видимости\n\t* Прозрение\n\t* Суть дела\n\t* Теперь я вижу\n\t* Циклы + замыкание\n\t* Модули\n* Приложение A: Динамическая область видимости\n* Приложение B: Полифиллинг блочной области видимости\n* Приложение C: Лексический this\n* Приложение D: Благодарности\n"
  },
  {
    "path": "this & object prototypes/README.md",
    "content": "# Вы не знаете JS: *this* и Прототипы Объектов\n\n<img src=\"cover.jpg\" width=\"300\">\n\n-----\n\n**[Купить цифровую или печатную книгу от издательства O'Reilly (англ.)](http://shop.oreilly.com/product/0636920033738.do)**\n\n-----\n\n[Оглавление](toc.md)\n\n* [Введение](foreword.md) (by [Nick Berardi](https://github.com/nberardi))\n* [Предисловие](../preface.md)\n* [Глава 1: *this* Or That?](ch1.md)\n* [Глава 2: *this* теперь приобретает смысл!](ch2.md)\n* [Глава 3: Объекты](ch3.md)\n* [Глава 4: Смешивая объекты \"классов\"](ch4.md)\n* [Глава 5: Прототипы](ch5.md)\n* [Глава 6: Делегирование поведения](ch6.md)\n* [Приложение A: ES6 *классы*](apA.md)\n* [Приложение B: Благодарности!](apB.md)\n"
  },
  {
    "path": "this & object prototypes/apA.md",
    "content": "# Вы не знаете JS: This и прототипы объектов\n# Приложение А: `class` в ES6\n\nЕсли что-то можно вынести из второй половины этой книги (Главы 4-6), так это то, что классы - необязательный паттерн проектирования кода (не является необходимым). Более того, зачастую, их неудобно реализовывать в «прототипном» языке вроде JS.\n\nЭто неудобство связано *не* только с синтаксисом, хоть он и играет значительную роль. В главах 4 и 5 мы рассмотрели некоторые синтаксические уродства: от многословных ссылок `.prototype`, загромождающих код, до *явного псевдо-полиморфизма* (см. главу 4), когда вы называете метод одним и тем же именем на разных уровнях цепочки и пытаетесь реализовать полиморфные отсылки из методов низкого уровня к методам высокого уровня. Еще одно синтаксическое уродство - `.constructor`, который ошибочно интерпретируется как «был сконструирован с помощью» и тем не менее ненадёжен из-за такого определения.\n\nНо проблема с дизайном классов намного глубже. Глава 4 указывает, что классы в традиционных класс-ориентированных языках на самом деле выполняют *копирование* от родительского к дочернему экземпляру, в то время как в `[[Prototype]]` выполняется не копирование, а скорее наоборот — связывающее делегирование.\n\nПо сравнению с простотой кода в OLOO-стиле и делегированием поведения (см. главу 6), которые принимает `[[Prototype]]`, а не прячет, классы торчат из JS как сломанный палец.\n\n## `class`\n\nНо нам *не нужно* повторять всё это. Я кратко упомянул эти проблемы только для того, чтобы вы держали их в голове, пока мы переключаем всё внимание на механизм `class` в ES6. Здесь мы покажем как они работают и посмотрим дает ли `class` что-то существенное для решения всех этих «классовых» проблем.\n\nДавайте вспомним пример `Widget` / `Button` из главы 6:\n\n```js\nclass Widget {\n\tconstructor(width,height) {\n\t\tthis.width = width || 50;\n\t\tthis.height = height || 50;\n\t\tthis.$elem = null;\n\t}\n\trender($where){\n\t\tif (this.$elem) {\n\t\t\tthis.$elem.css( {\n\t\t\t\twidth: this.width + \"px\",\n\t\t\t\theight: this.height + \"px\"\n\t\t\t} ).appendTo( $where );\n\t\t}\n\t}\n}\n\nclass Button extends Widget {\n\tconstructor(width,height,label) {\n\t\tsuper( width, height );\n\t\tthis.label = label || \"Default\";\n\t\tthis.$elem = $( \"<button>\" ).text( this.label );\n\t}\n\trender($where) {\n\t\tsuper.render( $where );\n\t\tthis.$elem.click( this.onClick.bind( this ) );\n\t}\n\tonClick(evt) {\n\t\tconsole.log( \"Button '\" + this.label + \"' clicked!\" );\n\t}\n}\n```\n\nКроме того, что синтаксис *выглядит* приятнее, какую проблему решает ES6?\n\n1. Больше нет (ну, типа того, см. ниже) отсылок к `.prototype`, загромождающих код.\n2. `Button` объявляется напрямую, чтобы «унаследовать» (`extends`) `Widget`, вместо использования `Object.create(..)` для замены привязанного `.prototype` или установки через `.__proto__` или `Object.setPrototypeOf(..)`.\n3. `super(..)` теперь дает нам полезную функцию — **относительный полиморфизм**, так что любой метод одного уровня цепочки может обратиться к методу с тем же именем на другой уровень выше по цепочке. Сюда входит решение к заметке из главы 4 о странностях конструкторов, не принадлежащих к их классу и не связанных друг с другом — `super()` работает внутри конструкторов именно так, как вы ожидаете.\n4. Литеральный синтаксис `class` не позволяет указать свойства (только методы). Для кого-то это покажется ограничением, но, скорее всего, большинство ситуаций, в которых свойство (состояние) существует где-либо, кроме конечных экземпляров, являются ошибочными и неожиданными (поскольку это состояние, которе явно «распространяется» по всем «экземплярам»).\nВ общем, *можно* сказать, что синтаксис `class` защищает вас от ошибок.\n5. `extends` позволяет вам расширить даже встроенные (под)типы объектов, вроде `Array` или `RegExp` очень естественным способом. Такие действия без `class .. extends` долгое время оставались избыточно сложной и удручающей задачей.\n\nСправедливости ради, это лишь некоторые из важных решений множества наиболее очевидных (синтаксических) проблем и сюрпризов, которые встречают люди с кодом в классическом прототипном стиле.\n\n## Глюки `class`\n\nНо не всё так радужно. До сих пор существуют некоторые глубокие и тревожащие проблемы с использованием «классов» в качестве паттерна проектирования на JS.\n\nВо-первых, синтаксис `class` может убедить вас, что в JS существует новый механизм «классов» ES6. **Нет**. `class` — это, в основном, синтаксический сахар поверх существующего механизма (делегирования!) `[[Prototype]]`.\n\nЭто означает, что `class` на самом деле не копирует содержимое статически во время объявления, как это происходит в традиционных класс-ориентированных языках. Если вы измените/замените метод (намеренно или случайно) родительского «класса», дочерний «класс» и/или экземпляр тоже будет затронут, поскольку они не копируются при объявлении, а всё еще используют модель делегирования, основанного на `[[Prototype]]`:\n\n```js\nclass C {\n\tconstructor() {\n\t\tthis.num = Math.random();\n\t}\n\trand() {\n\t\tconsole.log( \"Random: \" + this.num );\n\t}\n}\n\nvar c1 = new C();\nc1.rand(); // \"Random: 0.4324299...\"\n\nC.prototype.rand = function() {\n\tconsole.log( \"Random: \" + Math.round( this.num * 1000 ));\n};\n\nvar c2 = new C();\nc2.rand(); // \"Random: 867\"\n\nc1.rand(); // \"Random: 432\" -- Ой!!!\n```\n\nТакое поведение только кажется разумным *если вы уже знаете* о делегирующей природе вещей и не ожидаете *копий* из «настоящих классов». Поэтому задайте себе вопрос: почему вы выбираете синтаксис `class` для чего-то фундаментально отличающегося от классов?\n\nМожет быть синтаксис `class` в ES6 **просто мешает** увидеть и понять разницу между традиционными классами и делегированными объектами?\n\nСинтаксис `class` *не предоставляет* способа объявить свойства экземпляра класса (только методы). Поэтому если вам нужно это для отслеживания состояния между экземплярами, вы вернётесь обратно к некрасивому синтаксису `.prototype`, вроде такого:\n\n```js\nclass C {\n\tconstructor() {\n\t\t// убедитесь, что изменяете общее состояние,\n\t\t// а не добавляете затеняющее свойство\n\t\t// к экземплярам!\n\t\tC.prototype.count++;\n\n\t\t// Здесь, `this.count` работает как и ожидается\n\t\t// через делегирование\n\t\tconsole.log( \"Hello: \" + this.count );\n\t}\n}\n\n// добавим свойство для общего состояния напрямую\n// к объекту-прототипу\nC.prototype.count = 0;\n\nvar c1 = new C();\n// Hello: 1\n\nvar c2 = new C();\n// Hello: 2\n\nc1.count === 2; // true\nc1.count === c2.count; // true\n```\n\nСамая большая проблема здесь в том, что он предаёт синтаксис `class`, выставляя (утечка!) `.prototype` как часть реализации.\n\nНо у нас всё еще остался неожиданный глюк, когда `this.count++` неявно создает затеняющее свойство `.count` в обоих объектах `c1` и `c2`, вместо того, чтобы обновить общее состояние. `class` не предлагает нам решения этой проблемы, кроме, кажется, предположения, что вы не должны так делать *вообще*, в виду слабой поддержки синтаксиса.\n\nБолее того, случайное затенение всё еще представляет угрозу:\n\n```js\nclass C {\n\tconstructor(id) {\n\t\t// Ой, блин, мы затеняем метод `id()`\n\t\t// значением свойства в экземпляре\n\t\tthis.id = id;\n\t}\n\tid() {\n\t\tconsole.log( \"Id: \" + this.id );\n\t}\n}\n\nvar c1 = new C( \"c1\" );\nc1.id(); // TypeError -- `c1.id` стала строкой \"c1\"\n```\n\nСуществует еще один тонкий нюанс, связанный с работой `super`. Вы могли предположить, что `super` будет привязан по аналогии с привязкой `this` (см. главу 2), что `super` всегда будет привязан на уровень выше, вне зависимости от текущего положения метода в цепочке `[[Prototype]]`.\n\nТем не менее, в целях повышения производительности (привязка `this` и так дорого стоит), `super` не привязывается динамически. Его привязка вроде как «статичная», как и момент вызова. Не так уж страшно, верно?\n\nЭх... может быть, а может и нет. Если вы, как и большинство разработчиков на JS, начинаете назначать функции различным объектам (что следует из определения `class`) различными способами, вас, возможно, не очень обеспокоит, что под капотом механизм `super` вынужден каждый раз привязывать себя заново.\n\nИ в зависимости выбранного синтаксического подхода к присваиванию возможны случаи, когда `super` не может быть корректно привязан (по крайней мере не там, где вы ожидаете), поэтому вам может понадобиться (на момент написания обсуждение TC39 продолжается) привязать `super` вручную через `toMethod(..)` (наподобие того как вы делаете `bind(..)` для `this` -- см. главу 2).\n\nВы привыкли к возможности присваивать методы различным объектам чтобы *автоматически* получать выгоду от динамизма `this` через *скрытое привязывание* (см. главу 2). Но, похоже, всё это не сработает для методов, использующих `super`.\n\nРассмотрим что `super` должен делать здесь (напротив `D` и `E`):\n\n```js\nclass P {\n\tfoo() { console.log( \"P.foo\" ); }\n}\n\nclass C extends P {\n\tfoo() {\n\t\tsuper();\n\t}\n}\n\nvar c1 = new C();\nc1.foo(); // \"P.foo\"\n\nvar D = {\n\tfoo: function() { console.log( \"D.foo\" ); }\n};\n\nvar E = {\n\tfoo: C.prototype.foo\n};\n\n// Ссылка от E к D для делегирования\nObject.setPrototypeOf( E, D );\n\nE.foo(); // \"P.foo\"\n```\n\nЕсли вы думали (вполне обоснованно!), что `super` будет привязан динамически во время вызова, вы могли ожидать, что `super` автоматически распознает, что `E` делегирует к `D`, поэтому `E.foo()`, используя `super()`, должен вызвать `D.foo()`.\n\n**Нет.** В целях производительности, `super` не использует *отложенную привязку* (динамическую привязку) как это делает `this`. На самом деле он получен во время вызова из `[[HomeObject]].[[Prototype]]`, где `[[HomeObject]]` статично привязан в момент создания.\n\nВ данном конкретном примере `super()` всё еще разрешается в `P.foo()`, поскольку `[[HomeObject]]` этого метода всё еще `C`, а `C.[[Prototype]]` является `P`.\n\n*Возможно*, найдутся и пути решения таких проблем. Использование `toMethod(..)` чтобы привязать/перепривязать `[[HomeObject]]` для метода (вместе с заданием `[[Prototype]]` этого объекта!), кажется, сработает:\n\n```js\nvar D = {\n\tfoo: function() { console.log( \"D.foo\" ); }\n};\n\n// Привязать E к D для делегирования\nvar E = Object.create( D );\n\n// вручную связать `[[HomeObject]]` из `foo` в виде\n// `E`, а `E.[[Prototype]]` — это `D`, так что\n// `super()` — это `D.foo()`\nE.foo = C.prototype.foo.toMethod( E, \"foo\" );\n\nE.foo(); // \"D.foo\"\n```\n\n**Примечание:** `toMethod(..)` клонирует метод и принимает `homeObject` в качестве первого параметра (поэтому мы передаём `E`), а второй параметр (необязательный) задаёт `name` для нового метода (который хранится в «foo»).\n\nОсталось увидеть нет ли глюков в других крайних случаях, которые разрабы встретят за пределами описанного сценария. Как бы то ни было, вам нужно быть начеку и замечать места, где движок автоматически разбирается с `super` за вас, и места, где вам нужно самим об этом позаботиться. **Ох!**\n\n# Статический > Динамический?\n\nНо самая большая проблема `class` ES6 в том, что все эти глюки означают, что `class` как бы навязывает вам синтаксис, который, якобы, подразумевает (как традиционные классы), что однажды объявленный `class` является статическим определением чего-либо (наследуемого в будущем). Вы полностью теряете осознание факта, что `C` — это объект, конкретная вещь, с который вы можете взаимодействовать напрямую.\n\nВ традиционных класс-ориентированных языках вы никогда не измените определение класса в дальнейшем, поэтому классы как паттерн проектирования не предлагают таких возможностей. Но **одна из самых мощных особенностей** JS состоит в том, что он является *динамическим*, а определение любого объекта (пока вы не сделаете его иммутабельным) — это *вещь* подвижная и мутабельная.\n\n`class` вроде подразумевает, что вы не должны делать такие штуки, склоняя вас использовать уродливый синтаксис `.prototype` или заставляя вас думать о подвохах `super` и т.д. Он также предоставляет *очень слабую* поддержку на случай подводных камней, которые может принести такой динамизм.\n\nДругими словами, `class` как бы говорит вам: «Динамика — это сильно сложно, так что, возможно, это не лучшая идея. Вот вам синтаксис, который выглядит как статический, так что пишите свой код статически».\n\nКакой грустный комментарий к JS: **динамика слишком сложная, давайте притворимся (но на самом деле не будем) статикой**.\n\nЭто причины, по которым `class` в ES6 маскируется под красивое решение синтаксической головной боли, но, на самом деле, еще сильней мутит воду и ухудшает четкость и краткость понимания JS и его особенностей.\n\n**Примечание:** Если вы используете инструмент `.bind(..)`, чтобы создать жестко привязанную функцию (см. главу 2), эта функция не может быть наследована с помощью `extend` из ES6, в отличие от обычных функций.\n\n## Обзор (TL;DR)\n\n`class` очень хорошо притворяется, что решает проблемы с паттерном класс/наследование в JS. Но на самом деле делает обратное: **он скрывает многие проблемы, но приносит другие, незаметные, но опасные**.\n\n`class` способствует постоянной путанице с «классами» в JS, которая преследует язык около двух десятков лет. Во многом, он вызывает больше вопросов, чем ответов, и в целом чувствуется, что он противоестественно расположился над элегантной простотой механизма `[[Prototype]]`.\n\nИтоги: в ES6 `class` затрудняет надёжное использование `[[Prototype]]` и скрывает самую важную особенность механизма объектов в JS -- **живое делегирование связей между объектами** -- не лучше ли рассматривать `class` как создающий больше проблем, чем решающий, и просто отнести его к анти-паттерну?\n\nНа самом деле я не могу ответить за вас. Но я надеюсь, что эта книга для вас полностью раскрыла проблему на более глубоком уровне, чем когда-либо ранее, и дала вам необходимую информацию чтобы *вы сами смогли ответить*.\n"
  },
  {
    "path": "this & object prototypes/apB.md",
    "content": "# Вы не знаете JS: *this* и Прототипы Объектов\n# Приложение B: Благодарности\n\nЕсть множество людей, которых нужно поблагодарить за то, что появилась на свет эта книга и вся серия.\n\nВо-первых, я должен поблагодарить мою жену Кристен Симпсон (Christen Simpson) и двух моих детей Итана (Ethan) и Эмили (Emily), за то, что мирились с тем, что их папу вечно надо было отрывать от компьютера. Даже когда я не писал книги, моя одержимость JavaScript приклеивала мой взгляд к экрану больше, чем следовало. То время, которое я занял у моей семьи, и есть причина, по которой эти книги могут так глубоко и полностью объяснить JavaScript для вас, читатель. Я в большом долгу перед своей семьей.\n\nХочу поблагодарить моих редакторов в O'Reilly, а именно Simon St.Laurent и Brian MacDonald, как и остальных в команде редакторов и маркетинга. Работать с ними — одно удовольствие, и хочется особенно поблагодарить их за создание подходящих условий во время этого эксперимента с написанием \"open source\"-книги, за редактирование и выпуск.\n\nСпасибо всем тем, кто участвовал в улучшении этой серии книг присылая предложения по редактированию и корректировке, включая Shelley Powers, Tim Ferro, Evan Borden, Forrest L. Norvell, Jennifer Davis, Jesse Harlin и многих других. Большое спасибо Shane Hudson за написание предисловия к этой серии книг.\n\nСпасибо бесчисленным участникам сообщества, включая членов комитета TC39, кто поделился столько многим с нами и особенно за терпеливое отношение к моим бесконечным вопросам и изысканиям. John-David Dalton, Juriy \"kangax\" Zaytsev, Mathias Bynens, Axel Rauschmayer, Nicholas Zakas, Angus Croll, Reginald Braithwaite, Dave Herman, Brendan Eich, Allen Wirfs-Brock, Bradley Meck, Domenic Denicola, David Walsh, Tim Disney, Peter van der Zee, Andrea Giammarchi, Kit Cambridge, Eric Elliott и многие другие, я упомянул лишь малую часть.\n\nСерия книг *Вы не знаете JS* родилась на Kickstarter, поэтому я также хочу поблагодарить всех моих (почти) 500 щедрых инвесторов, без которых эта серия книг не появилась бы:\n\n> Jan Szpila, nokiko, Murali Krishnamoorthy, Ryan Joy, Craig Patchett, pdqtrader, Dale Fukami, ray hatfield, R0drigo Perez [Mx], Dan Petitt, Jack Franklin, Andrew Berry, Brian Grinstead, Rob Sutherland, Sergi Meseguer, Phillip Gourley, Mark Watson, Jeff Carouth, Alfredo Sumaran, Martin Sachse, Marcio Barrios, Dan, AimelyneM, Matt Sullivan, Delnatte Pierre-Antoine, Jake Smith, Eugen Tudorancea, Iris, David Trinh, simonstl, Ray Daly, Uros Gruber, Justin Myers, Shai Zonis, Mom & Dad, Devin Clark, Dennis Palmer, Brian Panahi Johnson, Josh Marshall, Marshall, Dennis Kerr, Matt Steele, Erik Slagter, Sacah, Justin Rainbow, Christian Nilsson, Delapouite, D.Pereira, Nicolas Hoizey, George V. Reilly, Dan Reeves, Bruno Laturner, Chad Jennings, Shane King, Jeremiah Lee Cohick, od3n, Stan Yamane, Marko Vucinic, Jim B, Stephen Collins, Ægir Þorsteinsson, Eric Pederson, Owain, Nathan Smith, Jeanetteurphy, Alexandre ELISÉ, Chris Peterson, Rik Watson, Luke Matthews, Justin Lowery, Morten Nielsen, Vernon Kesner, Chetan Shenoy, Paul Tregoing, Marc Grabanski, Dion Almaer, Andrew Sullivan, Keith Elsass, Tom Burke, Brian Ashenfelter, David Stuart, Karl Swedberg, Graeme, Brandon Hays, John Christopher, Gior, manoj reddy, Chad Smith, Jared Harbour, Minoru TODA, Chris Wigley, Daniel Mee, Mike, Handyface, Alex Jahraus, Carl Furrow, Rob Foulkrod, Max Shishkin, Leigh Penny Jr., Robert Ferguson, Mike van Hoenselaar, Hasse Schougaard, rajan venkataguru, Jeff Adams, Trae Robbins, Rolf Langenhuijzen, Jorge Antunes, Alex Koloskov, Hugh Greenish, Tim Jones, Jose Ochoa, Michael Brennan-White, Naga Harish Muvva, Barkóczi Dávid, Kitt Hodsden, Paul McGraw, Sascha Goldhofer, Andrew Metcalf, Markus Krogh, Michael Mathews, Matt Jared, Juanfran, Georgie Kirschner, Kenny Lee, Ted Zhang, Amit Pahwa, Inbal Sinai, Dan Raine, Schabse Laks, Michael Tervoort, Alexandre Abreu, Alan Joseph Williams, NicolasD, Cindy Wong, Reg Braithwaite, LocalPCGuy, Jon Friskics, Chris Merriman, John Pena, Jacob Katz, Sue Lockwood, Magnus Johansson, Jeremy Crapsey, Grzegorz Pawłowski, nico nuzzaci, Christine Wilks, Hans Bergren, charles montgomery, Ariel בר-לבב Fogel, Ivan Kolev, Daniel Campos, Hugh Wood, Christian Bradford, Frédéric Harper, Ionuţ Dan Popa, Jeff Trimble, Rupert Wood, Trey Carrico, Pancho Lopez, Joël kuijten, Tom A Marra, Jeff Jewiss, Jacob Rios, Paolo Di Stefano, Soledad Penades, Chris Gerber, Andrey Dolganov, Wil Moore III, Thomas Martineau, Kareem, Ben Thouret, Udi Nir, Morgan Laupies, jory carson-burson, Nathan L Smith, Eric Damon Walters, Derry Lozano-Hoyland, Geoffrey Wiseman, mkeehner, KatieK, Scott MacFarlane, Brian LaShomb, Adrien Mas, christopher ross, Ian Littman, Dan Atkinson, Elliot Jobe, Nick Dozier, Peter Wooley, John Hoover, dan, Martin A. Jackson, Héctor Fernando Hurtado, andy ennamorato, Paul Seltmann, Melissa Gore, Dave Pollard, Jack Smith, Philip Da Silva, Guy Israeli, @megalithic, Damian Crawford, Felix Gliesche, April Carter Grant, Heidi, jim tierney, Andrea Giammarchi, Nico Vignola, Don Jones, Chris Hartjes, Alex Howes, john gibbon, David J. Groom, BBox, Yu 'Dilys' Sun, Nate Steiner, Brandon Satrom, Brian Wyant, Wesley Hales, Ian Pouncey, Timothy Kevin Oxley, George Terezakis, sanjay raj, Jordan Harband, Marko McLion, Wolfgang Kaufmann, Pascal Peuckert, Dave Nugent, Markus Liebelt, Welling Guzman, Nick Cooley, Daniel Mesquita, Robert Syvarth, Chris Coyier, Rémy Bach, Adam Dougal, Alistair Duggin, David Loidolt, Ed Richer, Brian Chenault, GoldFire Studios, Carles Andrés, Carlos Cabo, Yuya Saito, roberto ricardo, Barnett Klane, Mike Moore, Kevin Marx, Justin Love, Joe Taylor, Paul Dijou, Michael Kohler, Rob Cassie, Mike Tierney, Cody Leroy Lindley, tofuji, Shimon Schwartz, Raymond, Luc De Brouwer, David Hayes, Rhys Brett-Bowen, Dmitry, Aziz Khoury, Dean, Scott Tolinski - Level Up, Clement Boirie, Djordje Lukic, Anton Kotenko, Rafael Corral, Philip Hurwitz, Jonathan Pidgeon, Jason Campbell, Joseph C., SwiftOne, Jan Hohner, Derick Bailey, getify, Daniel Cousineau, Chris Charlton, Eric Turner, David Turner, Joël Galeran, Dharma Vagabond, adam, Dirk van Bergen, dave ♥♫★ furf, Vedran Zakanj, Ryan McAllen, Natalie Patrice Tucker, Eric J. Bivona, Adam Spooner, Aaron Cavano, Kelly Packer, Eric J, Martin Drenovac, Emilis, Michael Pelikan, Scott F. Walter, Josh Freeman, Brandon Hudgeons, vijay chennupati, Bill Glennon, Robin R., Troy Forster, otaku_coder, Brad, Scott, Frederick Ostrander, Adam Brill, Seb Flippence, Michael Anderson, Jacob, Adam Randlett, Standard, Joshua Clanton, Sebastian Kouba, Chris Deck, SwordFire, Hannes Papenberg, Richard Woeber, hnzz, Rob Crowther, Jedidiah Broadbent, Sergey Chernyshev, Jay-Ar Jamon, Ben Combee, luciano bonachela, Mark Tomlinson, Kit Cambridge, Michael Melgares, Jacob Adams, Adrian Bruinhout, Bev Wieber, Scott Puleo, Thomas Herzog, April Leone, Daniel Mizieliński, Kees van Ginkel, Jon Abrams, Erwin Heiser, Avi Laviad, David newell, Jean-Francois Turcot, Niko Roberts, Erik Dana, Charles Neill, Aaron Holmes, Grzegorz Ziółkowski, Nathan Youngman, Timothy, Jacob Mather, Michael Allan, Mohit Seth, Ryan Ewing, Benjamin Van Treese, Marcelo Santos, Denis Wolf, Phil Keys, Chris Yung, Timo Tijhof, Martin Lekvall, Agendine, Greg Whitworth, Helen Humphrey, Dougal Campbell, Johannes Harth, Bruno Girin, Brian Hough, Darren Newton, Craig McPheat, Olivier Tille, Dennis Roethig, Mathias Bynens, Brendan Stromberger, sundeep, John Meyer, Ron Male, John F Croston III, gigante, Carl Bergenhem, B.J. May, Rebekah Tyler, Ted Foxberry, Jordan Reese, Terry Suitor, afeliz, Tom Kiefer, Darragh Duffy, Kevin Vanderbeken, Andy Pearson, Simon Mac Donald, Abid Din, Chris Joel, Tomas Theunissen, David Dick, Paul Grock, Brandon Wood, John Weis, dgrebb, Nick Jenkins, Chuck Lane, Johnny Megahan, marzsman, Tatu Tamminen, Geoffrey Knauth, Alexander Tarmolov, Jeremy Tymes, Chad Auld, Sean Parmelee, Rob Staenke, Dan Bender, Yannick derwa, Joshua Jones, Geert Plaisier, Tom LeZotte, Christen Simpson, Stefan Bruvik, Justin Falcone, Carlos Santana, Michael Weiss, Pablo Villoslada, Peter deHaan, Dimitris Iliopoulos, seyDoggy, Adam Jordens, Noah Kantrowitz, Amol M, Matthew Winnard, Dirk Ginader, Phinam Bui, David Rapson, Andrew Baxter, Florian Bougel, Michael George, Alban Escalier, Daniel Sellers, Sasha Rudan, John Green, Robert Kowalski, David I. Teixeira (@ditma, Charles Carpenter, Justin Yost, Sam S, Denis Ciccale, Kevin Sheurs, Yannick Croissant, Pau Fracés, Stephen McGowan, Shawn Searcy, Chris Ruppel, Kevin Lamping, Jessica Campbell, Christopher Schmitt, Sablons, Jonathan Reisdorf, Bunni Gek, Teddy Huff, Michael Mullany, Michael Fürstenberg, Carl Henderson, Rick Yoesting, Scott Nichols, Hernán Ciudad, Andrew Maier, Mike Stapp, Jesse Shawl, Sérgio Lopes, jsulak, Shawn Price, Joel Clermont, Chris Ridmann, Sean Timm, Jason Finch, Aiden Montgomery, Elijah Manor, Derek Gathright, Jesse Harlin, Dillon Curry, Courtney Myers, Diego Cadenas, Arne de Bree, João Paulo Dubas, James Taylor, Philipp Kraeutli, Mihai Păun, Sam Gharegozlou, joshjs, Matt Murchison, Eric Windham, Timo Behrmann, Andrew Hall, joshua price, Théophile Villard\n\nЭта серия книг выпускается в стиле \"open source\", включая редактирование и выпуск. Мы отдаем дань благодарности GitHub за предоставление такой возможности для сообщества!\n\nЕще раз спасибо всех бесчисленным людям, которых я не перечислил по имени, но кого я тем не менее должен поблагодарить. Пусть эта серия книг будет \"принадлежать\" всем нам и служить вкладом в увеличение информированности и понимании языка JavaScript, на благо все нынешних и будущих вкладчиков в общее дело сообщества.\n"
  },
  {
    "path": "this & object prototypes/ch1.md",
    "content": "# Вы не знаете JS: This и Прототипы Объектов\n# Глава 1: `this` (этот) или That (тот)?\n\nОдним из наиболее запутанных механизмов в Javascript является ключевое слово `this`. Это специальное ключевое слово идентификатор, которое автоматически определяется внутри области видимости каждой функции, но то, к чему именно оно относится, сбивает с толку даже опытных JavaScript-разработчиков.\n\n> Любая достаточно продвинутая технология неотличима от магии. -- Артур Си. Клэрк\n\nМеханизм `this` Javascript на самом деле не такой уж и продвинутый, но разработчики часто перефразируют эту цитату вставив \"сложный\" или \"сбивающий с толку\", и совершенно понятно, что без четкого понимания это может казаться совершенно магическим в вашем понимании.\n\n**Примечание:** Слово \"this\" — это достаточно распространенное местоимение в общих беседах. Поэтому, может быть очень сложно, особенно на словах, определить используем мы \"this\" как местоимение или же используем его, чтобы ссылаться на данное ключевое слово. Для ясности, я всегда буду использовать `this` для ссылки на специальное ключевое слово, а \"this\" или *this* или this в остальных случаях.\n\n## Зачем нужен `this`?\n\nРаз механизм `this` такой запутанный даже для опытных JavaScript-разработчиков, можно задаться вопросом, а точно ли он полезный? Может у него больше недостатков, чем достоинств?\nПеред тем, как перейти к тому *как он работает*, мы должны проанализировать *зачем он нужен*.\n\nДавайте попытаемся проиллюстрировать мотивацию и полезность механизма `this`:\n\n```js\nfunction identify() {\n\treturn this.name.toUpperCase();\n}\n\nfunction speak() {\n\tvar greeting = \"Hello, I'm \" + identify.call( this );\n\tconsole.log( greeting );\n}\n\nvar me = {\n\tname: \"Kyle\"\n};\n\nvar you = {\n\tname: \"Reader\"\n};\n\nidentify.call( me ); // KYLE\nidentify.call( you ); // READER\n\nspeak.call( me ); // Hello, I'm KYLE\nspeak.call( you ); // Hello, I'm READER\n```\n\nЕсли то, *как работает* этот фрагмент кода путает вас, не волнуйтесь! Мы скоро вернемся к этому. Просто отложите ваши вопросы в сторону, чтобы мы могли более четко взглянуть на то, *зачем* это нужно.\n\nЭтот фрагмент кода позволяет функциям `identify()` и `speak()` быть переиспользованными с разными объектами *контекста* (`me` и `you`), а не требовать новой версии функции для каждого объекта.\n\nВместо того, чтобы полагаться на `this`, вы могли бы явно передать *объект контекста* функциям `identify()` и `speak()`.\n\n```js\nfunction identify(context) {\n\treturn context.name.toUpperCase();\n}\n\nfunction speak(context) {\n\tvar greeting = \"Hello, I'm \" + identify( context );\n\tconsole.log( greeting );\n}\n\nidentify( you ); // READER\nspeak( me ); // Hello, I'm KYLE\n```\n\nОднако, механизм `this` предоставляет более элегантный путь, неявно \"передавая\" ссылку на объект, что приводит к чистому дизайну API и облегчению повторного переиспользования.\n\nЧем сложнее будет используемый вами паттерн, тем более ясно вы увидите, что указание контекста явным параметром часто запутаннее, чем неявное указание контекста `this`. Когда мы изучим объекты и прототипы, вы увидите полезность коллекции функций, которые способны автоматически ссылаться на правильный объект контекста.\n\n## Заблуждения\n\nМы скоро объясним как `this` *на самом деле* работает, но сначала мы должны рассеять несколько заблуждений о том, как он *на самом деле не* работает. \n\nИмя \"this\" создает заблуждение, когда разработчики пытаются думать о нем слишком буквально. Есть два часто предполагаемых значения, но оба являются неверными.\n\n### Сама функция\n\nПервый общий соблазн это предполагать, что `this` ссылается на саму функцию. Это, как минимум, резонное грамматическое заключение.\n\nНо зачем вы бы хотели ссылаться на функцию из неё же? Наиболее распространенной причиной может быть такая вещь как рекурсия (вызов функции внутри себя) или чтобы назначить обработчик события, который сможет отписаться, когда впервые будет вызван.\n\nРазработчики, незнакомые с механизмами JavaScript, часто думают, что ссылка на функцию как на объект (все функции в JavaScript являются объектами!) позволяет хранить состояния (значения в свойствах) между вызовами функций. Хотя это, конечно, возможно, но это имеет некоторые ограничения в использовании, остаток книги будет повествовать о многих других шаблонах для *лучшего* хранения состояния, чем объект функции.\n\nНо для начала мы используем этот шаблон, чтобы проиллюстрировать как `this` не дает функции получить ссылку на саму себя, как мы могли бы предположить.\n\nРассмотрим следующий код, где мы попытаемся отследить сколько раз функция (`foo`) была вызвана:\n\n```js\nfunction foo(num) {\n\tconsole.log( \"foo: \" + num );\n\n\t// Отслеживаем сколько раз `foo` была вызвана\n\tthis.count++;\n}\n\nfoo.count = 0;\n\nvar i;\n\nfor (i=0; i<10; i++) {\n\tif (i > 5) {\n\t\tfoo( i );\n\t}\n}\n// foo: 6\n// foo: 7\n// foo: 8\n// foo: 9\n\n// Сколько раз была вызвана `foo`?\nconsole.log( foo.count ); // 0 -- WTF?\n```\n\n`foo.count` *до сих пор* равен `0`, даже не смотря на то, что 4 инструкции `console.log` очевидно показывают, что `foo(..)` на самом деле была вызвана 4 раза. Разочарование происходит от *слишком буквального* толкования того, что означает `this` (в `this.count++`).\n\nКогда код выполняет команду `foo.count = 0`, он на самом деле добавляет свойство `count` в объект функции `foo`. Но для ссылки `this.count` внутри функции `this` фактически не указывает на тот же объект функции, и несмотря на то, что имена свойств одинаковые, это разные объекты, вот тут то и начинается неразбериха.\n\n**Примечание:** ответственный разработчик в этом месте должен спросить: \"Если я увеличил свойство `count`, но оно не то, которое я ожидал, то какое `count` было мной увеличено?\". На самом деле, если он копнет глубже, он обнаружит что случайно создал глобальную переменную `count`(смотрите в главе 2 *как* это произошло!), а её текущим значением является `NaN`. Конечно, после того, как он определит это, у него появится совсем другой ряд вопросов: \"почему она стала глобальной и почему она имеет значение `NaN`, вместо правильного значения счетчика?\". (см. главу 2).\n\nВместо того, чтобы остановиться на этом месте и копнуть глубже, чтобы узнать почему ссылка `this` не ведет себя как *ожидалось*, большинство разработчиков просто откладывают проблему целиком и ищут другие решения, например, создают другой объект для хранения свойства `count`:\n\n```js\nfunction foo(num) {\n\tconsole.log( \"foo: \" + num );\n\n\t// отслеживаем сколько раз вызывалась `foo`\n\tdata.count++;\n}\n\nvar data = {\n\tcount: 0\n};\n\nvar i;\n\nfor (i=0; i<10; i++) {\n\tif (i > 5) {\n\t\tfoo( i );\n\t}\n}\n// foo: 6\n// foo: 7\n// foo: 8\n// foo: 9\n\n// сколько раз вызывалась `foo`?\nconsole.log( data.count ); // 4\n```\n\nХоть это и верно, что этот подход \"решает\" проблему, к сожалению, это просто игнорирование реальной проблемы — недостатка понимания того, что значит `this` и как он работает и вместо этого возвращение в зону комфорта более простого механизма: области видимости.\n\n**Примечание:** Области видимости - замечательный и полезный механизм. Я не против использования их любым способом(см. книгу *\"Области видимости и замыкания\"* из этой серии книг). Но постоянно гадать, как использовать `this`, и, как правило, ошибаться — не лучшая причина возвращаться к областям видимости и никогда не узнать *почему* `this` ускользает от вас.\n\nДля ссылки на объект функции изнутри этой функции, `this` самого по себе обычно бывает недостаточно. Вам обычно нужна ссылка на объект функции через лексический идентификатор (переменную), который указывает на него.\n\nРассмотрим эти 2 функции:\n\n```js\nfunction foo() {\n\tfoo.count = 4; // `foo` ссылается на саму себя\n}\n\nsetTimeout( function(){\n\t// анонимная функция (без имени), не может\n\t// ссылаться на себя\n}, 10 );\n```\n\nВ первой функции вызывалась \"именованная функция\", `foo` — это ссылка, которая может быть использована для ссылки на функцию из самой себя.\n\nНо во втором примере функция обратного вызова, передаваемая в `setTimeout(..)`, не имела имени идентификатора (так называемая \"анонимная функция\"), так что у неё нет правильного пути чтобы обратиться к её объекту.\n\n**Примечание:** Старомодная, но ныне устаревшая и неиспользуемая ссылка `arguments.callee` внутри функции *также* указывает на объект функции, которая в данный момент выполняется. Эта ссылка обычно используется как возможность получить объект анонимной функции изнутри этой функции. Лучший подход, однако, состоит в том, чтобы избежать использования анонимных функций, по крайней мере тех, которые требуют обращения к себе изнутри, и вместо них использовать именованные функции. `arguments.callee` устарела и не должна использоваться.\n\nТаким образом, другое решение нашего примера — это использовать идентификатор `foo` как ссылку на объект функции в каждом месте и вообще не использовать `this`, и это *работает*:\n\n```js\nfunction foo(num) {\n\tconsole.log( \"foo: \" + num );\n\n\t// следим, сколько раз вызывается функция\n\tfoo.count++;\n}\n\nfoo.count = 0;\n\nvar i;\n\nfor (i=0; i<10; i++) {\n\tif (i > 5) {\n\t\tfoo( i );\n\t}\n}\n// foo: 6\n// foo: 7\n// foo: 8\n// foo: 9\n\n// сколько раз `foo` была вызвана?\nconsole.log( foo.count ); // 4\n```\n\nОднако, этот подход также является уклонением от фактического понимания `this`, и полностью зависит от области видимости переменной `foo`.\n\nЕще один путь решения проблемы - это заставить `this` действительно указывать на объект функции `foo`:\n\n```js\nfunction foo(num) {\n\tconsole.log( \"foo: \" + num );\n\n\t// следим, сколько раз вызывается функция\n\t// Заметьте: `this` теперь действительно ссылается на `foo`, это основано на том,\n\t// как `foo` вызывается (см. ниже)\n\tthis.count++;\n}\n\nfoo.count = 0;\n\nvar i;\n\nfor (i=0; i<10; i++) {\n\tif (i > 5) {\n\t\t// используя `call(..)` мы гарантируем что `this`\n\t\t// ссылается на объект функции (`foo`) изнутри\n\t\tfoo.call( foo, i );\n\t}\n}\n// foo: 6\n// foo: 7\n// foo: 8\n// foo: 9\n\n// сколько раз `foo` была вызвана?\nconsole.log( foo.count ); // 4\n```\n\n**Вместо избегания `this`, мы воспользовались им.** Мы отведем немного времени на то, чтобы объяснить более детально как такие методы работают, так что не волнуйтесь если вы до сих пор недоумеваете как это работает!\n\n### Это область видимости функции\n\nСледующее большое общее заблуждение касательно того, на что указывает `this` - это то, что он каким-то образом ссылается на область видимости функции. Это очень сложный вопрос, потому что с одной стороны так и есть, но с другой это совершенно не так.\n\nДля ясности, `this`, в любом случае, не ссылается на область видимости функции. Это правда, что внутри область видимости имеет вид объекта со свойствами для каждого определенного значения. Но \"объект\" области видимости не доступен в JavaScript коде. Это внутренняя часть механизма реализации языка (интерпретатора). \n\nРассмотрим код, который пытается (и безуспешно!) перейти границу и использовать `this` неявно ссылаясь на область видимости функции:\n\n```js\nfunction foo() {\n\tvar a = 2;\n\tthis.bar();\n}\n\nfunction bar() {\n\tconsole.log( this.a );\n}\n\nfoo(); //undefined\n```\nВ этом коде содержится более одной ошибки. Хотя он может казаться надуманным, код который вы видите — это фрагмент из реального практического кода, которым обменивались в публичных форумах сообщества. Это замечательная (если не печальная) иллюстрация того, насколько ошибочным может быть предположение о `this`.\n\nВо-первых, попытка ссылаться на функцию `bar()` как `this.bar()`. Это почти наверняка *случайность*, что это работает, но мы коротко объясним *как* это работает позже. Наиболее естественным путем вызвать `bar()` было бы опустить предшествующий `this.` и просто сделать ссылку на идентификатор.\n\nОднако, разработчик, который писал этот код, пытался использовать `this`, чтобы создать мост между областями видимости `foo()` и `bar()` так, чтобы `bar()` получила доступ к переменной `a` внутри области видимости `foo()`. **Не всякий мост возможен.** Вы не можете использовать ссылку `this`, чтобы найти что-нибудь в области видимости. Это невозможно.\n\nКаждый раз, когда вы чувствуете, что вы смешиваете поиски в области видимости с `this`, напоминайте себе: *это не мост*.\n\n## Что же такое `this`?\n\nОставив ошибочные предположения, давайте обратим наше внимание на то, как механизм `this` действительно работает.\n\nМы ранее сказали, что `this` привязывается не во время написания функции, а во время её вызова. Это вытекает из контекста, который основывается на обстоятельствах вызова функции. Привязка `this` не имеет ничего общего с определением функции, но зависит от того при каких условиях функция была вызвана.\n\nКогда функция вызывается, создается запись активации, также известная как контекст вызова. Эта запись содержит информацию о том, откуда функция была вызвана (стэк вызова), *как* функция была вызвана, какие параметры были в неё переданы и т.д. Одним из свойств этой записи является ссылка `this`, которая будет использоваться на протяжении выполнения этой функции.\n\nВ следующей главе мы научимся находить **место вызова** функции, чтобы определить как оно связано с определением `this`\n\n## Обзор (TL;DR)\n\nОпределение `this` - постоянный источник заблуждений для JavaScript разработчиков, которые не уделяют времени на изучение того, как этот механизм в действительности работает. Гадать, методом проб и ошибок, и слепо копировать код из StackOverflow - неэффективный и неправильный путь использовать этот важный механизм `this`.\n\nЧтобы понять что такое `this`, вам сначала нужно понять чем `this` не является, несмотря на любые предположения или заблуждения, которые могут тянуть вас вниз. `this` — это не ссылка функции на саму себя и это не ссылка на область видимости функции. \n\nВ действительности `this` — это привязка, которая создается во время вызова функции, и на *что* она ссылается определяется тем, где и при каких условиях функция была вызвана.\n"
  },
  {
    "path": "this & object prototypes/ch2.md",
    "content": "# Вы не знаете JS: *this* и прототипы объектов\n# Глава 2: Весь `this` теперь приобретает смысл!\n\nВ главе 1 мы отбросили различные ложные представления о `this` и взамен изучили, что привязка `this` происходит при каждом вызове функции, целиком на основании ее **места вызова** (как была вызвана функция).\n\n## Точка вызова\n\nЧтобы понять привязку `this`, мы должны понять что такое точка вызова: это место в коде, где была вызвана функция (**не там, где она объявлена**). Мы должны исследовать точку вызова, чтобы ответить на вопрос: на что же *этот* `this` указывает?\n\nВ общем поиск точки вызова выглядит так: \"найти откуда вызывается функция\", но это не всегда так уж легко, поскольку определенные шаблоны кодирования могут ввести в заблуждение относительно *истинной* точки вызова.\n\nВажно поразмышлять над **стеком вызовов** (стеком функций, которые были вызваны, чтобы привести нас к текущей точке исполнения кода). Точка вызова, которая нас интересует, находится *в* вызове *перед* текущей выполняемой функцией.\n\nПродемонстрируем стек вызовов и точку вызова:\n\n```js\nfunction baz() {\n    // стек вызовов: `baz`\n    // поэтому наша точка вызова — глобальная область видимости\n\n    console.log( \"baz\" );\n    bar(); // <-- точка вызова для `bar`\n}\n\nfunction bar() {\n    // стек вызовов: `baz` -> `bar`\n    // поэтому наша точка вызова в `baz`\n\n    console.log( \"bar\" );\n    foo(); // <-- точка вызова для `foo`\n}\n\nfunction foo() {\n    // стек вызовов: `baz` -> `bar` -> `foo`\n    // поэтому наша точка вызова в `bar`\n\n    console.log( \"foo\" );\n}\n\nbaz(); // <-- точка вызова для `baz`\n```\n\nПозаботьтесь при анализе кода о том, чтобы найти настоящую точку вызова (из стека вызовов), поскольку это единственная вещь, которая имеет значение для привязки `this`.\n\n**Примечание:** Вы можете мысленно визуализировать стек вызовов посмотрев цепочку вызовов функций в том порядке, в котором мы это делали в  комментариях в коде выше. Но это утомительно и чревато ошибками. Другой путь посмотреть стек вызовов — это использование инструмента отладки в вашем браузере. Во многих современных настольных браузерах есть встроенные инструменты разработчика, включающие JS-отладчик. В вышеприведенном коде вы могли бы поставить точку остановки в такой утилите на первой строке функции `foo()` или просто вставить оператор `debugger;` в первую строку. Как только вы запустите страницу, отладчик остановится в этом месте и покажет вам список функций, которые были вызваны, чтобы добраться до этой строки, каковые и будут являться необходимым стеком вызовов. Таким образом, если вы пытаетесь выяснить привязку `this`, используйте инструменты разработчика для получения стека вызовов, затем найдите второй элемент стека от его вершины и это и будет реальная точка вызова.\n\n## Ничего кроме правил\n\nТеперь обратим наш взор на то, *как* точка вызова определяет на что будет указывать `this` во время выполнения функции.\n\nВам нужно изучить точку вызова и определить какое из 4 правил применяется. Сначала разъясним каждое из 4 правил по отдельности, а затем проиллюстрируем их порядок приоритета, для случаев когда к точке вызова *могут* применяться несколько правил сразу.\n\n### Привязка по умолчанию\n\nПервое правило, которое мы изучим, исходит из самого распространенного случая вызовов функции: отдельный вызов функции. Представьте себе *это* правило `this` как правило, действующее по умолчанию когда остальные правила не применяются.\n\nРассмотрим такой код:\n\n```js\nfunction foo() {\n\tconsole.log( this.a );\n}\n\nvar a = 2;\n\nfoo(); // 2\n```\n\nПервая вещь, которую можно отметить, если вы еще не сделали этого, то, что переменные, объявленные в глобальной области видимости, как например `var a = 2`,  являются синонимами глобальных свойств-объектов с таким же именем. Они не являются копиями друг друга, они и *есть* одно и то же. Представляйте их как две стороны одной монеты.\n\nВо-вторых, видно, что когда вызывается `foo()` `this.a` указывает на нашу глобальную переменную  `a`. Почему? Потому что в этом случае, для `this` применяется *привязка по умолчанию* при вызове функции и поэтому `this` указывает на глобальный объект.\n\nОткуда мы знаем, что здесь применяется *привязка по умолчанию*? Мы исследуем точку вызова, чтобы выяснить как вызывается `foo()`. В нашем примере кода `foo()` вызывается по прямой, необернутой ссылке на функцию. Ни одного из демонстрируемых далее правил тут не будет применено, поэтому вместо них применяется *привязка по умолчанию*.\n\nКогда включен `strict mode`, объект 'global' не подпадает под действие *привязки по умолчанию*, поэтому в противоположность обычному режиму `this` устанавливается в `undefined`.\n\n```js\nfunction foo() {\n\t\"use strict\";\n\n\tconsole.log( this.a );\n}\n\nvar a = 2;\n\nfoo(); // TypeError: `this` is `undefined`\n```\n\nЕдва уловимая, но важная деталь: даже если все правила привязки `this` целиком основываются на точке вызова, глобальный объект подпадает под *привязку по умолчанию* **только** если **содержимое** `foo()` **не** выполняется в режиме `strict mode`; Состояние `strict mode` в точке вызова `foo()` не имеет значения.\n\n```js\nfunction foo() {\n\tconsole.log( this.a );\n}\n\nvar a = 2;\n\n(function(){\n\t\"use strict\";\n\n\tfoo(); // 2\n})();\n```\n\n**Примечание:** К намеренному смешиванию включения и выключения `strict mode` в коде обычно относятся неодобрительно. Вся программа пожалуй должна быть либо **строгой**, либо **нестрогой**. Однако, иногда вы подключаете сторонние библиотеки, в которых этот режим **строгости** отличается от вашего, поэтому нужно отнестись с вниманием к таким едва уловимым деталям совместимости.\n\n### Неявная привязка\n\nРассмотрим еще одно правило: есть ли у точки вызова объект контекста, также называемый как владеющий или содержащий объект, хотя *эти* альтернативные термины могут немного вводить в заблуждение.\n\nРассмотрим:\n\n```js\nfunction foo() {\n\tconsole.log( this.a );\n}\n\nvar obj = {\n\ta: 2,\n\tfoo: foo\n};\n\nobj.foo(); // 2\n```\n\nВо-первых, отметим способ, которым была объявлена `foo()`, а затем позже добавлена как ссылочное свойство в `obj`. Независимо от того была ли `foo()` изначально объявлена *в* `obj` или добавлена позднее как ссылка (как в вышеприведенном коде), ни в том, ни в другом случае **функция** на самом деле не \"принадлежит\" или \"содержится\" в объекте `obj`.\n\nОднако, точка вызова *использует* контекст `obj`, чтобы **ссылаться** на функцию, поэтому *можно* сказать, что объект `obj` \"владеет\" или \"содержит\" **ссылку на функцию** в момент вызова функции.\n\nКакое название вы бы ни выбрали для этого шаблона, в момент когда вызывается  `foo()`, ей предшествует объектная ссылка на `obj`. Когда есть объект контекста для ссылки на функцию, правило *неявной привязки* говорит о том, что именно *этот* объект и следует использовать для привязки `this` к вызову функции.\n\nПоскольку `obj` является `this` для вызова `foo()`, `this.a` — синоним  `obj.a`.\n\nТолько верхний/последний уровень ссылки на свойство объекта в цепочке имеет значение для точки вызова. Например:\n\n```js\nfunction foo() {\n\tconsole.log( this.a );\n}\n\nvar obj2 = {\n\ta: 42,\n\tfoo: foo\n};\n\nvar obj1 = {\n\ta: 2,\n\tobj2: obj2\n};\n\nobj1.obj2.foo(); // 42\n```\n\n#### Неявно потерянный\n\nОдним из самых распространенных недовольств, которые вызывает привязка `this` — когда *неявно привязанная* функция теряет эту привязку, что обычно означает что она вернется к *привязке по умолчанию*, либо объекта `global`, либо  `undefined`, в зависимости от режима `strict mode`.\n\nПредставим такой код:\n\n```js\nfunction foo() {\n\tconsole.log( this.a );\n}\n\nvar obj = {\n\ta: 2,\n\tfoo: foo\n};\n\nvar bar = obj.foo; // ссылка/алиас на функцию!\n\nvar a = \"ой, глобальная\"; // `a` также и свойство глобального объекта\n\nbar(); // \"ой, глобальная\"\n```\n\nНесмотря на то, что `bar` по всей видимости ссылка на `obj.foo`, фактически, это на самом деле другая ссылка на саму `foo`. Более того, именно точка вызова тут имеет значение, а точкой вызова является `bar()`, который является прямым непривязанным вызовом, а следовательно применяется *привязка по умолчанию*.\n\nБолее неочевидный, более распространенный и более неожиданный путь получить такую ситуацию когда мы предполагаем передать функцию обратного вызова:\n\n```js\nfunction foo() {\n\tconsole.log( this.a );\n}\n\nfunction doFoo(fn) {\n\t// `fn` — просто еще одна ссылка на `foo`\n\n\tfn(); // <-- точка вызова!\n}\n\nvar obj = {\n\ta: 2,\n\tfoo: foo\n};\n\nvar a = \"ой, глобальная\"; // `a` еще и переменная в глобальном объекте\n\ndoFoo( obj.foo ); // \"ой, глобальная\"\n```\n\nПередаваемый параметр — всего лишь неявное присваивание, а поскольку мы передаем функцию, это неявное присваивание ссылки, поэтому окончательный результат будет таким же как в предыдущем случае.\n\nЧто если функция, в которую вы передаете функцию обратного вызова, не ваша собственная, а встроенная в язык? Никакой разницы, такой же результат.\n\n```js\nfunction foo() {\n\tconsole.log( this.a );\n}\n\nvar obj = {\n\ta: 2,\n\tfoo: foo\n};\n\nvar a = \"ой, глобальная\"; // `a` еще и переменная в глобальном объекте\n\nsetTimeout( obj.foo, 100 ); // \"ой, глобальная\"\n```\n\nПоразмышляйте над этой грубой теоретической псевдо-реализацией `setTimeout()`, которая есть в качестве встроенной в JavaScript-среде:\n\n```js\nfunction setTimeout(fn,delay) {\n\t// подождать (так или иначе) `delay` миллисекунд\n\tfn(); // <-- точка вызова!\n}\n```\n\nДостаточно распространенная ситуация, когда функции обратного вызова *теряют* свою привязку `this`, как мы только что видели. Но еще один способ, которым `this` может удивить нас, когда функция, которой мы передаем нашу функцию обратного вызова, намеренно меняет `this` для этого вызова. Обработчики событий в популярных JavaScript-библиотеках часто любят, чтобы в вашей функции обратного вызова `this` принудительно указывал, например, на DOM-элемент, который вызвал это событие. Несмотря на то, что иногда это бывает полезно, в другое время это может прямо таки выводить из себя. К сожалению, эти инструменты редко дают возможность выбирать.\n\nКаким бы путем ни менялся неожиданно `this`, у вас в действительности нет контроля над тем как будет вызвана ваша функция обратного вызова, таким образом у вас нет возможности контролировать точку вызова, чтобы получить заданную привязку. Мы кратко рассмотрим способ \"починки\" этой проблемы  *починив* `this`.\n\n### Явная привязка\n\nВ случае *неявной привязки*, как мы только что видели, нам требуется менять объект, о котором идет речь, чтобы включить в него функцию и использовать эту ссылку на свойство-функцию, чтобы опосредованно (неявно) привязать `this` к этому объекту.\n\nНо, что если вам надо явно использовать при вызове функции указанный объект для привязки `this`, без помещения ссылки на свойство-функцию в объект?\n\nУ \"всех\" функций в языке есть несколько инструментов, доступных для них (через их `[[Прототип]]`, о котором подробности будут позже), которые могут оказаться полезными в решении этой задачи. Говоря конкретнее, у функций есть методы `call(..)` и `apply(..)` . Технически, управляющие среды JavaScript иногда обеспечивают функции, которые настолько специфичны, что у них нет такой функциональности. Но таких мало. Абсолютное большинство предоставляемых функций и конечно все функции, которые создаете вы сами, безусловно имеют доступ к `call(..)` и `apply(..)`.\n\nКак работают эти инструменты? Они оба принимают в качестве первого параметра объект, который будет использоваться в качестве `this`, а затем вызывают функцию с указанным `this`. Поскольку вы явно указываете какой `this` вы хотите использовать, мы называем такой способ *явной привязкой*.\n\nПредставим такой код:\n\n```js\nfunction foo() {\n\tconsole.log( this.a );\n}\n\nvar obj = {\n\ta: 2\n};\n\nfoo.call( obj ); // 2\n```\n\nВызов `foo` с *явной привязкой* посредством `foo.call(..)` позволяет нам указать, что `this` будет `obj`.\n\nЕсли в качестве привязки `this` вы передадите примитивное значение (типа `string`, `boolean` или `number`), то это примитивное значение будет обернуто в свою объектную форму (`new String(..)`, `new Boolean(..)` или `new Number(..)` соответственно). Часто это называют \"обертка\".\n\n**Примечание:** В отношении привязки `this` `call(..)` и `apply(..)` идентичны. Они *по-разному* ведут себя с дополнительными параметрами, но мы не будем сейчас на этом останавливаться.\n\nК сожалению, *явная привязка* сама по себе все-таки не предлагает никакого решения для указанной ранее проблемы \"потери\" функцией ее привязки `this`, либо оставляет это на усмотрение фреймворка.\n\n#### Жесткая привязка\n\nНо поиграв с вариациями на тему *явной привязки* на самом деле можно получить желаемое. Пример:\n\n```js\nfunction foo() {\n\tconsole.log( this.a );\n}\n\nvar obj = {\n\ta: 2\n};\n\nvar bar = function() {\n\tfoo.call( obj );\n};\n\nbar(); // 2\nsetTimeout( bar, 100 ); // 2\n\n// `bar` жестко привязывает `this` в `foo` к `obj`\n// поэтому его нельзя перекрыть\nbar.call( window ); // 2\n```\n\nДавайте изучим как работает этот вариант. Мы создаем функцию `bar()`, которая внутри вручную вызывает `foo.call(obj)`, таким образом принудительно вызывая `foo` с привязкой `obj` для `this`. Неважно как вы потом вызовете функцию  `bar`, она всегда будет вручную вызывать `foo` с `obj`. Такая привязка одновременно явная и сильная, поэтому мы называем ее *жесткой привязкой*.\n\nСамый типичный способ обернуть функцию с *жесткой привязкой* — создать сквозную обертку, передающую все параметры и возвращающую полученное значение:\n\n```js\nfunction foo(something) {\n\tconsole.log( this.a, something );\n\treturn this.a + something;\n}\n\nvar obj = {\n\ta: 2\n};\n\nvar bar = function() {\n\treturn foo.apply( obj, arguments );\n};\n\nvar b = bar( 3 ); // 2 3\nconsole.log( b ); // 5\n```\n\nЕще один способ выразить этот шаблон — создать переиспользуемую вспомогательную функцию:\n\n```js\nfunction foo(something) {\n\tconsole.log( this.a, something );\n\treturn this.a + something;\n}\n\n// простая вспомогательная функция `bind`\nfunction bind(fn, obj) {\n\treturn function() {\n\t\treturn fn.apply( obj, arguments );\n\t};\n}\n\nvar obj = {\n\ta: 2\n};\n\nvar bar = bind( foo, obj );\n\nvar b = bar( 3 ); // 2 3\nconsole.log( b ); // 5\n```\n\nПоскольку *жесткая привязка* — очень распространеный шаблон, он есть как встроенный инструмент в ES5: `Function.prototype.bind`, а используется вот так:\n\n```js\nfunction foo(something) {\n\tconsole.log( this.a, something );\n\treturn this.a + something;\n}\n\nvar obj = {\n\ta: 2\n};\n\nvar bar = foo.bind( obj );\n\nvar b = bar( 3 ); // 2 3\nconsole.log( b ); // 5\n```\n\n`bind(..)` возвращает новую функцию, в которой жестко задан вызов оригинальной функции с именно тем контекстом `this`, который вы указываете.\n\n**Примечание:** Начиная с ES6, в функции жесткой привязки, выдаваемой `bind(..)`, есть свойство `.name`, наследуемое от исходной *функции*. Например: у `bar = foo.bind(..)` должно быть в `bar.name` значение `\"bound foo\"`, которое является названием вызова функции, которое должно отражаться в стеке вызовов.\n\n#### \"Контексты\" в вызовах API \n\nФункции многих библиотек, и разумеется многие встроенные в язык JavaScript и во внешнее окружение функции, предоставляют необязательный параметр, обычно называемый \"контекст\", который спроектирован как обходной вариант для вас, чтобы не пользоваться `bind(..)`, чтобы гарантировать, что ваша функция обратного вызова использует данный `this`.\n\nНапример:\n\n```js\nfunction foo(el) {\n\tconsole.log( el, this.id );\n}\n\nvar obj = {\n\tid: \"awesome\"\n};\n\n// используем `obj` как `this` для вызовов `foo(..)`\n[1, 2, 3].forEach( foo, obj ); // 1 awesome  2 awesome  3 awesome\n```\n\nВнутренне эти различные функции почти наверняка используют *явную привязку* через `call(..)` или `apply(..)`, избавляя вас от хлопот.\n\n### Привязка `new`\n\nЧетвертое и последнее правило привязки `this` потребует от нас переосмысления самого распространенного заблуждения о функциях и объектах в JavaScript.\n\nВ традиционных классо-ориентированных языках, \"конструкторы\" — это особые методы, связанные с классами, таким образом, что когда создается экземпляр класса с помощью операции `new`, вызывается конструктор этого класса. Обычно это выглядит как-то так:\n\n```js\nsomething = new MyClass(..);\n```\n\nВ JavaScript есть операция `new` и шаблон кода, который используется для этого, выглядит в основном идентично такой же операции в класс-ориентированных языках; многие разработчики полагают, что механизм JavaScript выполняет что-то похожее. Однако, на самом деле *нет никакой связи* с классо-ориентированной функциональностью у той, что предполагает использование `new` в JS.\n\nВо-первых, давайте еще раз посмотрим что такое \"конструктор\" в JavaScript. В JS конструкторы — это **всего лишь функции**, которые, так уж получилось, были вызваны с операцией `new` перед ними. Они ни связаны с классами, ни создают экземпляров классов. Они — даже не особые типы функций. Они — всего лишь обычные функции, которые, по своей сути, \"украдены\" операцией `new` при их вызове.\n\nНапример, функция `Number(..)` действует как конструктор, цитируя спецификацию ES5.1:\n\n> 15.7.2 Конструктор Number\n>\n> Когда Number вызывается как часть выражения new, оно является конструктором: оно инициализирует только что созданный объект.\n\nТак что, практически любая старенькая функция, включая встроенные объектные функции, такие как `Number(..)` (см. главу 3), могут вызываться с `new` перед ними и это превратит такой вызов функции в *вызов конструктора*. Это важное, но едва уловимое различие: нет такой вещи как \"функции-конструкторы\", а скорее есть вызовы, конструирующие *из* функций.\n\nКогда функция вызывается с указанием перед ней `new`, также известный как вызов конструктора, автоматически выполняются следующие вещи:\n\n1. Создается новенький объект (т.е. конструируется) прямо из воздуха\n2. *Только что сконструированный объект связывается с `[[Прототипом]]`*\n3. Только что сконструированный объект устанавливается как привязка `this` для этого вызова функции\n4. За исключением тех случаев, когда функция возвращает свой собственный альтернативный **объект**, вызов функции с `new` *автоматически* вернет только что сконструированный объект.\n\nПункты 1, 3 и 4 применимы к нашему текущему обсуждению. Сейчас мы пропустим пункт 2 и вернемся к нему в главе 5.\n\nВзглянем на такой код:\n\n```js\nfunction foo(a) {\n\tthis.a = a;\n}\n\nvar bar = new foo( 2 );\nconsole.log( bar.a ); // 2\n```\n\nВызывая `foo(..)` с `new` впереди нее, мы конструируем новый объект и устанавливаем этот новый объект как `this` для вызова `foo(..)`. **Таким образом `new` — последний путь, которым `this` при вызове функции может быть привязан.** Мы называем это *привязкой new*.\n\n## Всё по порядку\n\nИтак, теперь мы раскрыли 4 правила привязки `this` в вызовах функций. *Всё*, что вам нужно сделать — это найти точку вызова и исследовать ее, чтобы понять какое правило применяется. Но что если к точке вызова можно применить несколько соответствующих правил? Должен быть порядок очередности применения этих правил, а потому далее мы покажем в каком порядке применяются эти правила.\n\nДумаю, совершенно ясно, что *привязка по умолчанию* имеет самый низкий приоритет из четырех. Поэтому мы отложим ее в сторону.\n\nЧто должно идти раньше: *неявная привязка* или *явная привязка*? Давайте проверим:\n\n```js\nfunction foo() {\n\tconsole.log( this.a );\n}\n\nvar obj1 = {\n\ta: 2,\n\tfoo: foo\n};\n\nvar obj2 = {\n\ta: 3,\n\tfoo: foo\n};\n\nobj1.foo(); // 2\nobj2.foo(); // 3\n\nobj1.foo.call( obj2 ); // 3\nobj2.foo.call( obj1 ); // 2\n```\n\nИтак, *явная привязка* имеет приоритет над *неявной привязкой*, что означает, что вы должны спросить себя применима ли **сначала** *явная привязка* до проверки на *неявную привязку*.\n\nТеперь, нам нужно всего лишь указать куда подходит по приоритету *привязка new*.\n\n```js\nfunction foo(something) {\n\tthis.a = something;\n}\n\nvar obj1 = {\n\tfoo: foo\n};\n\nvar obj2 = {};\n\nobj1.foo( 2 );\nconsole.log( obj1.a ); // 2\n\nobj1.foo.call( obj2, 3 );\nconsole.log( obj2.a ); // 3\n\nvar bar = new obj1.foo( 4 );\nconsole.log( obj1.a ); // 2\nconsole.log( bar.a ); // 4\n```\n\nХорошо, *привязка new* более приоритетна, чем *неявная привязка*. Но как вы думаете: *привязка new* более или менее приоритетна, чем *явная привязка*?\n\n**Примечание:** `new` и `call`/`apply` не могут использоваться вместе, поэтому `new foo.call(obj1)` не корректно, чтобы сравнить напрямую *привязку new* с *явной привязкой*. Но мы все-таки можем использовать *жесткую привязку*, чтобы проверить приоритет этих двух правил.\n\nДо того, как мы начнем исследовать всё это на примере кода, постарайтесь вспомнить как физически работает *жесткая привязка*, которая есть в `Function.prototype.bind(..)`, которая создает новую функцию-обертку, и в ней жестко задано игнорировать ее собственную привязку `this` (какой бы она ни была) и использовать указанную вручную нами.\n\nПо этой причине, кажется очевидным предполагать, что *жесткая привязка* (которая является формой *явной привязки*) более приоритетна, чем *привязка new*, а потому и не может быть перекрыта действием `new`.\n\nДавайте проверим:\n\n```js\nfunction foo(something) {\n\tthis.a = something;\n}\n\nvar obj1 = {};\n\nvar bar = foo.bind( obj1 );\nbar( 2 );\nconsole.log( obj1.a ); // 2\n\nvar baz = new bar( 3 );\nconsole.log( obj1.a ); // 2\nconsole.log( baz.a ); // 3\n```\n\nОго! `bar` жестко связан с `obj1`, но `new bar(3)` **не** меняет `obj1.a` на значение `3` что было бы ожидаемо нами. Вместо этого *жестко связанный* (с `obj1`) вызов `bar(..)` ***может*** быть перекрыт с `new`. Поскольку был применен `new`, обратно мы получили новый созданный объект, который мы назвали `baz`, и в результате видно, что в `baz.a` значение `3`.\n\nЭто должно быть удивительно с учетом ранее рассмотренной \"фальшивой\" вспомогательной функции привязки:\n\n```js\nfunction bind(fn, obj) {\n\treturn function() {\n\t\tfn.apply( obj, arguments );\n\t};\n}\n```\n\nЕсли вы порассуждаете о том, как работает код этой вспомогательной функции, в нем нет способа для перекрытия жесткой привязки к `obj` операцией `new` как мы только что выяснили.\n\nНо встроенная `Function.prototype.bind(..)` из ES5 — более сложная, даже очень на самом деле. Вот (немного отформатированный) полифиллинг кода, предоставленный со страницы MDN для функции `bind(..)`:\n\n```js\nif (!Function.prototype.bind) {\n\tFunction.prototype.bind = function(oThis) {\n\t\tif (typeof this !== \"function\") {\n\t\t\t// наиболее подходящая вещь в ECMAScript 5\n\t\t\t// внутренняя функция IsCallable\n\t\t\tthrow new TypeError( \"Function.prototype.bind - what \" +\n\t\t\t\t\"is trying to be bound is not callable\"\n\t\t\t);\n\t\t}\n\n\t\tvar aArgs = Array.prototype.slice.call( arguments, 1 ),\n\t\t\tfToBind = this,\n\t\t\tfNOP = function(){},\n\t\t\tfBound = function(){\n\t\t\t\treturn fToBind.apply(\n\t\t\t\t\t(\n\t\t\t\t\t\tthis instanceof fNOP &&\n\t\t\t\t\t\toThis ? this : oThis\n\t\t\t\t\t),\n\t\t\t\t\taArgs.concat( Array.prototype.slice.call( arguments ) )\n\t\t\t\t);\n\t\t\t}\n\t\t;\n\n\t\tfNOP.prototype = this.prototype;\n\t\tfBound.prototype = new fNOP();\n\n\t\treturn fBound;\n\t};\n}\n```\n\n**Примечание:** Полифиллинг `bind(..)`, показанный выше, отличается от встроенной `bind(..)` в ES5, учитывающей функции жесткой привязки, которые используются с `new` (см. ниже почему это может быть полезно). Поскольку полифиллинг не может создавать функцию без `.prototype` так, как это делает встроенная утилита, есть едва уловимый окольный путь, чтобы приблизиться к такому же поведению. Двигайтесь осторожно, если планируете использовать `new` вместе с функцией жесткой привязки и полагаетесь на этот полифиллинг.\n\nЧасть, которая позволяет перекрыть `new`:\n\n```js\nthis instanceof fNOP &&\noThis ? this : oThis\n\n// ... and:\n\nfNOP.prototype = this.prototype;\nfBound.prototype = new fNOP();\n```\n\nМы не будем на самом деле углубляться в объяснения того, как работает эта хитрость (это сложно и выходит за рамки нашего обсуждения), но по сути утилита определяет была ли вызвана или нет функция жесткой привязки с `new` (в результате получая новый сконструированный объект в качестве ее `this`), и если так, то она использует *этот* свежесозданный `this` вместо ранее указанной *жесткой привязки* для `this`.\n\nПочему перекрытие операцией `new` *жесткой привязки* может быть полезным?\n\nОсновная причина такого поведения — чтобы создать функцию (которую можно использовать вместе с `new` для конструирования объектов), которая фактически игнорирует *жесткую привязку* `this`, но которая инициализирует некоторые или все аргументы функции. Одной из возможностей `bind(..)` является умение сделать аргументы, переданные после аргумента, привязки `this`,  стандартными аргументами по умолчанию для предшествующей функции (технически называемое \"частичным применением\", которое является подмножеством \"карринга\").\n\nПример:\n\n```js\nfunction foo(p1,p2) {\n\tthis.val = p1 + p2;\n}\n\n// используем здесь `null`, т.к. нам нет дела до \n// жесткой привязки `this` в этом сценарии, и она \n// будет переопределена вызовом с операцией `new` в любом случае!\nvar bar = foo.bind( null, \"p1\" );\n\nvar baz = new bar( \"p2\" );\n\nbaz.val; // p1p2\n```\n\n### Определяем `this`\n\nТеперь можно кратко сформулировать правила для определения `this` по точке вызова функции, в порядке их приоритета. Зададим вопросы в том же порядке и остановимся как только будет применено первое же правило.\n\n1. Функция вызвана с `new` (**привязка new**)? Раз так, то `this` — новый сконструированный объект.\n\n    `var bar = new foo()`\n\n2. Функция вызвана с `call` или `apply` (**явная привязка**), даже скрыто внутри *жесткой привязки* в `bind`? Раз так, `this` — явно указанный объект.\n\n    `var bar = foo.call( obj2 )`\n\n3. Функция вызвана с контекстом (**неявная привязка**), иначе называемым как владеющий или содержащий объект? Раз так, `this` является *тем самым* объектом контекста.\n\n    `var bar = obj1.foo()`\n\n4. В противном случае, будет `this` по умолчанию (**привязка по умолчанию**). В режиме `strict mode`, это будет `undefined`, иначе будет объект `global`.\n\n    `var bar = foo()`\n\nВот и всё. Вот *всё, что нужно*, чтобы понимать правила привязки `this` для обычных вызовов функций. Ну... почти.\n\n## Исключения привязок\n\nКак обычно, из \"правил\" есть несколько *исключений*.\n\nПоведение привязки `this` в некоторых сценариях может быть неожиданным, там где вы подразумеваете одну привязку, а получаете в итоге поведение привязки по правилу *привязки по умолчанию* (см. ранее).\n\n### Проигнорированный `this`\n\nЕсли вы передаете `null` или `undefined` в качестве параметра привязки `this` в `call`, `apply` или `bind`, то эти значения фактически игнорируются, а взамен к вызову применяется правило *привязки по умолчанию*.\n\n```js\nfunction foo() {\n\tconsole.log( this.a );\n}\n\nvar a = 2;\n\nfoo.call( null ); // 2\n```\n\nЗачем вам бы понадобилось намеренно передавать что-то подобное `null` в качестве привязки `this`?\n\nДовольно распространено использовать `apply(..)` для распаковки массива значений в качестве параметров вызова функции. Аналогично и `bind(..)` может каррировать параметры (предварительно заданные значения), что может быть очень полезно.\n\n```js\nfunction foo(a,b) {\n\tconsole.log( \"a:\" + a + \", b:\" + b );\n}\n\n// распакуем массив как параметры\nfoo.apply( null, [2, 3] ); // a:2, b:3\n\n// каррируем с помощью `bind(..)`\nvar bar = foo.bind( null, 2 );\nbar( 3 ); // a:2, b:3\n```\n\nОбa этих инструмента требуют указания привязки `this` в качестве первого параметра. Если рассматриваемым функциям не важен `this`, то вам нужно -значение-заменитель, и `null` — это похоже разумный выбор, как мы видели выше.\n\n**Примечание:** В этой книге мы не уделим этому внимания, но в ES6 есть операция расширения `...`, которая дает возможности синтаксически \"развернуть\" массив как параметры без необходимости использования `apply(..)`, например как в `foo(...[1,2])`, что равносильно `foo(1,2)` — синтаксически избегая привязки `this`, раз она не нужна. К сожалению, в ES6 нет синтаксической замены каррингу, поэтому параметр `this` вызова `bind(..)` все еще требует внимания.\n\nОднако, есть некоторая скрытая \"опасность\" в том, чтобы всегда использовать `null`, когда вам не нужна привязка `this`. Если вы когда-нибудь воспользуетесь этим при вызове функции (например, функции сторонней библиотеки, которой вы не управляете) и эта функция *все-таки* воспользуется ссылкой на `this`, сработает правило *привязки по умолчанию*, что повлечет за собой ненамеренно ссылку (или еще хуже, мутацию!) на объект `global` (`window` в браузере).\n\nОчевидно, что такая ловушка может привести к ряду *очень трудно* диагностируемых/отслеживаемых ошибок.\n\n#### Более безопасный `this`\n\nПожалуй в некоторой степени \"более безопасная\" практика — передавать особым образом настроенный объект для `this`, который гарантирует отсутствие побочных эффектов в вашей программе. Заимствуя терминологию из сетевых (и военных) технологий, мы можем создать объект \"DMZ\" (демилитаризованной зоны (de-militarized zone)) — не более чем полностью пустой, неделегированный (см. главы 5 и 6) объект.\n\nЕсли всегда передавать DMZ-объект для привязок `this`, которые не требуются, то мы можем быть уверены в том, что любое скрытое/неожидаемое использование `this` будет ограничено пустым объектом, который защитит объект `global` нашей программы от побочных эффектов.\n\nПоскольку этот объект совершенно пустой, лично я люблю давать его переменной имя `ø` (математический символ пустого множества в нижнем регистре). На многих клавиатурах (как например US-раскладка на Mac), этот символ легко можно ввести с помощью `⌥`+`o` (option+`o`). В некоторых системах есть возможность назначать горячие клавиши на определенные символы. Если вам не нравится символ `ø` или на вашей клавиатуре сложно набрать такой символ, вы конечно же можете назвать переменную как вам угодно.\n\nКак бы вы ни назвали ее, самый простой путь получить **абсолютно пустой** объект — это `Object.create(null)` (см. главу 5). `Object.create(null)` — похож на `{ }`, но без передачи `Object.prototype`, поэтому он \"более пустой\", чем просто `{ }`.\n\n```js\nfunction foo(a,b) {\n\tconsole.log( \"a:\" + a + \", b:\" + b );\n}\n\n// наш пустой DMZ-объект\nvar ø = Object.create( null );\n\n// распаковываем массив как параметры\nfoo.apply( ø, [2, 3] ); // a:2, b:3\n\n// каррируем с помощью `bind(..)`\nvar bar = foo.bind( ø, 2 );\nbar( 3 ); // a:2, b:3\n```\n\nНе только функционально \"безопаснее\", но еще и стилистически выгоднее использовать `ø`, что семантически отражает желание \"Я хочу, чтобы `this` был пустым\" немного точнее, чем `null`. Но опять таки, называйте свой DMZ-объект как хотите.\n\n### Косвенность\n\nЕще одной вещью, которую нужно опасаться, является создание (намеренно или нет) \"косвенных ссылок\" на функции, и в этих случаях, когда такая ссылка на функцию вызывается, то также применяется правило *привязки по умолчанию*.\n\nСамый распространенный путь появления *косвенных ссылок* — при присваивании:\n\n```js\nfunction foo() {\n\tconsole.log( this.a );\n}\n\nvar a = 2;\nvar o = { a: 3, foo: foo };\nvar p = { a: 4 };\n\no.foo(); // 3\n(p.foo = o.foo)(); // 2\n```\n\n*Результатом* выражения присваивания `p.foo = o.foo` будет всего лишь ссылка  на внутренний объект функции. В силу этого, настоящая точка вызова - это просто `foo()`, а не `p.foo()` или `o.foo()` как вы могли бы предположить. Согласно вышеприведенным правилам будет применено правило *привязки по умолчанию*.\n\nНапоминание: независимо от того как вы добрались до вызова функции используя правило *привязки по умолчанию*, статус **содержимого** вызванной функции в режиме  `strict mode`, использующего ссылку на `this`, а не точка вызова функции, определяет значение *привязки по умолчанию*: либо объект `global` если не в `strict mode` или `undefined` в `strict mode`.\n\n### Смягчение привязки\n\nРанее мы отметили, что *жесткая привязка* была одной из стратегий для предотвращения случайного действия правила *привязки по умолчанию* при вызове функции, заставив ее привязаться к указанному `this` (до тех пор, пока вы не используете `new`, чтобы переопределить это поведение!). Проблема в том, что *жесткая привязка* значительно уменьшает гибкость функции, не давая указывать `this` вручную, чтобы перекрыть *неявную привязку* или даже последующие попытки *явной привязки*.\n\nБыло бы неплохо, если бы был путь указать другое умолчание для *привязки по умолчанию* (не `global` или `undefined`), но при этом оставив возможность для функции вручную привязать `this` через технику *неявной* или *явной* привязки.\n\nМожно собрать инструмент так называемой *мягкой привязки*, который эмулирует желаемое поведение.\n\n```js\nif (!Function.prototype.softBind) {\n\tFunction.prototype.softBind = function(obj) {\n\t\tvar fn = this,\n\t\t\tcurried = [].slice.call( arguments, 1 ),\n\t\t\tbound = function bound() {\n\t\t\t\treturn fn.apply(\n\t\t\t\t\t(!this ||\n\t\t\t\t\t\t(typeof window !== \"undefined\" &&\n\t\t\t\t\t\t\tthis === window) ||\n\t\t\t\t\t\t(typeof global !== \"undefined\" &&\n\t\t\t\t\t\t\tthis === global)\n\t\t\t\t\t) ? obj : this,\n\t\t\t\t\tcurried.concat.apply( curried, arguments )\n\t\t\t\t);\n\t\t\t};\n\t\tbound.prototype = Object.create( fn.prototype );\n\t\treturn bound;\n\t};\n}\n```\n\nИнструмент `softBind(..)`, представленный здесь, работает подобно встроенному  в ES5 инструменту `bind(..)`, за исключением нашего поведения *мягкой привязки*. Он делает обертку указанной функции с логикой, которая проверяет `this` в момент вызова и если это `global` или `undefined`, использует указанное заранее альтернативное *умолчание* (`obj`). В противном случае  `this` остается как есть. Также этот инструмент дает возможность опционального карринга (см. ранее обсуждение`bind(..)`).\n\nПродемонстрируем его в действии:\n\n```js\nfunction foo() {\n   console.log(\"name: \" + this.name);\n}\n\nvar obj = { name: \"obj\" },\n    obj2 = { name: \"obj2\" },\n    obj3 = { name: \"obj3\" };\n\nvar fooOBJ = foo.softBind( obj );\n\nfooOBJ(); // name: obj\n\nobj2.foo = foo.softBind(obj);\nobj2.foo(); // name: obj2   <---- смотрите!!!\n\nfooOBJ.call( obj3 ); // name: obj3   <---- смотрите!\n\nsetTimeout( obj2.foo, 10 ); // name: obj   <---- возврат к мягкой привяке\n```\n\nДля мягкопривязанной версии функции `foo()` можно вручную привязать `this` к `obj2` или `obj3` как показано выше, но он возвращается к `obj` в случае применения *привязки по умолчанию*.\n\n## Лексический `this`\n\nВ обычных функциях строго соблюдаются 4 правила, которые мы только что рассмотрели. Но в ES6 представлен особый вид функции, которая не использует эти правила: стрелочная функция.\n\nСтрелочные функции обозначаются не ключевым словом `function`, а операцией `=>`, так называемой \"жирной стрелкой\". Вместо использования четырех стандартных `this`-правил, стрелочные функции заимствуют привязку `this` из окружающей (функции или глобальной) области видимости.\n\nПроиллюстрируем лексическую область видимости стрелочной функции:\n\n```js\nfunction foo() {\n\t// возвращаем стрелочную функцию\n\treturn (a) => {\n\t\t// Здесь `this` лексически заимствован из `foo()`\n\t\tconsole.log( this.a );\n\t};\n}\n\nvar obj1 = {\n\ta: 2\n};\n\nvar obj2 = {\n\ta: 3\n};\n\nvar bar = foo.call( obj1 );\nbar.call( obj2 ); // 2, а не 3!\n```\n\nСтрелочная функция, созданная в `foo()`, лексически захватывает любой `this` в `foo()` во время ее вызова. Поскольку в `foo()` `this` был привязан к `obj1`, `bar` (ссылка на возвращаемую стрелочную функцию) также будет с привязкой `this` к `obj1`. Лексическая привязка стрелочной функции не может быть перекрыта (даже с помощью `new`!).\n\nСамый распространенный вариант использования стрелочной функции — обычно при использовании функций обратного вызова, таких как обработчики событий или таймеры:\n\n```js\nfunction foo() {\n\tsetTimeout(() => {\n\t\t// Здесь `this` лексически заимствован из `foo()`\n\t\tconsole.log( this.a );\n\t},100);\n}\n\nvar obj = {\n\ta: 2\n};\n\nfoo.call( obj ); // 2\n```\n\nНесмотря на то, что стрелочные функции предоставляют альтернативу применению `bind(..)` к функции, чтобы гарантировать определенный `this`, что может выглядеть весьма привлекательно, важно отметить, что они фактически запрещают традиционный механизм `this` в пользу более понятной лексической области видимости. До ES6, у нас уже был довольно распространенный шаблон для выполнения такой задачи, который по сути почти неотличим от сущности стрелочных функций ES6:\n\n```js\nfunction foo() {\n\tvar self = this; // лексический захват `this`\n\tsetTimeout( function(){\n\t\tconsole.log( self.a );\n\t}, 100 );\n}\n\nvar obj = {\n\ta: 2\n};\n\nfoo.call( obj ); // 2\n```\n\nВ том время как `self = this` и стрелочные функции обе кажутся хорошим \"решением\" при нежелании использовать `bind(..)`, они фактически убегают от `this` вместо того, чтобы понять и научиться использовать его.\n\nЕсли вы застали себя пишущим код в стиле `this`, но большую часть или всё время вы сводите на нет механизм `this` с помощью трюков лексической конструкции `self = this` или стрелочной функции, возможно вам следует сделать что-то одно из этого:\n\n1. Использовать только лексическую область видимости и забыть о фальшивости кода в стиле `this`.\n\n2. Полностью научиться использовать механизмы `this`-стиля, включая применение `bind(..)`, где необходимо, и попытаться избегать трюков \"лексического this\" с помощью `self = this` и стрелочной функции.\n\nПрограмма может эффективно использовать оба стиля кодирования (лексический и  `this`), но внутри одной и той же функции и, разумеется, при одних и тех же видах поисков переменных, смешивание двух этих механизмов обычно приводит к менее обслуживаемому коду, и возможно будет слишком перегруженным, чтобы выглядеть умным.\n\n## Обзор\n\nОпределение привязки `this` для вызова функции требует поиска непосредственной точки вызова этой функции. Как уже выяснилось, к точке вызова могут быть применены четыре правила, в *именно таком* порядке  приоритета:\n\n1. Вызвана с `new`? Используем только что созданный объект.\n\n2. Вызвана с помощью `call` или `apply` (или `bind`)? Используем указанный объект.\n\n3. Вызвана с объектом контекста, владеющего вызовом функции? Используем этот объект контекста.\n\n4. По умолчанию: `undefined` в режиме `strict mode`, в противном случае объект global.\n\nОстерегайтесь случайного/неумышленного вызова с применением правила *привязки по умолчанию*. В случаях, когда вам нужно \"безопасно\" игнорировать привязку `this`, \"DMZ\"-объект, подобный `ø = Object.create(null)`, — хорошая замена, защищающая объект `global` от непредусмотренных побочных эффектов.\n\nВместо четырех стандартных правил привязки стрелочные функции ES6 используют лексическую область видимости для привязки `this`, что означает, что они  заимствуют привязку `this` (какой бы она ни была) от вызова своей окружающей функции. Они по существу являются синтаксической заменой `self = this` в до-ES6 коде.\n"
  },
  {
    "path": "this & object prototypes/ch3.md",
    "content": "# Вы не знаете JS: *this* и прототипы объектов\n# Глава 3: Объекты\n\nВ первых двух главах мы объяснили как `this` указывает на разные объекты, в зависимости от места вызова функции. Но что представляют собой объекты на самом деле, и почему нам нужно указывать на них? Мы подробно рассмотрим объекты в этой главе.\n\n## Синтаксис\n\nОбъекты создаются двумя способами: декларативно (литерально) и с помощью конструктора.\n\nЛитеральный синтаксис для объекта выглядит так:\n\n```js\nvar myObj = {\nkey: value\n// ...\n};\n```\n\nКонструкторная форма выглядит так:\n\n```js\nvar myObj = new Object();\nmyObj.key = value;\n```\n\nКонструкторная и литеральная формы в результате дают одинаковые объекты. Единственное отличие в том, что в литеральной форме вы можете добавлять сразу несколько пар ключ-значение, в то время как с конструктором вам нужно добавлять свойства по одному.\n\n**Примечание:** Конструкторная форма для создания объектов, показанная выше, используется крайне редко. Почти всегда вы предпочтёте использовать литеральную форму. Это справедливо и для большинства встроенных объектов (смотрите ниже).\n\n## Тип\n\nОбъекты -- это основные элементы из которых построена большая часть JS. В JS есть шесть основных типов (в спецификации называются «языковые типы»):\n\n* `string`\n* `number`\n* `boolean`\n* `null`\n* `undefined`\n* `object`\n\nОбратите внимание, что *простые примитивы* (`string`, `number`, `boolean`, `null`, и `undefined`) сами по себе **не являются** объектами. `null` иногда упоминается как объект, но это заблуждение произошло из ошибки в языке, которая приводит к тому, что `typeof null` ошибочно возвращает `\"object\"`. По факту, `null` это самостоятельный примитивный тип.\n\n**Есть распространённое заблуждение, что «в JS всё является объектом». Это совсем не так.**\n\nОднако, *есть* несколько специальных подтипов, которые мы можем называть *сложными примитивами*.\n\n`function` -- это подтип объекта (технически, «вызываемый объект»). Говорят, что функции в JS это объекты «первого класса», поскольку в основном они являются обычными объектами и с ними можно работать как с любым другим объектом.\n\nМассивы -- это тоже форма объекта с расширенным поведением. Содержимое массивов организовано более структурировано, чем у обычных объектов.\n\n### Встроенные Объекты\n\nСуществует несколько других подтипов объектов, обычно называемых встроенными объектами. Некоторые их названия подразумевают, что они непосредственно относятся к соответствующим простым примитивам. На самом деле, их отношения гораздо сложнее. Скоро мы рассмотрим их подробнее.\n\n* `String`\n* `Number`\n* `Boolean`\n* `Object`\n* `Function`\n* `Array`\n* `Date`\n* `RegExp`\n* `Error`\n\nЭти подтипы выглядят как настоящие типы или даже классы, если вы полагаетесь на сходство с другими языками вроде класса `String` в Java.\n\nНо в JS это, на самом деле, встроенные функции. Каждая из этих встроенных функций может быть использована как конструктор (ага, вызов функции с оператором `new` -- смотрите Главу 2), а результатом будет новый *сконструированный* объект указанного подтипа. Например:\n\n```js\nvar strPrimitive = \"I am a string\";\ntypeof strPrimitive;\t// \"string\"\nstrPrimitive instanceof String;\t// false\nvar strObject = new String( \"I am a string\" );\ntypeof strObject; // \"object\"\nstrObject instanceof String;\t// true\n// проверим подтип объекта\nObject.prototype.toString.call( strObject );\t// [object String]\n```\n\nВ следующей главе мы подробно рассмотрим как именно работает `Object.prototype.toString...`. Вкратце: мы можем проверить внутренний подтип, заимствовав базовый стандартный метод `toString()`. Как видите, он показывает, что этот `strObject` -- на самом деле объект, созданный конструктором `String`.\n\nЗначение примитива «I am a string» это не объект, а литерал примитива, и его значение иммутабельно. Чтобы выполнять над ним операции вроде проверки длины, доступа к содержимому символов и т. д. требуется объект `String`.\n\nК счастью, при необходимости язык автоматически приводит примитив `\"string\"` к объекту `String`, а значит, вам почти никогда не придется дополнительно создавать форму Объекта. Большая часть сообщества JS **настоятельно рекомендует** по возможности использовать литеральную форму вместо конструкторной формы.\n\nРассмотрим:\n\n```js\nvar strPrimitive = \"I am a string\";\nconsole.log( strPrimitive.length );\t// 13\nconsole.log( strPrimitive.charAt( 3 ) );\t// \"m\"\n```\n\nВ обоих случаях мы вызываем свойство или метод строчного примитива и движок автоматически преобразует его к объекту `String`, так что свойство/метод работают.\n\nТакое же преобразование происходит между численным литеральным примитивом `42` и обёрткой объекта `new Number(42)` при использовании методов вроде `42.359.toFixed(2)`. То же самое и с объектом `Boolean` из примитива `\"boolean\"`.\n\n`null` и `undefined` не имеют формы Объекта, только значения их примитивов. В отличие от них, значения `Date` могут быть созданы *только* с помощью их конструкторной формы объекта, так как у них нет соответствующей литеральной формы.\n\n`Object`, `Array`, `Function`, и `RegExp` (регулярные выражения) -- это объекты, не зависимо от того, используется литеральная или конструкторная форма. Конструкторная форма в некоторых случаях предлагает больше опций для создания, чем литеральная. Поскольку объекты создаются в любом случае, простая литеральная форма почти универсальна. **Используйте конструкторную форму только если вам нужны дополнительные опции.**\n\nОбъекты `Error` редко создаются в коде в явном виде. Обычно они создаются автоматически, когда появляются исключения. Они могут быть созданы с помощью конструкторной формы `new Error(..)`, но обычно в этом нет необходимости.\n\n## Содержимое\n\nКак мы упоминали ранее, содержимое объекта состоит из значений (любого типа), которые хранятся в специально названных *местах*, которые мы называем свойствами.\n\nВажно отметить, что когда мы говорим о «содержимом» и подразумеваем, что эти значения хранятся прямо внутри объекта, то это лишь абстракция. Движок хранит значения в зависимости от его реализации и может запросто не хранить их *внутри* какого-нибудь контейнера объекта. Что *действительно* хранится в контейнере, так это названия свойств, которые работают как указатели (технически, *ссылаются*) туда, где хранятся значения.\n\nРассмотрим:\n\n```js\nvar myObject = {\n    a: 2\n};\nmyObject.a;\t    // 2\nmyObject[\"a\"];\t// 2\n```\n\nЧтобы получить значение по *адресу* `a` в `myObject` мы должны использовать либо оператор `.` либо оператор `[]`. Синтаксис `.a` обычно описывают как доступ к «свойству», а синтаксис `[\"a\"]` называют доступ по «ключу». В реальности они оба обращаются по одному *адресу* и выведут одно и то же значение `2`, так что эти термины взаимозаменяемы. Далее мы будем использовать наиболее общий термин «доступ к свойству».\n\nОсновное различие между двумя синтаксисами в том, что оператор `.` требует, чтобы после него шло название свойства, совместимое с `Идентификатором`, в то время как синтаксис `[\"..\"]` может принять в качестве имени свойства любую строку, совместимую с UTF-8/unicode.\n\nТакже, поскольку синтаксис `[\"..\"]` использует **значение** строки для указания адреса, можно программно сгенерировать значение этой строки, например, так:\n\n```js\nvar wantA = true;\nvar myObject = {\n    a: 2\n};\nvar idx;\nif (wantA) {\n    idx = \"a\";\n}\n// позже\nconsole.log( myObject[idx] ); // 2\n```\n\nВ объектах названия свойств **всегда** являются строкой. Если вы используете в качестве свойств любые другие значения кроме `string` (примитив), они будут сконвертированы в строку. Это относится и к числам, которые обычно используют как индексы массивов. Так что будьте осторожны и не путайте использование чисел в объектах и массивах.\n\n```js\nvar myObject = { };\nmyObject[true] = \"foo\";\nmyObject[3] = \"bar\";\nmyObject[myObject] = \"baz\";\nmyObject[\"true\"];\t            // \"foo\"\nmyObject[\"3\"];\t                // \"bar\"\nmyObject[\"[object Object]\"];\t// \"baz\"\n```\n\n### Вычисляемые имена свойств\n\nОписанный выше синтаксис доступа к свойствам вида `myObject[..]` полезен, когда необходимо использовать результат выражения *в качестве* ключа, вроде `myObject[prefix + name]`. Но он не сильно помогает при объявлении объектов через объектно-литеральный синтаксис.\n\nES6 добавляет *вычисляемые имена свойств*, где можно указать выражение, обрамленное `[ ]`, в качестве пары ключ-значение при литеральном объявлении объекта:\n\n```js\nvar prefix = \"foo\";\nvar myObject = {\n    [prefix + \"bar\"]: \"hello\",\n    [prefix + \"baz\"]: \"world\"\n};\nmyObject[\"foobar\"]; // hello\nmyObject[\"foobaz\"]; // world\n```\n\nНаиболее распространённым, вероятно, будет использование *вычисляемых имен свойств* для `Symbol` в ES6, которые не будут подробно рассматриваться в этой книге. Вкратце, это новый примитивный тип данных, значение которого непрозрачно и неопределимо (технически, это значение -- `string`). Вы будете сильно озадачены, работая с *действительным значением* `Symbol` (которое теоретически может быть разным в разных движках JS), поэтому вы будете использовать имя Символа, вроде `Symbol.Something` (просто выдуманное имя!):\n\n```js\nvar myObject = {\n    [Symbol.Something]: \"hello world\"\n};\n```\n\n### Свойство против Метода\n\nЕсли разговор идет о доступе к свойству объекта, некоторые разработчики считают, что есть различие, если запрашиваемое значение является функцией.\n\nИнтересно, что *спецификация делает такое же различие*.\n\nТехнически функции никогда не «относились» к объектам, поэтому утверждение, что функция, к которой обратились через объект автоматически становится «методом» похоже на растягивание семантики.\n\nЭто *правда*, что в некоторых функциях есть указание на `this` и *иногда* использование `this` связано с указанием на объект в точке вызова. Но такое использование не делает эту функцию более «методной», чем другую, поскольку `this` привязывается динамически во время вызова в точке вызова, и поэтому его отношение к объекту в лучшем случае косвенное.\n\nКаждый раз, когда вы запрашиваете свойство объекта, это **обращение к свойству**, вне зависимости от типа значения, которое вы получаете. Если *вдруг* вы получите в результате обращения к этому свойству функцию, она не превратится волшебным образом в «метод». Нет ничего особенного в том, что функция выводится при обращении к свойству (кроме возможной неявной привязки `this`, как было описано ранее).\n\nНапример:\n\n```js\nfunction foo() {\n    console.log( \"foo\" );\n}\nvar someFoo = foo;\t// переменная указывает на `foo`\nvar myObject = {\n    someFoo: foo\n};\nfoo;\t            // function foo(){..}\nsomeFoo;\t        // function foo(){..}\nmyObject.someFoo;\t// function foo(){..}\n```\n\n`someFoo` и `myObject.someFoo` это лишь две разных ссылки на одну функцию, и ни одна из них не подразумевает, что функция является особенной или «принадлежит» какому-то другому объекту.\n\n**Возможно, кто-то возразит**, что функция *становится методом* не в момент объявления, а в процессе выполнения конкретного вызова, в зависимости от того, как она была вызвана и точки ее вызова (в контексте ссылки на объект или нет -- подробнее смотрите в Главе 2). Даже такая интерпретация выглядит притянутой за уши.\n\nВозможно, самым безопасным выводом будет такой: «функция» и «метод» взаимозаменяемы в JavaScript.\n\n**Примечание:** ES6 добавляет указатель `super`, который обычно используется вместе с `class` (см. Приложение А). То, как работает `super` (статическая привязка вместо поздней привязки в виде `this`) прибавляет весомости идее, что функция, которую привязывает `super` больше похожа на «метод», чем на «функцию». Но опять же, это лишь тонкие нюансы семантики (и механики).\n\nДаже если вы объявляете функциональное выражение как часть литерала объекта, эта функция не становится волшебным образом более привязанной к объекту -- это по-прежнему лишь несколько указателей на ту же функцию.\n\n```js\nvar myObject = {\n    foo: function foo() {\n    console.log( \"foo\" );\n}\n};\nvar someFoo = myObject.foo;\nsomeFoo;\t    // function foo(){..}\nmyObject.foo;\t// function foo(){..}\n```\n\n**Примечание**: В Главе 6 мы рассмотрим сокращенный синтаксис ES6 для `foo: function foo(){ .. }` в нашем литерале объекта.\n\n### Массивы\n\nМассивы тоже используют для доступа форму `[ ]`, но, как упоминалось ранее, имеют более структурированную организацию того, как хранятся значения (хотя всё еще без ограничений *типов* хранимых значений). Массивы предполагают *числовую индексацию*. Это означает, что значения хранятся в местах, обычно называемых *индексами*, с неотрицательными целыми числами, вроде `0` и `42`.\n\n```js\nvar myArray = [ \"foo\", 42, \"bar\" ];\nmyArray.length;\t// 3\nmyArray[0];\t    // \"foo\"\nmyArray[2];\t    // \"bar\"\n```\n\nМассивы -- *это* объекты, поэтому даже если каждый индекс является положительным целым числом, вы можете *также* добавить свойства массива:\n\n```js\nvar myArray = [ \"foo\", 42, \"bar\" ];\nmyArray.baz = \"baz\";\nmyArray.length;\t// 3\nmyArray.baz;\t// \"baz\"\n```\n\nОбратите внимание, что добавление именованных свойств (не зависимо от синтаксиса `.` или `[ ]`) не влияет на выводимый результат свойства `length`.\n\nВы можете использовать массив как простой объект вида ключ/значение и не добавлять числовые индексы, но это плохая идея, поскольку у массивов есть особенное поведение и оптимизации, заточенные для их использования; то же самое и с обычными объектами. Используйте объекты для хранения пар ключ/значение, а массивы для хранения значений с числовыми индексами.\n\n**Осторожно**: Если вы попытаетесь добавить свойство к массиву, но имя свойства *выглядит* как число, оно добавится в виде числового индекса (таким образом изменится содержимое массива):\n\n```js\nvar myArray = [ \"foo\", 42, \"bar\" ];\nmyArray[\"3\"] = \"baz\";\nmyArray.length;\t// 4\nmyArray[3];\t    // \"baz\"\n```\n\n### Дублирование Объектов\n\nОдин из наиболее распространенных вопросов для разработчиков JavaScript, которые только знакомятся с языком, это копирование объекта. Казалось бы, должен быть простой встроенный метод `copy()`, верно? Оказывается, всё немного сложнее, потому что изначально не до конца понятно каким должен быть алгоритм для создания дубликата.\n\nДля примера рассмотрим этот объект:\n\n```js\nfunction anotherFunction() { /*..*/ }\nvar anotherObject = {\n    c: true\n};\nvar anotherArray = [];\nvar myObject = {\n    a: 2,\n    b: anotherObject,\t// ссылка, а не копия!\n    c: anotherArray,\t// еще одна ссылка!\n    d: anotherFunction\n};\nanotherArray.push( anotherObject, myObject );\n```\n\nКак же на самом деле должна выглядеть *копия* объекта `myObject`?\n\nВо-первых, мы должны решить будет это *поверхностная* или *глубокая* копия? Результатом *поверхностного копирования* в новом объекте будет свойство `a` в виде копии значения `2`, но свойства `b`, `c`, и `d` -- лишь в виде ссылки на те же места, что и в оригинальном массиве. *Глубокая копия* продублирует не только `myObject`, но и `anotherObject` и `anotherArray`. Но тогда у нас будет проблема с тем, что `anotherArray` содержит ссылки на `anotherObject` и `myObject`, так что их тоже нужно скопировать вместо того чтобы сохранять ссылку. Теперь у нас есть проблема бесконечного дублирования из-за зацикленности ссылок.\n\nДолжны ли мы выявлять цикличные ссылки и просто прерывать цикличный обход (оставляя глубокие элементы не до конца  продублированными)? Может просто вывести ошибку? Или что-то среднее?\n\nБолее того, не до конца ясно, что будет означать *дублирование* функции. Существует несколько хаков, вроде вытягивания исходного кода функции через `toString()` (которые варьируются в разных реализациях и даже не являются надежными для всех движков, в зависимости от типа проверяемой функции)\n\nТак как же нам решить все эти каверзные вопросы? Различные фреймворки имеют свои собственные интерпретации и решения. Но какое из них (если такое имеется) должен принять JS в качестве *стандартного*? Долгое время не было четкого ответа.\n\nОдно из решений заключается в том, что объекты безопасные для JSON (то есть те, которые можно преобразовать в строку JSON и распарсить с теми же значениями и структурой) могут быть легко продублированы с помощью:\n\n```js\nvar newObj = JSON.parse( JSON.stringify( someObj ) );\n```\n\nКонечно, для этого вам нужно убедиться, что ваш объект безопасен для JSON. В некоторых ситуациях это элементарно. В других этого недостаточно.\n\nВ то же время, поверхностное копирование достаточно понятно и имеет меньше проблем, поэтому в ES6 для этой задачи есть `Object.assign(..)`. `Object.assign(..)` принимает *целевой* объект в качестве первого параметра, а также один или более *исходных* объектов в качестве последующих параметров. Он проходит по всем *перечисляемым* (см. ниже), *собственным ключам* (**существующим непосредственно**) в *исходном* объекте(тах) и копирует их (только через присваивание `=`) в *целевой* объект. Кроме того, удобно, что он возвращает *целевой* объект, как показано ниже:\n\n\n```js\nvar newObj = Object.assign( {}, myObject );\nnewObj.a;\t                    // 2\nnewObj.b === anotherObject;\t    // true\nnewObj.c === anotherArray;\t    // true\nnewObj.d === anotherFunction;\t// true\n```\n\n**Примечание:** В следующем разделе мы опишем «дескрипторы свойств» (характеристики свойств) и покажем использование `Object.defineProperty(..)`. Как бы то ни было, дублирование, которое имеет место в `Object.assign(..)` это чистое присваивание в стиле `=`, так что любые особенные характеристики свойств (вроде `writable`) исходного объекта *не сохраняются* в целевом объекте.\n\n### Дескрипторы свойств\n\nВплоть до ES5 язык JavaScript не давал вашему коду напрямую проверить или описать различия между характеристиками свойств: например, узнать доступно ли свойство только для чтения или нет.\n\nНо в ES5 все свойства описываются с помощью **дескриптора свойств**.\n\nРассмотрим такой код:\n\n```js\nvar myObject = {\n    a: 2\n};\nObject.getOwnPropertyDescriptor( myObject, \"a\" );\n// {\n// value: 2,\n// writable: true,\n// enumerable: true,\n// configurable: true\n// }\n```\n\nКак видно, дескриптор свойства (называемый «дескриптором данных», поскольку он хранит только значение данных) для нашего обычного свойства `a` это больше чем просто его `value`, равное `2`.\n\nПоскольку мы знаем значения по умолчанию для характеристик дескриптора свойств при создании обычного свойства, мы можем использовать `Object.defineProperty(..)` для добавления нового или изменения существующего свойства (если оно является `configurable`!) с желаемыми характеристиками.\n\nНапример:\n\n\n```js\nvar myObject = {};\nObject.defineProperty( myObject, \"a\", {\n    value: 2,\n    writable: true,\n    configurable: true,\n    enumerable: true\n} );\nmyObject.a; // 2\n```\n\nС помощью `defineProperty(..)` мы вручную добавили простое, обычное свойство `a` к объекту `myObject` в явном виде. Как бы то ни было, в общем случае вам не придется использовать ручной способ, пока вы не захотите изменить обычное поведение характеристик дескриптора.\n\n#### Перезаписываемое\n\nВозможность изменить значение свойства контролируется характеристикой `writable`.\n\nРассмотрим:\n\n```js\nvar myObject = {};\nObject.defineProperty( myObject, \"a\", {\n    value: 2,\n    writable: false, // не перезаписываемо!\n    configurable: true,\n    enumerable: true\n} );\nmyObject.a = 3;\nmyObject.a;         // 2\n```\n\nКак видите, наша попытка модифицировать `value` не удалась, при этом мы не получили никакого уведомления об этом. В строгом режиме `strict mode` мы получим ошибку:\n\n```js\n\"use strict\";\nvar myObject = {};\nObject.defineProperty( myObject, \"a\", {\n    value: 2,\n    writable: false, // не перезаписываемо!\n    configurable: true,\n    enumerable: true\n} );\nmyObject.a = 3;     // TypeError\n```\n\n`TypeError` говорит о том, что мы не можем изменить неперезаписываемое свойство\n\n**Примечание**: Мы скоро обсудим геттеры и сеттеры, но вкратце, вы можете заметить, что `writable:false` означает, что значение нельзя изменить. Это отчасти равносильно указанию NOOP-сеттера. На самом деле, чтобы действительно соответствовать `writable:false` ваш NOOP-сеттер при вызове должен выдавать `TypeError`.\n\n#### Конфигурируемое\n\nПока свойство является конфигурируемым, мы можем изменять описание дескриптора, используя всё тот же инструмент `defineProperty(..)`.\n\n```js\nvar myObject = {\n    a: 2\n};\nmyObject.a = 3;\nmyObject.a;\t// 3\nObject.defineProperty( myObject, \"a\", {\n    value: 4,\n    writable: true,\n    configurable: false,\t// не конфигурируемо!\n    enumerable: true\n} );\nmyObject.a;\t// 4\nmyObject.a = 5;\nmyObject.a;\t// 5\nObject.defineProperty( myObject, \"a\", {\n    value: 6,\n    writable: true,\n    configurable: true,\n    enumerable: true\n} );        // TypeError\n```\n\nПоследний вызов `defineProperty(..)` приводит к ошибке TypeError, вне зависимости от `strict mode`, если вы пытаетесь изменить значение дескриптора неконфигурируемого свойства. Осторожно: как видите, изменение `configurable` на `false` необратимо и его нельзя отменить.\n\n**Примечание**: существует особенное исключение, о котором стоит помнить: если для свойства уже задано `configurable:false`, то `writable` может быть изменено с `true` на `false` без ошибки, но не обратно в `true` если оно уже `false`.\n\nА еще `configurable:false` препятствует возможности использовать оператор `delete` для удаления существующего свойства.\n\n```js\nvar myObject = {\n    a: 2\n};\nmyObject.a;     // 2\ndelete myObject.a;\nmyObject.a;     // undefined\nObject.defineProperty( myObject, \"a\", {\n    value: 2,\n    writable: true,\n    configurable: false,\n    enumerable: true\n} );\nmyObject.a;     // 2\ndelete myObject.a;\nmyObject.a;     // 2\n```\n\nКак видите, последний вызов `delete` не удался (без уведомления), потому что мы сделали свойство `a` неконфигурируемым.\n\n`delete` используется только для удаления свойств объекта (которое может быть удалено) напрямую из указанного объекта. Если свойство объекта -- это последняя оставшаяся *ссылка* на некоторый объект/функцию и вы удаляете его, то ссылка удалится и теперь не имеющий ссылок объект/функция могут быть убраны сборщиком мусора.\n\n#### Перечисляемое\n\nПоследнее свойство дескриптора, о котором мы расскажем (есть еще два других, с которыми мы будем иметь дело, когда обсудим геттеры/сеттеры), это `enumerable`.\n\nВозможно, это очевидно из названия, но этот параметр указывает, появится ли свойство в определенных перечислениях свойств объекта, таких как цикл `for..in`. Установите `false`, чтобы свойство не появлялось в подобных перечислениях, даже если оно по-прежнему полностью доступно. Установите `true`, чтобы оно присутствовало.\n\nВсе нормальные свойства, заданные пользователем, по умолчанию являются `enumerable`, поскольку обычно это то, что вам нужно. Но если у вас есть особенное свойство, которое вы хотите спрятать от перечислений, установите для него `enumerable:false`.\n\nМы скоро продемонстрируем перечисляемость более подробно, так что возьмите ее себе на заметку.\n\n### Иммутабельность\n\nИногда требуется создать свойства или объекты, которые не могут быть изменены (случайно или преднамеренно). ES5 добавляет для работы с этим несколько различных способов с определенными тонкостями.\n\nВажно отметить, что **всё** это -- попытки создать неглубокую иммутабельность. Они влияют только на объект и характеристики его непосредственных свойств. Если объект содержит указатель на другой объект (массив, объект, функцию и т.д.), то *содержимое* другого объекта не будет затронуто и останется изменяемым.\n\n```js\nmyImmutableObject.foo; // [1,2,3]\nmyImmutableObject.foo.push( 4 );\nmyImmutableObject.foo; // [1,2,3,4]\n```\n\nВ этом фрагменте мы предполагаем, что `myImmutableObject` уже создан и защищен как иммутабельный. Но, чтобы также защитить содержимое `myImmutableObject.foo` (которое само по себе является объектом-массивом), вам также нужно сделать иммутабельным `foo`, используя один или несколько следующих способов.\n\n**Примечание**: Нет ничего страшного в создании глубоко укоренившихся неизменяемых объектов в программах на JS. Особые случаи определённо требуют этого, но в качестве общего шаблона проектирования, если вы обнаружите у себя желание *запечатать* или *заморозить* все объекты, вы можете сделать шаг назад и пересмотреть структуру программы, чтобы сделать её более устойчивой к возможным изменениям в значениях объектов.\n\n#### Константа объекта\n\nКомбинируя `writable:false` и `configurable:false` вы по сути можете создать *константу* (не может быть изменена, переопределенна или удалена) в качестве свойства объекта, вроде:\n\n```js\nvar myObject = {};\nObject.defineProperty( myObject, \"FAVORITE_NUMBER\", {\n    value: 42,\n    writable: false,\n    configurable: false\n} );\n```\n\n#### Запрет расширения\n\nЕсли вы хотите запретить добавление новых свойств объекта, но в то же время оставить существующие свойства нетронутыми, используйте `Object.preventExtensions(..)`\n\n\n```js\nvar myObject = {\n    a: 2\n};\nObject.preventExtensions( myObject );\nmyObject.b = 3;\nmyObject.b; // undefined\n```\n\nВ `нестрогом режиме`, создание `b` завершится неудачей без ошибок. В `строгом режиме` это приведет к ошибке `TypeError`.\n\n#### Запечатывание\n\nМетод `Object.seal(..)` создает «запечатанный» объект -- то есть принимает существующий объект и, по сути, применяет к нему `Object.preventExtensions(..)`, но также помечает все существующие свойства как `configurable:false`.\n\nТаким образом, вы не можете не только добавлять свойства, но и переконфигурировать или удалить существующие (хотя вы всё еще *можете* изменять их значения).\n\n#### Заморозка\n\nМетод `Object.freeze(..)` создает замороженный объект, что означает, что он принимает существующий объект и по сути применяет к нему `Object.seal(..)`, но также помечает все свойства «доступа к данным» как `writable:false`, так, что их значения не могут быть изменены.\n\nЭтот подход дает наивысший уровень иммутабельности, который вы можете получить для самого объекта, поскольку он предотвращает любые изменения в объекте или его непосредственных свойствах (хотя, как сказано выше, содержимое любых других привязанных объектов не затрагивается).\n\nВы можете «глубоко заморозить» объект, применив `Object.freeze(..)` к объекту и рекурсивно перебрать все объекты, на которые он ссылается (которые еще не были затронуты) применив к ним `Object.freeze(..)`. Однако, будьте осторожны, поскольку это может затронуть другие (общие) объекты, которые вы не планировали менять.\n\n### `[[Get]]`\n\nЕсть одна маленькая, но важная деталь, связанная с тем, как происходит доступ к свойствам.\n\nРассмотрим:\n\n```js\nvar myObject = {\n    a: 2\n};\nmyObject.a; // 2\n```\n\n`myObject.a` -- это запрос свойства, но он не *просто* ищет в `myObject` свойство с именем `a`, как может показаться.\n\nСогласно спецификации, код выше выполняет операцию `[[Get]]` (что-то вроде вызова функции `[[Get]]()`) с объектом `myObject`. Стандартная встроенная операция `[[Get]]` проверяет объект на наличие запрашиваемого свойства и, если находит его, то возвращает соответствующее значение.\n\nОднако, в алгоритме `[[Get]]` описано важное поведение для случая, когда она *не* находит запрошенное свойство. В главе 5 мы узнаем что происходит *дальше* (обход по цепочке `[[Prototype]]`, если что).\n\nНо один из важных результатов операции `[[Get]]` заключается в том, что, если она по какой-либо причине не может найти значение запрошенного свойства, то вернёт значение `undefined`.\n\n```js\nvar myObject = {\n    a: 2\n};\nmyObject.b; // undefined\n```\n\nЭто поведение отличается от случая, когда вы обращаетесь к *переменным* по имени их идентификатора. Если вы запросите переменную, которая не может быть найдена с помощью поиска по лексической области видимости, то результатом будет не `undefined`, как у свойств объекта, а ошибка `ReferenceError`.\n\n```js\nvar myObject = {\n    a: undefined\n};\nmyObject.a; // undefined\nmyObject.b; // undefined\n```\n\nС точки зрения *значения*, нет разницы между этими двумя вызовами -- они оба выдадут `undefined`. Однако внутри операции `[[Get]]`, хоть это и не заметно на первый взгляд, потенциально выполняется немного больше «работы» для вывода `myObject.b`, чем для вывода `myObject.a`.\n\nПроверяя лишь результаты вывода значения, вы не можете отличить когда существует свойство, явно содержащее значение `undefined`, а когда свойство *не* существует и `undefined` -- это значение, по умолчанию возвращаемое, если `[[Get]]` не может вернуть нечто определённое.\n\n### `[[Put]]`\n\nПоскольку существует встроенная операция `[[Get]]` для получения значения свойства, очевидно, должна существовать и стандартная операция `[[Put]]`.\n\nЗаманчиво думать, что назначение свойства объекту просто вызовет `[[Put]]`, чтобы задать или создать это свойство для запрашиваемого объекта. Но ситуация сложнее, чем кажется.\n\nПоведение `[[Put]]` при вызове зависит от нескольких факторов, включая (наиболее значимый): существует ли такое свойство у объекта или нет.\n\nЕсли свойство существует, то алгоритм `[[Put]]` проверит примерно следующее:\n\n1. Является ли свойство дескриптором доступа (смотрите раздел «Геттеры и Сеттеры» ниже)? **Если да, то вызовет сеттер, если он есть.**\n2. Является ли свойство дескриптором данных с ключом `writable` равным `false`? **Если да, то тихо завершится в нестрогом режиме [`non-strict mode`], или выдаст ошибку `TypeError` в строгом режиме [`strict mode`].**\n3. Иначе, установит значение существующего свойства как обычно.\n\nЕсли свойство запрашиваемого объекта еще не задано, то операция `[[Put]]` еще более сложная и запутанная. Мы вернемся к этому сценарию в Главе 5, когда обсудим `[[Prototype]]`, чтобы внести больше ясности.\n\n### Геттеры и Сеттеры\n\nСтандартные операции объектов `[[Put]]` и `[[Get]]` полностью контролируют, как значения задаются для существующих или новых свойств и, соответственно, запрашиваются из существующих свойств.\n\n**Примечание**: При использовании будущих/расширенных возможностей языка можно переопределить стандартные операции `[[Get]]` или `[[Put]]` для всего объекта (а не только для свойства). Данная тема выходит за рамки обсуждения этой книги, но будет охвачена позже в серии «Вы не знаете JS».\n\nES5 представил способ переопределения части этих стандартных операций не на уровне объекта, а на уровне свойств, через использование геттеров и сеттеров. Геттеры -- это свойства, которые, на самом деле, вызывают скрытую функцию для получения значения. Сеттеры -- это свойства, которые, на самом деле, вызывают скрытую функцию для задания значения.\n\nКогда вы задаете свойству геттер или сеттер, оно определяется как «дескриптор доступа» (в противовес «дескриптору данных»). Для дескрипторов доступа, характеристики дескриптора `value` и `writable` игнорируются, а вместо этого JS рассматривает характеристики свойства `set` и `get` (а также `configurable` и `enumerable`).\n\nРассмотрим:\n\n```js\nvar myObject = {\n    // определяем геттер для `a`\n    get a() {\n        return 2;\n    }\n};\nObject.defineProperty(\n    myObject,\t// цель\n    \"b\",\t    // имя свойства\n    {\t// дескриптор\n        // определяем геттер для `b`\n        get: function(){ return this.a * 2 },\n        // убедимся что `b` будет отображаться как свойство объекта\n        enumerable: true\n    }\n);\nmyObject.a; // 2\nmyObject.b; // 4\n```\n\nКак в объектно-литеральном синтаксисе с использованием `get a() { .. }`, так и с помощью явного определения через `defineProperty(..)` мы создали свойство объекта, которое на самом деле не содержит значение, но доступ к которому приводит к вызову функции-геттера, чьё возвращаемое значение и будет результатом обращения к свойству.\n\n```js\nvar myObject = {\n    // определяем геттер для `a`\n    get a() {\n        return 2;\n    }\n};\nmyObject.a = 3;\nmyObject.a; // 2\n```\n\nПоскольку мы определили геттер для `a`, то если мы попытаемся установить значение `a`, операция не выдаст ошибки, а молча отбросит присваивание. Даже если бы тут был валидный сеттер, в нашем геттере жестко прописано вернуть только `2`, так что операция присваивания будет спорной.\n\nЧтобы сделать этот сценарий более разумным, свойства должны быть заданы с помощью сеттеров, которые переопределяют стандартную операцию `[[Put]]` (известную как присваивание) для каждого свойства, как вы того и ожидали. Скорее всего, вы захотите всегда объявлять и геттер, и сеттер (наличие только одного из них часто приводит к непредсказуемому/удивительному поведению):\n\n```js\nvar myObject = {\n    // определим геттер для `a`\n    get a() {\n        return this._a_;\n    },\n    // определим сеттер для `a`\n    set a(val) {\n        this._a_ = val * 2;\n    }\n};\nmyObject.a = 2;\nmyObject.a; // 4\n```\n\n**Примечание**: В этом примере мы на самом деле сохраняем указанное значение присваивания `2` (операция `[[Put]]`) в другой переменной `_a_`. Имя `_a_` здесь чисто для примера и не означает никакого особенного поведения -- это обычное свойство, как и любое другое.\n\n### Существование\n\nРанее мы показали, что запрос свойства вроде `myObject.a` может вывести значение `undefined`, как в случае, когда там явно задано `undefined`, так и в случае, когда свойство `a` вообще не существует. Если в обоих случаях значение одинаково, как же нам их различить?\n\nМы можем спросить есть ли у объекта свойство, не запрашивая значение свойства:\n\n```js\nvar myObject = {\n    a: 2\n};\n(\"a\" in myObject);\t            // true\n(\"b\" in myObject);\t            // false\nmyObject.hasOwnProperty( \"a\" );\t// true\nmyObject.hasOwnProperty( \"b\" );\t// false\n```\n\nОператор `in` проверит находится ли свойство `в` объекте или существует ли оно уровнем выше в цепочке `[[Prototype]]` объекта (смотрите Главу 5). `hasOwnProperty(..)` наоборот проверяет есть ли свойство *только* у объекта `myObject` или нет и *не* опрашивает цепочку `[[Prototype]]`. Мы еще вернёмся к важным различиям между этими двумя операциями в Главе 5, когда исследуем `[[Prototype]]` более подробно.\n\nМетод `hasOwnProperty(..)` доступен для всех нормальных объектов через делегирование `Object.prototype` (см. Главу 5). Но можно создать объект, который не привязан к `Object.prototype` (с помощью`Object.create(null)` -- см. Главу 5). В этом случае, вызвать метод `myObject.hasOwnProperty(..)` не получится.\n\nПри таком сценарии более надежным способом выполнить подобную проверку будет `Object.prototype.hasOwnProperty.call(myObject,\"a\")`, который заимствует базовый метод `hasOwnProperty` и использует *явную привязку `this`* (см. Главу 2), чтобы применить его к нашему `myObject`.\n\n**Примечание**: Оператор `in` выглядит так, будто он проверяет существование *значения* внутри контейнера, но, на самом деле, он проверяет существование имени свойства. Это отличие важно учитывать применительно к массивам, поскольку велик соблазн сделать проверку вроде `4 in [2, 4, 6]`, но она не будет вести себя так, как вы ожидали.\n\n#### Перечисление\n\nРанее мы кратко объяснили идею «перечисляемости», когда рассматривали `enumerable` -- характеристику дескриптора свойства. Давайте вернемся и рассмотрим её более подробно.\n\n```js\nvar myObject = { };\nObject.defineProperty(\n    myObject,\n    \"a\",\n    // сделаем `a` перечисляемой, как обычно\n    { enumerable: true, value: 2 }\n);\nObject.defineProperty(\nmyObject,\n    \"b\",\n    // сделаем `b` НЕперечисляемой\n    { enumerable: false, value: 3 }\n);\nmyObject.b;                     // 3\n(\"b\" in myObject);              // true\nmyObject.hasOwnProperty( \"b\" ); // true\n// .......\nfor (var k in myObject) {\n    console.log( k, myObject[k] );\n}\n// \"a\" 2\n```\n\nВы заметите, что `myObject.b` по факту **существует** и имеет доступное значение, но оно не отображается в цикле `for..in` (хотя, внезапно, оно *обнаружилось* проверкой на существование оператором `in`). Всё потому, что по сути «перечислимое» означает «будет учтено, если пройти перебором по свойствам объекта»).\n\n**Примечание**: Использование циклов `for..in` с массивами может выдать неожиданный результат, поскольку перечисление массива будет включать не только все численные индексы, но также перечисляемые свойства. Хорошая идея использовать циклы `for..in` *только* с объектами, а традиционные циклы `for` для перебора по численным индексам значений, хранящихся в массивах.\n\nЕще один способ определить перечисляемые и неперечисляемые свойства:\n\n\n```js\nvar myObject = { };\nObject.defineProperty(\n    myObject,\n    \"a\",\n    // сделаем `a` перечисляемым, как обычно\n    { enumerable: true, value: 2 }\n);\nObject.defineProperty(\n    myObject,\n    \"b\",\n    // сделаем `b` неперечисляемым\n    { enumerable: false, value: 3 }\n);\nmyObject.propertyIsEnumerable( \"a\" );   // true\nmyObject.propertyIsEnumerable( \"b\" );   // false\nObject.keys( myObject );                // [\"a\"]\nObject.getOwnPropertyNames( myObject ); // [\"a\", \"b\"]\n```\n\n`propertyIsEnumerable(..)` проверяет существует ли данное имя свойства *непосредственно* в объекте и установлено ли `enumerable:true`.\n\n`Object.keys(..)` возвращает массив всех перечисляемых свойств, в то время как `Object.getOwnPropertyNames(..)` возвращает массив *всех* свойств -- перечисляемых или нет.\n\nОтличия `in` от `hasOwnProperty(..)` в том, опрашивают ли они цепочку `[[Prototype]]` или нет. В то время как `Object.keys(..)` и `Object.getOwnPropertyNames(..)` проверяют *только* конкретный указанный объект.\n\nНе существует (пока) встроенного способа получить список **всех свойств**, эквивалентного тому, как опрашивает оператор  `in` (перебирая все свойства по всей цепочке `[[Prototype]]`, как описано в Главе 5). Приблизительно, такой инструмент можно сделать, если рекурсивно перебирать цепочку `[[Prototype]]` объекта и на каждом уровне выбирать список из `Object.keys(..)` -- только перечисляемых свойств.\n\n## Итерация\n\nЦикл `for..in` проходит по списку перечисляемых свойств объекта (включая его цепочку `[[Prototype]]`). Но что, если вместо этого вы хотите перебрать именно значения?\n\nВ массивах с числовыми индексами перебор значений обычно выполняется стандартным циклом `for`, вроде:\n\n```js\nvar myArray = [1, 2, 3];\nfor (var i = 0; i < myArray.length; i++) {\n    console.log( myArray[i] );\n}\n// 1 2 3\n```\n\nЭто не перебор значений, а перебор индексов, где вы используете индекс для получения значения, наподобие `myArray[i]`.\n\nES5 добавил несколько вспомогательных итераторов для массивов, включая `forEach(..)`, `every(..)`, и `some(..)`. Каждый из этих помощников принимает функцию обратного вызова для каждого элемента массива. Отличия только в том, как они реагируют на значение, возвращаемое этой функцией.\n\n`forEach(..)` перебирает все значения массива и игнорирует любые значения, возвращаемые функцией обратного вызова. `every(..)` продолжает перебор до конца *или* пока функция не вернёт `false` (или «ложное» значение), в то время как `some(..)` продолжает до конца *или* пока функция не вернёт значение `true` (или «истинное» значение).\n\nЭти специальные возвращаемые значения внутри `every(..)` и `some(..)` действуют наподобие инструкции `break` внутри обычного цикла, поскольку они прекращают перебор задолго до конца.\n\nЕсли вы перебираете объект циклом `for..in`, вы также лишь косвенно запрашиваете значения, поскольку он, на самом деле, перебирает только перечисляемые свойства объекта, заставляя вас обращаться к свойствам вручную для получения значений.\n\n**Примечание:** В противовес перебору индексов массива в числовой последовательности (циклы `for` или другие итераторы), порядок перебора свойств объекта *не гарантирован* и может различаться в разных движках JS. **Не полагайтесь** на любую наблюдаемую последовательность для всего, что требует постоянства окружения, поскольку любое наблюдаемое ненадежно.\n\nНо что если вместо индексов массива (или свойств объекта) вы хотите перебрать значения напрямую? К счастью, ES6 добавляет синтаксис цикла `for..of` для перебора массивов (и объектов, если объект определяет свой собственный итератор).\n\n\n```js\nvar myArray = [ 1, 2, 3 ];\nfor (var v of myArray) {\n    console.log( v );\n}\n// 1\n// 2\n// 3\n```\n\nЦикл `for..of` запрашивает объект-итератор (из стандартной встроенной функции, на языке спецификации известной как `@@iterator`) у перебираемой сущности, а затем перебирает возвращаемые значения, вызывая метод `next()` объекта-итератора для каждой итерации цикла.\n\nМассивы имеют встроенный `@@iterator`, поэтому `for..of` легко работает с ними, как показано выше. Давайте переберем массив вручную, используя встроенный `@@iterator`, чтобы посмотреть как он работает:\n\n```js\nvar myArray = [ 1, 2, 3 ];\nvar it = myArray[Symbol.iterator]();\nit.next(); // { value:1, done:false }\nit.next(); // { value:2, done:false }\nit.next(); // { value:3, done:false }\nit.next(); // { done:true }\n```\n\n**Примечание:** В `@@iterator` мы получаем *внутреннее свойство* объекта, используя `Symbol` из ES6: `Symbol.iterator`. Мы уже упоминали семантику `Symbol` ранее в этой главе (см. «Вычисляемые имена свойств»), здесь применяются те же рассуждения. Как правило, вы захотите обращаться к таким особенным свойствам через имя `Symbol`, а не через специальное значение, которое оно может содержать. Не смотря на подтекст в названии, `@@iterator` является **не объектом-итератором**, а **функцией, возвращающей** объект-итератор -- маленькая, но важная деталь.\n\nКак показывает фрагмент выше, значение, которое возвращает вызов `next()` итератора, -- это объект вида `{ value: .. , done: .. }`, где `value` -- это значение текущей итерации, а `done` -- это `boolean`, показывающее, остались ли элементы для перебора.\n\nОбратите внимание, что значение `3` вернулось вместе с `done:false`, что на первый взгляд может показаться странным. Вам нужно вызвать `next()` четвертый раз (что автоматически делает `for..of` из предыдущего фрагмента) чтобы получить `done:true` и понять, что вы действительно закончили перебор. Причина такого костыля находится за рамками текущего обсуждения, но она исходит из семантики генерирующих функций стандарта ES6.\n\nВ то время, как массивы автоматически перебираются циклами `for..of`, обычные объекты **не имеют встроенного `@@iterator`**. Причины такого намеренного упущения намного сложнее чем то, что мы рассмотрим. В общих чертах, правильным было решение не добавлять реализацию, которая будет проблемной для будущих типов объектов.\n\nДля перебора любого объекта *можно* определить свой собственный стандартный `@@iterator`. Например:\n\n```js\nvar myObject = {\n    a: 2,\n    b: 3\n};\nObject.defineProperty( myObject, Symbol.iterator, {\n    enumerable: false,\n    writable: false,\n    configurable: true,\n    value: function() {\n        var o = this;\n        var idx = 0;\n        var ks = Object.keys( o );\n        return {\n            next: function() {\n                return {\n                    value: o[ks[idx++]],\n                    done: (idx > ks.length)\n                };\n            }\n        };\n    }\n} );\n// перебираем `myObject` вручную\nvar it = myObject[Symbol.iterator]();\nit.next(); // { value:2, done:false }\nit.next(); // { value:3, done:false }\nit.next(); // { value:undefined, done:true }\n// перебираем `myObject` с помощью `for..of`\nfor (var v of myObject) {\n    console.log( v );\n}\n// 2\n// 3\n```\n\n**Примечание:** Мы использовали `Object.defineProperty(..)` чтобы задать свой `@@iterator` (в основном для того, чтобы сделать его неперечисляемым), но, используя `Symbol` как *рассчитанное имя свойства* (описанное ранее в этой главе), мы могли бы объявить его напрямую, вроде `var myObject = { a:2, b:3, [Symbol.iterator]: function(){ /* .. */ } }`.\n\nКаждый раз, когда цикл `for..of` вызовет `next()` из итератора объекта `myObject`, внутренний указатель переместится и вернёт следующее значение из списка свойств объекта (см. примечание о порядке перебора свойств/значений объекта).\n\nМы продемонстрировали простой перебор «значение за значением», но вы, конечно, можете задать перебор произвольной сложности для своих структур данных так, как вам будет удобней. Самодельные итераторы вкупе с циклом `for..of` из ES6 -- мощный инструмент для работы с объектами, определяемыми пользователем.\n\nНапример, для списка объектов `Pixel` (со значениями координат `x` и `y`) можно упорядочить перебор в зависимости от линейного расстояния до начала координат `(0,0)` или отфильтровать точки, которые расположены «слишком далеко». Пока ваш итератор возвращает предполагаемое `{ value: .. }`, возвращает значения при вызове `next()` и `{ done: true }`, когда перебор завершен, цикл `for..of` стандарта ES6 сможет выполнить перебор.\n\nФактически, вы можете сгенерировать «бесконечные» итераторы, которые никогда не «завершатся» и всегда будут возвращать новое значение (вроде случайного числа, инкрементированного значения, уникального идентификатора и т.д.), хотя, скорее всего, вы не захотите использовать такие итераторы в неограниченном цикле `for..of`, поскольку он никогда не закончится и повесит вашу программу.\n\n```js\nvar randoms = {\n    [Symbol.iterator]: function() {\n        return {\n            next: function() {\n                return { value: Math.random() };\n            }\n        };\n    }\n};\nvar randoms_pool = [];\nfor (var n of randoms) {\n    randoms_pool.push( n );\n    // не продолжаем бесконечно!\n    if (randoms_pool.length === 100) break;\n}\n```\n\nЭтот итератор будет генерировать случайные числа «вечно», поэтому мы позаботились о том, чтобы получить только 100 значений, и наша программа не зависла.\n\n## Обзор (TL;DR)\n\nОбъекты в JS имеют литеральную форму (вроде `var a = { .. }`) и конструкторную форму (вроде `var a = new Array(..)`). Литеральная форма почти всегда предпочтительнее, но конструкторная форма в некоторых случаях предлагает больше опций при создании.\n\nМногие ошибочно заявляют, что «в JS всё является объектом», но это некорректно. Объекты -- это один из 6 (или 7, в зависимости от ваших взглядов) примитивных типов. Существуют подтипы объектов, в том числе `function`, а также подтипы со специальным поведением, наподобие `[object Array]`, представляющего внутреннее обозначение такого подтипа объекта, как массив.\n\nОбъекты -- это коллекции ключ-значение. Значения могут быть получены через свойства, посредством синтаксиса `.propName` или `[\"propName\"]`. Вне зависимости от синтаксиса, движок вызывает встроенную стандартную операцию `[[Get]]` (и `[[Put]]` для установки значений), которая не только ищет свойство непосредственно в объекте, но и перемещается по цепочке `[[Prototype]]` (см. Главу 5), если свойство не найдено.\n\nУ свойств есть определенные характеристики, которыми можно управлять через дескрипторы свойств, такие как `writable` и `configurable`. В дополнение, мутабельностью объектов (и их свойств) можно управлять на разных уровнях иммутабельности, используя `Object.preventExtensions(..)`, `Object.seal(..)`, и `Object.freeze(..)`.\n\nСвойства не обязательно содержат значения -- они могут быть также «свойствами доступа» с геттерами/сеттерами. Они могут быть *перечисляемыми* или нет, что влияет на их появление в итерациях цикла, например `for..in`.\n\nВы также можете перебирать **значения** структур данных (массивов, объектов и т.п.) используя синтаксис ES6 `for..of`, который ищет встроенный или самодельный объект `@@iterator`, содержащий метод `next()` для перебора значений по одному.\n"
  },
  {
    "path": "this & object prototypes/ch4.md",
    "content": "# Вы не знаете JS: This и Прототипы Объектов\n# Глава 4: Смешивая объекты \"классов\"\n\nПродолжая исследование объектов, начатое в предыдущей главе, вполне естественно, что теперь мы обратим внимание на «объектно-ориентированное (OO) программирование», с «классами».  Мы рассмотрим «класс-ориентированность» в качестве шаблона проектирования, прежде чем изучать механику «классов»: «создание экземпляров», «наследование» и «(относительный) полиморфизм».\n\nМы увидим, что эти понятия на самом деле не очень хорошо соотносятся с механизмами работы с объектами в JS (mixins и т. д.), и усилия, которые многие разработчики JavaScript прикладывают, чтобы это преодолеть.\n\n**Примечание:** В этой главе уделяется довольно много внимания (первая половина!) тяжеловесной  теории «объективно-ориентированного программирования». В конце концов, мы свяжем эти идеи с реальным JavaScript кодом во второй половине, где мы поговорим о «миксинах (mixins)». Но рассмотрим много концепций и псевдокода прежде, чем продвинуться вперед, поэтому не теряйтесь - просто потерпите!\n\n## Теория классов\n\n\"Классовое наследование\" описывает определенный подход к архитектуре и организации кода - способ моделирования реальных проблемных областей в нашем программном обеспечении.\n\nОО или класс-ориентированное программирование делает акцент на том, что данные в действительности имеют схожее поведение (конечно, разное в зависимости от типа и природы данных!), влияющее на них, поэтому соответствующий дизайн должен упаковать (ака, инкапсулировать) данные и их поведение вместе. В формальной информатике это иногда называют \"структурами данных\".\n\nНапример, некая последовательность символов, представляющая собой слово или фразу, обычно называется \"строка\". Данными здесь являются символы. Но вам почти никогда не интересны данные, обычно Вы хотите с этими данными *что-то делать*, поэтому все операции, которые могут применяться *к* этим данным (вычисление длины, добавление данных, поиск и т. д.) разработаны как методы класса 'String'.\n\nЛюбая данная строка просто является экземпляром этого класса, что означает, что это аккуратно собранная упаковка как символьных данных, так и функциональности, которую мы можем к ним применить.\n\nКлассы также подразумевают *классификацию* определенной структуры данных. Мы это делаем, воспринимая любую данную структуру как конкретную вариацию более общего базового определения.\n\nДавайте рассмотрим этот процесс \"классификации\" на часто используемом примере: *автомобиль* можно описать как некую частную реализацию более общего \"класса\" предметов, называемого *транспортные средства*.\n\nВ программном обеспечении мы моделируем данную связь с помощью классов, определяя класс `транспортные средства` и класс `автомобиль`.\n\nОпределение `транспортные средства` может включать в себя такие понятия, как силовая установка (ДВС и т. д.), способность перевозить людей, и так далее, все это будет неким поведением класса. Все, что мы определяем в \"транспортном средстве\", - это принципы, являющиеся общими для всех (или большинства) возможных типов транспортных средств (\"самолеты, поезда и автомобили\").\n\nВозможно, нет смысла снова и снова переопределять в нашей программе базовую сущность \"способности перевозить людей\" для каждого типа транспортного средства. Вместо этого мы определим данную возможность один раз в \"транспортном средстве\", а далее, описывая \"автомобиль\", мы просто укажем, что он \"наследует\" (или \"расширяет\") базовое определение от \"транспортного средства\". Определение \"автомобиля\", как говорят, уточняет, общее определение \"транспортного средства\".\n\nВ то время как `транспортное средство` и `автомобиль` определяют поведение посредством методов, данными экземпляра будут такие вещи, как уникальный VIN конкретного автомобиля и т. д.\n\n**Таким образом возникают классы, наследование и создание экземпляров.**\n\nДругим ключевым понятием касательно классов является \"полиморфизм\", который описывает идею о том, что общее поведение, описанное в родительском классе может быть переопределено в дочернем классе, чтобы придать ему больше конкретики. Фактически, относительный полиморфизм позволяет нам ссылаться на базовое поведение из переопределенного.\n\nТеория классов предполагает, что родительский и дочерний классы разделяют название методов для описания определенного поведения, так что потомок переопределяет родительскую реализацию. Как мы увидим позже, подобные вещи в вашем JavaScript коде могут привести к разочарованию и хрупкости кода.\n\n### Шаблон проектирования \"Класс\"\n\nВозможно, вы никогда не смотрели на классы как на \"шаблон проектирования\", так как чаще всего обсуждаются популярные \"OO шаблоны проектирования\", такие как \"итератор\", \"наблюдатель\", \"фабрика\", \"синглтон\" и т.д. При этом сразу предполагается, что OO классы являются механизмами более низкого уровня, с помощью которых мы реализуем все шаблоны проектирования (более высокого уровня), как будто OO является единственно-верной основой для *всего* (правильного) кода.\n\nВ зависимости от вашего уровня формального образования в области программирования, вы, возможно, слышали о \"процедурном программировании\" как способе описания кода, который состоит только из процедур (ака, функций), вызывающих другие функции, без каких-либо более высокоуровневых абстракций. Возможно, вас учили, что классы были *правильным* способом преобразования процедурного \"спагетти-кода\" в хорошо оформленный организованный код.\n\nКонечно, если у вас есть опыт в \"функциональном программировании\" (монады и др.), вы хорошо знаете, что классы являются лишь одним из нескольких распространенных шаблонов проектирования. Но другие, возможно, впервые спросят себя, а действительно ли классы являются фундаментальной основой для написания кода, или они являются необязательной абстракцией.\n\nНекоторые языки (например, Java) не оставляют вам выбора, поэтому это вовсе не *опционально* - все это класс. Другие языки, такие как C/C++ или PHP, предоставляют вам как процедурные, так и классовые синтаксисы, и больше зависит от выбора разработчика, какой стиль или смесь стилей ему подойдет.\n\n### \"Классы\" JavaScript\n\nГде JavaScript начинает иметь к этому всему отношение? JS имеет *некоторые* синтаксические элементы, подобные классу (например, `new` и `instanceof`) довольно давно, а в последнее время в ES6 появились некоторые дополнения, такие как ключевое слово `class` (см. приложение A).\n\nНо значит ли это, что в JavaScript действительно *есть* классы? Строго и однозначно: **Нет.**\n\nПоскольку классы являются шаблоном проектирования, вы *можете*, приложив немало усилий (как мы увидим далее в этой главе), реализовать некоторое приближение для большей части классической функциональности класса. JS пытается удовлетворить чрезвычайно распространенное *желание* проектировать с классами, предоставляя, казалось бы, похожий на классы синтаксис.\n\nХотя у нас и может быть синтаксис, похожий на классы, это больше похоже на то, что механика JavaScript борется против того, чтобы вы использовали шаблон проектирования *class*. Так как под капотом механизмы, которые вы строите, работают совсем по-другому. Синтаксический сахар и (очень широко используемые) JS библиотеки для работы с \"классами\" проходят долгий путь скрывая эту реальность от вас, но рано или поздно вы столкнетесь с тем, что *классы* которые у вас есть в других языках не похожи на фейковые \"классы\", которые мы создаем себе в JS.\n\nВсе это сводится к тому, что классы не являются обязательным шаблоном при разработке программного обеспечения, и у вас есть выбор, использовать их в JavaScript или нет. Поскольку многие разработчики имеют сильную тягу к класс-ориентированному дизайну программного обеспечения, мы посвятим оставшуюся часть этой главы рассмотрению того, чего стоит поддержание иллюзии классов с использованием тех механизмов, что предоставляет JS, и тех проблем, которые мы при этом испытываем.\n\n## Механика Классов\n\nВо многих классовых языках \"стандартная библиотека\" предоставляет \"стековую\" структуру данных (push, pop и др.) как класс `Stack`. Этот класс имеет внутренний набор переменных, которые хранят данные, и набор публичных методов, которые дают вашему коду возможность взаимодействовать со (скрытыми) данными (добавление и удаление данных и т. д.).\n\nНо в подобных языках вы на самом деле не работаете непосредственно со `Stack` (если только речь не идет о **Static** члене класса, но это выходит за рамки нашего обсуждения). Класс `Stack` - это просто абстрактное описание того, что должен делать *любой* \"стек\", но это не *сам* \"стек\". Вы должны **создать экземпляр** класса `Stack`, прежде чем у вас будет конкретная структура данных *нечто* для работы с ней.\n\n### Строительство\n\nТрадиционная метафора понимания концепции «класс» и «экземпляр» основана на конструировании здания.\n\nАрхитектор планирует все характеристики здания: какова его ширина, высота, сколько окон и в каких местах, даже какой материал использовать для стен и крыши. На данном этапе архитектору не важно *где* будет построено здание, равно как и *сколько* копий этого здания будет построено.\n\nАрхитектор также не очень заботится о внутренностях здания - мебели, обоях, потолочных вентиляторах и т.д. - только о том, какой тип конструкции будет иметь здание.\n\nАрхитектурные проекты являются всего лишь *планами* здания. Они на самом деле не представляют собой здание, в которое мы можем войти и сесть. Нам нужен строитель для этой задачи. Строитель возьмет эти планы и будет следовать им по мере того, как он *строит* здание. Он «копирует» намеченные характеристики из планов в физическое здание.\n\nПосле завершения строительства это будет физическое воплощение планов, которые, как мы надеемся, по сути, будут идеальной копией. И тогда застройщик может перейти к открытому участку по соседству и сделать это снова, создав еще одну *копию*.\n\nОтношения между строительством и планом косвенные. Вы можете изучить чертеж, чтобы понять, как строилось здание, для любых частей, где прямой осмотр самого здания был недостаточен. Но если вы хотите открыть дверь, вы должны пойти в само здание - на чертеже просто нарисованы линии, которые *представляют*, где должна быть дверь.\n\nКласс - это план. Чтобы на самом деле *получить* объект, с которым мы можем взаимодействовать, мы должны построить (иначе, \"создать экземпляр\") что-то из класса. Конечным результатом такой «конструкции» является объект, обычно называемый «экземпляром», с помощью которого мы можем напрямую вызывать методы и обращаться к любым общедоступным свойствам данных при необходимости.\n\n**Этот объект является *копией*** всех характеристик, описанных классом.\n\nВы, вероятно, не ожидаете, что войдете в здание и найдете висящую в рамке на стене копию чертежей, используемых для планирования здания, хотя чертежи, вероятно, хранятся в государственном архиве. Точно так же вы обычно не используете экземпляр объекта для прямого доступа к его классу и манипулирования им, но, обычно, возможно, по крайней мере, определить, *из какого класса* исходит экземпляр объекта.\n\nБолее полезно рассмотреть прямую связь класса с экземпляром, а не любые косвенные отношения между экземпляром и классом, из которого он получен. **Класс создается в форме объекта с помощью операции копирования.**\n\n<img src = \"fig1.png\">\n\nКак видно, стрелки перемещаются слева направо и сверху вниз, что указывает на операции копирования, которые происходят как концептуально, так и физически.\n\n### Конструктор\n\nЭкземпляры классов создаются специальным методом класса, обычно с тем же именем, что и класс, называемым *конструктор*. Задача этого метода - инициализировать любую информацию (состояние), которая понадобится экземпляру.\n\nНапример, рассмотрим этот свободный псевдокод (изобретенный синтаксис) для классов:\n\n```js\nclass CoolGuy {\n\tspecialTrick = nothing\n\n\tCoolGuy( trick ) {\n\t\tspecialTrick = trick\n\t}\n\n\tshowOff() {\n\t\toutput( \"Зацените мой трюк: \", specialTrick )\n\t}\n}\n```\n\nЧтобы *сделать* экземпляр `CoolGuy`, мы бы вызвали конструктор класса:\n\n```js\nJoe = new CoolGuy( \"Прыжок через скакалку\" )\n\nJoe.showOff() // Зацените мой трюк: прыжок через скакалку\n```\n\nОбратите внимание, что класс `CoolGuy` имеет конструктор `CoolGuy()`, который фактически является тем, что мы вызываем, когда мы говорим `new CoolGuy (..)`. Обратно из конструктора мы получаем объект (экземпляр нашего класса), и мы можем вызвать метод `showOff()`, который выводит особый трюк `CoolGuy`.\n\n*Очевидно, прыжки со скакалкой делают Джо довольно крутым парнем.*\n\nКонструктор класса *принадлежит* классу, почти всегда с тем же именем, что и класс. Кроме того, конструкторы всегда нужно вызывать с помощью `new`, чтобы языковой движок знал, что вы хотите создать *новый* экземпляр класса.\n\n## Наследование классов\n\nВ класс-ориентированных языках вы можете не только определить класс, для которого можно создать сам экземпляр, но вы можете определить другой класс, который **наследуется** от первого класса.\n\nВторой класс часто называют «дочерним классом», тогда как первый - «родительским классом». Эти термины, очевидно, происходят из метафоры \"родители и дети\", хотя метафоры здесь немного растянуты, как вы скоро увидите.\n\nКогда у родителя есть биологический ребенок, генетические характеристики родителя копируются в ребенка. Очевидно, что в большинстве систем биологического размножения есть два родителя, которые в равной степени передают гены ребёнку. Но в нашей метафоре мы будем предполагать только одного родителя.\n\nКогда ребенок существует, он или она отделяется от родителя. Изначально ребенок находится под сильным влиянием наследования от своего родителя, но со временем начинает отличаться от него всё больше и больше. Если у ребенка появляются рыжие волосы, это не значит, что волосы родителя *были* или автоматически *становятся* рыжими.\n\nАналогичным образом, после определения дочернего класса он становится отдельным и отличным от родительского класса. Дочерний класс содержит начальную копию поведения от родителя, но затем может переопределить любое унаследованное поведение и даже определить новое поведение.\n\nВажно помнить, что мы говорим о родительских и дочерних **классах**, которые не являются физическими. Вот где метафора «родитель-ребенок» становится немного запутанной, потому что на самом деле мы должны сказать, что родительский класс похож на ДНК родителя, а дочерний класс похож на ДНК ребенка. Мы должны сделать (или «создать экземпляр») человека из каждого набора ДНК, чтобы на самом деле иметь живого собеседника.\n\nДавайте оставим в стороне биологических родителей и детей и рассмотрим наследование через несколько иную линзу: разные типы транспортных средств. Это одна из самых канонических (и часто достойных восклицания) метафор для понимания наследования.\n\nДавайте вернемся к обсуждению `Транспортное средство` и `Автомобиль`, описанному ранее в этой главе. Рассмотрим этот свободный псевдокод (изобретенный синтаксис) для унаследованных классов:\n\n```js\nclass Vehicle {\n\tengines = 1\n\n\tignition() {\n\t\toutput( \"Завожу двигатель.\" )\n\t}\n\n\tdrive() {\n\t\tignition()\n\t\toutput( \"Двигаюсь вперёд!\" )\n\t}\n}\n\nclass Car inherits Vehicle {\n\twheels = 4\n\n\tdrive() {\n\t\tinherited:drive()\n\t\toutput( \"Еду на всех \", wheels, \" колёсах!\" )\n\t}\n}\n\nclass SpeedBoat inherits Vehicle {\n\tengines = 2\n\n\tignition() {\n\t\toutput( \"Завожу мои \", engines, \" двигатели.\" )\n\t}\n\n\tpilot() {\n\t\tinherited:drive()\n\t\toutput( \"Скольжу по воде с ветерком!\" )\n\t}\n}\n```\n\n**Примечание:** Для ясности и краткости конструкторы для этих классов были опущены.\n\nМы определяем класс «Транспортное средство» - `Vehicle`, который предполагает двигатель, способ включения зажигания и способ передвижения. Но вы бы никогда не произвели просто универсальное «транспортное средство», так что на самом деле это просто абстрактная концепция.\n\nИтак, мы определяем два конкретных типа транспортных средств: «Автомобиль» - `Car` и «Скоростной катер» - `SpeedBoat`. Каждый из них наследует общие характеристики «Транспортного средства» - `Vehicle`, но затем они специализируют характеристики соответствующие для каждого вида. Автомобилю нужно 4 колеса, а скоростному катеру - 2 двигателя, а это значит, что для включения зажигания обоих двигателей требуется дополнительное внимание.\n\n### Полиморфизм\n\n`Car` определяет свой собственный метод `drive()`, который переопределяет метод с тем же именем, унаследованный от `Vehicle`. Но затем метод `drive()` из `Сar` вызывает `inherited:drive()`, что указывает на то, что `Car` может ссылаться на исходный предварительно переопределенный метод `drive()`, который он унаследовал. Метод `pilot()` из `SpeedBoat` также ссылается на его унаследованную копию `drive()`.\nЭта техника называется «полиморфизм» или «виртуальный полиморфизм». Приближённо к нашей теме, мы будем называть это «относительным полиморфизмом».\n\nПолиморфизм - гораздо более широкая тема, чем мы здесь рассмотрели, но наша текущая «относительная» семантика относится к одному конкретному аспекту: идее о том, что любой метод может ссылаться на другой метод (с тем же или другим именем) на более высоком уровне иерархии наследования. Мы говорим «относительный», потому что мы не определяем абсолютно к какому уровню наследования (классу) мы хотим получить доступ, а скорее ссылаемся на него, по сути, «на один уровень вверх».\n\nВо многих языках используется ключевое слово «super» вместо «inherited:», это основывается на идее, что «super class» является родителем/предком текущего класса.\n\nДругой аспект полиморфизма заключается в том, что имя метода может иметь несколько определений на разных уровнях цепочки наследования, и эти определения автоматически выбираются соответствующим образом при определении того, какие методы вызываются.\n\nМы видим два случая такого поведения в нашем примере выше: `drive()` определен как в `Vehicle`, так и в `Car`, а `ignition()` определен как в `Vehicle`, так и в `SpeedBoat`.\n\n**Примечание:** Еще одна вещь, которую дают вам традиционные класс-ориентированные языки через `super`, - это возможность прямо ссылаться на конструктор родительского класса из конструктора дочернего класса. Это в значительной степени верно, потому что с реальными классами конструктор принадлежит классу. Однако в JS все наоборот - на самом деле более уместно думать о «классе», принадлежащем конструктору (ссылки на типы `Foo.prototype ...`). Поскольку в JS отношения между дочерними и родительскими объектами существуют только между двумя объектами `.prototype` соответствующих конструкторов, сами конструкторы не связаны напрямую, и, следовательно, не существует простого способа ссылаться из одного конструктора в другой (см. Приложение A для ES6 `class`, который \"решает\" это с помощью `super`).\n\nИнтересное следствие полиморфизма можно увидеть именно с помощью функции `ignition()`. Внутри `pilot()` делается относительная-полиморфная ссылка на (унаследованную) версию `Vehicle` `drive()`. Но этот `drive()` ссылается на метод `ignition()` только по имени (без относительной ссылки).\n\nКакую версию `ignition()` будет использовать языковой движок: `Vehicle` или `SpeedBoat`? **Он использует версию SpeedBoat `ignition()`.** Если бы вы *должны были* создать экземпляр самого класса `Vehicle`, а затем вызвать его метод `drive()`, языковой движок использовал бы метод `ignition()` от `Vehicle`.\n\nДругими словами, определение для метода `ignition()` - *полиморфно* (изменяется) в зависимости от того, на какой класс (уровень наследования) вы ссылаетесь для экземпляра.\n\nЭто может показаться слишком глубокими академическими подробностями. Но понимание этих деталей необходимо для правильного сопоставления аналогичного (но отличного) поведения в механизме JavaScript `[[Prototype]]`.\n\nКогда классы наследуются, существует способ **для самих классов** (а не для созданных из них экземпляров!) *относительно* ссылаться на класс-источник наследования, и эта относительная ссылка обычно называется `super`.\n\nРанее мы рассматривали схему:\n\n<img src=\"fig1.png\">\n\nОбратите внимание, как для экземпляров (`a1`, `a2`, `b1` и `b2`) *и* наследования (`Bar`) стрелки указывают операцию копирования.\n\nКонцептуально может показаться, что дочерний класс `Bar` может обращаться к методам своего родительского `Foo`, используя относительную полиморфную ссылку (известную как `super`). Однако в действительности дочернему классу просто дается копия унаследованного поведения от его родительского класса. Если дочерний элемент «переопределяет» метод, который он наследует, то исходная и переопределенная версии метода фактически поддерживаются, так что обе версии метода доступны.\n\nНе позволяйте полиморфизму сбить вас с толку, думая, что дочерний класс связан с его родительским классом. Дочерний класс вместо этого получает копию того, что ему нужно, от родительского класса. **Дочерний класс подразумевает копии.**\n\n### Множественное наследование\n\nПомните наше предыдущее обсуждение родителей и детей, а также ДНК? Мы сказали, что метафора была немного странной, потому что биологически большинство потомков происходит от двух родителей. Если бы класс мог наследовать от двух других классов, он более точно соответствовал бы метафоре родитель / потомок.\n\nНекоторые ориентированные на классы языки позволяют указывать более одного «родительского» класса для «наследования». Множественное наследование означает, что каждое определение родительского класса копируется в дочерний класс.\n\nНа первый взгляд, это кажется мощным дополнением к возможностям классов, что позволяет нам объединить больше функциональных возможностей. Однако, безусловно, возникают некоторые сложные вопросы. Если оба родительских класса предоставляют метод с именем `drive()`, на какую версию ссылается ссылка `drive()` в дочернем элементе? Всегда ли вам нужно вручную указывать, какой родительский тип `drive()` вы имели в виду, теряя при этом некоторую грациозность полиморфного наследования?\n\nЕсть еще один вариант, так называемая «проблема алмазов», которая относится к сценарию, где дочерний класс «D» наследует от двух родительских классов («B» и «C»), а каждый из них, в свою очередь, наследуется от общего класса «A». «A» предоставляет метод `drive()`, и оба класса \"B\" и \"C\" переопределяют (полиморфируют) этот метод. Когда `D` ссылается на `drive()`, какую версию следует использовать (`B:drive()` или `C:drive()`)?\n\n<img src=\"fig2.png\">\n\nНо на деле всё ещё сложнее, чем кажется на первый взгляд. Мы рассматриваем это только для того, чтобы мы могли противопоставить работу механизмов JavaScript.\n\nJavaScript проще: он не предоставляет нативный механизм «множественного наследования». Многие считают, что это хорошо, потому что экономия на сложности более чем компенсирует «урезанную» функциональность языка. Но это не мешает разработчикам пытаться подделать его(механизм) различными способами, как мы увидим дальше.\n\n## Mixins - Примеси\n\nМеханизм объектов JavaScript не *автоматически* выполняет поведение копирования, когда вы «наследуете» или «создаете экземпляр». Проще говоря, в JavaScript нет «классов» для создания экземпляров, только объекты. И объекты не копируются в другие объекты, они *связываются вместе* (подробнее об этом в главе 5).\n\nПоскольку наблюдаемое поведение классов в других языках подразумевает наличие копий, давайте рассмотрим, как разработчики JS **подделывают** поведение копирования *отсутствующего* в JavaScript классах с помощью примесей(Mixins). Мы рассмотрим два типа «примесей»: **явные** и **неявные**.\n\n### Явные примеси\n\nДавайте снова вернемся к нашему примеру «Транспортное средство» - `Vehicle` и «Автомобиль» - `Car`. Поскольку JavaScript не будет автоматически копировать поведение из `Vehicle` в `Car`, мы можем вместо этого создать утилиту, которая будет это делать. Такая утилита часто называется `extend(..)` многими библиотеками / фреймворками, но мы будем называть ее `mixin(..)` здесь для наглядности.\n\n```js\n// значительно упрощенный пример `mixin(..)`:\nfunction mixin( sourceObj, targetObj ) {\n\tfor (var key in sourceObj) {\n\t\t// копируем только если его еще нет\n\t\tif (!(key in targetObj)) {\n\t\t\ttargetObj[key] = sourceObj[key];\n\t\t}\n\t}\n\n\treturn targetObj;\n}\n\nvar Vehicle = {\n\tengines: 1,\n\n\tignition: function() {\n\t\tconsole.log( \"Завожу двигатель.\" );\n\t},\n\n\tdrive: function() {\n\t\tthis.ignition();\n\t\tconsole.log( \"Двигаюсь вперёд!\" );\n\t}\n};\n\nvar Car = mixin( Vehicle, {\n\twheels: 4,\n\n\tdrive: function() {\n\t\tVehicle.drive.call( this );\n\t\tconsole.log( \"Еду на всех моих \" + this.wheels + \" колёсах!\" );\n\t}\n} );\n```\n\n**Примечание:** Важная деталь - мы больше не имеем дело с классами, потому что в JavaScript нет классов. «Транспортное средство» - `Vehicle` и «Автомобиль» - `Car` — это просто объекты, с которых мы делаем копии, соответственно.\n\n`Car` теперь имеет копию свойств и функций из `Vehicle`. Технически, функции на самом деле не дублируются, а копируются *ссылки* на функции. Таким образом, `Car` теперь имеет свойство под названием `ignition`, которое является скопированной ссылкой на функцию `ignition()`, а также свойство, называемое `engines`, со скопированным значением `1` из `Vehicle`.\n\n`Car` *уже* имеет свойство (функцию) `drive`, поэтому ссылка на свойство не была переопределена (см. Инструкцию `if` в `mixin(..)` выше).\n\n#### \"Полиморфизм\" вновь\n\nДавайте рассмотрим это утверждение: `Vehicle.drive.call(this)`. Это то, что я называю «явным псевдополиморфизмом». Напомню, что в псевдокоде, который мы рассматривали выше, эта строка была `inherited:drive()`, которую мы назвали «относительным полиморфизмом».\n\nJavaScript не имеет (до ES6; см. Приложение A) средства для относительного полиморфизма. Итак, **потому что `Car` и `Vehicle` имеют функцию с одинаковым именем: `drive()`**, чтобы различать вызов той или иной функции, мы должны сделать абсолютную (не относительную) ссылку. Мы явно указываем объект `Vehicle` по имени и вызываем функцию `drive()` для него.\n\nНо если бы мы сказали `Vehicle.drive()`, привязка `this` для этого вызова функции была бы объектом `Vehicle` вместо объекта `Car` (см. Главу 2), а это не то, что нам нужно. Таким образом, вместо этого мы используем `.call(this)` (Глава 2), чтобы гарантировать, что `drive()` выполняется в контексте объекта `Car`.\n\n**Примечание:** Если идентификатор имени функции для `Car.drive()` не перекрывался (\"затенялся\"; см. Главу 5) с `Vehicle.drive()`, мы бы не выполняли «метод полиморфизма». Таким образом, ссылка на `Vehicle.drive()` была бы скопирована вызовом `mixin(..)`, и мы могли бы получить прямой доступ с помощью `this.drive()`. Выбранный идентификатор перекрывается **затенением**, поэтому *мы* должны использовать более сложный *явный подход псевдополиморфизма*.\n\nВ ориентированных на классы языках, которые имеют относительный полиморфизм, связь между `Car` и `Vehicle` устанавливается один раз, в верхней части определения класса, что дает только одно место для поддержания таких отношений.\n\nНо из-за особенностей JavaScript явный псевдополиморфизм (из-за затенения!) Создает хрупкую ручную/явную связь **в каждой отдельной функции, где вам нужна такая (псевдо-) полиморфная ссылка**. Это может значительно увеличить стоимость обслуживания. Более того, хотя явный псевдополиморфизм может эмулировать поведение «множественного наследования», он только увеличивает сложность и хрупкость.\n\nРезультатом таких подходов обычно является более сложный, трудный для чтения и сложный в обслуживании код. **По возможности следует избегать явного псевдополиморфизма**, потому что стоимость в большинстве случаев перевешивает выгоду.\n\n#### Смешивание копий\n\nВспомните утилиту `mixin(..)` сверху:\n\n```js\n// значительно упрощенный пример `mixin(..)`:\nfunction mixin( sourceObj, targetObj ) {\n\tfor (var key in sourceObj) {\n\t\t// копируем только если его еще нет\n\t\tif (!(key in targetObj)) {\n\t\t\ttargetObj[key] = sourceObj[key];\n\t\t}\n\t}\n\n\treturn targetObj;\n}\n```\n\nТеперь давайте посмотрим, как работает `mixin(..)`. Он перебирает свойства `sourceObj` (в нашем примере - `Vehicle`), и если в `targetObj` (в нашем примере, `Car`) нет соответствующего свойства с этим именем, он создает копию. Поскольку мы делаем копию после того, как объект уже был проинициализирован, мы стараемся не копировать целевое свойство.\n\nЕсли мы сначала сделаем копии, прежде чем указывать содержимое `Car`, мы могли бы опустить эту проверку для `targetObj`, но это немного более неуклюже и менее эффективно, поэтому обычно это менее предпочтительно:\n\n```js\n// альтернативный миксин, менее \"безопасный\" для перезаписи\nfunction mixin( sourceObj, targetObj ) {\n\tfor (var key in sourceObj) {\n\t\ttargetObj[key] = sourceObj[key];\n\t}\n\n\treturn targetObj;\n}\n\nvar Vehicle = {\n\t// ...\n};\n\n// сначала создаем пустой объект со\n// скопированными свойствами `Vehicle`\nvar Car = mixin( Vehicle, { } );\n\n// теперь копируем содержимое в Car\nmixin( {\n\twheels: 4,\n\n\tdrive: function() {\n\t\t// ...\n\t}\n}, Car );\n```\n\nПри любом подходе мы явно копировали неперекрывающееся содержимое `Vehicle` в `Car`. Название `mixin` происходит от альтернативного способа объяснения задачи: у `Car` **смешанное** с `Vehicle` содержимое, как вы смешиваете шоколадные крошки в своем любимом тесте для печенья чтобы получить печенье с шоколадной крошкой.\n\nВ результате операции копирования `Car` будет работать несколько иначе, чем `Vehicle`. Если вы добавите свойство в `Car`, оно не повлияет на `Vehicle`, и наоборот.\n\n**Примечание:** Здесь были рассмотрены несколько мелких деталей. Есть и некоторые другие тонкости, которые позволяют двум объектам «влиять» друг на друга даже после копирования, например, если они оба имеют общую ссылку на общий объект (такой как массив).\n\nПоскольку эти два объекта также имеют общие ссылки на свои общие функции, это означает, что **даже ручное копирование функций (иначе говоря, подмешивание) из одного объекта в другой *фактически не эмулирует* реальное дублирование от класса к экземпляру, которое происходит в класс-ориентированных языках**.\n\nФункции JavaScript на самом деле не могут быть дублированы (стандартным, надежным способом), поэтому вместо этого мы получаем **дублированную ссылку** на один и тот же объект общей функции (функции являются объектами; см. Главу 3). Если вы изменили один из общих **функциональных объектов** (например, `ignition()`), добавив к нему свойства, то и `Vehicle`, и `Car` будут «затронуты» через общую ссылку.\n\nЯвные примеси - это прекрасный механизм в JavaScript. Но они кажутся более могущественными, чем они есть на самом деле. На самом деле *небольшая выгода* получается от копирования свойства из одного объекта в другой, **в отличие от простого определения свойств дважды**, один раз для каждого объекта. И это особенно верно, учитывая нюанс ссылки на функцию-объект, который мы только что упомянули.\n\nЕсли вы явно смешиваете два или более объекта в целевой объект, вы можете **частично эмулировать** поведение «множественного наследования», но нет прямого способа обработки коллизий, если один и тот же метод или свойство копируется из более чем одного источника. Некоторые разработчики/библиотеки придумали методы «позднего связывания» и другие экзотические обходные пути, но по сути эти «уловки» *обычно* требуют больше усилий (и меньшей производительности!), чем дают пользы.\n\nПозаботьтесь только о том, чтобы использовать явные примеси, когда это действительно помогает сделать код более читабельным, и избегайте шаблонов, если вы обнаружите, что он делает код сложным для отслеживания или он создает ненужные или громоздкие зависимости между объектами.\n\n**Если при использовании примесей писать и поддерживать код становится труднее, чем если бы вы их не использовали**, вам, вероятно, следует прекратить использовать примеси. Фактически, если вам нужно использовать сложную библиотеку/утилиту для проработки всех этих деталей, это может быть признаком того, что вы идете по этому пути сложнее, возможно, чем следовало бы. В главе 6 мы попытаемся найти более простой способ достижения желаемых результатов без суеты.\n\n#### Паразитическое наследование\n\nВариант этого явного паттерна подмешивания, который в некоторых отношениях явный, а в других неявный, называется «паразитическим наследованием», популяризируемый в основном Дугласом Крокфордом.\n\nВот как это может работать:\n\n```js\n// \"Традиционный JS класс\" `Vehicle`\nfunction Vehicle() {\n\tthis.engines = 1;\n}\nVehicle.prototype.ignition = function() {\n\tconsole.log( \"Завожу двигатель.\" );\n};\nVehicle.prototype.drive = function() {\n\tthis.ignition();\n\tconsole.log( \"Двигаюсь вперёд!\" );\n};\n\n// \"Паразитический класс\" `Car`\nfunction Car() {\n\t// во-первых, `car` это `Vehicle`\n\tvar car = new Vehicle();\n\n\t// теперь, давайте модифицируем `car` чтобы придать ей специфичности\n\tcar.wheels = 4;\n\n\t// сохранить привилегированную ссылку в `Vehicle::drive()`\n\tvar vehDrive = car.drive;\n\n\t// переопределяем `Vehicle::drive()`\n\tcar.drive = function() {\n\t\tvehDrive.call( this );\n\t\tconsole.log( \"Еду на всех моих \" + this.wheels + \" колёсах!\" );\n\t};\n\n\treturn car;\n}\n\nvar myCar = new Car();\n\nmyCar.drive();\n// Завожу двигатель.\n// Двигаюсь вперёд!\n// Еду на всех моих 4 колёсах!\n```\n\nКак вы можете видеть, мы сначала делаем копию определения из «родительского класса» (объекта) `Vehicle`, затем смешиваем наше определение «дочернего класса» (объекта) (сохраняя при необходимости ссылки на привилегированный родительский класс) и передаем от этого составного объекта `car` в качестве нашего дочернего экземпляра.\n\n**Примечание:** когда мы вызываем `new Car()`, создается новый объект и на него ссылается ссылка `this` (см. Главу 2). Но поскольку мы не используем этот объект и вместо этого возвращаем наш собственный объект `car`, первоначально созданный объект просто отбрасывается. Таким образом, `Car()` может быть вызван без ключевого слова `new`, а приведенные выше функциональные возможности будут идентичны, но без ненужного создания объекта/сборки мусора.\n\n### Неявные примеси\n\nНеявные примеси тесно связаны с *явным псевдополиморфизмом*, как объяснено ранее. Как таковые, они приходят с одинаковыми предостережениями и предупреждениями.\n\nРассмотрим этот код:\n\n```js\nvar Something = {\n\tcool: function() {\n\t\tthis.greeting = \"Привет, мир\";\n\t\tthis.count = this.count ? this.count + 1 : 1;\n\t}\n};\n\nSomething.cool();\nSomething.greeting; // \"Привет, мир\"\nSomething.count; // 1\n\nvar Another = {\n\tcool: function() {\n\t\t// неявное смешивание `Something` с `Another`\n\t\tSomething.cool.call( this );\n\t}\n};\n\nAnother.cool();\nAnother.greeting; // \"Привет, мир\"\nAnother.count; // 1 (нет общего состояния с `Something`)\n```\n\nС помощью `Something.cool.call(this)`, которое может происходить либо при вызове «конструктора» (наиболее часто), либо при вызове метода (показано здесь), мы, по сути, «заимствуем» функцию `Something.cool()` и вызываем его в контексте `Another` (через привязку `this`; см. главу 2) вместо `Something`. Конечным результатом является то, что назначения, которые выполняет `Something.cool()`, применяются к объекту `Another`, а не к объекту `Something`.\n\nИтак, сказано, что мы «смешали» поведение Something с (или в) `Another`.\n\nХотя этот вид техники, кажется, использует полезные преимущества функции связывания this, это хрупкий вызов `Something.cool.call(this)`, который нельзя превратить в относительную (и, следовательно, более гибкую) ссылку, с которой вам **следует соблюдать осторожность**. Как правило, **по возможности избегайте таких конструкций**, чтобы сохранить более чистый и более понятный код.\n\n## Обзор (TL; DR)\n\nКлассы - это шаблон кодирования. Многие языки предоставляют синтаксис, который позволяет проектировать класс-ориентированное программное обеспечение. JS также имеет похожий синтаксис, но он ведет себя **совсем иначе**, чем вы ожидаете от классов из этих других языков.\n\n**Классы означают копии.**\n\nПри создании объектов традиционных классов, происходит копирование поведения от класса к экземпляру. Когда классы наследуются, также происходит копирование поведения от родителя к потомку.\n\nМожет показаться что полиморфизм (имеющий разные функции на нескольких уровнях цепочки наследования с одним и тем же именем) подразумевает относительную ссылку от дочернего элемента к родительскому, но это все еще просто результат поведения копирования.\n\nJavaScript **автоматически не** создает копии (как подразумевают классы) между объектами.\n\nШаблон примеси (как явный, так и неявный) часто используется для *эмуляции* поведения копирования классов, но это обычно приводит к уродливому и хрупкому синтаксису, например явному псевдополиморфизму (`OtherObj.methodName.call(this, ...)`), что часто приводит к усложнению понимания и поддержки кода.\n\nЯвные примеси также не совсем совпадают с *копированием* классов, поскольку объекты (и функции!) дублируются только общими ссылками, а сами объекты/функции не дублируются. Не обратив внимания на такой нюанс вы получите источник множества недочетов.\n\nВ целом, фальшивые классы в JS часто устанавливают больше мин для будущего кодирования, чем решают *реальные* проблемы.\n"
  },
  {
    "path": "this & object prototypes/ch5.md",
    "content": "# # Вы не знаете JS: _this_ и прототипы объектов\r\n\r\n# Глава 5: Прототипы\r\n\r\nВ главах 3 и 4 мы неоднократно упоминали цепочку `[[Prototype]]`, но не уточняли что это такое. Пришло время разобраться с тем, как работают прототипы.\r\n\r\n**Примечание:** Любые попытки эмуляции копирования классов, упомянутые в главе 4 как \"примеси\", полностью обходят механизм цепочки `[[Prototype]]`, рассматриваемый в этой главе.\r\n\r\n## `[[Prototype]]`\r\n\r\nОбъекты в JavaScript имеют внутреннее свойство, обозначенное в спецификации как `[[Prototype]]`, которое является всего лишь ссылкой на другой объект. Почти у всех объектов при создании это свойство получает не-`null` значение.\r\n\r\n**Примечание:** Чуть ниже мы увидим, что объект _может_ иметь пустую ссылку `[[Prototype]]`, хотя такой вариант встречается реже.\r\n\r\nРассмотрим пример:\r\n\r\n```js\r\nvar myObject = {\r\n  a: 2,\r\n};\r\n\r\nmyObject.a; // 2\r\n```\r\n\r\nДля чего используется ссылка `[[Prototype]]`? В главе 3 мы изучили операцию `[[Get]]`, которая вызывается когда вы ссылаетесь на свойство объекта, например `myObject.a`. Стандартная операция `[[Get]]` сначала проверяет, есть ли у объекта собственное свойство `a`, если да, то оно используется.\r\n\r\n**Примечание:** Прокси-объекты ES6 выходят за рамки этой книги (мы увидим их в одной из следующих книг серии!), но имейте в виду, что обсуждаемое нами стандартное поведение `[[Get]]` и `[[Put]]` неприменимо если используются `Proxy`.\r\n\r\nНо нас интересует то, что происходит, когда `a` **отсутствует** в `myObject`, т.к. именно здесь вступает в действие ссылка `[[Prototype]]` объекта.\r\n\r\nЕсли стандартная операция `[[Get]]` не может найти запрашиваемое свойство в самом объекте, то она следует по **ссылке** `[[Prototype]]` этого объекта.\r\n\r\n```js\r\nvar anotherObject = {\r\n  a: 2,\r\n};\r\n\r\n// создаем объект, привязанный к `anotherObject`\r\nvar myObject = Object.create(anotherObject);\r\n\r\nmyObject.a; // 2\r\n```\r\n\r\n**Примечание:** Чуть позже мы объясним что делает `Object.create(..)` и как он работает. Пока же считайте, что создается объект со ссылкой `[[Prototype]]` на указанный объект.\r\n\r\nИтак, у нас есть `myObject`, который теперь связан с `anotherObject` через ссылку `[[Prototype]]`. Очевидно, что `myObject.a` на самом деле не существует, однако обращение к свойству выполнилось успешно (свойство нашлось в `anotherObject`) и действительно вернуло значение `2`.\r\n\r\nЕсли бы `a` не нашлось и в объекте `anotherObject`, то теперь уже его цепочка `[[Prototype]]` использовалась бы для дальнейшего поиска.\r\n\r\nЭтот процесс продолжается до тех пор, пока либо не будет найдено свойство с совпадающим именем, либо не закончится цепочка `[[Prototype]]`. Если по достижении конца цепочки искомое свойство _так и не будет_ найдено, операция `[[Get]]` вернет `undefined`.\r\n\r\nПо аналогии с этим процессом поиска по цепочке `[[Prototype]]`, если вы используете цикл `for..in` для итерации по объекту, будут перечислены все свойства, достижимые по его цепочке (при условии, что они перечислимые — см. `enumerable` в главе 3). Если вы используете оператор `in` для проверки существования свойства в объекте, то `in` проверит всю цепочку объекта (независимо от _перечисляемости_).\r\n\r\n```js\r\nvar anotherObject = {\r\n  a: 2,\r\n};\r\n\r\n// создаем объект, привязанный к `anotherObject`\r\nvar myObject = Object.create(anotherObject);\r\n\r\nfor (var k in myObject) {\r\n  console.log(\"найдено: \" + k);\r\n}\r\n// найдено: a\r\n\r\n\"a\" in myObject; // true\r\n```\r\n\r\nИтак, ссылки в цепочке `[[Prototype]]` используются одна за другой, когда вы тем или иным способом пытаетесь найти свойство. Поиск заканчивается при нахождении свойства или достижении конца цепочки.\r\n\r\n### `Object.prototype`\r\n\r\nНо _где_ именно \"заканчивается\" цепочка `[[Prototype]]`?\r\n\r\nВ конце каждой _типичной_ цепочки `[[Prototype]]` находится встроенный объект `Object.prototype`. Этот объект содержит различные утилиты, используемые в JS повсеместно, поскольку все обычные (встроенные, не связанные с конкретной средой исполнения) объекты в JavaScript \"происходят от\" объекта `Object.prototype` (иными словами, имеют его на вершине своей цепочки `[[Prototype]]`).\r\n\r\nНекоторые утилиты этого объекта могут быть вам знакомы: `.toString()` и `.valueOf()`. В главе 3 мы видели еще одну: `.hasOwnProperty(..)`. Еще одна функция `Object.prototype`, о которой вы могли не знать, но узнаете далее в этой главе — это `.isPrototypeOf(..)`.\r\n\r\n### Установка и затенение свойств\r\n\r\nРанее в главе 3 мы отмечали, что установка свойств объекта происходит чуть сложнее, чем просто добавление к объекту нового свойства или изменение значения существующего свойства.\r\n\r\n```js\r\nmyObject.foo = \"bar\";\r\n```\r\n\r\nЕсли непосредственно у `myObject` есть обычное свойство доступа к данным с именем `foo`, то присваивание сводится к изменению значения существующего свойства.\r\n\r\nЕсли непосредственно у `myObject` нет `foo`, то выполняется обход цепочки `[[Prototype]]` по аналогии с операцией `[[Get]]`. Если `foo` не будет найдено в цепочке, то свойство `foo` добавляется непосредственно к `myObject` и получает указанное значение, как мы того и ожидаем.\r\n\r\nОднако если `foo` находится где-то выше по цепочке, то присваивание `myObject.foo = \"bar\"` может повлечь за собой более сложное (и даже неожиданное) поведение. Рассмотрим этот вопрос подробнее.\r\n\r\nЕсли свойство с именем `foo` присутствует как у самого `myObject`, так и где-либо выше в цепочке `[[Prototype]]`, начинающейся с `myObject`, то такая ситуация называется _затенением_. Свойство `foo` самого `myObject` _затеняет_ любые свойства `foo`, расположенные выше по цепочке, потому что поиск `myObject.foo` всегда находит свойство `foo`, ближайшее к началу цепочки.\r\n\r\nКак уже отмечалось, затенение `foo` в `myObject` происходит не так просто, как может показаться. Мы рассмотрим три сценария присваивания `myObject.foo = \"bar\"`, когда `foo` **не** содержится непосредственно в `myObject`, а **находится** выше по цепочке `[[Prototype]]` объекта `myObject`:\r\n\r\n1. Если обычное свойство доступа к данным (см. главу 3) с именем `foo` находится выше по цепочке `[[Prototype]]`, **и свойство доступно для записи (`writable:true`)**, то новое свойство `foo` добавляется непосредственно в объект `myObject`, и происходит **затенение свойства**.\r\n2. Если `foo` находится выше по цепочке `[[Prototype]]`, но отмечено как **только для чтения (`writable:false`)**, то установка значения этого существующего свойства, равно как и создание затеняющего свойства у `myObject`, **запрещены**. Если код выполняется в `strict mode`, то будет выброшена ошибка, если нет, то попытка установить значение свойства будет проигнорирована. В любом случае, **затенения не происходит**.\r\n3. Если `foo` находится выше по цепочке `[[Prototype]]` и является сеттером (см. главу 3), то всегда будет вызываться сеттер. Свойство `foo` не будет добавлено в `myObject`, сеттер `foo` не будет переопределен.\r\n\r\nБольшинство разработчиков предполагает, что присваивание свойства (`[[Put]]`) всегда приводит к затенению, если свойство уже существует выше по цепочке `[[Prototype]]`, но как видите это является правдой лишь в одной (№1) из трех рассмотренных ситуаций.\r\n\r\nЕсли вы хотите затенить `foo` в случаях №2 и №3, то вместо присваивания `=` нужно использовать `Object.defineProperty(..)` (см. главу 3) чтобы добавить `foo` в `myObject`.\r\n\r\n**Примечание:** Ситуация №2 может показаться наиболее удивительной из трех. Наличие свойства _только для чтения_ мешает нам неявно создать (затенить) свойство с таким же именем на более низком уровне цепочки `[[Prototype]]`. Причина такого ограничения по большей части кроется в желании поддержать иллюзию наследования свойств класса. Если представить, что `foo` с верхнего уровня цепочки наследуется (копируется) в `myObject`, то имеет смысл запретить изменение этого свойства `foo` в `myObject`. Но если перейти от иллюзий к фактам и согласиться с тем, что никакого наследования с копированием _на самом деле_ не происходит (см. главы 4 и 5), то кажется немного странным, что `myObject` не может иметь свойство `foo` лишь потому, что у какого-то другого объекта есть неизменяемое свойство `foo`. Еще более странно то, что это ограничение действует только на присваивание `=`, но не распространяется на `Object.defineProperty(..)`.\r\n\r\nЗатенение при использовании **методов** приведет к уродливому _явному псевдополиморфизму_ (см. главу 4) если вам потребуется делегирование между ними. Обычно затенение приносит больше проблем и сложностей, чем пользы, **поэтому старайтесь избегать его если это возможно**. В главе 6 вы увидите альтернативный шаблон проектирования, который наряду с другими вещами предполагает отказ от затенения в пользу более разумных альтернатив.\r\n\r\nЗатенение может даже произойти неявно, поэтому если вы хотите его избежать, будьте бдительны. Например:\r\n\r\n```js\r\nvar anotherObject = {\r\n  a: 2,\r\n};\r\n\r\nvar myObject = Object.create(anotherObject);\r\n\r\nanotherObject.a; // 2\r\nmyObject.a; // 2\r\n\r\nanotherObject.hasOwnProperty(\"a\"); // true\r\nmyObject.hasOwnProperty(\"a\"); // false\r\n\r\nmyObject.a++; // ой, неявное затенение!\r\n\r\nanotherObject.a; // 2\r\nmyObject.a; // 3\r\n\r\nmyObject.hasOwnProperty(\"a\"); // true\r\n```\r\n\r\nХотя может показаться, что выражение `myObject.a++` должно (через делегирование) найти и просто инкрементировать свойство `anotherObject.a`, вместо этого операция `++` соответствует выражению `myObject.a = myObject.a + 1`. В результате `[[Get]]` ищет свойство `a` через `[[Prototype]]` и получает текущее значение `2` из `anotherObject.a`, далее это значение увеличивается на 1, после чего `[[Put]]` присваивает значение `3` новому затеняющему свойству `a` в `myObject`. Ой!\r\n\r\nБудьте очень осторожны при работе с делегированными свойствами, пытаясь изменить их значение. Если вам нужно инкрементировать `anotherObject.a`, то вот единственно верный способ сделать это: `anotherObject.a++`.\r\n\r\n## \"Класс\"\r\n\r\nВы уже могли задаться вопросом: \"_Зачем_ одному объекту нужна ссылка на другой объект?\" Какой от этого толк? Это очень хороший вопрос, но сначала нам нужно выяснить, чем `[[Prototype]]` **не является**, прежде чем мы сможем понять и оценить то, чем он _является_, и какая от него польза.\r\n\r\nВ главе 4 мы выяснили, что в отличие от класс-ориентированных языков в JavaScript нет абстрактных шаблонов/схем объектов, называемых \"классами\". В JavaScript **просто** есть объекты.\r\n\r\nНа самом деле, JavaScript — **практически уникальный** язык, ведь пожалуй только он имеет право называться \"объектно-ориентированным\", т.к. относится к весьма немногочисленной группе языков, где объекты можно создавать напрямую, без классов.\r\n\r\nВ JavaScript классы не могут описывать поведение объекта (учитывая тот факт, что их вообще не существует!). Объект сам определяет собственное поведение. **Есть _только_ объект.**\r\n\r\n### Функции \"классов\"\r\n\r\nВ JavaScript есть специфическое поведение, которым долгие годы цинично злоупотребляли для создания _поделок_, внешне _похожих_ на \"классы\". Рассмотрим этот подход более подробно.\r\n\r\nСпецифическое поведение \"как бы классов\" основано на одной странной особенности: у всех функций по умолчанию есть публичное, неперечислимое (см. главу 3) свойство, называемое `prototype`, которое указывает на некий объект.\r\n\r\n```js\r\nfunction Foo() {\r\n  // ...\r\n}\r\n\r\nFoo.prototype; // { }\r\n```\r\n\r\nЭтот объект часто называют \"прототипом Foo\", поскольку обращение к нему происходит через свойство с неудачно выбранным названием `Foo.prototype`. Как мы вскоре увидим, такая терминология обречена приводить людей в замешательство. Вместо этого, я буду называть его \"объектом, ранее известным как прототип Foo\". Ладно, шучу. Как насчет этого: \"объект, условно называемый 'Foo точка prototype'\"?\r\n\r\nКак бы мы не называли его, что же это за объект?\r\n\r\nПроще всего объяснить так: у каждого объекта, создаваемого с помощью вызова `new Foo()` (см. главу 2), ссылка `[[Prototype]]` будет указывать на этот объект \"Foo точка prototype\".\r\n\r\nПроиллюстрируем на примере:\r\n\r\n```js\r\nfunction Foo() {\r\n  // ...\r\n}\r\n\r\nvar a = new Foo();\r\n\r\nObject.getPrototypeOf(a) === Foo.prototype; // true\r\n```\r\n\r\nКогда `a` создается путем вызова `new Foo()`, одним из результатов (все _четыре_ шага см. в главе 2) будет создание в `a` внутренней ссылки `[[Prototype]]` на объект, на который указывает `Foo.prototype`.\r\n\r\nОстановитесь на секунду и задумайтесь о смысле этого утверждения.\r\n\r\nВ класс-ориентированных языках множественные **копии** (или \"экземпляры\") создаются как детали, штампуемые на пресс-форме. Как мы видели в главе 4, так происходит потому что процесс создания экземпляра (или наследования от) класса означает \"скопировать поведение из этого класса в физический объект\", и это выполняется для каждого нового экземпляра.\r\n\r\nНо в JavaScript такого копирования не происходит. Вы не создаете множественные экземпляры класса. Вы можете создать множество объектов, *связанных* ссылкой `[[Prototype]]` с общим объектом. Но по умолчанию никакого копирования не происходит, поэтому эти объекты не становятся полностью автономными и не соединенными друг с другом, напротив, они весьма *связаны*.\r\n\r\nВызов `new Foo()` создает новый объект (мы назвали его `a`), и **этот** новый объект `a` связан внутренней ссылкой `[[Prototype]]` с объектом `Foo.prototype`.\r\n\r\n**В результате получилось два объекта, связанных друг с другом.** Вот и _все_. Мы не создали экземпляр класса. И мы уж точно не копировали никакого поведения из \"класса\" в реальный объект. Мы просто связали два объекта друг с другом.\r\n\r\nНа самом деле секрет, о котором не догадывается большинство JS разработчиков, состоит в том, что вызов функции `new Foo()` практически никак _напрямую_ не связан с процессом создания ссылки. **Это всегда было неким побочным эффектом.** `new Foo()` — это косвенный, окольный путь к желаемому результату: **новому объекту, связанному с другим объектом**.\r\n\r\nМожем ли мы добиться желаемого более _прямым_ путем? **Да!** Герой дня — `Object.create(..)`. Но мы вернемся к нему чуть позже.\r\n\r\n#### Что значит имя?\r\n\r\nВ JavaScript мы не делаем _копии_ из одного объекта (\"класса\") в другой (\"экземпляр\"). Мы создаем _ссылки_ между объектами. В механизме `[[Prototype]]` визуально стрелки идут справа налево и снизу вверх.\r\n\r\n<img src=\"fig3.png\">\r\n\r\nЭтот механизм часто называют \"прототипным наследованием\" (мы подробнее рассмотрим код чуть ниже), которое обычно считается вариантом \"классического наследования\" для динамических языков. Это попытка воспользоваться общепринятым пониманием термина \"наследование\" в класс-ориентированных языках и *подогнать* знакомую семантику под динамический язык.\r\n\r\nТермин \"наследование\" имеет очень четкий смысл (см. главу 4). Добавление перед ним слова \"прототипное\" чтобы обозначить _на самом деле почти противоположное_ поведение привело к неразберихе в течение двух десятков лет.\r\n\r\nЯ люблю говорить, что использовать слово \"прототипное\" перед \"наследованием\" для придания существенно иного смысла — это как держать в одной руке апельсин, а в другой яблоко и настаивать на том, что яблоко — это \"красный апельсин\". Не важно, какое прилагательное я добавлю перед ним, это не изменит тот _факт_, что один фрукт — яблоко, а другой — апельсин.\r\n\r\nЛучше называть яблоко яблоком, применяя аккуратную и точную терминологию. Это позволяет нам легко понимать их **многочисленные сходства и отличия**, потому что мы все имеем ясное представление что такое \"яблоко\".\r\n\r\nИз-за всей этой неразберихи с терминами я считаю, что само название \"прототипное наследование\" (а также некорректное использование связанных с ним терминов, таких как \"класс\", \"конструктор\", \"экземпляр\", \"полиморфизм\" и т.д.) принесло **больше вреда чем пользы** в понимании того, как _на самом деле_ работает JavaScript.\r\n\r\n\"Наследование\" подразумевает операцию _копирования_, а JavaScript не копирует свойства объекта (по умолчанию). Вместо этого JS создает ссылку между двумя объектами, в результате один объект по сути _делегирует_ доступ к свойствам/функциям другому объекту. \"Делегирование\" (см. главу 6) — более точный термин для описания механизма связывания объектов в JavaScript.\r\n\r\nДругой термин, который иногда встречается в JavaScript - это \"дифференциальное наследование\". Суть в том, что мы описываем поведение объекта с точки зрения того, что _отличается_ в нем от более общего описания. Например, вы можете сказать, что автомобиль является видом транспортного средства, у которого ровно 4 колеса, вместо того чтобы заново описывать все свойства транспортного средства (двигатель, и т.д.).\r\n\r\nЕсли представить, что любой объект в JS является суммой всего поведения, которое _доступно_ через делегирование, и **мысленно объединить** все это поведение в одну реальную **сущность**, то можно предположить, что \"дифференциальное наследование\" (вроде как) подходящий термин.\r\n\r\nНо как и \"прототипное наследование\", \"дифференциальное наследование\" претендует на то, что мысленная модель важнее того, что физически происходит в языке. Здесь упускается из виду факт, что объект `B` на самом деле не создается дифференциально, а создается с конкретно заданными характеристиками, а также с \"дырами\", где ничего не задано. Эти дыры (пробелы или отсутствующие определения) _могут_ заменяться механизмом делегирования, который на лету \"заполняет их\" делегированным поведением.\r\n\r\nОбъект по умолчанию не сворачивается в единый дифференциальный объект **посредством копирования**, как это подразумевается в мысленной модели \"дифференциального наследования\". Таким образом, \"дифференциальное наследование\" не слишком подходит для описания реального механизма работы `[[Prototype]]` в JavaScript.\r\n\r\nВы **можете** придерживаться терминологии и мысленной модели \"дифференциального наследования\", но нельзя отрицать тот факт, что это *лишь* упражнение ума в вашей голове, а не реальное поведение движка.\r\n\r\n### \"Конструкторы\"\r\n\r\nВернемся к рассмотренному ранее коду:\r\n\r\n```js\r\nfunction Foo() {\r\n  // ...\r\n}\r\n\r\nvar a = new Foo();\r\n```\r\n\r\nЧто именно заставляет нас подумать, что `Foo` является \"классом\"?\r\n\r\nС одной стороны, мы видим использование ключевого слова `new`, совсем как в класс-ориентированных языках, когда создаются экземпляры классов. С другой стороны, кажется, что мы на самом деле выполняем метод _конструктора_ класса, потому что метод `Foo()` на самом деле вызывается, так же как конструктор реального класса вызывается при создании экземпляра.\r\n\r\nУ объекта `Foo.prototype` есть еще один фокус, который усиливает недоразумение, связанное с семантикой \"конструкторов\". Посмотрите на этот код:\r\n\r\n```js\r\nfunction Foo() {\r\n  // ...\r\n}\r\n\r\nFoo.prototype.constructor === Foo; // true\r\n\r\nvar a = new Foo();\r\na.constructor === Foo; // true\r\n```\r\n\r\nПо умолчанию объект `Foo.prototype` (во время объявления в первой строке примера!) получает публичное неперечислимое (см. главу 3) свойство `.constructor`, и это свойство является обратной ссылкой на функцию (в данном случае `Foo`), с которой связан этот объект. Более того, мы видим, что объект `a`, созданный путем вызова \"конструктора\" `new Foo()`, похоже тоже имеет свойство с именем `.constructor`, также указывающее на \"функцию, создавшую его\".\r\n\r\n**Примечание:** На самом деле это неправда. У `a` нет свойства `.constructor`, и хотя `a.constructor` действительно разрешается в функцию `Foo`, \"конструктор\" **на самом деле не значит** \"был сконструирован этой функцией\". Мы разберемся с этим курьезом чуть позже.\r\n\r\nАх, да, к тому же... в мире JavaScript принято соглашение об именовании \"классов\" с заглавной буквы, поэтому тот факт что это `Foo`, а не `foo` является четким указанием, что мы хотим определить \"класс\". Это ведь абсолютно очевидно, не так ли!?\r\n\r\n**Примечание:** Это соглашение имеет такое влияние, что многие JS линтеры _возмущаются_ когда вы вызываете `new` с методом, имя которого состоит из строчных букв, или не вызываете `new` с функцией, начинающейся с заглавной буквы. Удивительно, что мы с таким трудом пытаемся добиться (фальшивой) \"класс-ориентированности\" в JavaScript, что даже создаем правила для линтеров, чтобы гарантировать использование заглавных букв, хотя заглавные буквы _вообще_ **ничего** не значат для движка JS.\r\n\r\n#### Конструктор или вызов?\r\n\r\nВ примере выше есть соблазн предположить, что `Foo` — это \"конструктор\", потому что мы вызываем её с `new` и видим, что она \"конструирует\" объект.\r\n\r\nВ действительности, `Foo` такой же \"конструктор\", как и любая другая функция в вашей программе. Функции сами по себе **не** являются конструкторами. Однако когда вы добавляете ключевое слово `new` перед обычным вызовом функции, это превращает вызов функции в \"вызов конструктора\". На самом деле `new` как бы перехватывает любую обычную функцию и вызывает её так, что в результате создается объект, **а также выполняется код самой функции**.\r\n\r\nНапример:\r\n\r\n```js\r\nfunction NothingSpecial() {\r\n  console.log(\"Don't mind me!\");\r\n}\r\n\r\nvar a = new NothingSpecial();\r\n// \"Don't mind me!\"\r\n\r\na; // {}\r\n```\r\n\r\n`NothingSpecial` — обычная функция, но когда она вызывается с `new`, то практически в качестве побочного эффекта _создает_ объект, который мы присваиваем `a`. Этот **вызов** был _вызовом конструктора_, но сама по себе функция `NothingSpecial` не является _конструктором_.\r\n\r\nИначе говоря, в JavaScript \"конструктор\" — это **любая функция, вызванная с ключевым словом `new`** перед ней.\r\n\r\nФункции не являются конструкторами, но вызовы функций являются \"вызовами конструктора\" тогда и только тогда, когда используется `new`.\r\n\r\n### Механика\r\n\r\nЯвляются ли эти особенности единственными причинами многострадальных дискуссий о \"классах\" в JavaScript?\r\n\r\n**Не совсем.** JS разработчики постарались симулировать поведение классов настолько, насколько это возможно:\r\n\r\n```js\r\nfunction Foo(name) {\r\n  this.name = name;\r\n}\r\n\r\nFoo.prototype.myName = function () {\r\n  return this.name;\r\n};\r\n\r\nvar a = new Foo(\"a\");\r\nvar b = new Foo(\"b\");\r\n\r\na.myName(); // \"a\"\r\nb.myName(); // \"b\"\r\n```\r\n\r\nЭтот пример показывает два дополнительных трюка для \"класс-ориентированности\":\r\n\r\n1. `this.name = name`: свойство `.name` добавляется в каждый объект (`a` и `b`, соответственно; см. главу 2 о привязке `this`), аналогично тому как экземпляры классов инкапсулируют значения данных.\r\n\r\n2. `Foo.prototype.myName = ...`: возможно более интересный прием, добавляет свойство (функцию) в объект `Foo.prototype`. Теперь работает `a.myName()`, но каким образом?\r\n\r\nВ примере выше велик соблазн думать, что при создании `a` и `b` свойства/функции объекта `Foo.prototype` _копируются_ в каждый из объектов `a` и `b`. **Однако этого не происходит**.\r\n\r\nВ начале этой главы мы изучали ссылку `[[Prototype]]` — часть стандартного алгоритма `[[Get]]`, которая предоставляет запасной вариант поиска, если ссылка на свойство отсутствует в самом объекте.\r\n\r\nВ силу того, как создаются `a` и `b`, оба объекта получают внутреннюю ссылку `[[Prototype]]` на `Foo.prototype`. Когда `myName` не находится в `a` или `b` соответственно, она обнаруживается (через делегирование, см. главу 6) в `Foo.prototype`.\r\n\r\n#### И снова о \"конструкторе\"\r\n\r\nВспомните наше обсуждение свойства `.constructor`. _Кажется_, что `a.constructor === Foo` означает, что в `a` есть реальное свойство `.constructor`, указывающее на `Foo`, верно? **Не верно.**\r\n\r\nЭто всего лишь путаница. На самом деле ссылка `.constructor` также _делегируется_ вверх по цепочке в `Foo.prototype`, у которого, **так уж случилось**, по умолчанию есть свойство `.constructor`, указывающее на `Foo`.\r\n\r\n_Кажется_ ужасно удобным, что у объекта `a`, \"созданного\" `Foo`, будет доступ к свойству `.constructor`, которое указывает на `Foo`. Но это ложное чувство безопасности. Лишь по счастливой _случайности_ `a.constructor` указывает на `Foo` через делегирование `[[Prototype]]` по умолчанию. На самом деле есть несколько способов наломать дров, предполагая что `.constructor` означает \"использовался для создания\".\r\n\r\nНачнем с того, что свойство `.constructor` в `Foo.prototype` по умолчанию есть лишь у объекта, создаваемого в момент объявления функции `Foo`. Если создать новый объект и заменить у функции ссылку на стандартный объект `.prototype`, то новый объект по умолчанию не получит свойства `.constructor`.\r\n\r\nРассмотрим:\r\n\r\n```js\r\nfunction Foo() {\r\n  /* .. */\r\n}\r\n\r\nFoo.prototype = {\r\n  /* .. */\r\n}; // создаем новый объект-прототип\r\n\r\nvar a1 = new Foo();\r\na1.constructor === Foo; // false!\r\na1.constructor === Object; // true!\r\n```\r\n\r\n`Object(..)` не был \"конструктором\" `a1`, не так ли? Выглядит так, будто \"конструктором\" объекта должна быть `Foo()`. Многие разработчики думают, что `Foo()` создает объект, но эта идея трещит по швам, когда вы думаете что \"constructor\" значит \"был создан при помощи\". Ведь в таком случае `a1.constructor` должен указывать на `Foo`, но это не так!\r\n\r\nЧто же происходит? У `a1` нет свойства `.constructor`, поэтому он делегирует вверх по цепочке `[[Prototype]]` к `Foo.prototype`. Но и у этого объекта нет `.constructor` (в отличие от стандартного объекта `Foo.prototype`!), поэтому делегирование идет дальше, на этот раз до `Object.prototype` — вершины цепочки делегирования. У _этого_ объекта действительно есть `.constructor`, который указывает на встроенную функцию `Object(..)`.\r\n\r\n**Разрушаем заблуждение.**\r\n\r\nКонечно, можно вернуть объекту `Foo.prototype` свойство `.constructor`, но это придется сделать вручную, особенно если вы хотите, чтобы свойство соответствовало стандартному поведению и было не перечислимым (см. главу 3).\r\n\r\nНапример:\r\n\r\n```js\r\nfunction Foo() {\r\n  /* .. */\r\n}\r\n\r\nFoo.prototype = {\r\n  /* .. */\r\n}; // создаем новый объект-прототип\r\n\r\n// Необходимо правильно \"пофиксить\" отсутствующее свойство `.constructor`\r\n// у нового объекта, выступающего в роли `Foo.prototype`.\r\n// См. главу 3 про `defineProperty(..)`.\r\nObject.defineProperty(Foo.prototype, \"constructor\", {\r\n  enumerable: false,\r\n  writable: true,\r\n  configurable: true,\r\n  value: Foo, // `.constructor` теперь указывает на `Foo`\r\n});\r\n```\r\n\r\nКак видите, для исправления `.constructor` необходимо много ручной работы. Больше того, все это мы делаем ради поддержания ошибочного представления о том, что \"constructor\" означает \"используется для создания\". _Дорого_ же нам обходится эта иллюзия.\r\n\r\nФакт в том, что `.constructor` объекта по умолчанию указывает на функцию, которая, в свою очередь, имеет обратную ссылку на объект — ссылку `.prototype`. Слова \"конструктор\" и \"прототип\" лишь наделяются по умолчанию ненадежным смыслом, который позднее может оказаться неверным. Лучше всего постоянно напоминать себе, что \"конструктор не значит используется для создания\".\r\n\r\n`.constructor` — это не магическое неизменяемое свойство. Оно _является_, неперечисляемым (см. пример выше), но его значение доступно для записи (может быть изменено), и более того, вы можете добавить или перезаписать (намеренно или случайно) свойство с именем `constructor` в любом объекте любой цепочки `[[Prototype]]`, задав ему любое подходящее вам значение.\r\n\r\nВ силу того как алгоритм `[[Get]]` обходит цепочку `[[Prototype]]`, ссылка на свойство `.constructor`, найденная в любом узле цепочки, может получать значение, весьма отличающееся от ожидаемого.\r\n\r\nВидите, насколько произвольным является его значение?\r\n\r\nЧто в итоге? Некая произвольная ссылка на свойство объекта, например `a1.constructor`, не может считаться _надежной_ ссылкой на функцию по умолчанию. Более того, как мы вскоре увидим, в результате небольшого упущения `a1.constructor` может вообще указывать на весьма странное и бессмысленное значение.\r\n\r\n`a1.constructor` — слишком ненадежная и небезопасная ссылка, чтобы полагаться на нее в коде. **В общем случае таких ссылок по возможности следует избегать.**\r\n\r\n## \"(Прототипное) наследование\"\r\n\r\nМы увидели некоторые типичные хаки для добавления механики \"классов\" в программы на JavaScript. Но \"классы\" JavaScript были бы неполными без попыток смоделировать \"наследование\".\r\n\r\nНа самом деле мы уже видели механизм под названием \"прототипное наследование\", когда объект `a` \"унаследовал от\" `Foo.prototype` функцию `myName()`. Но обычно под \"наследованием\" подразумевается отношение между двумя \"классами\", а не между \"классом\" и \"экземпляром\".\r\n\r\n<img src=\"fig3.png\">\r\n\r\nМы уже видели эту схему, на которой показано не только делегирование от объекта (или \"экземпляра\") `a1` к объекту `Foo.prototype`, но и от `Bar.prototype` к `Foo.prototype`, что отчасти напоминает концепцию наследования классов родитель-потомок. Вот только направление стрелок здесь другое, поскольку изображены делегирующие ссылки, а не операции копирования.\r\n\r\nВот типичный пример кода в \"прототипном стиле\", где создаются такие ссылки:\r\n\r\n```js\r\nfunction Foo(name) {\r\n  this.name = name;\r\n}\r\n\r\nFoo.prototype.myName = function () {\r\n  return this.name;\r\n};\r\n\r\nfunction Bar(name, label) {\r\n  Foo.call(this, name);\r\n  this.label = label;\r\n}\r\n\r\n// здесь мы создаем `Bar.prototype`\r\n// связанный с `Foo.prototype`\r\nBar.prototype = Object.create(Foo.prototype);\r\n\r\n// Осторожно! Теперь `Bar.prototype.constructor` отсутствует,\r\n// и это придется \"пофиксить\" вручную,\r\n// если вы привыкли полагаться на подобные свойства!\r\n\r\nBar.prototype.myLabel = function () {\r\n  return this.label;\r\n};\r\n\r\nvar a = new Bar(\"a\", \"obj a\");\r\n\r\na.myName(); // \"a\"\r\na.myLabel(); // \"obj a\"\r\n```\r\n\r\n**Примечание:** Чтобы понять, почему `this` указывает на `a`, см. главу 2.\r\n\r\nСамая важная строка здесь `Bar.prototype = Object.create( Foo.prototype )`. `Object.create(..)` _создает_ \"новый\" объект из ничего, и связывает внутреннюю ссылку `[[Prototype]]` этого объекта с указанным объектом (в данном случае `Foo.prototype`).\r\n\r\nДругими словами, эта строка означает: \"создать _новый_ объект 'Bar точка prototype', связанный с 'Foo точка prototype'\".\r\n\r\nПри объявлении `function Bar() { .. }` функция `Bar`, как и любая другая, получает ссылку `.prototype` на объект по умолчанию. Но _этот_ объект не ссылается на `Foo.prototype`, как мы того хотим. Поэтому мы создаем **новый** объект, который **имеет** нужную ссылку, и отбрасываем исходный, неправильно связанный объект.\r\n\r\n**Примечание:** Типичная ошибка — пытаться использовать следующие варианты, думая, что они _тоже_ сработают, но это приводит к неожиданным результатам:\r\n\r\n```js\r\n// работает не так, как вы ожидаете!\r\nBar.prototype = Foo.prototype;\r\n\r\n// работает почти так, как нужно,\r\n// но с побочными эффектами, которые возможно нежелательны :(\r\nBar.prototype = new Foo();\r\n```\r\n\r\n`Bar.prototype = Foo.prototype` не создает новый объект, на который ссылалось бы `Bar.prototype`. Вместо этого `Bar.prototype` становится еще одной ссылкой на `Foo.prototype`, и в результате `Bar` напрямую связывается с **тем же самым объектом**, что и `Foo`: `Foo.prototype`. Это значит, что когда вы начнете присваивать значения, например `Bar.prototype.myLabel = ...`, вы будете изменять **не отдельный объект**, а общий объект `Foo.prototype`, что повлияет на любые объекты, привязанные к `Foo.prototype`. Это наверняка не то, чего вы хотите. В противном случае вам вообще не нужен `Bar`, и стоит использовать только `Foo`, сделав код проще.\r\n\r\n`Bar.prototype = new Foo()` **действительно** создает новый объект, корректно привязанный к `Foo.prototype`. Но для этого используется \"вызов конструктора\" `Foo(..)`. Если эта функция имеет какие-либо побочные эффекты (логирование, изменение состояния, регистрация в других объектах, **добавление свойств в `this`**, и т.д.), то эти побочные эффекты сработают во время привязывания (и возможно в отношении неправильного объекта!), а не только при создании конечных \"потомков\" `Bar`, как можно было бы ожидать.\r\n\r\nПоэтому, для правильного привязывания нового объекта без побочных эффектов от вызова `Foo(..)` у нас остается лишь `Object.create(..)`. Небольшой недостаток состоит в том, что нам приходится создавать новый объект и выбрасывать старый, вместо того чтобы модифицировать существующий стандартный объект.\r\n\r\nБыло бы _здорово_ если бы существовал стандартный и надежный способ поменять привязку существующего объекта. До ES6 был нестандартный и не полностью кроссбраузерный способ через свойство `.__proto__`, которое можно изменять. В ES6 добавлена вспомогательная утилита `Object.setPrototypeOf(..)`, которая проделывает нужный трюк стандартным и предсказуемым способом.\r\n\r\nСравните пред-ES6 и стандартизованный в ES6 способ привязки `Bar.prototype` к `Foo.prototype`:\r\n\r\n```js\r\n// пред-ES6\r\n// выбрасывает стандартный существующий `Bar.prototype`\r\nBar.prototype = Object.create(Foo.prototype);\r\n\r\n// ES6+\r\n// изменяет существующий `Bar.prototype`\r\nObject.setPrototypeOf(Bar.prototype, Foo.prototype);\r\n```\r\n\r\nЕсли отбросить небольшой проигрыш в производительности (выбрасывание объекта, который позже удаляется сборщиком мусора), то способ с `Object.create(..)` немного короче и может даже читабельнее, чем подход ES6+. Хотя это всего лишь пустые разговоры о синтаксисе.\r\n\r\n### Инспектируем связи между \"классами\"\r\n\r\nЧто если у вас есть объект `a` и вы хотите выяснить, какому объекту он делегирует? Инспектирование экземпляра (объект в JS) с целью найти его предка (делегирующая связь в JS) в традиционных класс-ориентированных языках часто называют _интроспекцией_ (или _рефлексией_).\r\n\r\nРассмотрим:\r\n\r\n```js\r\nfunction Foo() {\r\n\t// ...\r\n}\r\n\r\nFoo.prototype.blah = ...;\r\n\r\nvar a = new Foo();\r\n```\r\n\r\nКак выполнить интроспекцию `a`, чтобы найти его \"предка\" (делегирующую связь)? Первый подход использует путаницу с \"классами\":\r\n\r\n```js\r\na instanceof Foo; // true\r\n```\r\n\r\nОператор `instanceof` принимает в качестве операнда слева обычный объект, а в качества операнда справа — **функцию**. `instanceof` отвечает на следующий вопрос: **присутствует ли где-либо в цепочке `[[Prototype]]` объекта `a` объект, на который указывает `Foo.prototype`?**\r\n\r\nК сожалению, это значит, что вы можете получить сведения о \"происхождении\" некоторого объекта (`a`) только имея некоторую **функцию** (`Foo` c её ссылкой `.prototype`). Если у вас есть два произвольных объекта, например `a` и `b`, и вы хотите узнать, связаны ли сами эти _объекты_ друг с другом через цепочку `[[Prototype]]`, одного `instanceof` будет недостаточно.\r\n\r\n**Примечание:** Если вы используете встроенную утилиту `.bind(..)` для создания жестко привязанной функции (см. главу 2), то у созданной функции не будет свойства `.prototype`. При использовании `instanceof` с такой функцией прозрачно подставляется `.prototype` _целевой функции_, из которой была создана жестко привязанная функция.\r\n\r\nИспользование функции с жесткой привязкой для \"вызова конструктора\" крайне маловероятно, но если вы сделаете это, то она будет вести себя так, как если бы вы вызвали _целевую функцию_. Это значит, что вызов `instanceof` с жестко привязанной функцией также ведет себя в соответствии с оригинальной функцией.\r\n\r\nЭтот фрагмент кода показывает нелепость попыток рассуждать об отношениях между **двумя объектами** используя семантику \"классов\" и `instanceof`:\r\n\r\n```js\r\n// вспомогательная утилита для проверки\r\n// связан ли `o1` (через делегирование) с `o2`\r\nfunction isRelatedTo(o1, o2) {\r\n  function F() {}\r\n  F.prototype = o2;\r\n  return o1 instanceof F;\r\n}\r\n\r\nvar a = {};\r\nvar b = Object.create(a);\r\n\r\nisRelatedTo(b, a); // true\r\n```\r\n\r\nВнутри `isRelatedTo(..)` мы временно используем функцию `F`, меняя значение её свойства `.prototype` на объект `o2`, а затем спрашиваем, является ли `o1` \"экземпляром\" `F`. Ясно, что `o1` _на самом деле_ не унаследован от и даже не создан с помощью `F`, поэтому должно быть понятно, что подобные приемы бессмысленны и сбивают с толку. **Проблема сводится к несуразности семантики классов, навязываемой JavaScript**, что наглядно показано на примере косвенной семантики `instanceof`.\r\n\r\nВторой подход к рефлексии `[[Prototype]]` более наглядный:\r\n\r\n```js\r\nFoo.prototype.isPrototypeOf(a); // true\r\n```\r\n\r\nЗаметьте, что в этом случае нам неинтересна (и даже _не нужна_) `Foo`. Нам просто нужен **объект** (в данном случае произвольный объект с именем `Foo.prototype`) для сопоставления его с другим **объектом**. `isPrototypeOf(..)` отвечает на вопрос: **присутствует ли где-либо в цепочке `[[Prototype]]` объекта `a` объект `Foo.prototype`?**\r\n\r\nТот же вопрос, и в точности такой же ответ. Но во втором подходе нам не нужна **функция** (`Foo`) для косвенного обращения к её свойству `.prototype`.\r\n\r\nНам _просто нужны_ два **объекта** для выявления связи между ними. Например:\r\n\r\n```js\r\n// Просто: присутствует ли `b` где-либо\r\n// в цепочке [[Prototype]] объекта `c`\r\nb.isPrototypeOf(c);\r\n```\r\n\r\nЗаметьте, что в этом подходе вообще не требуется функция (\"класс\"). Используются прямые ссылки на объекты `b` и `c`, чтобы выяснить нет ли между ними связи. Другими словами, наша утилита `isRelatedTo(..)` уже встроена в язык и называется `isPrototypeOf(..)`.\r\n\r\nМы можем напрямую получить `[[Prototype]]` объекта. В ES5 появился стандартный способ сделать это:\r\n\r\n```js\r\nObject.getPrototypeOf(a);\r\n```\r\n\r\nЗдесь видно, что ссылка на объект является тем, что мы и ожидаем:\r\n\r\n```js\r\nObject.getPrototypeOf(a) === Foo.prototype; // true\r\n```\r\n\r\nВ большинстве браузеров (но не во всех!) давно добавлена поддержка нестандартного альтернативного способа доступа к `[[Prototype]]`:\r\n\r\n```js\r\na.__proto__ === Foo.prototype; // true\r\n```\r\n\r\nЗагадочное свойство `.__proto__` (стандартизовано лишь в ES6!) \"магически\" возвращает ссылку на внутреннее свойство `[[Prototype]]` объекта, что весьма полезно, если вы хотите напрямую проинспектировать (или даже обойти: `.__proto__.__proto__...`) цепочку.\r\n\r\nАналогично рассмотренному ранее `.constructor`, свойство `.__proto__` отсутствует у инспектируемого объекта (`a` в нашем примере). На самом деле оно есть (и является неперечисляемым, см. главу 2) у встроенного `Object.prototype`, наряду с другими известными утилитами (`.toString()`, `.isPrototypeOf(..)`, и т.д.).\r\n\r\nБолее того, `.__proto__` выглядит как свойство, но правильнее думать о нем как о геттере/сеттере (см. главу 3).\r\n\r\nГрубо говоря, можно представить, что `.__proto__` реализовано так (см. главу 3 об определениях свойств объекта):\r\n\r\n```js\r\nObject.defineProperty(Object.prototype, \"__proto__\", {\r\n  get: function () {\r\n    return Object.getPrototypeOf(this);\r\n  },\r\n  set: function (o) {\r\n    // setPrototypeOf(..) доступно начиная с ES6\r\n    Object.setPrototypeOf(this, o);\r\n    return o;\r\n  },\r\n});\r\n```\r\n\r\nТаким образом, когда мы обращаемся (получаем значение) к `a.__proto__`, это похоже на вызов `a.__proto__()` (вызов функции геттера). В *этом* вызове функции `this` указывает на `a`, несмотря на то что функция геттера находится в объекте `Object.prototype` (см. главу 2 о правилах привязки `this`), так что это равносильно `Object.getPrototypeOf( a )`.\r\n\r\nЗначение `.__proto__` можно также изменять, например с помощью функции `Object.setPrototypeOf(..)` в ES6, как показано выше. Однако обычно **не следует изменять `[[Prototype]]` существующего объекта**.\r\n\r\nГлубоко внутри некоторых фреймворков можно встретить сложные, продвинутые механизмы, позволяющие выполнять трюки наподобие \"создания производного класса\" от `Array`, но обычно подобные вещи не поощряются в повседневной практике, поскольку такой код _гораздо_ труднее понимать и сопровождать.\r\n\r\n**Примечание:** В ES6 добавлено ключевое слово `class`, с помощью которого можно делать вещи, напоминающие \"создание производных классов\" от встроенных объектов, таких как `Array`. Обсуждение синтаксиса `class` из ES6 см. в Приложении А.\r\n\r\nВ остальном же единственным исключением будет установка свойства `[[Prototype]]` стандартного объекта `.prototype` функции, чтобы оно ссылалось на какой-то другой объект (помимо `Object.prototype`). Это позволит избежать замены этого стандартного объекта новым объектом. В любой другой ситуации **лучше всего считать ссылку `[[Prototype]]` доступной только для чтения**, чтобы облегчить чтение вашего кода в будущем.\r\n\r\n**Примечание:** В сообществе JavaScript неофициально закрепилось название двойного подчеркивания, особенно перед именами свойств (как `__proto__`): \"dunder\". Поэтому в мире JavaScript \"крутые ребята\" обычно произносят `__proto__` как \"dunder proto\".\r\n\r\n## Объектные ссылки\r\n\r\nКак мы уже видели, механизм `[[Prototype]]` является внутренней ссылкой, существующей у объекта, который ссылается на другой объект.\r\n\r\nПереход по этой ссылке выполняется (в основном) когда происходит обращение к свойству/методу первого объекта, и это свойство/метод отсутствует. В таком случае ссылка `[[Prototype]]` указывает движку, что свойство/метод нужно искать в связанном объекте. Если и в этом объекте ничего не находится, то происходит переход по его ссылке `[[Prototype]]`, и так далее. Эта последовательность ссылок между объектами образует то, что называется \"цепочкой прототипов\".\r\n\r\n### Создание ссылок\r\n\r\nМы подробно объяснили, почему механизм `[[Prototype]]` в JavaScript **не** похож на \"классы\", и увидели, что вместо этого создаются **ссылки** между подходящими объектами.\r\n\r\nВ чем смысл механизма `[[Prototype]]`? Почему многие JS разработчики прикладывают так много усилий (эммулируя классы), чтобы настроить эти ссылки?\r\n\r\nПомните, как в начале этой главы мы сказали, что `Object.create(..)` станет нашим героем? Теперь вы готовы это увидеть.\r\n\r\n```js\r\nvar foo = {\r\n  something: function () {\r\n    console.log(\"Скажи что-нибудь хорошее...\");\r\n  },\r\n};\r\n\r\nvar bar = Object.create(foo);\r\n\r\nbar.something(); // Скажи что-нибудь хорошее...\r\n```\r\n\r\n`Object.create(..)` создает новый объект (`bar`), связанный с объектом, который мы указали (`foo`), и это дает нам всю мощь (делегирование) механизма `[[Prototype]]`, но без ненужных сложностей вроде функции `new`, выступающей в роли классов и вызовов конструктора, сбивающих с толку ссылок `.prototype` и `.constructor`, и прочих лишних вещей.\r\n\r\n**Примечание:** `Object.create(null)` создает объект с пустой (или `null`) ссылкой `[[Prototype]]`, поэтому этот объект не сможет ничего делегировать. Поскольку у такого объекта нет цепочки прототипов, оператору `instanceof` (рассмотренному ранее) нечего проверять, и он всегда вернет `false`. Эти специальные объекты с пустым `[[Prototype]]` часто называют \"словарями\", поскольку они обычно используются исключительно для хранения данных в свойствах, потому что у них не может быть никаких побочных эффектов от делегируемых свойств/функций цепочки `[[Prototype]]`, и они являются абсолютно плоскими хранилищами данных.\r\n\r\nДля создания продуманных связей между двумя объектами нам не _нужны_ классы. Нам нужно **только лишь** связать объекты друг с другом для делегирования, и `Object.create(..)` дает нам эту связь без лишней возни с классами.\r\n\r\n#### Полифилл для `Object.create()`\r\n\r\n`Object.create(..)` была добавлена в ES5. Вам может понадобиться поддержка пред-ES5 окружения (например, старые версии IE), поэтому давайте рассмотрим простенький **частичный** полифилл для `Object.create(..)`:\r\n\r\n```js\r\nif (!Object.create) {\r\n  Object.create = function (o) {\r\n    function F() {}\r\n    F.prototype = o;\r\n    return new F();\r\n  };\r\n}\r\n```\r\n\r\nВ этом полифилле используется временно создаваемая функция `F`, и её свойство `.prototype` переопределяется так, чтобы указывать на объект, с которым нужно создать связь. Затем мы используем `new F()`, чтобы создать новый объект, который будет привязан нужным нам образом.\r\n\r\nТакой вариант использования `Object.create(..)` встречается в подавляющем большинстве случаев, поскольку эту часть _можно_ заменить полифиллом. В ES5 стандартная функция `Object.create(..)` предоставляет дополнительную функциональность, которую нельзя **заменить полифиллом** в пред-ES5. Для полноты картины рассмотрим, в чем она заключается:\r\n\r\n```js\r\nvar anotherObject = {\r\n  a: 2,\r\n};\r\n\r\nvar myObject = Object.create(anotherObject, {\r\n  b: {\r\n    enumerable: false,\r\n    writable: true,\r\n    configurable: false,\r\n    value: 3,\r\n  },\r\n  c: {\r\n    enumerable: true,\r\n    writable: false,\r\n    configurable: false,\r\n    value: 4,\r\n  },\r\n});\r\n\r\nmyObject.hasOwnProperty(\"a\"); // false\r\nmyObject.hasOwnProperty(\"b\"); // true\r\nmyObject.hasOwnProperty(\"c\"); // true\r\n\r\nmyObject.a; // 2\r\nmyObject.b; // 3\r\nmyObject.c; // 4\r\n```\r\n\r\nВторой аргумент `Object.create(..)` указывает свойства, которые будут добавлены в создаваемый объект, объявляя _дескриптор_ каждого нового свойства (см. главу 3). Поскольку полифиллинг дескрипторов свойств в пред-ES5 невозможен, эту дополнительную функциональность `Object.create(..)` также невозможно реализовать в виде полифилла.\r\n\r\nВ большинстве случаев используется лишь та часть функциональности `Object.create(..)`, которую можно заменить полифиллом, поэтому большинство разработчиков устраивает использование **частичного полифилла** в пред-ES5 окружениях.\r\n\r\nНекоторые разработчики придерживаются более строгого подхода, считая, что можно использовать только _полные_ полифиллы. Поскольку `Object.create(..)` — одна из тех утилит, что нельзя полностью заменить полифиллом, такой строгий подход предписывает, что если вы хотите использовать `Object.create(..)` в пред-ES5 окружении, то вместо полифилла следует применить собственную утилиту, и вообще воздержаться от использования имени `Object.create`. Вместо этого можно определить свою собственную утилиту:\r\n\r\n```js\r\nfunction createAndLinkObject(o) {\r\n  function F() {}\r\n  F.prototype = o;\r\n  return new F();\r\n}\r\n\r\nvar anotherObject = {\r\n  a: 2,\r\n};\r\n\r\nvar myObject = createAndLinkObject(anotherObject);\r\n\r\nmyObject.a; // 2\r\n```\r\n\r\nЯ не разделяю такой подход. Меня полностью устраивает показанный выше частичный полифилл `Object.create(..)` и его использование в коде даже в пред-ES5. Решайте сами, какой подход вам ближе.\r\n\r\n### Ссылки в роли запасных свойств?\r\n\r\nСуществует соблазн думать, что эти ссылки между объектами _в основном_ предоставляют что-то вроде запасного варианта на случай \"отсутствующих\" свойств или методов. И хотя такой вывод допустим, я не считаю что это верный способ размышления о `[[Prototype]]`.\r\n\r\nРассмотрим:\r\n\r\n```js\r\nvar anotherObject = {\r\n  cool: function () {\r\n    console.log(\"круто!\");\r\n  },\r\n};\r\n\r\nvar myObject = Object.create(anotherObject);\r\n\r\nmyObject.cool(); // \"круто!\"\r\n```\r\n\r\nЭтот код работает благодаря `[[Prototype]]`, но если вы написали его так, что `anotherObject` играет роль запасного варианта **на случай если** `myObject` не сможет обработать обращение к некоторому свойству/методу, то вероятно ваше ПО будет содержать больше \"магии\" и будет сложнее для понимания и сопровождения.\r\n\r\nЯ не хочу сказать, что такой подход является в корне неверным шаблоном проектирования, но он нехарактерен для JS. Если вы используете его, возможно вам стоит сделать шаг назад и подумать, является ли такое решение уместным и разумным.\r\n\r\n**Примечание:** В ES6 добавлена продвинутая функциональность, называемая `Proxy`, с помощью которой можно реализовать что-то наподобие поведения \"отсутствующих методов\". `Proxy` выходит за рамки этой книги, но будет подробно рассмотрена в одной из следующих книг серии _\"Вы не знаете JS\"_.\r\n\r\n**Не упустите одну важную, но едва уловимую мысль.**\r\n\r\nЯвно проектируя ПО таким образом, что разработчик может вызвать, к примеру, `myObject.cool()`, и это будет работать даже при отсутствии метода `cool()` у `myObject`, вы добавляете немного \"магии\" в дизайн вашего API, что может в будущем преподнести сюрприз другим разработчикам, которые будут поддерживать ваш код.\r\n\r\nНо вы можете спроектировать API и без подобной \"магии\", не отказываясь при этом от преимуществ ссылки `[[Prototype]]`.\r\n\r\n```js\r\nvar anotherObject = {\r\n  cool: function () {\r\n    console.log(\"круто!\");\r\n  },\r\n};\r\n\r\nvar myObject = Object.create(anotherObject);\r\n\r\nmyObject.doCool = function () {\r\n  this.cool(); // внутреннее делегирование!\r\n};\r\n\r\nmyObject.doCool(); // \"круто!\"\r\n```\r\n\r\nЗдесь мы вызываем `myObject.doCool()` — метод, который _действительно есть_ у объекта `myObject`, делая наш API более явным (менее \"магическим\"). _Внутри_ наша реализация следует **шаблону делегирования** (см. главу 6), используя делегирование `[[Prototype]]` к `anotherObject.cool()`.\r\n\r\nДругими словами, делегирование как правило преподносит меньше сюрпризов, если оно является частью внутренней реализации, а не выставлено наружу в дизайне API. Мы изучим **делегирование** в мельчайших подробностях в следующей главе.\r\n\r\n## Обзор\r\n\r\nПри попытке обратиться к несуществующему свойству объекта внутренняя ссылка `[[Prototype]]` этого объекта задает дальнейшее направление поиска для операции `[[Get]]` (см. главу 3). Этот каскад ссылок от объекта к объекту образует \"цепочку прототипов\" (чем то похожую на цепочку вложенных областей видимости) для обхода при разрешении свойства.\r\n\r\nУ обычных объектов есть встроенный объект `Object.prototype` на конце цепочки прототипов (похоже на глобальную область видимости при поиске по цепочке областей видимости), где процесс разрешения свойства остановится, если свойство не будет найдено в предыдущих звеньях цепочки. У этого объекта есть утилиты `toString()`, `valueOf()` и несколько других, благодаря чему все объекты в языке имеют доступ к ним.\r\n\r\nНаиболее популярный способ связать два объекта друг с другом — использовать ключевое слово `new` с вызовом функции, что помимо четырех шагов (см. главу 2) создаст новый объект, привязанный к другому объекту.\r\n\r\nЭтим \"другим объектом\" является объект, на который указывает свойство `.prototype` функции, вызванной с `new`. Функции, вызываемые с `new`, часто называют \"конструкторами\", несмотря на то что они не создают экземпляры классов, как это делают _конструкторы_ в традиционных класс-ориентированных языках.\r\n\r\nХотя эти механизмы JavaScript могут напоминать \"создание экземпляров классов\" и \"наследование классов\" из традиционных класс-ориентированных языков, ключевое отличие в том, что в JavaScript не создаются копии. Вместо этого объекты связываются друг с другом через внутреннюю цепочку `[[Prototype]]`.\r\n\r\nПо множеству причин, среди которых не последнюю роль играет терминологический прецедент, \"наследование\" (и \"прототипное наследование\") и все остальные ОО-термины не имеют смысла, учитывая то как _на самом деле_ работает JavaScript.\r\n\r\nБолее подходящим термином является \"делегирование\", поскольку эти связи являются не _копиями_, а делегирующими **ссылками**.\r\n"
  },
  {
    "path": "this & object prototypes/ch6.md",
    "content": "# \r\n# Вы не знаете JS: *this* и прототипы объектов\r\n# Глава 6: Делегирование поведения\r\n\r\nВ главе 5 мы подробно изучили механизм `[[Prototype]]` и показали, *почему* его нельзя корректно описать в терминах \"класс\" или \"наследование\" (несмотря на бесчисленные попытки на протяжении почти двух десятилетий). Нам пришлось продираться не только через многословный синтаксис (`.prototype`, захламляющий код), но и через всевозможные ловушки (такие как непредвиденное разрешение `.constructor` или уродливый псевдополиморфный синтаксис). Мы также рассмотрели различные варианты использования \"примесей\", которые часто используются, чтобы сгладить эти острые углы.\r\n\r\nВозникает закономерный вопрос: почему так сложно делать такие простые вещи? Теперь, когда мы приоткрыли завесу и увидели, насколько грязно все устроено внутри, неудивительно, что большинство JS разработчиков никогда не погружаются так глубоко, поручая эту работу библиотеке \"классов\".\r\n\r\nЯ надеюсь, что вы не собираетесь просто обойти все эти детали, поручив их \"черному ящику\". Так что давайте разберемся, как мы *могли и должны были бы* думать о механизме `[[Prototype]]` в JS, используя **гораздо более простой и прямой путь**, чем вся эта путаница с классами.\r\n\r\nКак вы уже знаете из Главы 5, механизм `[[Prototype]]` — это внутренняя ссылка, которая существует в одном объекте и ссылается на другой объект.\r\n\r\nЭта ссылка используется при обращении к несуществующему свойству/методу первого объекта. В таком случае ссылка `[[Prototype]]` говорит движку, что свойство/метод нужно искать в связанном объекте. В свою очередь, если поиск в этом объекте завершается неудачно, то происходит переход уже по его ссылке `[[Prototype]]` и так далее. Эта последовательность ссылок между объектами образует так называемую \"цепочку прототипов\".\r\n\r\nДругими словами, реальный механизм, важнейшая часть функциональности, доступной нам в JavaScript — это по сути **объекты, связанные с другими объектами**.\r\n\r\nДанное наблюдение является фундаментальным и критически важным для понимания мотивов и подходов, описанных далее в этой главе!\r\n\r\n## Проектирование, ориентированное на делегирование\r\n\r\nЧтобы использовать `[[Prototype]]` наиболее правильным способом, необходимо осознавать, что этот шаблон проектирования фундаментально отличается от классов (см. главу 4).\r\n\r\n**Примечание:** *Некоторые* принципы класс-ориентированного проектирования остаются крайне актуальными, так что не отбрасывайте все, что вы знаете (а всего лишь большую часть!). Например, *инкапсулирование* — весьма мощный инструмент, совместимый с делегированием (хотя такое сочетание встречается редко).\r\n\r\nНам нужно изменить наш способ мышления с шаблона проектирования \"класс/наследование\" на шаблон проектирования \"делегирование поведения\". Если большую часть вашего обучения или карьеры в программировании вы имели дело с классами, это может показаться некомфортным или неестественным. Попробуйте проделать это умственное упражнение несколько раз, чтобы привыкнуть к такому совершенно иному способу мышления.\r\n\r\nСначала я покажу вам некоторые теоретические упражнения, а затем мы посмотрим на более конкретный пример, который вы сможете использовать на практике в вашем коде.\r\n\r\n### Теория классов\r\n\r\nПредположим, что у нас есть несколько похожих задач (\"XYZ\", \"ABC\", etc), которые мы хотим смоделировать в нашем ПО.\r\n\r\nПри использовании классов проектирование происходит так: определяем общий родительский (базовый) класс `Task`, в котором задается поведение всех \"похожих\" задач. Затем определяем дочерние классы `XYZ` и `ABC`, которые  наследуют от `Task` и добавляют уточненное поведение для выполнения собственных задач.\r\n\r\n**Важно отметить,** что шаблон проектирования классов диктует нам для получения максимальной выгоды от наследования использовать переопределение методов (и полиморфизм). В этом случае мы переопределяем определение некоторого общего метода `Task` в `XYZ`, возможно даже используя `super` для вызова базовой версии метода, добавляя к нему новое поведение. **Вероятно вы найдете довольно много мест**, где можно \"абстрагировать\" общее поведение в родительский класс, и уточнить (переопределить) его в дочерних классах.\r\n\r\nВот примерный псевдокод для такого сценария:\r\n\r\n```js\r\nclass Task {\r\n\tid;\r\n\r\n\t// конструктор `Task()`\r\n\tTask(ID) { id = ID; }\r\n\toutputTask() { output( id ); }\r\n}\r\n\r\nclass XYZ inherits Task {\r\n\tlabel;\r\n\r\n\t// конструктор `XYZ()`\r\n\tXYZ(ID,Label) { super( ID ); label = Label; }\r\n\toutputTask() { super(); output( label ); }\r\n}\r\n\r\nclass ABC inherits Task {\r\n\t// ...\r\n}\r\n```\r\n\r\nТеперь вы можете создать одну или более **копий** дочернего класса `XYZ`, и использовать эти экземпляры для выполнения задачи \"XYZ\". Эти экземпляры **копируют** как общее поведение из `Task`, так и уточненное поведение из `XYZ`. Аналогично и экземпляры класса `ABC` будут иметь копии поведения `Task` и уточненного поведения `ABC`. Обычно после создания вы взаимодействуете только с этими экземплярами (но не с классами), поскольку у каждого экземпляра есть копия всего поведения, которое необходимо для выполнения задачи.\r\n\r\n### Теория делегирования\r\n\r\nА теперь давайте поразмышляем о той же предметной области, но с использованием *делегирования поведения* вместо *классов*.\r\n\r\nСначала определяется **объект** (не класс и не `function`, что бы ни говорили вам большинство JS разработчиков) по имени `Task` с конкретным поведением, включающим в себя вспомогательные методы, которыми могут пользоваться различные задачи (читай *делегировать*!). Затем для каждой задачи (\"XYZ\", \"ABC\") вы определяете **объект** с данными/поведением, специфичными для данной задачи. Вы **связываете** специфические объекты задач со вспомогательным объектом `Task`, позволяя им делегировать ему в случае необходимости.\r\n\r\nВ сущности, для выполнения задачи \"XYZ\" нам необходимо поведение двух объектов одного уровня (`XYZ` и `Task`). Но вместо композиции через копирование классов мы можем оставить их в виде отдельных объектов, и разрешить объекту `XYZ` **делегировать** объекту `Task`, когда это необходимо.\r\n\r\nВот простой пример кода, показывающий как этого добиться:\r\n\r\n```js\r\nvar Task = {\r\n\tsetID: function(ID) { this.id = ID; },\r\n\toutputID: function() { console.log( this.id ); }\r\n};\r\n\r\n// `XYZ` делегирует `Task`\r\nvar XYZ = Object.create( Task );\r\n\r\nXYZ.prepareTask = function(ID,Label) {\r\n\tthis.setID( ID );\r\n\tthis.label = Label;\r\n};\r\n\r\nXYZ.outputTaskDetails = function() {\r\n\tthis.outputID();\r\n\tconsole.log( this.label );\r\n};\r\n\r\n// ABC = Object.create( Task );\r\n// ABC ... = ...\r\n```\r\n\r\nВ этом примере `Task` и `XYZ` не являются классами (или функциями), это **просто объекты**. С помощью `Object.create(..)` объект `XYZ` делегирует объекту `Task` через ссылку `[[Prototype]]` (см. главу 5).\r\n\r\nПо аналогии с класс-ориентированностью (или, OO — объектно-ориентированный), я назвал этот стиль кода **\"OLOO\"** (objects-linked-to-other-objects — \"объекты, связанные с другими объектами\"). Все, что нас *действительно* интересует — это тот факт, что объект `XYZ` делегирует объекту `Task` (как и объект `ABC`).\r\n\r\nВ JavaScript механизм `[[Prototype]]` связывает **объекты** с другими **объектами**. Нет никаких абстрактных механизмов наподобие \"классов\", как бы вы ни пытались убедить себя в обратном. Это как грести на каноэ вверх по реке: вы *можете* это сделать, но *выбираете* путь против естественного течения, так что вам очевидно **будет труднее добраться в нужное место**.\r\n\r\nВот некоторые другие отличия **стиля OLOO**:\r\n\r\n1. Оба члена данных `id` и `label` из предыдущего примера с классами являются здесь свойствами данных непосредственно `XYZ` (ни одного из них нет в `Task`). Как правило в случае делегирования через `[[Prototype]]`, **вы хотите, чтобы состояние хранилось в делегирующих объектах** (`XYZ`, `ABC`), а не в делегате (`Task`).\r\n2. При использовании шаблона проектирования классов мы специально назвали `outputTask` одинаково как в родителе (`Task`), так и в потомке (`XYZ`), чтобы воспользоваться переопределением (полиморфизм). В случае делегирования поведения мы делаем ровно наоборот: **при любой возможности избегаем одинаковых имен** на разных уровнях цепочки `[[Prototype]]` (это называется затенением — см. главу 5), поскольку коллизии имен вынуждают использовать ужасный/хрупкий код для устранения неоднозначности ссылок (см. главу 4), а мы хотим избежать этого.\r\n\r\n   Этот шаблон проектирования предписывает отказ от общих, расплывчатых имен методов (предрасположенных к переопределению) в пользу более описательных имен, *характерных* для поведения каждого конкретного объекта. **Это может сделать код проще для понимания/сопровождения**, потому что имена методов (не только в месте их определения, но и по всему коду) становятся более очевидными (самодокументируемыми).\r\n3. `this.setID(ID);` внутри метода объекта `XYZ` сначала ищет `setID(..)` в `XYZ`, но поскольку метода с таким именем нет в `XYZ`, *делегирование* `[[Prototype]]` означает, что можно пройти по ссылке на `Task`, чтобы найти там `setID(..)`, что и происходит. Более того, благодаря неявным правилам привязки `this` (см. главу 2), при выполнении `setID(..)`, хотя этот метод и был найден в `Task`, `this` для данного вызова функции — это `XYZ`, как мы того и желали. То же самое происходит и с `this.outputID()` чуть дальше в листинге кода.\r\n\r\n   Другими словами, методы общего назначения, существующие в `Task`, доступны нам при взаимодействии с `XYZ`, потому что `XYZ` может делегировать `Task`.\r\n\r\n**Делегирование поведения** означает: пусть у одного объекта (`XYZ`) будет делегирование (к `Task`) для обращения к свойству или методу, отсутствующему в объекте (`XYZ`).\r\n\r\nЭто *чрезвычайно мощный* шаблон проектирования, сильно отличающийся от идеи родительских и дочерних классов, наследования, полиморфизма, и т.п. Вместо того чтобы мысленно выстраивать вертикальную иерархию объектов от Родителей к Потомкам, представьте себе равноправные объекты одного уровня, между которыми в любом направлении могут идти делегирующие ссылки.\r\n\r\n**Примечание:** Правильнее использовать делегирование как внутреннюю деталь реализации, а не выставлять его наружу в дизайне API. В нашем дизайне API в примере выше мы не подталкиваем разработчиков использовать `XYZ.setID()` (хотя могли бы это сделать!). Мы как бы *прячем* делегирование как внутреннюю деталь нашего API, где `XYZ.prepareTask(..)` делегирует к `Task.setID(..)`. Подробнее см. главу 5, раздел \"Ссылки в роли запасных свойств?\".\r\n\r\n#### Взаимное делегирование (запрещено)\r\n\r\nНельзя создавать *цикл*, где между двумя или более объектами есть взаимное (двунаправленное) делегирование. Если вы создадите `B`, связанный с `A`, а затем попытаетесь связать `A` с `B`, то получите ошибку.\r\n\r\nЖаль, что это запрещено (не то чтобы ужасно, но слегка раздражает). Если бы вы обратились к свойству/методу, которого нет ни у одного из объектов, это привело бы к бесконечной рекурсии в цикле `[[Prototype]]`. Но если бы все ссылки были на месте, тогда `B` мог делегировать `A` и наоборот, и это *могло* бы сработать. Это позволило бы использовать любой из объектов для делегирования другому. Есть несколько частных случаев, где это было бы полезным.\r\n\r\nНо это запрещено, потому что разработчики конкретных реализаций движка обнаружили, что с точки зрения производительности выгоднее проверить (и отклонить!) наличие бесконечных циклических ссылок один раз во время установки, чем выполнять эту проверку каждый раз при обращении к свойству объекта.\r\n\r\n#### Отладка\r\n\r\nРассмотрим вкратце один тонкий момент, который иногда сбивает с толку разработчиков. В целом спецификация JS не контролирует то, в каком виде конкретные значения и структуры отображаются в консоли разработчика в браузере. Поэтому каждый браузер/движок интерпретирует подобные вещи по-своему, и эта интерпретация *может различаться*. В частности поведение, которое мы сейчас рассмотрим, встречается только в Chrome Developer Tools.\r\n\r\nПосмотрите на этот \"традиционный\" стиль \"конструктора классов\" в JS коде, и то, что отображается в *консоли* Chrome Developer Tools:\r\n\r\n```js\r\nfunction Foo() {}\r\n\r\nvar a1 = new Foo();\r\n\r\na1; // Foo {}\r\n```\r\n\r\nОбратите внимание на последнюю строку кода: в результате вычисления выражения `a1` выводится `Foo {}`. Если запустить этот код в Firefox, то скорее всего мы увидим `Object {}`. Почему такая разница, и что означают эти значения в консоли?\r\n\r\nChrome по сути говорит нам, что \"{} — это пустой объект, который был создан функцией с именем 'Foo'\". Firefox же говорит, что \"{} — это пустой объект, созданный на основе Object\". Маленькое отличие состоит в том, что Chrome отслеживает в виде *внутреннего свойства* имя реальной функции, создавшей объект, а другие браузеры такую информацию не отслеживают.\r\n\r\nЕсть соблазн попытаться объяснить это с помощью механизмов JavaScript:\r\n\r\n```js\r\nfunction Foo() {}\r\n\r\nvar a1 = new Foo();\r\n\r\na1.constructor; // Foo(){}\r\na1.constructor.name; // \"Foo\"\r\n```\r\n\r\nПолучается, что Chrome выводит \"Foo\", всего-навсего проверяя свойство `.constructor.name` объекта? И \"да\", и \"нет\".\r\n\r\nРассмотрим код:\r\n\r\n```js\r\nfunction Foo() {}\r\n\r\nvar a1 = new Foo();\r\n\r\nFoo.prototype.constructor = function Gotcha(){};\r\n\r\na1.constructor; // Gotcha(){}\r\na1.constructor.name; // \"Gotcha\"\r\n\r\na1; // Foo {}\r\n```\r\n\r\nНесмотря на то, что мы изменили `a1.constructor.name` на другое значение (\"Gotcha\"), консоль Chrome по-прежнему использует имя \"Foo\".\r\n\r\nИтак, получается, что ответ на предыдущий вопрос (используется ли `.constructor.name`?) — **нет**, информация отслеживается где-то в другом месте, внутри движка.\r\n\r\nНо не торопитесь! Давайте посмотрим, как это работает при использовании стиля OLOO:\r\n\r\n```js\r\nvar Foo = {};\r\n\r\nvar a1 = Object.create( Foo );\r\n\r\na1; // Object {}\r\n\r\nObject.defineProperty( Foo, \"constructor\", {\r\n\tenumerable: false,\r\n\tvalue: function Gotcha(){}\r\n});\r\n\r\na1; // Gotcha {}\r\n```\r\n\r\nАга! **Попались!** Здесь консоль Chrome **нашла** и использует `.constructor.name`. На самом деле, на момент написания этой книги данное поведение было идентифицировано как баг в Chrome, и сейчас, когда вы её читаете, баг скорее всего исправлен. Поэтому в вашем браузере может выдаваться корректный результат `a1; // Object {}`.\r\n\r\nЕсли не обращать внимания на этот баг, то внутреннее отслеживание \"имени конструктора\" (по-видимому, только в целях отладки в консоли) в Chrome является собственным поведением Chrome, выходящим за рамки спецификации.\r\n\r\nЕсли вы не используете \"конструктор\" для создания объектов, как того и требует OLOO стиль кодирования в этой главе, тогда Chrome *не* будет отслеживать внутреннее \"имя конструктора\" для этих объектов, и они будут отображаться в консоли как \"Object {}\", то есть, \"объекты, созданные из Object()\".\r\n\r\n**Не думайте**, что это является недостатком OLOO стиля. Когда вы используете шаблон проектирования на основе OLOO и делегирования поведения, совершенно неважно, *кто* \"создал\" объект (то есть, *какая функция* была вызвана с `new`?). Отслеживание \"имени конструктора\" внутри Chrome полезно только если вы полностью пишете код \"в стиле классов\", но совершенно неактуально при использовании OLOO делегирования.\r\n\r\n### Сравнение мысленных моделей\r\n\r\nТеперь, когда вы видите как минимум теоретическую разницу между шаблонами проектирования \"класс\" и \"делегирование\", давайте посмотрим на то, как эти шаблоны влияют на мысленные модели, которые мы используем, рассуждая о коде.\r\n\r\nМы рассмотрим абстрактный код (\"Foo\", \"Bar\"), и сравним два способа его реализации (OO против OLOO). Первый фрагмент кода использует классический (\"прототипный\") OO стиль:\r\n\r\n```js\r\nfunction Foo(who) {\r\n\tthis.me = who;\r\n}\r\nFoo.prototype.identify = function() {\r\n\treturn \"I am \" + this.me;\r\n};\r\n\r\nfunction Bar(who) {\r\n\tFoo.call( this, who );\r\n}\r\nBar.prototype = Object.create( Foo.prototype );\r\n\r\nBar.prototype.speak = function() {\r\n\talert( \"Hello, \" + this.identify() + \".\" );\r\n};\r\n\r\nvar b1 = new Bar( \"b1\" );\r\nvar b2 = new Bar( \"b2\" );\r\n\r\nb1.speak();\r\nb2.speak();\r\n```\r\n\r\nРодительский класс `Foo` наследуется дочерним классом `Bar`, после чего создаются два экземпляра этого класса `b1` и `b2`. В результате `b1` делегирует `Bar.prototype`, который делегирует `Foo.prototype`. Все выглядит довольно знакомо, ничего особенного.\r\n\r\nТеперь давайте реализуем **ту же самую** функциональность, используя код в стиле *OLOO*:\r\n\r\n```js\r\nvar Foo = {\r\n\tinit: function(who) {\r\n\t\tthis.me = who;\r\n\t},\r\n\tidentify: function() {\r\n\t\treturn \"I am \" + this.me;\r\n\t}\r\n};\r\n\r\nvar Bar = Object.create( Foo );\r\n\r\nBar.speak = function() {\r\n\talert( \"Hello, \" + this.identify() + \".\" );\r\n};\r\n\r\nvar b1 = Object.create( Bar );\r\nb1.init( \"b1\" );\r\nvar b2 = Object.create( Bar );\r\nb2.init( \"b2\" );\r\n\r\nb1.speak();\r\nb2.speak();\r\n```\r\n\r\nМы используем преимущество делегирования `[[Prototype]]` от `b1` к `Bar`, и от `Bar` к `Foo`, аналогично тому, как сделали это в предыдущем примере с `b1`, `Bar.prototype`, и `Foo.prototype`. **У нас по-прежнему есть те же самые 3 объекта, связанные вместе**.\r\n\r\nНо важно то, что мы значительно упростили *все остальное*, потому что теперь у нас просто есть **объекты**, связанные друг с другом, без всех этих ненужных вещей, которые выглядят (но не ведут себя) как классы, с конструкторами, прототипами и вызовами `new`.\r\n\r\nСпросите себя: если я могу получить с OLOO точно такую же функциональность, что и с \"классами\", но OLOO проще и понятнее, **может быть OLOO лучше**?\r\n\r\nДавайте рассмотрим мысленные модели, связанные с двумя этими примерами.\r\n\r\nПример с классами предполагает следующую мысленную модель сущностей и взаимосвязей между ними:\r\n\r\n<img src=\"fig4.png\">\r\n\r\nНа самом деле, это немного нечестно, потому что здесь показано множество дополнительных нюансов, которые вы *строго говоря* не должны постоянно держать в голове (хотя вам *надо* понимать их!). С одной стороны, это довольно сложная последовательность взаимосвязей. Но с другой стороны, если вы внимательно изучите эти стрелки со связями, то поймете, что механизмы JS обладают **потрясающей внутренней целостностью и непротиворечивостью**.\r\n\r\nНапример, функции в JS могут обращаться к `call(..)`, `apply(..)` и `bind(..)` (см. главу 2), поскольку сами по себе являются объектами, и у них есть ссылка `[[Prototype]]` на объект `Function.prototype`. В этом объекте определены стандартные методы, которым может делегировать любая функция-объект. JS может делать такие вещи, *и вы тоже можете!*.\r\n\r\nХорошо, давайте теперь посмотрим на *слегка* упрощенную версию этой диаграммы, чтобы сделать наше сравнение чуть более \"честным\". Здесь показаны лишь *ключевые* сущности и взаимосвязи.\r\n\r\n<img src=\"fig5.png\">\r\n\r\nПо-прежнему довольно сложно, не так ли? Пунктирными линиями обозначены неявные взаимосвязи, когда вы установили \"наследование\" между `Foo.prototype` и `Bar.prototype`, но пока еще не *исправили* ссылку на **отсутствующее** свойство `.constructor` (см. раздел \"И снова о конструкторе\" в главе 5). Даже без этих пунктирных линий вам придется мысленно проделывать очень много работы каждый раз, когда вы имеете дело с объектными.\r\n\r\nА теперь давайте посмотрим на мысленную модель для кода в OLOO-стиле:\r\n\r\n<img src=\"fig6.png\">\r\n\r\nИз этого сравнения очевидно, что в OLOO-стиле вам нужно учитывать *гораздо меньшее количество нюансов*, поскольку в OLOO принимается за аксиому тот **факт**, что нас интересуют только **объекты, связанные с другими объектами**.\r\n\r\nВесь остальной \"классовый\" хлам — запутанный и сложный способ для получения такого же конечного результата. Уберите его, и вещи станут гораздо проще (без потери какой-либо функциональности).\r\n\r\n## Классы против объектов\r\n\r\nМы только что провели теоретические рассуждения и сравнили мысленные модели \"классов\" и \"делегирования поведения\". А теперь давайте посмотрим более реальные примеры кода, чтобы увидеть как на деле применять эти идеи.\r\n\r\nСначала мы рассмотрим типичный сценарий фронтенд-разработки: создание UI-виджетов (кнопки, раскрывающиеся списки, и т.п.).\r\n\r\n### \"Классы\" виджетов\r\n\r\nЕсли вы привыкли использовать шаблон проектирования OO, то скорее всего сразу же представите себе предметную область в виде родительского класса (например, `Widget`) с базовым поведением виджета и дочерних производных классов для виджетов конкретного типа (например, `Button`).\r\n\r\n**Примечание:** Для работы с DOM и CSS мы используем jQuery, поскольку в данном обсуждении нас не интересуют подобные детали. В приведенном ниже коде выбор конкретного JS фреймворка (jQuery, Dojo, YUI, и т.п.) для решения рутинных задач не имеет никакого значения.\r\n\r\nДавайте посмотрим, как бы мы могли реализовать архитектуру \"классов\" на чистом JS, без каких-либо вспомогательных библиотек \"классов\" или синтаксиса:\r\n\r\n```js\r\n// Родительский класс\r\nfunction Widget(width,height) {\r\n\tthis.width = width || 50;\r\n\tthis.height = height || 50;\r\n\tthis.$elem = null;\r\n}\r\n\r\nWidget.prototype.render = function($where){\r\n\tif (this.$elem) {\r\n\t\tthis.$elem.css( {\r\n\t\t\twidth: this.width + \"px\",\r\n\t\t\theight: this.height + \"px\"\r\n\t\t} ).appendTo( $where );\r\n\t}\r\n};\r\n\r\n// Дочерний класс\r\nfunction Button(width,height,label) {\r\n\t// вызов конструктора \"super\"\r\n\tWidget.call( this, width, height );\r\n\tthis.label = label || \"Default\";\r\n\r\n\tthis.$elem = $( \"<button>\" ).text( this.label );\r\n}\r\n\r\n// `Button` \"наследует\" от `Widget`\r\nButton.prototype = Object.create( Widget.prototype );\r\n\r\n// переопределяем базовый \"унаследованный\" `render(..)`\r\nButton.prototype.render = function($where) {\r\n\t// вызов \"super\"\r\n\tWidget.prototype.render.call( this, $where );\r\n\tthis.$elem.click( this.onClick.bind( this ) );\r\n};\r\n\r\nButton.prototype.onClick = function(evt) {\r\n\tconsole.log( \"Button '\" + this.label + \"' clicked!\" );\r\n};\r\n\r\n$( document ).ready( function(){\r\n\tvar $body = $( document.body );\r\n\tvar btn1 = new Button( 125, 30, \"Hello\" );\r\n\tvar btn2 = new Button( 150, 40, \"World\" );\r\n\r\n\tbtn1.render( $body );\r\n\tbtn2.render( $body );\r\n} );\r\n```\r\n\r\nШаблон проектирования OO предписывает нам объявить базовый метод `render(..)` в родительском классе, и переопределить его в дочернем классе, но не заменять его полностью, а дополнить базовую функциональность поведением, характерным для кнопки.\r\n\r\nОбратите внимание на уродливый *явный псевдополиморфизм* ссылок `Widget.call` и `Widget.prototype.render.call` для имитации вызова \"super\" из методов дочернего \"класса\". Фу, гадость!\r\n\r\n#### Синтаксический сахар ES6: `class`\r\n\r\nМы подробно рассмотрим синтаксический сахар `class` в ES6 в Приложении А. Ну а пока давайте узнаем, как мы могли бы реализовать тот же самый код с помощью `class`:\r\n\r\n```js\r\nclass Widget {\r\n\tconstructor(width,height) {\r\n\t\tthis.width = width || 50;\r\n\t\tthis.height = height || 50;\r\n\t\tthis.$elem = null;\r\n\t}\r\n\trender($where){\r\n\t\tif (this.$elem) {\r\n\t\t\tthis.$elem.css( {\r\n\t\t\t\twidth: this.width + \"px\",\r\n\t\t\t\theight: this.height + \"px\"\r\n\t\t\t} ).appendTo( $where );\r\n\t\t}\r\n\t}\r\n}\r\n\r\nclass Button extends Widget {\r\n\tconstructor(width,height,label) {\r\n\t\tsuper( width, height );\r\n\t\tthis.label = label || \"Default\";\r\n\t\tthis.$elem = $( \"<button>\" ).text( this.label );\r\n\t}\r\n\trender($where) {\r\n\t\tsuper.render( $where );\r\n\t\tthis.$elem.click( this.onClick.bind( this ) );\r\n\t}\r\n\tonClick(evt) {\r\n\t\tconsole.log( \"Button '\" + this.label + \"' clicked!\" );\r\n\t}\r\n}\r\n\r\n$( document ).ready( function(){\r\n\tvar $body = $( document.body );\r\n\tvar btn1 = new Button( 125, 30, \"Hello\" );\r\n\tvar btn2 = new Button( 150, 40, \"World\" );\r\n\r\n\tbtn1.render( $body );\r\n\tbtn2.render( $body );\r\n} );\r\n```\r\n\r\nНесомненно, `class` в ES6 делает предыдущий классический код менее ужасным. В частности, довольно приятно наличие `super(..)` (хотя если копнуть поглубже, все не так красиво!).\r\n\r\nНесмотря на улучшение синтаксиса, **это не настоящие классы**, поскольку они по-прежнему работают поверх механизма `[[Prototype]]`. Им присущи те же самые концептуальные несостыковки, рассмотренные нами в 4 и 5 главах, и в начале этой главы. В Приложении А мы подробно изучим синтаксис `class` в ES6 и последствия его применения. Мы увидим, почему устранение проблем с синтаксисом не избавляет нас от путаницы с классами в JS, хотя и преподносится как решение.\r\n\r\nНеважно, используете ли вы классический прототипный синтаксис или новый синтаксический сахар ES6, вы по-прежнему моделируете предметную область с помощью \"классов\". И как показано в нескольких предыдущих главах, такой *выбор* в JavaScript сулит вам дополнительные проблемы и концептуальные трудности.\r\n\r\n### Делегирование объектов виджетов\r\n\r\nВот более простая реализация нашего примера с `Widget` / `Button`,  использующая **делегирование в стиле OLOO**:\r\n\r\n```js\r\nvar Widget = {\r\n\tinit: function(width,height){\r\n\t\tthis.width = width || 50;\r\n\t\tthis.height = height || 50;\r\n\t\tthis.$elem = null;\r\n\t},\r\n\tinsert: function($where){\r\n\t\tif (this.$elem) {\r\n\t\t\tthis.$elem.css( {\r\n\t\t\t\twidth: this.width + \"px\",\r\n\t\t\t\theight: this.height + \"px\"\r\n\t\t\t} ).appendTo( $where );\r\n\t\t}\r\n\t}\r\n};\r\n\r\nvar Button = Object.create( Widget );\r\n\r\nButton.setup = function(width,height,label){\r\n\t// делегированный вызов\r\n\tthis.init( width, height );\r\n\tthis.label = label || \"Default\";\r\n\r\n\tthis.$elem = $( \"<button>\" ).text( this.label );\r\n};\r\nButton.build = function($where) {\r\n\t// делегированный вызов\r\n\tthis.insert( $where );\r\n\tthis.$elem.click( this.onClick.bind( this ) );\r\n};\r\nButton.onClick = function(evt) {\r\n\tconsole.log( \"Button '\" + this.label + \"' clicked!\" );\r\n};\r\n\r\n$( document ).ready( function(){\r\n\tvar $body = $( document.body );\r\n\r\n\tvar btn1 = Object.create( Button );\r\n\tbtn1.setup( 125, 30, \"Hello\" );\r\n\r\n\tvar btn2 = Object.create( Button );\r\n\tbtn2.setup( 150, 40, \"World\" );\r\n\r\n\tbtn1.build( $body );\r\n\tbtn2.build( $body );\r\n} );\r\n```\r\n\r\nПрименяя OLOO-стиль, мы не думаем о `Widget` и `Button` как о родительском и дочернем классах. Вместо этого, `Widget` — **это просто объект**, некий набор утилит, которым может делегировать любой конкретный тип виджета, а `Button` — **это тоже самостоятельный объект** (с делегирующей ссылкой на `Widget`, разумеется!).\r\n\r\nМы **не** используем в обоих объектах одно и то же имя метода `render(..)`, как это предписывается шаблоном проектирования классов. Вместо этого мы выбрали разные имена (`insert(..)` и `build(..)`), которые более точно описывают решаемую каждым классом задачу. *Инициализирующие* методы названы `init(..)` и `setup(..)`, соответственно, по тем же причинам.\r\n\r\nЭтот шаблон проектирования с использованием делегирования не только предлагает различающиеся и более содержательные имена (вместо одинаковых и более общих), но и избавляет нас от некрасивых явных псевдополиморфных вызовов (`Widget.call` и `Widget.prototype.render.call`), заменяя их на простые, относительные делегирующие вызовы `this.init(..)` и `this.insert(..)`.\r\n\r\nИз синтаксиса исчезли конструкторы, `.prototype` и `new`, поскольку на самом деле для нас они бесполезны.\r\n\r\nЕсли вы были внимательны, то могли заметить, что вместо одного вызова (`var btn1 = new Button(..)`) у нас теперь два (`var btn1 = Object.create(Button)` и `btn1.setup(..)`). Поначалу это может показаться недостатком (больше кода).\r\n\r\nОднако даже это является **преимуществом кодирования в OLOO-стиле** по сравнению с классическим прототипным кодом. Почему?\r\n\r\nКонструкторы классов \"вынуждают\" вас выполнять создание и инициализацию за один шаг (по крайней мере, это настоятельно рекомендуется). Однако во многих случаях нужна большая гибкость и возможность выполнения этих этапов отдельно друг от друга (что и происходит в OLOO!).\r\n\r\nДопустим, в начале программы вы создаете все сущности и помещаете их в пул, но прежде чем извлечь их из этого пула и использовать, нужно дождаться, пока они не будут инициализированы. В примере выше оба вызова находятся рядом друг c другом, но разумеется их можно выполнять в совершенно разное время и в разных местах кода, если это необходимо.\r\n\r\n**OLOO** обеспечивает *лучшую* поддержку принципа разделения ответственности, поскольку создание и инициализацию необязательно объединять в одну операцию.\r\n\r\n## Более простой дизайн\r\n\r\nПомимо того, что OLOO обеспечивает нарочито более простой (и гибкий!) код, делегирование поведения может упростить архитектуру кода. Давайте рассмотрим последний пример, показывающий, как OLOO в целом упрощает дизайн.\r\n\r\nВ нашем примере будут два объекта-контроллера, один из которых обрабатывает форму входа на веб-странице, а другой отвечает за аутентификацию на сервере.\r\n\r\nНам понадобится вспомогательная утилита для Ajax-взаимодействия с сервером. Мы используем jQuery (хотя подойдет любой фреймворк), поскольку она не только выполняет за нас Ajax-запрос, но и возвращает в ответ promise (обещание), так что мы можем прослушивать ответ в вызывающем коде с помощью `.then(..)`.\r\n\r\n**Примечание:** Мы рассмотрим обещания (promises) в одной из будущих книг серии \"Вы не знаете JS\".\r\n\r\nПридерживаясь типичного шаблона проектирования классов, мы разобьем задачу и вынесем базовую функциональность в класс `Controller`, а затем создадим два дочерних класса, `LoginController` и `AuthController`, унаследованных от `Controller` и уточняющих базовое поведение.\r\n\r\n```js\r\n// Родительский класс\r\nfunction Controller() {\r\n\tthis.errors = [];\r\n}\r\nController.prototype.showDialog = function(title,msg) {\r\n\t// показывает пользователю заголовок и сообщение в диалоговом окне\r\n};\r\nController.prototype.success = function(msg) {\r\n\tthis.showDialog( \"Success\", msg );\r\n};\r\nController.prototype.failure = function(err) {\r\n\tthis.errors.push( err );\r\n\tthis.showDialog( \"Error\", err );\r\n};\r\n```\r\n\r\n```js\r\n// Дочерний класс\r\nfunction LoginController() {\r\n\tController.call( this );\r\n}\r\n// Привязываем дочерний класс к родительскому\r\nLoginController.prototype = Object.create( Controller.prototype );\r\nLoginController.prototype.getUser = function() {\r\n\treturn document.getElementById( \"login_username\" ).value;\r\n};\r\nLoginController.prototype.getPassword = function() {\r\n\treturn document.getElementById( \"login_password\" ).value;\r\n};\r\nLoginController.prototype.validateEntry = function(user,pw) {\r\n\tuser = user || this.getUser();\r\n\tpw = pw || this.getPassword();\r\n\r\n\tif (!(user && pw)) {\r\n\t\treturn this.failure( \"Please enter a username & password!\" );\r\n\t}\r\n\telse if (pw.length < 5) {\r\n\t\treturn this.failure( \"Password must be 5+ characters!\" );\r\n\t}\r\n\r\n\t// добрались сюда? валидация прошла успешно!\r\n\treturn true;\r\n};\r\n// Переопределяем для расширения базового `failure()`\r\nLoginController.prototype.failure = function(err) {\r\n\t// вызов \"super\"\r\n\tController.prototype.failure.call( this, \"Login invalid: \" + err );\r\n};\r\n```\r\n\r\n```js\r\n// Дочерний класс\r\nfunction AuthController(login) {\r\n\tController.call( this );\r\n\t// помимо наследования, нам необходима композиция\r\n\tthis.login = login;\r\n}\r\n// Привязываем дочерний класс к родительскому\r\nAuthController.prototype = Object.create( Controller.prototype );\r\nAuthController.prototype.server = function(url,data) {\r\n\treturn $.ajax( {\r\n\t\turl: url,\r\n\t\tdata: data\r\n\t} );\r\n};\r\nAuthController.prototype.checkAuth = function() {\r\n\tvar user = this.login.getUser();\r\n\tvar pw = this.login.getPassword();\r\n\r\n\tif (this.login.validateEntry( user, pw )) {\r\n\t\tthis.server( \"/check-auth\",{\r\n\t\t\tuser: user,\r\n\t\t\tpw: pw\r\n\t\t} )\r\n\t\t.then( this.success.bind( this ) )\r\n\t\t.fail( this.failure.bind( this ) );\r\n\t}\r\n};\r\n//  Переопределяем для расширения базового `success()`\r\nAuthController.prototype.success = function() {\r\n\t// вызов \"super\"\r\n\tController.prototype.success.call( this, \"Authenticated!\" );\r\n};\r\n// Переопределяем для расширения базового `failure()`\r\nAuthController.prototype.failure = function(err) {\r\n\t// вызов \"super\"\r\n\tController.prototype.failure.call( this, \"Auth Failed: \" + err );\r\n};\r\n```\r\n\r\n```js\r\nvar auth = new AuthController(\r\n\t// помимо наследования, нам необходима композиция\r\n\tnew LoginController()\r\n);\r\nauth.checkAuth();\r\n```\r\n\r\nУ всех контроллеров есть общее базовое поведение: `success(..)`, `failure(..)` и `showDialog(..)`. Дочерние классы `LoginController` и `AuthController` переопределяют `failure(..)` и `success(..)`, дополняя стандартное поведение базового класса. Обратите внимание, что `AuthController` необходим экземпляр `LoginController` для взаимодействия с формой входа, поэтому он становится свойством данных.\r\n\r\nМы также добавили к наследованию немного *композиции*. `AuthController` должен знать о `LoginController`, поэтому мы создаем экземпляр (`new LoginController()`) и сохраняем ссылку на него в члене данных класса `this.login`, так что `AuthController` может вызывать поведение `LoginController`.\r\n\r\n**Примечание:** Мы могли бы поддаться легкому искушению и унаследовать `AuthController` от `LoginController`, или наоборот, получив *виртуальную композицию* в цепочке наследования. Но это яркий пример того, какие проблемы порождает наследование классов в качестве *модели* предметной области. Ведь ни `AuthController`, ни `LoginController` не уточняют поведение друг друга, поэтому наследование между ними не имеет смысла, если только классы не являются вашим единственным шаблоном проектирования. Вместо этого мы добавили простую *композицию*, и теперь оба класса могут взаимодействовать, сохранив при этом преимущества наследования от базового класса `Controller`.\r\n\r\nЕсли вы разбираетесь в класс-ориентированном (ОО) проектировании, то все это должно выглядеть знакомым и естественным.\r\n\r\n### Де-класс-ификация\r\n\r\nНо **действительно ли нам нужно моделировать эту проблему** с помощью родительского класса `Controller`, двух дочерних классов и **композиции**? Можно ли воспользоваться преимуществами делегирования поведения в стиле OLOO и получить *гораздо* более простой дизайн? **Да!**\r\n\r\n```js\r\nvar LoginController = {\r\n\terrors: [],\r\n\tgetUser: function() {\r\n\t\treturn document.getElementById( \"login_username\" ).value;\r\n\t},\r\n\tgetPassword: function() {\r\n\t\treturn document.getElementById( \"login_password\" ).value;\r\n\t},\r\n\tvalidateEntry: function(user,pw) {\r\n\t\tuser = user || this.getUser();\r\n\t\tpw = pw || this.getPassword();\r\n\r\n\t\tif (!(user && pw)) {\r\n\t\t\treturn this.failure( \"Please enter a username & password!\" );\r\n\t\t}\r\n\t\telse if (pw.length < 5) {\r\n\t\t\treturn this.failure( \"Password must be 5+ characters!\" );\r\n\t\t}\r\n\r\n\t\t// добрались сюда? валидация прошла успешно!\r\n\t\treturn true;\r\n\t},\r\n\tshowDialog: function(title,msg) {\r\n\t\t// показывает пользователю сообщение об успехе в диалоговом окне\r\n\t},\r\n\tfailure: function(err) {\r\n\t\tthis.errors.push( err );\r\n\t\tthis.showDialog( \"Error\", \"Login invalid: \" + err );\r\n\t}\r\n};\r\n```\r\n\r\n```js\r\n// Связываем `AuthController` для делегирования к `LoginController`\r\nvar AuthController = Object.create( LoginController );\r\n\r\nAuthController.errors = [];\r\nAuthController.checkAuth = function() {\r\n\tvar user = this.getUser();\r\n\tvar pw = this.getPassword();\r\n\r\n\tif (this.validateEntry( user, pw )) {\r\n\t\tthis.server( \"/check-auth\",{\r\n\t\t\tuser: user,\r\n\t\t\tpw: pw\r\n\t\t} )\r\n\t\t.then( this.accepted.bind( this ) )\r\n\t\t.fail( this.rejected.bind( this ) );\r\n\t}\r\n};\r\nAuthController.server = function(url,data) {\r\n\treturn $.ajax( {\r\n\t\turl: url,\r\n\t\tdata: data\r\n\t} );\r\n};\r\nAuthController.accepted = function() {\r\n\tthis.showDialog( \"Success\", \"Authenticated!\" )\r\n};\r\nAuthController.rejected = function(err) {\r\n\tthis.failure( \"Auth Failed: \" + err );\r\n};\r\n```\r\n\r\nПоскольку `AuthController` теперь просто объект (как и `LoginController`), нам не нужно создавать экземпляр (`new AuthController()`) для решения нашей задачи. Все, что надо сделать:\r\n\r\n```js\r\nAuthController.checkAuth();\r\n```\r\n\r\nПри работе с OLOO вы легко можете добавить один или несколько объектов в цепочку делегирования, и вам не придется создавать экземпляры классов:\r\n\r\n```js\r\nvar controller1 = Object.create( AuthController );\r\nvar controller2 = Object.create( AuthController );\r\n```\r\n\r\nПри делегировании поведения `AuthController` и `LoginController` являются **просто объектами**, которые находятся на одном уровне и не выстроены в иерархию, как родительские и дочерние классы в класс-ориентированом подходе. Мы выбрали направление делегирования от `AuthController` к `LoginController` произвольно — оно вполне могло быть и противоположным.\r\n\r\nОсновной результат в том, что во втором листинге кода у нас осталось только две сущности (`LoginController` и `AuthController`), **а не три** как раньше.\r\n\r\nНам не нужен базовый класс `Controller` с \"общим\" поведением для двух других, поскольку делегирование поведения — достаточно мощный механизм, предоставляющий нам все требуемую функциональность. Нам также не нужно создавать экземпляры классов, поскольку классов нет, а есть **лишь сами объекты**. Более того, нет нужды в *композиции*, потому что делегирование позволяет обоим объектам взаимодействовать как угодно.\r\n\r\nНаконец, мы избежали ловушек с полиморфизмом в класс-ориентированном дизайне, отказавшись от одинаковых имен `success(..)` и `failure(..)` в обоих классах, ведь иначе нам потребовался бы уродливый явный псевдополиморфизм. Вместо этого, мы назвали их `accepted()` и `rejected(..)` в `AuthController`, и эти имена немного лучше описывают выполняемые задачи.\r\n\r\n**Подведем итог**: мы получили ту же функциональность, но (гораздо) более простой дизайн. В этом и состоит мощь OLOO-стиля и шаблона проектирования *делегирования поведения*.\r\n\r\n## Более элегантный синтаксис\r\n\r\nОдно из приятных новшеств, которое делает `class` в ES6 обманчиво притягательным (о том, почему стоит его избегать, см. в Приложении А!), —  сокращенный синтаксис для объявления методов класса:\r\n\r\n```js\r\nclass Foo {\r\n\tmethodName() { /* .. */ }\r\n}\r\n```\r\n\r\nМы избавились от ключевого слова `function` в объявлении, что обрадовало JS-разработчиков по всему миру!\r\n\r\nВы наверное заметили, что в OLOO синтаксисе `function` встречается на каждом шагу, что немного расходится с нашей целью упростить код. **Но мы можем это исправить!**\r\n\r\nВ ES6 мы можем использовать *сокращенные объявления методов* в любом объектном литерале, поэтому объект в OLOO-стиле можно объявить так (такой же сокращенный синтаксис, что и в теле `class`):\r\n\r\n```js\r\nvar LoginController = {\r\n\terrors: [],\r\n\tgetUser() { // Смотри-ка, нет `function`!\r\n\t\t// ...\r\n\t},\r\n\tgetPassword() {\r\n\t\t// ...\r\n\t}\r\n\t// ...\r\n};\r\n```\r\n\r\nЕдинственная разница в том, что в объектных литералах по-прежнему надо использовать разделители `,` между элементами, тогда как синтаксис `class` этого не требует. Но на фоне общей картины это сущий пустяк.\r\n\r\nБолее того, в ES6 мы можем заменить неуклюжий синтаксис с отдельным присваиванием каждого свойства (как в определении `AuthController`) на объектный литерал (с помощью сокращенной формы записи методов), и изменить `[[Prototype]]` этого объекта на `Object.setPrototypeOf(..)`:\r\n\r\n```js\r\n// используем более красивый синтаксис объектного литерала\r\n// с краткими методами!\r\nvar AuthController = {\r\n\terrors: [],\r\n\tcheckAuth() {\r\n\t\t// ...\r\n\t},\r\n\tserver(url,data) {\r\n\t\t// ...\r\n\t}\r\n\t// ...\r\n};\r\n\r\n// ТЕПЕРЬ, свяжем `AuthController` через делегирование с `LoginController`\r\nObject.setPrototypeOf( AuthController, LoginController );\r\n```\r\n\r\nС краткими методами ES6 наш OLOO-стиль **стал еще более удобным** чем раньше (но даже без этого он и так был гораздо проще и симпатичнее чем классический прототипный код). Чтобы получить красивый и чистый объектный синтаксис, **вам не нужны классы**!\r\n\r\n### Лексический недостаток\r\n\r\nУ кратких методов *есть* небольшой недостаток, о котором нужно знать. Рассмотрим код:\r\n\r\n```js\r\nvar Foo = {\r\n\tbar() { /*..*/ },\r\n\tbaz: function baz() { /*..*/ }\r\n};\r\n```\r\n\r\nЕсли убрать синтаксический сахар, то этот код будет работать так:\r\n\r\n```js\r\nvar Foo = {\r\n\tbar: function() { /*..*/ },\r\n\tbaz: function baz() { /*..*/ }\r\n};\r\n```\r\n\r\nВидите разницу? Сокращенный вариант `bar()` превратился в *анонимное функциональное выражение* (`function()..`), привязанное к свойству `bar`, поскольку у объекта функции нет имени. Сравните это с указанным вручную *именованным функциональным выражением* (`function baz()..`), которое не только привязано к свойству `.baz`, но и имеет лексический идентификатор `baz`.\r\n\r\nИ что из этого? В книге *\"Область видимости и замыкания\"* нашей серии *\"Вы не знаете JS\"*, мы подробно рассмотрели три основных недостатка *анонимных функциональных выражений*. Перечислим их еще раз и посмотрим, что из этого затрагивает краткие методы.\r\n\r\nОтсутствие идентификатора `name` у анонимной функции:\r\n\r\n1. усложняет отладку стектрейсов (stack traces)\r\n2. усложняет работу с функциями, ссылающимися на самих себя (рекурсия, подписка/отписка обработчика события, и т.п.)\r\n3. немного затрудняет понимание кода\r\n\r\nПункты 1 и 3 не относятся к кратким методам.\r\n\r\nНесмотря на то, что код без синтаксического сахара превращается в *анонимное функциональное выражение*, у которого обычно нет `name` в стектрейсах, краткие методы имеют внутреннее свойство `name` для объекта функции, поэтому стектрейсы могут его использовать (хотя это зависит от реализации и не гарантируется).\r\n\r\nПункт 2, к сожалению, **является недостатком кратких методов**. У них нет лексического идентификатора, на который они могли бы ссылаться. Рассмотрим:\r\n\r\n```js\r\nvar Foo = {\r\n\tbar: function(x) {\r\n\t\tif (x < 10) {\r\n\t\t\treturn Foo.bar( x * 2 );\r\n\t\t}\r\n\t\treturn x;\r\n\t},\r\n\tbaz: function baz(x) {\r\n\t\tif (x < 10) {\r\n\t\t\treturn baz( x * 2 );\r\n\t\t}\r\n\t\treturn x;\r\n\t}\r\n};\r\n```\r\n\r\nЯвная ссылка `Foo.bar(x*2)` в этом примере вроде бы решает проблему, но во многих случаях у функции нет такой возможности, например когда функция совместно используется различными объектами через делегирование, когда используется привязка `this`, и т.п. Вам придется использовать реальную ссылку функции на саму себя, и лучший способ сделать это — идентификатор `name` объекта функции.\r\n\r\nПросто помните об этой особенности кратких методов, и если возникнет проблема со ссылкой функции на саму себя, откажитесь от краткого синтаксиса **в данном конкретном объявлении** метода в пользу *именованного функционального выражения*: `baz: function baz(){..}`.\r\n\r\n## Интроспекция\r\n\r\nЕсли вы долгое время писали программы в класс-ориентированном стиле (в JS или других языках), то наверняка знаете, что такое *интроспекция типа*: проверка экземпляра с целью выяснить, какого *вида* объект перед вами. Основная цель *интроспекции типа* экземпляра класса — узнать о структуре и функциональных возможностях объекта исходя из того *как он был создан*.\r\n\r\nРассмотрим пример кода, в котором для интроспекции объекта `a1` используется `instanceof` (см. главу 5):\r\n\r\n```js\r\nfunction Foo() {\r\n\t// ...\r\n}\r\nFoo.prototype.something = function(){\r\n\t// ...\r\n}\r\n\r\nvar a1 = new Foo();\r\n\r\n// позднее\r\n\r\nif (a1 instanceof Foo) {\r\n\ta1.something();\r\n}\r\n```\r\n\r\nБлагодаря `Foo.prototype` (не `Foo`!) в цепочке `[[Prototype]]` (см. главу 5) объекта `a1`, оператор `instanceof` сообщает нам, что `a1` будто бы является экземпляром \"класса\" `Foo`. Исходя из этого мы предполагаем, что у `a1` есть функциональные возможности, описанные в \"классе\" `Foo`.\r\n\r\nРазумеется, никакого класса `Foo` не существует, есть всего-навсего обычная функция `Foo`, у которой есть ссылка на некоторый объект (`Foo.prototype`), с которым `a1` связывается ссылкой делегирования. По идее, оператор `instanceof` исходя из его названия должен проверять взаимосвязь между `a1` и `Foo`, но на самом деле он лишь сообщает нам, связаны ли `a1` и некий объект, на который ссылается `Foo.prototype`.\r\n\r\nСемантическая путаница (и косвенность) синтаксиса `instanceof` приводит к тому, что для интроспекции объекта `a1` с целью выяснить, обладает ли он функциональными возможностями искомого объекта, вам *необходима* функция, содержащая ссылку на этот объект. То есть, вы не можете напрямую узнать, связаны ли два объекта.\r\n\r\nВспомните абстрактный пример `Foo` / `Bar` / `b1`, который мы рассматривали ранее в этой главе:\r\n\r\n```js\r\nfunction Foo() { /* .. */ }\r\nFoo.prototype...\r\n\r\nfunction Bar() { /* .. */ }\r\nBar.prototype = Object.create( Foo.prototype );\r\n\r\nvar b1 = new Bar( \"b1\" );\r\n```\r\n\r\nВот список проверок, которые вам придется выполнить для *интроспекции типов* этих сущностей с помощью семантики `instanceof` и `.prototype`:\r\n\r\n```js\r\n// устанавливаем связь между `Foo` и `Bar`\r\nBar.prototype instanceof Foo; // true\r\nObject.getPrototypeOf( Bar.prototype ) === Foo.prototype; // true\r\nFoo.prototype.isPrototypeOf( Bar.prototype ); // true\r\n\r\n// устанавливаем связь между `b1` и `Foo` и `Bar`\r\nb1 instanceof Foo; // true\r\nb1 instanceof Bar; // true\r\nObject.getPrototypeOf( b1 ) === Bar.prototype; // true\r\nFoo.prototype.isPrototypeOf( b1 ); // true\r\nBar.prototype.isPrototypeOf( b1 ); // true\r\n```\r\n\r\nСогласитесь, что это немного отстойно. Например, интуитивно хочется, чтобы была возможность написать что-то вроде `Bar instanceof Foo` (потому что \"instance\" — довольно широкое понятие, и можно подумать, что оно включает в себя и \"наследование\"). Но такое сравнение в JS бессмысленно. Вместо этого приходится использовать `Bar.prototype instanceof Foo`.\r\n\r\nЕще один распространенный, но возможно менее надежный метод *интроспекции типов*, который многие разработчики предпочитают оператору `instanceof`, называется \"утиная типизация\". Этот термин берет свое начало из афоризма \"если нечто выглядит как утка и крякает как утка, то возможно это и есть утка\".\r\n\r\nПример:\r\n\r\n```js\r\nif (a1.something) {\r\n\ta1.something();\r\n}\r\n```\r\n\r\nВместо того, чтобы проверять связь между `a1` и объектом, содержащим делегируемую функцию  `something()`, мы предполагаем, что успешная проверка `a1.something` означает, что `a1` позволяет вызывать `.something()` (неважно, найден ли метод непосредственно в `a1` или делегирован какому-то другому объекту). Само по себе это предположение не такое уж и рискованное.\r\n\r\nОднако зачастую понятие \"утиной типизации\" расширяется, и делаются **дополнительные предположения о возможностях объекта**, выходящие за рамки проверки. Разумеется, это увеличивает риски и делает дизайн более хрупким.\r\n\r\nЯрким примером \"утиной типизации\" являются обещания (Promises) в ES6 (как мы уже говорили, их рассмотрение выходит за рамки этой книги).\r\n\r\nВ ряде случаев возникает необходимость проверить, является ли ссылка на некий объект *обещанием*, причем это делается путем проверки наличия у объекта функции `then()`. Другими словами, **если у какого угодно объекта** найдется метод `then()`, то механизм обещаний ES6 будет считать что это **\"thenable\"** объект, и будет ожидать от него стандартного поведения Promises.\r\n\r\nЕсли у вас какой-либо не-Promise объект, у которого по какой-то причине есть метод `then()`, то настоятельно рекомендуется держать его подальше от механизма ES6 Promise, чтобы избежать некорректных предположений.\r\n\r\nЭтот пример наглядно иллюстрирует риски \"утиной типизации\". Подобные вещи следует использовать лишь в разумных пределах и в контролируемом окружении.\r\n\r\nВозвращаясь к коду в стиле OLOO отметим, что *интроспекция типов* в данном случае может быть гораздо элегантнее. Давайте вспомним фрагмент OLOO кода `Foo` / `Bar` / `b1`, рассмотренный ранее в этой главе:\r\n\r\n```js\r\nvar Foo = { /* .. */ };\r\n\r\nvar Bar = Object.create( Foo );\r\nBar...\r\n\r\nvar b1 = Object.create( Bar );\r\n```\r\n\r\nПоскольку в OLOO у нас есть лишь обычные объекты, связанные делегированием `[[Prototype]]`, мы можем использовать гораздо более простую форму *интроспекции типов*:\r\n\r\n```js\r\n// устанавливаем связь между `Foo` и `Bar`\r\nFoo.isPrototypeOf( Bar ); // true\r\nObject.getPrototypeOf( Bar ) === Foo; // true\r\n\r\n// устанавливаем связь между `b1` и `Foo` и `Bar`\r\nFoo.isPrototypeOf( b1 ); // true\r\nBar.isPrototypeOf( b1 ); // true\r\nObject.getPrototypeOf( b1 ) === Bar; // true\r\n```\r\n\r\nМы больше не используем `instanceof`, потому что он претендует на то, что каким-то образом связан с классами. Теперь мы просто задаем (неформальный) вопрос \"являешься ли ты моим прототипом?\" Больше не нужны косвенные обращения, такие как `Foo.prototype` или ужасно многословное `Foo.prototype.isPrototypeOf(..)`.\r\n\r\nЯ считаю, что эти проверки гораздо более простые и не такие запутанные, как предыдущий набор интроспектирующих проверок. **И снова мы видим, что в JavaScript подход OLOO проще, чем кодирование в стиле классов (и при этом обладает теми же возможностями).**\r\n\r\n## Обзор (TL;DR)\r\n\r\nКлассы и наследование — это один из возможных шаблонов проектирования, который вы можете *использовать* или *не использовать* в архитектуре вашего ПО. Большинство разработчиков считают само собой разумеющимся тот факт, что классы являются единственным (правильным) способом организации кода. Но в этой главе мы увидели другой, менее популярный, но весьма мощный шаблон проектирования: **делегирование поведения**.\r\n\r\nДелегирование поведения предполагает, что все объекты находятся на одном уровне и связаны друг с другом делегированием, а не отношениями родитель-потомок. Механизм `[[Prototype]]` в JavaScript по своему замыслу является механизмом делегирования поведения. Это значит, что мы можем либо всячески пытаться реализовать механику классов поверх JS (см. главы 4 и 5), либо принять истинную сущность `[[Prototype]]` как механизма делегирования.\r\n\r\nЕсли вы проектируете код, используя только объекты, это не только упрощает синтаксис, но и позволяет добиться более простой архитектуры кода.\r\n\r\n**OLOO** (объекты, связанные с другими объектами) — это стиль кодирования, в котором объекты создаются и связываются друг с другом без абстракции классов. OLOO вполне естественным образом реализует делегирование поведения при помощи `[[Prototype]]`.\r\n\r\n\r\n"
  },
  {
    "path": "this & object prototypes/foreword.md",
    "content": "# Вы не знаете JS: *this* и Прототипы Объектов\n# Введение\n\nКогда я читал эту книгу и готовился написать введение, я задумался над тем, как изучал JavaScript и как сильно он изменился за последние 15 лет которые я программирую и разрабатываю на нем.\n\nКогда я 15 лет назад начал использовать JavaScript практика использования не-HTML технологий, таких как CSS и JS на ваших веб-страницах называлась DHTML или Dynamic HTML. Тогда польза от JavaScript, казалось, заключалась в добавлении анимированных снежинок на ваши веб-страницы или динамических часах, которые показывали время в строке состояния. Достаточно сказать, что в начале своей карьеры я не уделял много времени на изучение JavaScript из-за его новизны, которую я часто встречал в интернете.\n\nТолько в 2005 году я впервые открыл для себя JavaScript как настоящий язык программирования на который стоит обратить пристальное внимание. Покопавшись в первом бета-релизе Google Maps, я заметил потенциал, который у него был. В то время Google Maps был первым в своем роде приложением – оно позволяло перемещать карту с помощью мыши, увеличивать и уменьшать масштаб, выполнять запросы к серверу без перезагрузки страницы и все это с помощью JavaScript. Это было похоже на магию!\n\nКогда что-то кажется магией – это хороший признак того, что вы на заре нового способа создавать вещи. И ребята, сегодня я могу точно сказать, что я не ошибся, JavaScript является одним из основных языков, который используется для клиентского и серверного программирования, у меня не было другого пути.\n\nОдно из моих сожалений, когда я смотрю на последние 15 лет, заключается в том, что я не дал шанс JavaScript до 2005 года или если быть точнее, что мне не хватило дальновидности, чтобы увидеть JavaScript как настоящий язык программирования, который так же полезен, как C++, C#, Java и многие другие.\n\nЕсли бы в начале моей карьеры была серия книг *Вы не знаете JS* моя карьера сложилась бы совсем иначе. Одна из вещей, которая нравится мне в этой серии: она помогает вам понять JS в веселой и познавательной форме.\n\nКнига *this и Прототипы Объектов* - это замечательное продолжение серии. Она помогает закрепить материал из предыдущей книги *Область Видимости и Замыкания* и применить полученные знания на очень важную часть языка JS – ключевое слово `this` и прототипы. Эти две простые вещи имеют огромное значение для изучения реального программирования на JavaScript. Принцип создания объектов, их связывание и расширение необходим для создания больших и сложных приложений на JavaScript. Без этого создание сложных приложений (таких, как Google Maps) было бы невозможно.\n\nЯ хочу сказать, что большинство веб-разработчиков никогда не создавали объекты в JavaScript, и просто рассматривают язык как связующее звено между кнопками и AJAX-запросами. В какой-то момент своей карьеры я был в этом же лагере, но после того как я освоил работу с прототипами и объектами в JavaScript мне открылся мир возможностей. Если вы относитесь к категории разработчиков, создающих код-клей для связывания событий эта книга является для вас обязательной к прочтению. Если вам просто нужно повторить материал эта книга будет вашим ресурсом. В любом случае, вы не будете разочарованы. Доверьтесь мне!\n\nNick Berardi<br>\n[nickberardi.com](http://nickberardi.com), [@nberardi](http://twitter.com/nberardi)\n"
  },
  {
    "path": "this & object prototypes/toc.md",
    "content": "# You Don't Know JS: *this* & Object Prototypes\n\n## Table of Contents\n\n* Foreword\n* Preface\n* Chapter 1: `this` Or That?\n\t* Why `this`?\n\t* Confusions\n\t* What's `this`?\n* Chapter 2: `this` All Makes Sense Now!\n\t* Call-site\n\t* Nothing But Rules\n\t* Everything In Order\n\t* Binding Exceptions\n\t* Lexical `this`\n* Chapter 3: Objects\n\t* Syntax\n\t* Type\n\t* Contents\n\t* Iteration\n* Chapter 4: Mixing (Up) \"Class\" Objects\n\t* Class Theory\n\t* Class Mechanics\n\t* Class Inheritance\n\t* Mixins\n* Chapter 5: Prototypes\n\t* `[[Prototype]]`\n\t* \"Class\"\n\t* \"(Prototypal) Inheritance\"\n\t* Object Links\n* Chapter 6: Behavior Delegation\n\t* Towards Delegation-Oriented Design\n\t* Classes vs. Objects\n\t* Simpler Design\n\t* Nicer Syntax\n\t* Introspection\n* Appendix A: ES6 `class`\n* Appendix B: Acknowledgments\n\n"
  },
  {
    "path": "types & grammar/README.md",
    "content": "# Вы не знаете JS: Типы и грамматика\n\n<img src=\"cover.jpg\" width=\"300\">\n\n-----\n\n**[Купить цифровую или печатную книгу от издательства O'Reilly (англ.)](http://shop.oreilly.com/product/0636920033745.do)**\n\n-----\n\n[Оглавление](toc.md)\n\n* [Введение](foreword.md) (от [Дэвида Уолша](http://davidwalsh.name))\n* [Предисловие](../preface.md)\n* [Глава 1: Типы](ch1.md)\n* [Глава 2: Values](ch2.md)\n* [Глава 3: Natives](ch3.md)\n* [Глава 4: Coercion](ch4.md)\n* [Глава 5: Grammar](ch5.md)\n* [Приложение A: Mixed Environment JavaScript](apA.md)\n* [Приложение B: Благодарности!](apB.md)\n"
  },
  {
    "path": "types & grammar/apA.md",
    "content": "# You Don't Know JS: Types & Grammar\n# Appendix A: Mixed Environment JavaScript\n\nBeyond the core language mechanics we've fully explored in this book, there are several ways that your JS code can behave differently when it runs in the real world. If JS was executing purely inside an engine, it'd be entirely predictable based on nothing but the black-and-white of the spec. But JS pretty much always runs in the context of a hosting environment, which exposes your code to some degree of unpredictability.\n\nFor example, when your code runs alongside code from other sources, or when your code runs in different types of JS engines (not just browsers), there are some things that may behave differently.\n\nWe'll briefly explore some of these concerns.\n\n## Annex B (ECMAScript)\n\nIt's a little known fact that the official name of the language is ECMAScript (referring to the ECMA standards body that manages it). What then is \"JavaScript\"? JavaScript is the common tradename of the language, of course, but more appropriately, JavaScript is basically the browser implementation of the spec.\n\nThe official ECMAScript specification includes \"Annex B,\" which discusses specific deviations from the official spec for the purposes of JS compatibility in browsers.\n\nThe proper way to consider these deviations is that they are only reliably present/valid if your code is running in a browser. If your code always runs in browsers, you won't see any observable difference. If not (like if it can run in node.js, Rhino, etc.), or you're not sure, tread carefully.\n\nThe main compatibility differences:\n\n* Octal number literals are allowed, such as `0123` (decimal `83`) in non-`strict mode`.\n* `window.escape(..)` and `window.unescape(..)` allow you to escape or unescape strings with `%`-delimited hexadecimal escape sequences. For example: `window.escape( \"?foo=97%&bar=3%\" )` produces `\"%3Ffoo%3D97%25%26bar%3D3%25\"`.\n* `String.prototype.substr` is quite similar to `String.prototype.substring`, except that instead of the second parameter being the ending index (noninclusive), the second parameter is the `length` (number of characters to include).\n\n### Web ECMAScript\n\nThe Web ECMAScript specification (http://javascript.spec.whatwg.org/) covers the differences between the official ECMAScript specification and the current JavaScript implementations in browsers.\n\nIn other words, these items are \"required\" of browsers (to be compatible with each other) but are not (as of the time of writing) listed in the \"Annex B\" section of the official spec:\n\n* `<!--` and `-->` are valid single-line comment delimiters.\n* `String.prototype` additions for returning HTML-formatted strings: `anchor(..)`, `big(..)`, `blink(..)`, `bold(..)`, `fixed(..)`, `fontcolor(..)`, `fontsize(..)`, `italics(..)`, `link(..)`, `small(..)`, `strike(..)`, and `sub(..)`. **Note:** These are very rarely used in practice, and are generally discouraged in favor of other built-in DOM APIs or user-defined utilities.\n* `RegExp` extensions: `RegExp.$1` .. `RegExp.$9` (match-groups) and `RegExp.lastMatch`/`RegExp[\"$&\"]` (most recent match).\n* `Function.prototype` additions: `Function.prototype.arguments` (aliases internal `arguments` object) and `Function.caller` (aliases internal `arguments.caller`). **Note:** `arguments` and thus `arguments.caller` are deprecated, so you should avoid using them if possible. That goes doubly so for these aliases -- don't use them!\n\n**Note:** Some other minor and rarely used deviations are not included in our list here. See the external \"Annex B\" and \"Web ECMAScript\" documents for more detailed information as needed.\n\nGenerally speaking, all these differences are rarely used, so the deviations from the specification are not significant concerns. **Just be careful** if you rely on any of them.\n\n## Host Objects\n\nThe well-covered rules for how variables behave in JS have exceptions to them when it comes to variables that are auto-defined, or otherwise created and provided to JS by the environment that hosts your code (browser, etc.) -- so called, \"host objects\" (which include both built-in `object`s and `function`s).\n\nFor example:\n\n```js\nvar a = document.createElement( \"div\" );\n\ntypeof a;\t\t\t\t\t\t\t\t// \"object\" -- as expected\nObject.prototype.toString.call( a );\t// \"[object HTMLDivElement]\"\n\na.tagName;\t\t\t\t\t\t\t\t// \"DIV\"\n```\n\n`a` is not just an `object`, but a special host object because it's a DOM element. It has a different internal `[[Class]]` value (`\"HTMLDivElement\"`) and comes with predefined (and often unchangeable) properties.\n\nAnother such quirk has already been covered, in the \"Falsy Objects\" section in Chapter 4: some objects can exist but when coerced to `boolean` they (confoundingly) will coerce to `false` instead of the expected `true`.\n\nOther behavior variations with host objects to be aware of can include:\n\n* not having access to normal `object` built-ins like `toString()`\n* not being overwritable\n* having certain predefined read-only properties\n* having methods that cannot be `this`-overriden to other objects\n* and more...\n\nHost objects are critical to making our JS code work with its surrounding environment. But it's important to note when you're interacting with a host object and be careful assuming its behaviors, as they will quite often not conform to regular JS `object`s.\n\nOne notable example of a host object that you probably interact with regularly is the `console` object and its various functions (`log(..)`, `error(..)`, etc.). The `console` object is provided by the *hosting environment* specifically so your code can interact with it for various development-related output tasks.\n\nIn browsers, `console` hooks up to the developer tools' console display, whereas in node.js and other server-side JS environments, `console` is generally connected to the standard-output (`stdout`) and standard-error (`stderr`) streams of the JavaScript environment system process.\n\n## Global DOM Variables\n\nYou're probably aware that declaring a variable in the global scope (with or without `var`) creates not only a global variable, but also its mirror: a property of the same name on the `global` object (`window` in the browser).\n\nBut what may be less common knowledge is that (because of legacy browser behavior) creating DOM elements with `id` attributes creates global variables of those same names. For example:\n\n```html\n<div id=\"foo\"></div>\n```\n\nAnd:\n\n```js\nif (typeof foo == \"undefined\") {\n\tfoo = 42;\t\t// will never run\n}\n\nconsole.log( foo );\t// HTML element\n```\n\nYou're perhaps used to managing global variable tests (using `typeof` or `.. in window` checks) under the assumption that only JS code creates such variables, but as you can see, the contents of your hosting HTML page can also create them, which can easily throw off your existence check logic if you're not careful.\n\nThis is yet one more reason why you should, if at all possible, avoid using global variables, and if you have to, use variables with unique names that won't likely collide. But you also need to make sure not to collide with the HTML content as well as any other code.\n\n## Native Prototypes\n\nOne of the most widely known and classic pieces of JavaScript *best practice* wisdom is: **never extend native prototypes**.\n\nWhatever method or property name you come up with to add to `Array.prototype` that doesn't (yet) exist, if it's a useful addition and well-designed, and properly named, there's a strong chance it *could* eventually end up being added to the spec -- in which case your extension is now in conflict.\n\nHere's a real example that actually happened to me that illustrates this point well.\n\nI was building an embeddable widget for other websites, and my widget relied on jQuery (though pretty much any framework would have suffered this gotcha). It worked on almost every site, but we ran across one where it was totally broken.\n\nAfter almost a week of analysis/debugging, I found that the site in question had, buried deep in one of its legacy files, code that looked like this:\n\n```js\n// Netscape 4 doesn't have Array.push\nArray.prototype.push = function(item) {\n\tthis[this.length] = item;\n};\n```\n\nAside from the crazy comment (who cares about Netscape 4 anymore!?), this looks reasonable, right?\n\nThe problem is, `Array.prototype.push` was added to the spec sometime subsequent to this Netscape 4 era coding, but what was added is not compatible with this code. The standard `push(..)` allows multiple items to be pushed at once. This hacked one ignores the subsequent items.\n\nBasically all JS frameworks have code that relies on `push(..)` with multiple elements. In my case, it was code around the CSS selector engine that was completely busted. But there could conceivably be dozens of other places susceptible.\n\nThe developer who originally wrote that `push(..)` hack had the right instinct to call it `push`, but didn't foresee pushing multiple elements. They were certainly acting in good faith, but they created a landmine that didn't go off until almost 10 years later when I unwittingly came along.\n\nThere's multiple lessons to take away on all sides.\n\nFirst, don't extend the natives unless you're absolutely sure your code is the only code that will ever run in that environment. If you can't say that 100%, then extending the natives is dangerous. You must weigh the risks.\n\nNext, don't unconditionally define extensions (because you can overwrite natives accidentally). In this particular example, had the code said this:\n\n```js\nif (!Array.prototype.push) {\n\t// Netscape 4 doesn't have Array.push\n\tArray.prototype.push = function(item) {\n\t\tthis[this.length] = item;\n\t};\n}\n```\n\nThe `if` statement guard would have only defined this hacked `push()` for JS environments where it didn't exist. In my case, that probably would have been OK. But even this approach is not without risk:\n\n1. If the site's code (for some crazy reason!) was relying on a `push(..)` that ignored multiple items, that code would have been broken years ago when the standard `push(..)` was rolled out.\n2. If any other library had come in and hacked in a `push(..)` ahead of this `if` guard, and it did so in an incompatible way, that would have broken the site at that time.\n\nWhat that highlights is an interesting question that, frankly, doesn't get enough attention from JS developers: **Should you EVER rely on native built-in behavior** if your code is running in any environment where it's not the only code present?\n\nThe strict answer is **no**, but that's awfully impractical. Your code usually can't redefine its own private untouchable versions of all built-in behavior relied on. Even if you *could*, that's pretty wasteful.\n\nSo, should you feature-test for the built-in behavior as well as compliance-testing that it does what you expect? And what if that test fails -- should your code just refuse to run?\n\n```js\n// don't trust Array.prototype.push\n(function(){\n\tif (Array.prototype.push) {\n\t\tvar a = [];\n\t\ta.push(1,2);\n\t\tif (a[0] === 1 && a[1] === 2) {\n\t\t\t// tests passed, safe to use!\n\t\t\treturn;\n\t\t}\n\t}\n\n\tthrow Error(\n\t\t\"Array#push() is missing/broken!\"\n\t);\n})();\n```\n\nIn theory, that sounds plausible, but it's also pretty impractical to design tests for every single built-in method.\n\nSo, what should we do? Should we *trust but verify* (feature- and compliance-test) **everything**? Should we just assume existence is compliance and let breakage (caused by others) bubble up as it will?\n\nThere's no great answer. The only fact that can be observed is that extending native prototypes is the only way these things bite you.\n\nIf you don't do it, and no one else does in the code in your application, you're safe. Otherwise, you should build in at least a little bit of skepticism, pessimism, and expectation of possible breakage.\n\nHaving a full set of unit/regression tests of your code that runs in all known environments is one way to surface some of these issues earlier, but it doesn't do anything to actually protect you from these conflicts.\n\n### Shims/Polyfills\n\nIt's usually said that the only safe place to extend a native is in an older (non-spec-compliant) environment, since that's unlikely to ever change -- new browsers with new spec features replace older browsers rather than amending them.\n\nIf you could see into the future, and know for sure what a future standard was going to be, like for `Array.prototype.foobar`, it'd be totally safe to make your own compatible version of it to use now, right?\n\n```js\nif (!Array.prototype.foobar) {\n\t// silly, silly\n\tArray.prototype.foobar = function() {\n\t\tthis.push( \"foo\", \"bar\" );\n\t};\n}\n```\n\nIf there's already a spec for `Array.prototype.foobar`, and the specified behavior is equal to this logic, you're pretty safe in defining such a snippet, and in that case it's generally called a \"polyfill\" (or \"shim\").\n\nSuch code is **very** useful to include in your code base to \"patch\" older browser environments that aren't updated to the newest specs. Using polyfills is a great way to create predictable code across all your supported environments.\n\n**Tip:** ES5-Shim (https://github.com/es-shims/es5-shim) is a comprehensive collection of shims/polyfills for bringing a project up to ES5 baseline, and similarly, ES6-Shim (https://github.com/es-shims/es6-shim) provides shims for new APIs added as of ES6. While APIs can be shimmed/polyfilled, new syntax generally cannot. To bridge the syntactic divide, you'll want to also use an ES6-to-ES5 transpiler like Traceur (https://github.com/google/traceur-compiler/wiki/GettingStarted).\n\nIf there's likely a coming standard, and most discussions agree what it's going to be called and how it will operate, creating the ahead-of-time polyfill for future-facing standards compliance is called \"prollyfill\" (probably-fill).\n\nThe real catch is if some new standard behavior can't be (fully) polyfilled/prollyfilled.\n\nThere's debate in the community if a partial-polyfill for the common cases is acceptable (documenting the parts that cannot be polyfilled), or if a polyfill should be avoided if it purely can't be 100% compliant to the spec.\n\nMany developers at least accept some common partial polyfills (like for instance `Object.create(..)`), because the parts that aren't covered are not parts they intend to use anyway.\n\nSome developers believe that the `if` guard around a polyfill/shim should include some form of conformance test, replacing the existing method either if it's absent or fails the tests. This extra layer of compliance testing is sometimes used to distinguish \"shim\" (compliance tested) from \"polyfill\" (existence checked).\n\nThe only absolute take-away is that there is no absolute *right* answer here. Extending natives, even when done \"safely\" in older environments, is not 100% safe. The same goes for relying upon (possibly extended) natives in the presence of others' code.\n\nEither should always be done with caution, defensive code, and lots of obvious documentation about the risks.\n\n## `<script>`s\n\nMost browser-viewed websites/applications have more than one file that contains their code, and it's common to have a few or several `<script src=..></script>` elements in the page that load these files separately, and even a few inline-code `<script> .. </script>` elements as well.\n\nBut do these separate files/code snippets constitute separate programs or are they collectively one JS program?\n\nThe (perhaps surprising) reality is they act more like independent JS programs in most, but not all, respects.\n\nThe one thing they *share* is the single `global` object (`window` in the browser), which means multiple files can append their code to that shared namespace and they can all interact.\n\nSo, if one `script` element defines a global function `foo()`, when a second `script` later runs, it can access and call `foo()` just as if it had defined the function itself.\n\nBut global variable scope *hoisting* (see the *Scope & Closures* title of this series) does not occur across these boundaries, so the following code would not work (because `foo()`'s declaration isn't yet declared), regardless of if they are (as shown) inline `<script> .. </script>` elements or externally loaded `<script src=..></script>` files:\n\n```html\n<script>foo();</script>\n\n<script>\n  function foo() { .. }\n</script>\n```\n\nBut either of these *would* work instead:\n\n```html\n<script>\n  foo();\n  function foo() { .. }\n</script>\n```\n\nOr:\n\n```html\n<script>\n  function foo() { .. }\n</script>\n\n<script>foo();</script>\n```\n\nAlso, if an error occurs in a `script` element (inline or external), as a separate standalone JS program it will fail and stop, but any subsequent `script`s will run (still with the shared `global`) unimpeded.\n\nYou can create `script` elements dynamically from your code, and inject them into the DOM of the page, and the code in them will behave basically as if loaded normally in a separate file:\n\n```js\nvar greeting = \"Hello World\";\n\nvar el = document.createElement( \"script\" );\n\nel.text = \"function foo(){ alert( greeting );\\\n } setTimeout( foo, 1000 );\";\n\ndocument.body.appendChild( el );\n```\n\n**Note:** Of course, if you tried the above snippet but set `el.src` to some file URL instead of setting `el.text` to the code contents, you'd be dynamically creating an externally loaded `<script src=..></script>` element.\n\nOne difference between code in an inline code block and that same code in an external file is that in the inline code block, the sequence of characters `</script>` cannot appear together, as (regardless of where it appears) it would be interpreted as the end of the code block. So, beware of code like:\n\n```html\n<script>\n  var code = \"<script>alert( 'Hello World' )</script>\";\n</script>\n```\n\nIt looks harmless, but the `</script>` appearing inside the `string` literal will terminate the script block abnormally, causing an error. The most common workaround is:\n\n```js\n\"</sc\" + \"ript>\";\n```\n\nAlso, beware that code inside an external file will be interpreted in the character set (UTF-8, ISO-8859-8, etc.) the file is served with (or the default), but that same code in an inline `script` element in your HTML page will be interpreted by the character set of the page (or its default).\n\n**Warning:** The `charset` attribute will not work on inline script elements.\n\nAnother deprecated practice with inline `script` elements is including HTML-style or X(HT)ML-style comments around inline code, like:\n\n```html\n<script>\n<!--\nalert( \"Hello\" );\n//-->\n</script>\n\n<script>\n<!--//--><![CDATA[//><!--\nalert( \"World\" );\n//--><!]]>\n</script>\n```\n\nBoth of these are totally unnecessary now, so if you're still doing that, stop it!\n\n**Note:** Both `<!--` and `-->` (HTML-style comments) are actually specified as valid single-line comment delimiters (`var x = 2; <!-- valid comment` and `--> another valid line comment`) in JavaScript (see the \"Web ECMAScript\" section earlier), purely because of this old technique. But never use them.\n\n## Reserved Words\n\nThe ES5 spec defines a set of \"reserved words\" in Section 7.6.1 that cannot be used as standalone variable names. Technically, there are four categories: \"keywords\", \"future reserved words\", the `null` literal, and the `true` / `false` boolean literals.\n\nKeywords are the obvious ones like `function` and `switch`. Future reserved words include things like `enum`, though many of the rest of them (`class`, `extends`, etc.) are all now actually used by ES6; there are other strict-mode only reserved words like `interface`.\n\nStackOverflow user \"art4theSould\" creatively worked all these reserved words into a fun little poem (http://stackoverflow.com/questions/26255/reserved-keywords-in-javascript/12114140#12114140):\n\n> Let this long package float,\n> Goto private class if short.\n> While protected with debugger case,\n> Continue volatile interface.\n> Instanceof super synchronized throw,\n> Extends final export throws.\n>\n> Try import double enum?\n> - False, boolean, abstract function,\n> Implements typeof transient break!\n> Void static, default do,\n> Switch int native new.\n> Else, delete null public var\n> In return for const, true, char\n> …Finally catch byte.\n\n**Note:** This poem includes words that were reserved in ES3 (`byte`, `long`, etc.) that are no longer reserved as of ES5.\n\nPrior to ES5, the reserved words also could not be property names or keys in object literals, but that restriction no longer exists.\n\nSo, this is not allowed:\n\n```js\nvar import = \"42\";\n```\n\nBut this is allowed:\n\n```js\nvar obj = { import: \"42\" };\nconsole.log( obj.import );\n```\n\nYou should be aware though that some older browser versions (mainly older IE) weren't completely consistent on applying these rules, so there are places where using reserved words in object property name locations can still cause issues. Carefully test all supported browser environments.\n\n## Implementation Limits\n\nThe JavaScript spec does not place arbitrary limits on things such as the number of arguments to a function or the length of a string literal, but these limits exist nonetheless, because of implementation details in different engines.\n\nFor example:\n\n```js\nfunction addAll() {\n\tvar sum = 0;\n\tfor (var i=0; i < arguments.length; i++) {\n\t\tsum += arguments[i];\n\t}\n\treturn sum;\n}\n\nvar nums = [];\nfor (var i=1; i < 100000; i++) {\n\tnums.push(i);\n}\n\naddAll( 2, 4, 6 );\t\t\t\t// 12\naddAll.apply( null, nums );\t\t// should be: 499950000\n```\n\nIn some JS engines, you'll get the correct `499950000` answer, but in others (like Safari 6.x), you'll get the error: \"RangeError: Maximum call stack size exceeded.\"\n\nExamples of other limits known to exist:\n\n* maximum number of characters allowed in a string literal (not just a string value)\n* size (bytes) of data that can be sent in arguments to a function call (aka stack size)\n* number of parameters in a function declaration\n* maximum depth of non-optimized call stack (i.e., with recursion): how long a chain of function calls from one to the other can be\n* number of seconds a JS program can run continuously blocking the browser\n* maximum length allowed for a variable name\n* ...\n\nIt's not very common at all to run into these limits, but you should be aware that limits can and do exist, and importantly that they vary between engines.\n\n## Review\n\nWe know and can rely upon the fact that the JS language itself has one standard and is predictably implemented by all the modern browsers/engines. This is a very good thing!\n\nBut JavaScript rarely runs in isolation. It runs in an environment mixed in with code from third-party libraries, and sometimes it even runs in engines/environments that differ from those found in browsers.\n\nPaying close attention to these issues improves the reliability and robustness of your code.\n"
  },
  {
    "path": "types & grammar/apB.md",
    "content": "# Вы не знаете JS: Типы и грамматика\n# Приложение B: Благодарности\n\nЕсть множество людей, которых нужно поблагодарить за то, что появилась на свет эта книга и вся серия.\n\nВо-первых, я должен поблагодарить мою жену Кристен Симпсон (Christen Simpson) и двух моих детей Итана (Ethan) и Эмили (Emily), за то, что мирились с тем, что их папу вечно надо было отрывать от компьютера. Даже когда я не писал книги, моя одержимость JavaScript приклеивала мой взгляд к экрану больше, чем следовало. То время, которое я занял у моей семьи, и есть причина, по которой эти книги могут так глубоко и полностью объяснить JavaScript для вас, читатель. Я в большом долгу перед своей семьей.\n\nХочу поблагодарить моих редакторов в O'Reilly, а именно Simon St.Laurent и Brian MacDonald, как и остальных в команде редакторов и маркетинга. Работать с ними — одно удовольствие, и хочется особенно поблагодарить их за создание подходящих условий во время этого эксперимента с написанием \"open source\"-книги, за редактирование и выпуск.\n\nСпасибо всем тем, кто участвовал в улучшении этой серии книг присылая предложения по редактированию и корректировке, включая Shelley Powers, Tim Ferro, Evan Borden, Forrest L. Norvell, Jennifer Davis, Jesse Harlin и многих других. Большое спасибо Shane Hudson за написание предисловия к этой серии книг.\n\nСпасибо бесчисленным участникам сообщества, включая членов комитета TC39, кто поделился столько многим с нами и особенно за терпеливое отношение к моим бесконечным вопросам и изысканиям. John-David Dalton, Juriy \"kangax\" Zaytsev, Mathias Bynens, Axel Rauschmayer, Nicholas Zakas, Angus Croll, Reginald Braithwaite, Dave Herman, Brendan Eich, Allen Wirfs-Brock, Bradley Meck, Domenic Denicola, David Walsh, Tim Disney, Peter van der Zee, Andrea Giammarchi, Kit Cambridge, Eric Elliott и многие другие, я упомянул лишь малую часть.\n\nСерия книг *Вы не знаете JS* родилась на Kickstarter, поэтому я также хочу поблагодарить всех моих (почти) 500 щедрых инвесторов, без которых эта серия книг не появилась бы:\n\n> Jan Szpila, nokiko, Murali Krishnamoorthy, Ryan Joy, Craig Patchett, pdqtrader, Dale Fukami, ray hatfield, R0drigo Perez [Mx], Dan Petitt, Jack Franklin, Andrew Berry, Brian Grinstead, Rob Sutherland, Sergi Meseguer, Phillip Gourley, Mark Watson, Jeff Carouth, Alfredo Sumaran, Martin Sachse, Marcio Barrios, Dan, AimelyneM, Matt Sullivan, Delnatte Pierre-Antoine, Jake Smith, Eugen Tudorancea, Iris, David Trinh, simonstl, Ray Daly, Uros Gruber, Justin Myers, Shai Zonis, Mom & Dad, Devin Clark, Dennis Palmer, Brian Panahi Johnson, Josh Marshall, Marshall, Dennis Kerr, Matt Steele, Erik Slagter, Sacah, Justin Rainbow, Christian Nilsson, Delapouite, D.Pereira, Nicolas Hoizey, George V. Reilly, Dan Reeves, Bruno Laturner, Chad Jennings, Shane King, Jeremiah Lee Cohick, od3n, Stan Yamane, Marko Vucinic, Jim B, Stephen Collins, Ægir Þorsteinsson, Eric Pederson, Owain, Nathan Smith, Jeanetteurphy, Alexandre ELISÉ, Chris Peterson, Rik Watson, Luke Matthews, Justin Lowery, Morten Nielsen, Vernon Kesner, Chetan Shenoy, Paul Tregoing, Marc Grabanski, Dion Almaer, Andrew Sullivan, Keith Elsass, Tom Burke, Brian Ashenfelter, David Stuart, Karl Swedberg, Graeme, Brandon Hays, John Christopher, Gior, manoj reddy, Chad Smith, Jared Harbour, Minoru TODA, Chris Wigley, Daniel Mee, Mike, Handyface, Alex Jahraus, Carl Furrow, Rob Foulkrod, Max Shishkin, Leigh Penny Jr., Robert Ferguson, Mike van Hoenselaar, Hasse Schougaard, rajan venkataguru, Jeff Adams, Trae Robbins, Rolf Langenhuijzen, Jorge Antunes, Alex Koloskov, Hugh Greenish, Tim Jones, Jose Ochoa, Michael Brennan-White, Naga Harish Muvva, Barkóczi Dávid, Kitt Hodsden, Paul McGraw, Sascha Goldhofer, Andrew Metcalf, Markus Krogh, Michael Mathews, Matt Jared, Juanfran, Georgie Kirschner, Kenny Lee, Ted Zhang, Amit Pahwa, Inbal Sinai, Dan Raine, Schabse Laks, Michael Tervoort, Alexandre Abreu, Alan Joseph Williams, NicolasD, Cindy Wong, Reg Braithwaite, LocalPCGuy, Jon Friskics, Chris Merriman, John Pena, Jacob Katz, Sue Lockwood, Magnus Johansson, Jeremy Crapsey, Grzegorz Pawłowski, nico nuzzaci, Christine Wilks, Hans Bergren, charles montgomery, Ariel בר-לבב Fogel, Ivan Kolev, Daniel Campos, Hugh Wood, Christian Bradford, Frédéric Harper, Ionuţ Dan Popa, Jeff Trimble, Rupert Wood, Trey Carrico, Pancho Lopez, Joël kuijten, Tom A Marra, Jeff Jewiss, Jacob Rios, Paolo Di Stefano, Soledad Penades, Chris Gerber, Andrey Dolganov, Wil Moore III, Thomas Martineau, Kareem, Ben Thouret, Udi Nir, Morgan Laupies, jory carson-burson, Nathan L Smith, Eric Damon Walters, Derry Lozano-Hoyland, Geoffrey Wiseman, mkeehner, KatieK, Scott MacFarlane, Brian LaShomb, Adrien Mas, christopher ross, Ian Littman, Dan Atkinson, Elliot Jobe, Nick Dozier, Peter Wooley, John Hoover, dan, Martin A. Jackson, Héctor Fernando Hurtado, andy ennamorato, Paul Seltmann, Melissa Gore, Dave Pollard, Jack Smith, Philip Da Silva, Guy Israeli, @megalithic, Damian Crawford, Felix Gliesche, April Carter Grant, Heidi, jim tierney, Andrea Giammarchi, Nico Vignola, Don Jones, Chris Hartjes, Alex Howes, john gibbon, David J. Groom, BBox, Yu 'Dilys' Sun, Nate Steiner, Brandon Satrom, Brian Wyant, Wesley Hales, Ian Pouncey, Timothy Kevin Oxley, George Terezakis, sanjay raj, Jordan Harband, Marko McLion, Wolfgang Kaufmann, Pascal Peuckert, Dave Nugent, Markus Liebelt, Welling Guzman, Nick Cooley, Daniel Mesquita, Robert Syvarth, Chris Coyier, Rémy Bach, Adam Dougal, Alistair Duggin, David Loidolt, Ed Richer, Brian Chenault, GoldFire Studios, Carles Andrés, Carlos Cabo, Yuya Saito, roberto ricardo, Barnett Klane, Mike Moore, Kevin Marx, Justin Love, Joe Taylor, Paul Dijou, Michael Kohler, Rob Cassie, Mike Tierney, Cody Leroy Lindley, tofuji, Shimon Schwartz, Raymond, Luc De Brouwer, David Hayes, Rhys Brett-Bowen, Dmitry, Aziz Khoury, Dean, Scott Tolinski - Level Up, Clement Boirie, Djordje Lukic, Anton Kotenko, Rafael Corral, Philip Hurwitz, Jonathan Pidgeon, Jason Campbell, Joseph C., SwiftOne, Jan Hohner, Derick Bailey, getify, Daniel Cousineau, Chris Charlton, Eric Turner, David Turner, Joël Galeran, Dharma Vagabond, adam, Dirk van Bergen, dave ♥♫★ furf, Vedran Zakanj, Ryan McAllen, Natalie Patrice Tucker, Eric J. Bivona, Adam Spooner, Aaron Cavano, Kelly Packer, Eric J, Martin Drenovac, Emilis, Michael Pelikan, Scott F. Walter, Josh Freeman, Brandon Hudgeons, vijay chennupati, Bill Glennon, Robin R., Troy Forster, otaku_coder, Brad, Scott, Frederick Ostrander, Adam Brill, Seb Flippence, Michael Anderson, Jacob, Adam Randlett, Standard, Joshua Clanton, Sebastian Kouba, Chris Deck, SwordFire, Hannes Papenberg, Richard Woeber, hnzz, Rob Crowther, Jedidiah Broadbent, Sergey Chernyshev, Jay-Ar Jamon, Ben Combee, luciano bonachela, Mark Tomlinson, Kit Cambridge, Michael Melgares, Jacob Adams, Adrian Bruinhout, Bev Wieber, Scott Puleo, Thomas Herzog, April Leone, Daniel Mizieliński, Kees van Ginkel, Jon Abrams, Erwin Heiser, Avi Laviad, David newell, Jean-Francois Turcot, Niko Roberts, Erik Dana, Charles Neill, Aaron Holmes, Grzegorz Ziółkowski, Nathan Youngman, Timothy, Jacob Mather, Michael Allan, Mohit Seth, Ryan Ewing, Benjamin Van Treese, Marcelo Santos, Denis Wolf, Phil Keys, Chris Yung, Timo Tijhof, Martin Lekvall, Agendine, Greg Whitworth, Helen Humphrey, Dougal Campbell, Johannes Harth, Bruno Girin, Brian Hough, Darren Newton, Craig McPheat, Olivier Tille, Dennis Roethig, Mathias Bynens, Brendan Stromberger, sundeep, John Meyer, Ron Male, John F Croston III, gigante, Carl Bergenhem, B.J. May, Rebekah Tyler, Ted Foxberry, Jordan Reese, Terry Suitor, afeliz, Tom Kiefer, Darragh Duffy, Kevin Vanderbeken, Andy Pearson, Simon Mac Donald, Abid Din, Chris Joel, Tomas Theunissen, David Dick, Paul Grock, Brandon Wood, John Weis, dgrebb, Nick Jenkins, Chuck Lane, Johnny Megahan, marzsman, Tatu Tamminen, Geoffrey Knauth, Alexander Tarmolov, Jeremy Tymes, Chad Auld, Sean Parmelee, Rob Staenke, Dan Bender, Yannick derwa, Joshua Jones, Geert Plaisier, Tom LeZotte, Christen Simpson, Stefan Bruvik, Justin Falcone, Carlos Santana, Michael Weiss, Pablo Villoslada, Peter deHaan, Dimitris Iliopoulos, seyDoggy, Adam Jordens, Noah Kantrowitz, Amol M, Matthew Winnard, Dirk Ginader, Phinam Bui, David Rapson, Andrew Baxter, Florian Bougel, Michael George, Alban Escalier, Daniel Sellers, Sasha Rudan, John Green, Robert Kowalski, David I. Teixeira (@ditma, Charles Carpenter, Justin Yost, Sam S, Denis Ciccale, Kevin Sheurs, Yannick Croissant, Pau Fracés, Stephen McGowan, Shawn Searcy, Chris Ruppel, Kevin Lamping, Jessica Campbell, Christopher Schmitt, Sablons, Jonathan Reisdorf, Bunni Gek, Teddy Huff, Michael Mullany, Michael Fürstenberg, Carl Henderson, Rick Yoesting, Scott Nichols, Hernán Ciudad, Andrew Maier, Mike Stapp, Jesse Shawl, Sérgio Lopes, jsulak, Shawn Price, Joel Clermont, Chris Ridmann, Sean Timm, Jason Finch, Aiden Montgomery, Elijah Manor, Derek Gathright, Jesse Harlin, Dillon Curry, Courtney Myers, Diego Cadenas, Arne de Bree, João Paulo Dubas, James Taylor, Philipp Kraeutli, Mihai Păun, Sam Gharegozlou, joshjs, Matt Murchison, Eric Windham, Timo Behrmann, Andrew Hall, joshua price, Théophile Villard\n\nЭта серия книг выпускается в стиле \"open source\", включая редактирование и выпуск. Мы отдаем дань благодарности GitHub за предоставление такой возможности для сообщества!\n\nЕще раз спасибо всех бесчисленным людям, которых я не перечислил по имени, но кого я тем не менее должен поблагодарить. Пусть эта серия книг будет \"принадлежать\" всем нам и служить вкладом в увеличение информированности и понимании языка JavaScript, на благо все нынешних и будущих вкладчиков в общее дело сообщества.\n"
  },
  {
    "path": "types & grammar/ch1.md",
    "content": "# Вы не знаете JS: Типы и грамматика\n# Глава 1: Типы\n\nБольшинство разработчиков скажут, что динамический язык (как JS) не имеет *типов*. Посмотрим, что спецификация ES5.1 (http://www.ecma-international.org/ecma-262/5.1/) говорит об этом:\n\n> Алгоритмы в этой спецификации управляют значениями, каждое из которых имеет связанный с ним тип. Возможные типы значений — это именно те, которые определены в этом разделе. Далее типы подразделяются на типы языка ECMAScript и типы спецификации.\n>\n> Тип языка ECMAScript соответствует значениям, которые непосредственно обрабатываются программистом ECMAScript с использованием языка ECMAScript. Типы языка ECMAScript это: Undefined, Null, Boolean, String, Number и Object.\n\nЕсли вы поклонник строго типизированных (статически типизированных) языков, вы можете возражать против этого использования слова «тип». В этих языках «тип» означает гораздо *больше*, чем здесь, в JS.\n\nНекоторые люди говорят, что JS не должен претендовать на то, что имеет «типы», и их следует вместо этого называть «тегами» или, допустим, «подтипами».\n\nФух! Мы будем использовать вот это грубое определение (то же самое, что, похоже, подразумевает формулировка из спецификации): *тип* — это встроенный набор характеристик, который однозначно идентифицирует поведение конкретного значения и отличает его от других значений, как для движка, **так и для разработчика**.\n\nДругими словами, если и движок, и разработчик обрабатывают значение `42` (число) иначе, чем они обрабатывают значение `\"42\"` (строка), то эти два значения имеют разные *типы* — `number` и `string`, соответственно. Когда вы используете `42`, вы *собираетесь* делать что-то числовое, например, математику. Но когда вы используете `\"42\"`, вы *собираетесь* делать что-то строковое, например, выводить на страницу и т.д. **Эти два значения имеют разные типы.**\n\nЭто далеко не идеальное определение. Но оно достаточно хорошее для обсуждения. И согласуется с тем, как JS описывает себя.\n\n# Тип, как бы он ни назывался...\n\nЗа пределами академических разногласий в определениях, почему важно, имеет JavaScript *типы* или нет?\n\nНаличие правильного понимания каждого *типа* и его внутреннего поведения абсолютно необходимо для понимания того, как правильно и точно преобразовывать значения в разные типы (см. «Приведение типов», глава 4). Почти каждая программа на JS, когда-либо написанная, должна будет обрабатывать приведение типов значений в каком-то виде или форме, поэтому важно, чтобы вы делали это ответственно и уверенно.\n\nЕсли у вас есть значение `42` типа `number`, но вы хотите обрабатывать его как `string`, например, вытаскивая `\"2\"` в качестве символа в позиции `1`, вы, очевидно, должны сначала преобразовать (привести) значение из `number` к `string`.\n\nЭто кажется довольно простым.\n\nНо существует много разных способов такого приведения. Некоторые из них ясны, понятны и надёжны. Но если вы не будете осторожны, приведение может произойти очень странным и непредсказуемым образом.\n\nПутаница с приведением, возможно, является одним из самых глубоких разочарований для разработчиков JavaScript. Его часто критикуют за то, что оно настолько *опасно*, что считается недостатком в устройстве языка, которого следует сторониться и избегать.\n\nВооружившись полным пониманием типов JavaScript, мы попытаемся проиллюстрировать, почему *плохая репутация* приведения в значительной степени раздута и несколько незаслуженна — чтобы взглянуть на вещи с другой точки зрения, увидеть силу и полезность приведения. Но во-первых, мы должны получше разобраться со значениями и типами.\n\n## Встроенные типы\n\nВ JavaScript определены семь встроенных типов:\n\n* `null`\n* `undefined`\n* `boolean`\n* `number`\n* `string`\n* `object`\n* `symbol` — добавлен в ES6!\n\n**Примечание:** Все эти типы, кроме `object`, называют \"примитивами\".\n\nОператор `typeof` проверяет тип заданного значения и всегда возвращает одно из семи строковых значений — и как ни странно, они не имеют точного соответствия с семью встроенными типами, которые мы только что перечислили.\n\n```js\ntypeof undefined     === \"undefined\"; // true\ntypeof true          === \"boolean\";   // true\ntypeof 42            === \"number\";    // true\ntypeof \"42\"          === \"string\";    // true\ntypeof { life: 42 }  === \"object\";    // true\n\n// добавлен в ES6!\ntypeof Symbol()      === \"symbol\";    // true\n```\n\nЭти шесть перечисленных типов имеют значения соответствующего типа и возвращают строковое значение с таким именем, как показано в примере. `Symbol` — это новый тип данных из ES6, он будет рассмотрен в главе 3.\n\nКак вы могли заметить, я исключил `null` из приведённого выше списка. Он *особенный* — особенный в том смысле, что в сочетании с оператором `typeof` он глючит:\n\n```js\ntypeof null === \"object\"; // true\n```\n\nБыло бы неплохо (и правильно!), если бы вернулось `\"null\"`, но эта оригинальная ошибка в JS сохраняется почти два десятилетия и, скорее всего, никогда не будет исправлена, потому что существует настолько много кода в вебе, который полагается на это глючное поведение, что «исправление» ошибки *создало бы* больше «ошибок» и сломало бы много веб-программ.\n\nЕсли вы хотите проверить значение `null`, используя его тип, вам потребуется составное условие:\n\n```js\nvar a = null;\n\n(!a && typeof a === \"object\"); // true\n```\n\n`null` — единственное примитивное значение, которое является «ложным» (или «подобным ложному», см. главу 4), но также возвращает «объект» из проверки типа.\n\nТак каково же седьмое строковое значение, возвращаемое `typeof`?\n\n```js\ntypeof function a(){ /* .. */ } === \"function\"; // true\n```\n\nЛегко решить, что `function` это встроенный тип верхнего уровня в JS, особенно учитывая такое поведение оператора `typeof`. Однако, если вы прочитаете спецификацию, вы увидите, что это фактически «подтип» объекта. В частности, функцию называют «вызываемым объектом» — объектом, который имеет внутреннее свойство `[[Call]]`, которое позволяет ему вызываться.\n\nТот факт, что функции фактически являются объектами, весьма полезен. Самое главное, они могут иметь свойства. Например:\n\n```js\nfunction a(b,c) {\n\t/* .. */\n}\n```\n\nОбъект функции имеет свойство `length`, определяемое числом формальных параметров, с которыми он был объявлен.\n\n```js\na.length; // 2\n```\n\nПоскольку вы объявили функцию с двумя формальными именованными параметрами (`b` и `c`), «длина функции» равна `2`.\n\nЧто насчёт массивов? В JS они нативные, так особый ли это тип?\n\n```js\ntypeof [1,2,3] === \"object\"; // true\n```\n\nНет, это просто объекты. Наиболее целесообразно думать о них также как о «подтипе» объектов (см. Главу 3), в данном случае — с дополнительными характеристиками численного индексирования (в отличие от просто строковых ключей, как у обычных объектов) и поддержкой автоматически обновляемого свойства `.length`.\n\n## Значения как типы\n\nВ JavaScript переменные не имеют типов — **значения имеют типы**. Переменные могут хранить любое значение в любой момент времени.\n\nДругими словами, JS не имеет «принудительного применения типа», поскольку движок не настаивает на том, чтобы *переменная* всегда содержала значение *того же начального типа*, с которого инициализировалась. Переменная может в одном операторе присваивания содержать `string`, а в следующем — `number` и т.д.\n\n*Значение* `42` имеет встроенный тип `number`, и этот *тип* не может быть изменён. Другое значение, например, `\"42\"` с типом `string`, может быть получено *из* значения `42` типа `number` с помощью **приведения типов** (см. Главу 4).\n\nЕсли вы используете `typeof` для переменной, он не спрашивает: «Какой тип у этой переменной?», как может показаться, поскольку переменные в JS не имеют типов. Вместо этого он спрашивает: «Какой тип значения *в* этой переменной?».\n\n```js\nvar a = 42;\ntypeof a; // \"number\"\n\na = true;\ntypeof a; // \"boolean\"\n```\n\nОператор `typeof` всегда возвращает строку. Поэтому:\n\n```js\ntypeof typeof 42; // \"string\"\n```\n\nСначала `typeof 42` возвращает `\"number\"`, и `typeof \"number\"` это `\"string\"`.\n\n### Неопределённые и необъявленные переменные\n\nПеременные, которые не имеют значения *в данный момент*, фактически имеют значение `undefined`. Вызов `typeof` для таких переменных возвращает `\"undefined\"`:\n\n```js\nvar a;\n\ntypeof a; // \"undefined\"\n\nvar b = 42;\nvar c;\n\n// далее\nb = c;\n\ntypeof b; // \"undefined\"\ntypeof c; // \"undefined\"\n```\n\nДля большинства разработчиков удобно думать о слове «undefined» («неопределённый») как о синониме слова «undeclared» («необъявленный»). Однако в JS две эти концепции — совершенно разные.\n\n«Неопределённая» переменная — это та, которая была объявлена в доступной области видимости, но *в данный момент* не имеющая значения. В отличие от этого, «необъявленная» переменная — это та, которая не была объявлена в доступной области видимости.\n\nПосмотрите внимательно:\n\n```js\nvar a;\n\na; // undefined\nb; // ReferenceError: b is not defined\n```\n\nДосадную путаницу создаёт сообщение об ошибке, которое браузеры назначают этой ситуации. Как вы можете видеть, сообщение — «b is not defined» («b не определено»), которое, конечно, очень легко и логично спутать с «b is undefined» («b неопределено»). Ещё раз: «неопределено» и «не определено» — это совершенно разные вещи. Было бы неплохо, если бы браузеры писали что-то вроде «b не найдено» или «b не объявлено», чтобы уменьшить путаницу!\n\nСуществует также особое поведение у `typeof`, связанное с необъявленными переменными, которое ещё больше усиливает путаницу. Смотрите:\n\n```js\nvar a;\n\ntypeof a; // \"undefined\"\n\ntypeof b; // \"undefined\"\n```\n\nОператор `typeof` возвращает `\"undefined\"` даже для «необъявленных» (или «не определённых») переменных. Обратите внимание, что при выполнении `typeof b` ошибки не возникло, хотя `b` является необъявленной переменной. Это особая мера безопасности в поведении `typeof`.\n\nКак и в примере выше, было бы неплохо, если бы `typeof`, используемый с необъявленной переменной, возвращал «undeclared» («необъявлено») вместо объединения результата с другой ситуацией, когда переменная «undefined» («неопределена»).\n\n### `typeof` для необъявленных переменных\n\nТем не менее, эта мера безопасности является полезной функцией при работе с JavaScript в браузере, где несколько файлов скриптов могут загружать переменные в общее глобальное пространство имён.\n\n**Примечание:** Многие разработчики считают, что в глобальном пространстве имён никогда не должно быть никаких переменных, и что всё должно содержаться в модулях и закрытых/отдельных пространствах имён. Это прекрасно в теории, но практически невозможно на практике; хотя всё же это хорошая цель, к которой нужно стремиться! К счастью, ES6 добавил первоклассную поддержку модулей, что в конечном итоге сделает это гораздо более удобным.\n\nВ качестве простого примера представьте, что в вашей программе есть «режим отладки», который управляется глобальной переменной (флагом) под названием `DEBUG`. Вы хотите проверить, была ли объявлена эта переменная перед выполнением задачи отладки, например, вывода сообщения в консоль. Глобальное объявление `var DEBUG = true` верхнего уровня будет включено только в файл «debug.js», который вы загружаете в браузер только тогда, когда находитесь в режиме разработки/тестирования, но не для продакшна.\n\nОднако вы должны позаботиться о том, как вы проверяете глобальную переменную `DEBUG` в остальной части кода своего приложения, чтобы не получить `ReferenceError`. В этом случае безопасность в `typeof` станет вашим другом.\n\n```js\n// упс, здесь будет ошибка!\nif (DEBUG) {\n\tconsole.log( \"Debugging is starting\" );\n}\n\n// это безопасная проверка на наличие\nif (typeof DEBUG !== \"undefined\") {\n\tconsole.log( \"Debugging is starting\" );\n}\n```\n\nЭтот вид проверки полезен, даже если вы работаете не с переменными, определяемыми пользователем (как `DEBUG`). Если вы выполняете проверку функционала для встроенного API, для вас также может быть полезна проверка без выброса ошибки:\n\n```js\nif (typeof atob === \"undefined\") {\n\tatob = function() { /*..*/ };\n}\n```\n\n**Примечание:** Если вы определяете полифилл для функционала, которого ещё не существует, вы, вероятно, захотите избежать использования `var`, чтобы объявить `atob`. Если вы объявляете `var atob` внутри оператора `if`, это объявление всплывёт (см. книгу *Область видимости и замыкания* из этой серии) в верхнюю часть области видимости, даже если условие `if` не выполнится (потому что глобальная `atob` уже существует!). В некоторых браузерах и для некоторых специальных типов глобальных встроенных переменных (часто называемых «host-объектами») это дублирующее объявление может вызвать ошибку. Опущение `var` предотвращает это объявление от всплытия.\n\nДругой способ выполнения этих проверок глобальных переменных, но без защиты `typeof` — это увидеть, что все глобальные переменные также являются свойствами глобального объекта, который в браузере обычно является объектом `window`. Таким образом, вышеуказанные проверки могли быть выполнены (совершенно безопасно) вот так:\n\n```js\nif (window.DEBUG) {\n\t// ..\n}\n\nif (!window.atob) {\n\t// ..\n}\n```\n\nВ отличие от ссылок на необъявленные переменные, при попытке доступа к свойству объекта (даже глобального объекта `window`), ошибки `ReferenceError` выброшено не будет.\n\nС другой стороны, ручное обращение к глобальной переменной с помощью `window` — это то, чего некоторые разработчики предпочитают избегать, особенно если ваш код должен запускаться в нескольких JS-средах (не только в браузерах, но и в серверном node.js, например), где глобальная переменная не всегда называется `window`.\n\nТехнически, эта защита в `typeof` полезна, даже если вы не используете глобальные переменные, хотя такие условия более редки, и некоторые разработчики могут найти этот подход к стилю кода менее желательным. Представьте себе функцию-утилиту, которая предназначена вами для копирования и вставки в чужие программы или модули, в которой вы хотите проверить, определила ли основная программа какую-то переменную (чтобы вы могли её использовать) или нет:\n\n```js\nfunction doSomethingCool() {\n\tvar helper =\n\t\t(typeof FeatureXYZ !== \"undefined\") ?\n\t\tFeatureXYZ :\n\t\tfunction() { /*.. функция по умолчанию ..*/ };\n\n\tvar val = helper();\n\t// ..\n}\n```\n\n`doSomethingCool()` проверяет переменную с именем `FeatureXYZ`, и если она найдена, использует её, но если нет, то использует свою собственную. Теперь, если кто-то включает эту утилиту в свой модуль/программу, она надёжно проверяет, определена `FeatureXYZ` или нет:\n\n```js\n// IIFE (см. обсуждение \"Immediately Invoked Function Expressions\"\n// (\"Немедленно вызываемых функций\") в книге *Область видимости и замыкания* из этой серии)\n(function(){\n\tfunction FeatureXYZ() { /*.. моя функция XYZ ..*/ }\n\n\t// подключаем `doSomethingCool(..)`\n\tfunction doSomethingCool() {\n\t\tvar helper =\n\t\t\t(typeof FeatureXYZ !== \"undefined\") ?\n\t\t\tFeatureXYZ :\n\t\t\tfunction() { /*.. функция по умолчанию ..*/ };\n\n\t\tvar val = helper();\n\t\t// ..\n\t}\n\n\tdoSomethingCool();\n})();\n```\n\nЗдесь `FeatureXYZ` — вовсе не глобальная переменная, но мы по-прежнему используем защиту `typeof`, чтобы сделать проверку безопасной. И что важно, здесь *нет* объекта, который мы можем использовать (как мы делали для глобальных переменных с `window.___`), чтобы сделать проверку, поэтому `typeof` весьма полезен.\n\nДругие разработчики предпочли бы шаблон проектирования, называемый «внедрение зависимости», где вместо неявной проверки в `doSomethingCool()`, объявлена ли `FeatureXYZ` вне её, нужно явно передать зависимость, например:\n\n```js\nfunction doSomethingCool(FeatureXYZ) {\n\tvar helper = FeatureXYZ ||\n\t\tfunction() { /*.. функция по умолчанию ..*/ };\n\n\tvar val = helper();\n\t// ..\n}\n```\n\nСуществует множество вариантов реализации такого функционала. Ни один шаблон здесь не является «правильным» или «неправильным» — существуют разные нюансы у каждого подхода. Но в целом, приятно, что защита `typeof` для необъявленных переменных даёт нам больше возможностей.\n\n## Обзор\n\nВ JavaScript есть семь встроенных *типов*: `null`, `undefined`, `boolean`, `number`, `string`, `object`, `symbol`. Их можно определить с помощью оператора `typeof`.\n\nПеременные не имеют типов, но их имеют значения переменных. Эти типы определяют внутреннее поведение значений.\n\nМногие разработчики полагают, что «неопределённый» и «необъявленный» — это примерно одно и то же, но в JavaScript это совершенно разные вещи. `undefined` («неопределённый») — это значение, которое может содержать объявленная переменная. «Undeclared» («необъявленный») означает, что переменная не была объявлена.\n\nJavaScript, к сожалению, в некотором роде отождествляет эти два термина, не только в сообщениях об ошибках («ReferenceError: a is not defined»), но также и в значении, возвращаемом `typeof`, являющемся `\"undefined\"` для обоих случаев.\n\nОднако защита (предотвращение ошибки) в `typeof` при использовании с необъявленной переменной может быть полезна в некоторых случаях.\n"
  },
  {
    "path": "types & grammar/ch2.md",
    "content": "# Вы не знаете JS: Типы и грамматика\n# Глава 2: Типы\n\n`array`, `string`, и `number` являются основными составными элементами любой программы, но в JavaScript, при работе с этими типами данных, есть несколько особенностей, которые могут смутить или запутать вас.\n\nДавайте посмотрим на несколько встроенных типов JS, и разберемся как мы можем полностью понять и корректно использовать их поведение.\n\n## Массивы\n\nЕсли сравнивать с другими строго типизированными языками, в JavaScript массивы - всего  лишь контейнеры для любых типов значений, начиная от  `string` до `number`, `object` и даже других `array` (с помощью которых можно создавать многомерные массивы).\n\n```js\nvar a = [ 1, \"2\", [3] ];\n\na.length;\t\t// 3\na[0] === 1;\t\t// true\na[2][0] === 3;\t// true\n```\n\nВам не нужно предварительно устанавливать размер `array` (подробнее в \"Массивы\" Глава 3), вы можете просто объявить их и добавлять значения когда вам нужно:\n\n```js\nvar a = [ ];\n\na.length;\t// 0\n\na[0] = 1;\na[1] = \"2\";\na[2] = [ 3 ];\n\na.length;\t// 3\n```\n\n**Предупреждение:** Используя `delete` для значения `array` будет удалена ячейка `array` с этим значением, но даже если вы удалите последний элемент таким способом, это **НЕ** обновит свойство `length`, так что будьте осторожны! Работа оператора `delete` более детально будет рассмотрена в Главе 5.\n\nБудьте осторожны при создании \"разрозненных\" массивов (оставляя или создавая пустые/пропущенные ячейки):\n\n```js\nvar a = [ ];\n\na[0] = 1;\n// ячейка `a[1]` отсутствует\na[2] = [ 3 ];\n\na[1];\t\t// undefined\n\na.length;\t// 3\n```\n\nТакой код может привести к странному поведению \"пустых ячеек\" оставленных между элементами массива. Пустой слот со значением `undefined` внутри, ведет себя не так же как явно объявленный элемент массива (`a[1] = undefined`). Подробнее в главе 3 \"Массивы\".\n\nМассивы `array`s проиндексированы числами (как и ожидается), но хитрость в том, что они также являются объектами, которые могут иметь `string` ключи/свойства, добавленные к ним (но такие свойства не будут посчитаны в длине массива `length`):\n\n```js\nvar a = [ ];\n\na[0] = 1;\na[\"foobar\"] = 2;\n\na.length;\t\t// 1\na[\"foobar\"];\t// 2\na.foobar;\t\t// 2\n```\n\nКак бы там ни было, нужно быть осторожнее при использовании индексов массива в виде `string`, т.к. это значение может быть преобразовано в тип `number`, потому что использование индекса `number` для массива предпочтительнее чем `string`!\n\n```js\nvar a = [ ];\n\na[\"13\"] = 42;\n\na.length; // 14\n```\n\nВ общем, это не самая лучшая идея использовать пару `string` ключ/свойство как элемент массива `array`. Используйте `object` для хранения пар ключ/свойство, а массивы `array`s приберегите для хранения значений в ячейках с числовыми индексами.\n\n### Массивоподобные\n\nБывают случаи когда нужно преобразовать  массивоподобное значение (пронумерованную коллекцию значений) в настоящий массив `array`, обычно таким образом вы сможете применить методы массива (такие как `indexOf(..)`, `concat(..)`, `forEach(..)`, etc.) к коллекции значений.\n\nНапример, различные DOM запросы возвращают список DOM элементов который не является настоящим массивом `array`, но, при этом он достаточно похож на массив для преобразования. Другой общеизвестный пример - когда функция предоставляет свои аргументы `arguments` в виде массивоподобного объекта (в ES6, считается устаревшим), чтобы получить доступ к списку аргументов.\n\nОдин из самых распространенных способов осуществить такое преобразование одолжить метод `slice(..)` для значения:\n\n```js\nfunction foo() {\n\tvar arr = Array.prototype.slice.call( arguments );\n\tarr.push( \"bam\" );\n\tconsole.log( arr );\n}\n\nfoo( \"bar\", \"baz\" ); // [\"bar\",\"baz\",\"bam\"]\n```\n\nЕсли `slice()` вызван без каких-либо параметров, как в примере выше, стандартные значения его параметров позволят продублировать массив `array` (а в нашем случае, массивоподобное значение).\n\nВ ES6, есть встроенный метод `Array.from(..)` который при вызове выполнит то же самое:\n\n```js\n...\nvar arr = Array.from( arguments );\n...\n```\n\n**Примечание:** `Array.from(..)` имеет несколько мощных возможностей, детально о них рассказано в книге *ES6 и не только* данной серии.\n\n## Строки\n\nЕсть общее мнение, что строки `string` являются всего лишь массивами `array` из символов. Пока мы решаем можно или нельзя использовать `array`, важно осознавать что JavaScript `string` на самом деле не то же самое что массивы `array` символов. Это сходство по большей части поверхностное.\n\nНапример, давайте сравним два значения:\n\n```js\nvar a = \"foo\";\nvar b = [\"f\",\"o\",\"o\"];\n```\n\nСтроки имеют поверхностные сходства по отношению к массивам -- и массивоподобным, как выше -- например, оба из них имеют свойство `length`, метод `indexOf(..)` (`array` только в ES5), и метод `concat(..)`:\n\n```js\na.length;\t\t\t\t\t\t\t// 3\nb.length;\t\t\t\t\t\t\t// 3\n\na.indexOf( \"o\" );\t\t\t\t\t// 1\nb.indexOf( \"o\" );\t\t\t\t\t// 1\n\nvar c = a.concat( \"bar\" );\t\t\t// \"foobar\"\nvar d = b.concat( [\"b\",\"a\",\"r\"] );\t// [\"f\",\"o\",\"o\",\"b\",\"a\",\"r\"]\n\na === c;\t\t\t\t\t\t\t// false\nb === d;\t\t\t\t\t\t\t// false\n\na;\t\t\t\t\t\t\t\t\t// \"foo\"\nb;\t\t\t\t\t\t\t\t\t// [\"f\",\"o\",\"o\"]\n```\n\nИтак, строки по большей части это \"массивы символов\", верно? **НЕ совсем**:\n\n```js\na[1] = \"O\";\nb[1] = \"O\";\n\na; // \"foo\"\nb; // [\"f\",\"O\",\"o\"]\n```\n\nВ JavaScript строки `string` неизменяемы, тогда как массивы `array` достаточно изменяемы. Более того форма доступа к символу строки вида `a[1]` не совсем правильный JavaScript. Старые версии IE не разрешают такой синтаксис (в новых версиях IE это работает). Вместо него нужно использовать *корректный* способ -  `a.charAt(1)`.\n\nЕще одним последствием неизменяемости строк `string` является то что ни один метод строки `string` меняющий ее содержимое не может делать это по месту, скорее метод создаст и вернет новые строки. И напротив, большинство методов изменяющих содержимое массива `array` действительно *делают* изменения по месту.\n\n```js\nc = a.toUpperCase();\na === c;\t// false\na;\t\t\t// \"foo\"\nc;\t\t\t// \"FOO\"\n\nb.push( \"!\" );\nb;\t\t\t// [\"f\",\"O\",\"o\",\"!\"]\n```\n\nТакже многие из методов массива `array`, которые могут быть полезны при работе со строками `string` вообще для них недоступны, но мы можем \"одолжить\" не изменяющие методы массива `array` для нашей строки `string`:\n\n```js\na.join;\t\t\t// undefined\na.map;\t\t\t// undefined\n\nvar c = Array.prototype.join.call( a, \"-\" );\nvar d = Array.prototype.map.call( a, function(v){\n\treturn v.toUpperCase() + \".\";\n} ).join( \"\" );\n\nc;\t\t\t\t// \"f-o-o\"\nd;\t\t\t\t// \"F.O.O.\"\n```\n\nДавайте возьмем другой пример: реверсируем строку `string` (кстати, это довольно тривиальный общий вопрос на  JavaScript собеседованиях!). У массивов `array` есть метод `reverse()` осуществляющий изменение по месту, но для строки `string` такого метода нет:\n\n```js\na.reverse;\t\t// undefined\n\nb.reverse();\t// [\"!\",\"o\",\"O\",\"f\"]\nb;\t\t\t\t// [\"!\",\"o\",\"O\",\"f\"]\n```\n\nК несчастью, это \"одалживание\" не сработает с методами изменяющими массив `array`, потому что строки `string` неизменяемы и поэтому не могут быть изменены по месту:\n\n```js\nArray.prototype.reverse.call( a );\n// все еще возвращаем объект-обертку String (подробнее в Главе 3)\n// для \"foo\" :(\n```\n\nДругое временное решение (хак) отконвертировать строку `string` в массив `array`, выполнить желаемое действие, и затем отконвертировать обратно в строку `string`.\n\n```js\nvar c = a\n\t// разбиваем `a` на массив символов\n\t.split( \"\" )\n\t// реверсируем массив символов\n\t.reverse()\n\t// объединяем массив символов обратно в строку\n\t.join( \"\" );\n\nc; // \"oof\"\n```\n\nЕсли кажется, что это выглядит безобразно, так и есть. Тем не менее, *это работает* для простых строк `string`, так что, если вам нужно \"склепать\" что-нибудь по-быстрому, часто такой подход позволит выполнить работу.\n\n**Предупреждение:** Будьте осторожны! Этот подход **не работает** для строк `string` со сложными (unicode) символами в них (astral symbols, multibyte characters, etc.). Вам потребуются более сложные библиотеки которые распознают unicode символы для правильного выполнения подобных операций. Подробнее можно посмотреть в работе Mathias Bynens': *Esrever* (https://github.com/mathiasbynens/esrever).\n\nХотя с другой стороны: если вы чаще работаете с вашими \"строками\",  интерпретируя их как *массивы символов*, возможно лучше просто записывать их в массив `array` вместо строк `string`. Возможно вы избавите себя от хлопот при переводе строки `string` в массив `array` каждый раз. Вы всегда можете вызвать `join(\"\")` для массива `array` *символов* когда вам понадобится представление в виде строки `string`.\n\n## Числа\n\nВ JavaScript есть один числовой тип: `number`. Этот тип включает в себя как \"целые\" (\"integer\") значения так и десятичные дробные числа. Я заключил \"целые\" (\"integer\") в кавычки, потому что в JS это понятие подвергается критике, поскольку здесь нет реально целых значений, как в других языках программирования. Возможно в будущем это изменится, но сейчас, у нас просто есть тип `number` для всего.\n\nИтак, в JS, \"целое\" (\"integer\") это просто числовое значение, которое не имеет десятичной составляющей после запятой . Так например, `42.0` более может считаться \"целым\" (\"integer\"), чем `42`.\n\nКак и в большинстве современных языков, включая практически все скриптовые языки, реализация чисел `number` в JavaScript основана на стандарте \"IEEE 754\", который часто называют \"числа с плавающей точкой\" (\"floating-point\"). JavaScript особенно использует формат \"двойной степени точности\" (как \"64-битные в бинарном формате\") этого стандарта.\n\nВ интернете есть множество статей о подробных деталях того, как бинарные числа с плавающей точкой записываются в память, и последствия выбора таких чисел. Т.к. понимание того как работает запись в память не строго необходимо для того чтобы корректно использовать числа `number` в JS, мы оставим это упражнение для заинтересованного читателя, если вы захотите более детально разобраться со стандартом IEEE 754.\n\n### Числовой синтаксис\n\nЧисловые литералы в JavaScript в большинстве представлены как литералы десятичных дробей. Например:\n\n```js\nvar a = 42;\nvar b = 42.3;\n```\n\nЕсли целая часть дробного числа - `0`, можно ее опустить:\n\n```js\nvar a = 0.42;\nvar b = .42;\n```\n\nАналогично, если дробная часть после точки `.`, - `0`, можно ее опустить:\n\n```js\nvar a = 42.0;\nvar b = 42.;\n```\n\n**Предупреждение:** `42.` выглядит достаточно необычно, и возможно это не лучшая идея если вы хотите избежать недопонимания со стороны других людей при работе с вашим кодом. Но, в любом случае, это корректная запись.\n\nПо умолчанию, большинство чисел `number` выводятся как десятичные дроби, с удаленными нулями `0` в конце дробной части. Так:\n\n```js\nvar a = 42.300;\nvar b = 42.0;\n\na; // 42.3\nb; // 42\n```\n\nОчень большие или очень маленькие числа `number` по умолчанию выводятся в экспоненциальной форме, также как и результат метода `toExponential()`, например:\n\n```js\nvar a = 5E10;\na;\t\t\t\t\t// 50000000000\na.toExponential();\t// \"5e+10\"\n\nvar b = a * a;\nb;\t\t\t\t\t// 2.5e+21\n\nvar c = 1 / a;\nc;\t\t\t\t\t// 2e-11\n```\n\nТ.к. числовые значения `number` могут быть помещены в объект - обертку `Number` (подробнее Глава 3), числовые значения `number` могут получать методы встроенные в `Number.prototype` (подробнее Глава 3). Например, метод `toFixed(..)` позволяет вам определить с точностью до скольких знаков после запятой вывести дробную часть:\n\n```js\nvar a = 42.59;\n\na.toFixed( 0 ); // \"43\"\na.toFixed( 1 ); // \"42.6\"\na.toFixed( 2 ); // \"42.59\"\na.toFixed( 3 ); // \"42.590\"\na.toFixed( 4 ); // \"42.5900\"\n```\n\nЗаметьте что результат - строковое `string` представление числа `number`, и таким образом `0`- будет добавлено справа если вам понадобится больше знаков после запятой, чем есть сейчас.\n\n`toPrecision(..)` похожий метод, но он определяет сколько *цифровых знаков* должно использоваться в выводимом значении:\n\n```js\nvar a = 42.59;\n\na.toPrecision( 1 ); // \"4e+1\"\na.toPrecision( 2 ); // \"43\"\na.toPrecision( 3 ); // \"42.6\"\na.toPrecision( 4 ); // \"42.59\"\na.toPrecision( 5 ); // \"42.590\"\na.toPrecision( 6 ); // \"42.5900\"\n```\n\nВам не обязательно использовать переменные для хранения чисел, чтобы применить эти методы; вы можете применять методы прямо к числовым литералам `number`. Но, будьте осторожны с оператором `.`. Т.к. `.` это еще и числовой оператор, и, если есть такая  возможность, он в первую очередь будет интерпретирован как часть числового литерала `number`, вместо того чтобы получать доступ к свойству.\n\n```js\n// неправильный синтаксис:\n42.toFixed( 3 );\t// SyntaxError\n\n// это корректное обращение к методам:\n(42).toFixed( 3 );\t// \"42.000\"\n0.42.toFixed( 3 );\t// \"0.420\"\n42..toFixed( 3 );\t// \"42.000\"\n```\n\n`42.toFixed(3)` неверный синтаксис, потому что `.` станет частью числового литерала `42.` (такая запись корректна -- смотрите выше!), и тогда оператор `.`, который должен получить доступ к методу `.toFixed`, отсутствует.\n\n`42..toFixed(3)` работает т.к. первый оператор `.` часть числового литерала `number` вторая `.` оператор доступа к свойству. Но, возможно это выглядит странно, и на самом деле очень редко можно увидеть что-то подобное в реальном JavaScript коде. Фактически, это нестандартно -- применять методы прямо к примитивным значениям. Нестандартно не значит *плохо* или *неправильно*.\n\n**Примечание:** Есть библиотеки расширяющие встроенные методы `Number.prototype` (подробнее Глава 3) для поддержки операций над/с числами `number`, и в этих случаях, совершенно правильно использовать `10..makeItRain()` чтобы отключить 10-секундную анимацию денежного дождя, или еще что-нибудь такое же глупое.\n\nТакже технически корректной будет такая запись (заметьте пробел):\n\n```js\n42 .toFixed(3); // \"42.000\"\n```\n\nТем не менее, с числовыми литералами `number` особенно, **это чрезвычайно запутанный стиль кода** и он не преследует иных целей кроме как запутать разработчиков при работе с кодом (в том числе и вас в будущем). Избегайте этого.\n\nЧисла `number` также могут быть представлены в экспоненциальной форме, которую обычно используют для представления больших чисел `number` таких, как:\n\n```js\nvar onethousand = 1E3;\t\t\t\t\t\t// means 1 * 10^3\nvar onemilliononehundredthousand = 1.1E6;\t// means 1.1 * 10^6\n```\n\nЧисловые литералы `number` могут быть также выражены в других формах, таких как, двоичная, восьмеричная, и шестнадцатеричная.\n\nЭти форматы работают в текущей версии JavaScript:\n\n```js\n0xf3; // шестнадцатиричная для: 243\n0Xf3; // то же самое\n\n0363; // восьмеричная для: 243\n```\n\n**Примечание:** Начиная с ES6 с включенным `strict` режимом, восьмеричная форма `0363` больше не разрешена (смотрите ниже новую форму). Форма `0363` все еще разрешена в `non-strict` режиме, но в любом случае нужно прекратить ее использовать, чтобы использовать современный подход (и потому что пора бы использовать `strict` режим уже сейчас!).\n\nДля ES6, доступны новые формы записи:\n\n```js\n0o363;\t\t// восьмеричная для: 243\n0O363;\t\t// то же самое\n\n0b11110011;\t// двоичная для: 243\n0B11110011; // то же самое\n```\n\nИ, пожалуйста, окажите вашим коллегам - разработчикам услугу: никогда не используйте форму вида `0O363`. `0` перед заглавной `O` может лишь вызвать затруднение при чтении кода. Всегда используйте нижний регистр в подобных формах: `0x`, `0b`, и `0o`.\n\n### Маленькие дробные числа\n\nСамый известный побочный эффект от использования бинарной формы чисел с плавающей точкой (которая, как мы помним, справедлива для **всех** языков использующих стандарт IEEE 754 -- не *только* JavaScript как многие привыкли предполагать) это:\n\n```js\n0.1 + 0.2 === 0.3; // false\n```\n\nМатематически, что результатом выражения должно быть `true`. Почему же в результате получается `false`?\n\nЕсли по-простому, представления чисел `0.1` и `0.2` в бинарном виде с плавающей точкой не совсем точные, поэтому когда мы их складываем, результат не совсем `0.3`. Это **действительно** близко: `0.30000000000000004`, но если сравнение не прошло, \"близко\" уже не имеет значения.\n\n**Примечание:** Должен ли JavaScript перейти на другую реализацию числового типа `number` которая имеет точные представления для всех значений? Некоторые так думают. За все годы появлялось много альтернатив. Никакие из них до сих пор не были утверждены, и возможно никогда не будут. Кажется что это также легко, как просто поднять руку и сказать \"Да исправьте вы уже этот баг!\", но это вовсе не так. Если бы это было легко, это определенно было бы исправлено намного раньше.\n\nСейчас, вопрос в том, что если есть числа `number` для которых нельзя быть *уверенным* в их точности, может нам совсем не стоит использовать числа `number`? **Конечно нет.**\n\nЕсть несколько случаев применения чисел, где нужно быть осторожными, особенно имея дело с дробными числами. Также есть достаточно (возможно большинство?) случаев когда мы имеем дело только с целыми числами (\"integers\"), и более того, работаем только с числами максимум до миллиона или триллиона. Такие случаи применения чисел всегда были, и будут, **превосходно безопасными** для проведения числовых операций в JS.\n\nА что если нам *было* нужно сравнить два числа `number` таких, как `0.1 + 0.2` и `0.3`, зная что обычный тест на равенство не сработает?\n\nСамая общепринятая практика использование миниатюрной \"ошибки округления\" как *допуска* для сравнения. Это малюсенькое значение часто называют \"машинной эпсилон,\" которое составляет `2^-52` (`2.220446049250313e-16`) для числового типа `number` в JavaScript.\n\nВ ES6, `Number.EPSILON` определено заранее этим пороговым значением, так что если вы хотите его использовать, нужно применить полифилл для определения порогового значения для стандартов до-ES6:\n\n```js\nif (!Number.EPSILON) {\n\tNumber.EPSILON = Math.pow(2,-52);\n}\n```\n\nМы можем использовать это значение `Number.EPSILON` для проверки двух чисел `number` на \"равенство\" (с учетом допуска ошибки округления):\n\n```js\nfunction numbersCloseEnoughToEqual(n1,n2) {\n\treturn Math.abs( n1 - n2 ) < Number.EPSILON;\n}\n\nvar a = 0.1 + 0.2;\nvar b = 0.3;\n\nnumbersCloseEnoughToEqual( a, b );\t\t\t\t\t// true\nnumbersCloseEnoughToEqual( 0.0000001, 0.0000002 );\t// false\n```\n\nМаксимальное значение числа с плавающей точкой приблизительно `1.798e+308` (реально огромное число!), определено как `Number.MAX_VALUE`. Минимальное значение, `Number.MIN_VALUE` приблизительно `5e-324`, оно положительное, но очень близко к нулю!\n\n### Безопасные диапазоны целых чисел\n\nИз-за представления чисел `number` в JS, существует диапазон \"безопасных\" значений для всех чисел `number` \"integers\", и он существенно меньше значения `Number.MAX_VALUE`.\n\nМаксимальное целое число, которое может быть \"безопасно\" представлено (это означает гарантию того, что запрашиваемое значение будет представлено совершенно определенно) это `2^53 - 1`, что составляет `9007199254740991`. Если вы добавите запятые, то увидите что это немного больше 9 квадриллионов. Так что это чертовски много для верхнего диапазона чисел `number`.\n\nЭто значение автоматически предопределено в ES6, как `Number.MAX_SAFE_INTEGER`. Ожидаемо, минимальное значение, `-9007199254740991`, соответственно предопределено в ES6 как `Number.MIN_SAFE_INTEGER`.\n\nЧаще всего JS программы могут столкнуться с такими большими числами, когда имеют дело с 64-битными ID баз данных, и т.п. 64-битные не могут быть точно представлены типом `number`, так что они должны быть записаны (и переданы в/из) JavaScript с помощью строкового `string` представления.\n\nМатематические операции с ID `number` значениями (кроме сравнения, которое отлично пройдет со строками `string`) обычно не выполняются, к счастью. Но если вам *необходимо* выполнить математическую операцию с очень большими числами, сейчас вы можете использовать утилиту *big number*. Поддержка больших чисел может быть реализована в будущих стандартах JavaScript.\n\n### Проверяем является ли число целым\n\nЧтобы проверить, является ли число целым, вы можете использовать специальный ES6-метод `Number.isInteger(..)`:\n\n```js\nNumber.isInteger( 42 );\t\t// true\nNumber.isInteger( 42.000 );\t// true\nNumber.isInteger( 42.3 );\t// false\n```\n\nПолифилл для `Number.isInteger(..)` для стандартов до-ES6:\n\n```js\nif (!Number.isInteger) {\n\tNumber.isInteger = function(num) {\n\t\treturn typeof num == \"number\" && num % 1 == 0;\n\t};\n}\n```\n\nДля проверки на нахождение числа в безопасном диапазоне *safe integer*, используется ES6-метод  `Number.isSafeInteger(..)`:\n\n```js\nNumber.isSafeInteger( Number.MAX_SAFE_INTEGER );\t// true\nNumber.isSafeInteger( Math.pow( 2, 53 ) );\t\t\t// false\nNumber.isSafeInteger( Math.pow( 2, 53 ) - 1 );\t\t// true\n```\n\nПолифилл для `Number.isSafeInteger(..)` для стандартов до-ES6:\n\n```js\nif (!Number.isSafeInteger) {\n\tNumber.isSafeInteger = function(num) {\n\t\treturn Number.isInteger( num ) &&\n\t\t\tMath.abs( num ) <= Number.MAX_SAFE_INTEGER;\n\t};\n}\n```\n\n### 32-битные целые числа (со знаком)\n\nПока целые числа могут быть приблизительно до 9 квадриллионов (53 бита), есть несколько числовых операторов (например побитовые операторы), которые определены для 32-битных чисел `number`, так \"безопасный диапазон\" для чисел `number` используемый в таких случаях намного меньше.\n\nДиапазоном является от `Math.pow(-2,31)` (`-2147483648`, около -2.1 миллиардов) до `Math.pow(2,31)-1` (`2147483647`, около +2.1 миллиардов).\n\nЧтобы записать число `number` из переменной `a` в 32-битное целое число, используем `a | 0`. Это сработает т.к.  `|` побитовый оператор и работает только с 32-битными целыми числами (это означает что он будет работать только с 32 битами, а остальные биты будут утеряны). Ну, а \"ИЛИ\" с нулем побитовый оператор, который не проводит операций с битами.\n\n**Примечание:** Определенные специальные значения (о которых будет рассказано далее) такие как `NaN` и  `Infinity` не являются \"32-битными безопасными значениями\" и в случае передачи этих значений побитовому оператору, будет применен абстрактный оператор  `ToInt32` (смотрите главу 4) результатом которого будет значение`+0` для последующего применения побитового оператора.\n\n## Специальные значения\n\nЕсть несколько специальных значений, которые распространяются на все типы, и с которыми *внимательный* JS разработчик должен быть осторожен, и использовать их по назначению.\n\n### Отсутствие значения\n\nДля типа `undefined`, есть только одно значение: `undefined`. Для типа `null`, есть только одно значение: `null`. Итак, для них обоих, есть свой тип и свое значение.\n\nИ `undefined` и `null` часто считаются взаимозаменяемыми, как либо \"пустое\" значение, либо его \"отсутствие\". Другие разработчики различают их в соответствии с их особенностями. Например:\n\n* `null` пустое значение\n* `undefined` отсутствующее значение\n\nИли:\n\n* `undefined` значение пока не присвоено\n* `null` значение есть и там ничего не содержится\n\nНезависимо от того, как вы \"определяете\" и используете эти два значения, `null` это специальное ключевое слово, не является идентификатором, и таким образом нельзя его использовать для назначения переменной (зачем вообще это делать!?). Как бы там ни было, `undefined` *является* (к несчастью) идентификатором. Увы и ах.\n\n### Undefined\n\nВ нестрогом режиме non-`strict`, действительно есть возможность (хоть это и чрезвычайно плохая идея!) присваивать значение глобальному идентификатору `undefined` :\n\n```js\nfunction foo() {\n\tundefined = 2; // очень плохая идея!\n}\n\nfoo();\n```\n\n```js\nfunction foo() {\n\t\"use strict\";\n\tundefined = 2; // TypeError!\n}\n\nfoo();\n```\n\nКак в нестрогом non-`strict` так и в строгом `strict` режимах, тем не менее, вы можете создать локальную переменную `undefined`. Но, еще раз, это ужасная идея!\n\n```js\nfunction foo() {\n\t\"use strict\";\n\tvar undefined = 2;\n\tconsole.log( undefined ); // 2\n}\n\nfoo();\n```\n\n**Настоящие друзья никогда не позволят друзьям переназначить `undefined`.** Никогда.\n\n#### Оператор `void`\n\nПока `undefined` является встроенным идентификатором который содержит (если только кто-нибудь это не изменил -- см. выше!) встроенное значение `undefined`, другой способ получить это значение - оператор `void`.\n\nВыражение `void ___` \"аннулирует\" любое значение, так что результатом выражения всегда будет являться значение `undefined`. Это выражение не изменяет действующее значение; оно просто дает нам уверенность в том, что мы не получим назад другого значения после применения оператора.\n\n```js\nvar a = 42;\n\nconsole.log( void a, a ); // undefined 42\n```\n\nПо соглашению (большей частью из C-языка программирования), для получения только самого значения `undefined` вместо использования `void`, вы можете использовать `void 0` (хотя и понятно что даже `void true` или любое другое `void` выражение выполнит то же самое). На практике нет никакой разницы между `void 0`, `void 1`, и `undefined`.\n\nНо, оператор `void` может быть полезен в некоторых других обстоятельствах, например, если нужно быть уверенным, что выражение не вернет никакого результата (даже если оно имеет побочный эффект).\n\nНапример:\n\n```js\nfunction doSomething() {\n\t// примечание: `APP.ready` поддерживается нашим приложением\n\tif (!APP.ready) {\n\t\t// попробуйте еще раз позже\n\t\treturn void setTimeout( doSomething, 100 );\n\t}\n\n\tvar result;\n\n\t// делаем что - нибудь другое\n\treturn result;\n}\n\n// есть возможность выполнить задачу прямо сейчас?\nif (doSomething()) {\n\t// выполняем следующие задания немедленно right away\n}\n```\n\nЗдесь, функция `setTimeout(..)` возвращает числовое значение (уникальный идентификатор интервала таймера, если вы захотите его отменить), но нам нужно применить оператор `void` чтобы значение, которое вернет функция не было  ложноположительным  с инструкцией `if`.\n\nМногие разработчики  предпочитают выполнять действия по отдельности, что в результате работает так же, но не требует применения оператора `void`:\n\n```js\nif (!APP.ready) {\n\t// попробуйте еще раз позже\n\tsetTimeout( doSomething, 100 );\n\treturn;\n}\n```\n\nИтак, если есть место где существует значение (как результат выражения), и вы находите полезным получить вместо него `undefined`, используйте оператор `void`. Возможно это не должно часто встречаться в ваших программах, но в редких случаях, когда это понадобится, это может быть довольно полезным.\n\n### Специальные числа\n\nТип `number` включает в себя несколько специальных значений. Рассмотрим каждое более подробно.\n\n#### НЕ Число, Число\n\nЛюбая математическая операция, которую выполняют с операндами не являющимися числами `number` (или значениями которые могут быть интерпретированы как числа `number` в десятичной или шестнадцатеричной форме) приведет к ошибке при попытке получить значение числового типа `number`, в этом случае вы получите значение `NaN`.\n\n`NaN` буквально означает \"not a `number`\" (\"НЕ число\"), хотя это название/описание довольно скудное и обманчивое, как мы скоро увидим. Было бы правильнее думать о `NaN` как о \"неправильном числе\", \"ошибочном числе\", или даже \"плохом числе\", чем думать о нем как о \"НЕ числе\".\n\nНапример:\n\n```js\nvar a = 2 / \"foo\";\t\t// NaN\n\ntypeof a === \"number\";\t// true\n```\n\nДругими словами: \"Типом НЕ-числа является число 'number'!\" Ура запутывающим именам и семантике.\n\n`NaN` что-то вроде \"сторожевого значения\" (другими словами нормальное значение, которое несет специальный смысл), которое определяет сбой при проведении операции назначения числа `number`. Эта ошибка, по сути означает следующее: \"Я попробовал выполнить математическую операцию и произошла ошибка, поэтому, вместо результата, здесь ошибочное число `number`.\"\n\nИтак, если у вас есть значение в какой-нибудь переменной, и вы хотите проверить, не является ли оно ошибочным числом `NaN`, вы должно быть думаете что можно просто его сравнить прямо с `NaN`, как с любым другим значением, например `null` или `undefined`. Неа.\n\n```js\nvar a = 2 / \"foo\";\n\na == NaN;\t// false\na === NaN;\t// false\n```\n\n`NaN` очень особенное значение и оно никогда не будет равно другому значению `NaN` (т.е., оно не равно самому себе). Фактически, это всего лишь значение, которое не рефлексивно (без возможности идентификации `x === x`). Итак, `NaN !== NaN`. Немного странно, да?\n\nТак как мы *можем* его проверить, если нельзя сравнить с `NaN` (т.к. сравнение не сработает)?\n\n```js\nvar a = 2 / \"foo\";\n\nisNaN( a ); // true\n```\n\nДостаточно просто, верно? Мы использовали встроенную глобальную функцию, которая называется `isNaN(..)` и она сообщила нам является значение `NaN` или нет. Проблема решена!\n\nНе так быстро.\n\nУ функции `isNaN(..)` есть большой недостаток. Он появляется при попытках воспринимать значение `NaN` (\"НЕ-Число\") слишком буквально -- вот, вкратце, как это работает: \"проверяем то, что нам передали -- либо это не является числом `number`, либо -- это число `number`.\" Но это не совсем правильно.\n\n```js\nvar a = 2 / \"foo\";\nvar b = \"foo\";\n\na; // NaN\nb; // \"foo\"\n\nwindow.isNaN( a ); // true\nwindow.isNaN( b ); // true -- упс!\n```\n\nПонятно, `\"foo\"` буквально *НЕ-Число*, но и определенно не является значением `NaN`! Этот баг был в JS с самого начала (более 19 лет *упс*).\n\nВ ES6, наконец была представлена функция: `Number.isNaN(..)`. Простым полифиллом, чтобы вы могли проверить на значение `NaN` *прямо сейчас*, даже в браузерах не поддерживающих-ES6, будет:\n\n```js\nif (!Number.isNaN) {\n\tNumber.isNaN = function(n) {\n\t\treturn (\n\t\t\ttypeof n === \"number\" &&\n\t\t\twindow.isNaN( n )\n\t\t);\n\t};\n}\n\nvar a = 2 / \"foo\";\nvar b = \"foo\";\n\nNumber.isNaN( a ); // true\nNumber.isNaN( b ); // false -- фуух!\n```\n\nВообще,  мы можем реализовать полифилл `Number.isNaN(..)` даже проще, если воспользоваться специфической особенностью `NaN`, которое не равно самому себе. `NaN` *единственное* для которого это справедливо; любое другое значение всегда **равно самому себе**.\n\nИтак:\n\n```js\nif (!Number.isNaN) {\n\tNumber.isNaN = function(n) {\n\t\treturn n !== n;\n\t};\n}\n```\n\nСтранно, правда? Но это работает!\n\n`NaN`могут появляться во многих действующих JS программах, намеренно или случайно. Это действительно хорошая идея проводить надежную проверку, например `Number.isNaN(..)` если это поддерживается (или полифилл), чтобы распознать их должным образом.\n\nЕсли вы все еще используете `isNaN(..)` в своей программе, плохая новость: в вашей программе *есть баг*, даже если вы с ним еще не столкнулись!\n\n#### Бесконечности\n\nРазработчики пришедшие из традиционных компилируемых языков вроде C, возможно, привыкли видеть ошибку компилирования или выполнения, например \"деление на ноль,\" для подобных операций:\n\n```js\nvar a = 1 / 0;\n```\n\nКак бы там ни было, в JS, эта операция четко определена, и ее результатом будет являться -- бесконечность `Infinity` (ну или `Number.POSITIVE_INFINITY`). Как и ожидается:\n\n```js\nvar a = 1 / 0;\t// Infinity\nvar b = -1 / 0;\t// -Infinity\n```\n\nКак вы видите, `-Infinity` (или `Number.NEGATIVE_INFINITY`) получается при делении на ноль где один из операторов (но не оба!) является отрицательным.\n\nJS использует вещественное представление чисел (IEEE 754 числа с плавающей точкой, о котором было рассказано ранее), вразрез с чистой математикой, похоже что *есть* возможность переполнения при выполнении таких операций как сложение или вычитание, и в этом случае результатом будет `Infinity` или `-Infinity`.\n\nНапример:\n\n```js\nvar a = Number.MAX_VALUE;\t// 1.7976931348623157e+308\na + a;\t\t\t\t\t\t// Infinity\na + Math.pow( 2, 970 );\t\t// Infinity\na + Math.pow( 2, 969 );\t\t// 1.7976931348623157e+308\n```\n\nСогласно спецификации, если, в результате операции вроде сложения, получается число, превышающее максимальное число, которое может быть представлено, функция IEEE 754 \"округления-до-ближайшего\" определит, каким должен быть результат. Итак, если проще, `Number.MAX_VALUE + Math.pow( 2, 969 )` ближе к `Number.MAX_VALUE` чем к бесконечности `Infinity`, так что его \"округляем вниз,\" тогда как `Number.MAX_VALUE + Math.pow( 2, 970 )` ближе к бесконечности `Infinity`, поэтому его \"округляем вверх\".\n\nЕсли слишком много об этом думать, то у вас так скоро голова заболит. Не нужно. Серьезно, перестаньте!\n\nЕсли однажды вы перешагнете одну из *бесконечностей*, в любом случае, назад пути уже не будет. Другими словами, в почти литературной форме, вы можете прийти из действительности в бесконечность, но не из бесконечности в действительность.\n\nЭто фактически философский вопрос: \"Что если бесконечность разделить на бесконечность\". Наш наивный мозг скажет что-нибудь вроде \"1\", или, может, \"бесконечность.\" Но ни то, ни другое, не будет верным. И в математике, и в JavaScript, операция `Infinity / Infinity` не определена. В JS, результатом будет `NaN`.\n\nНо, что если любое вещественное положительное число `number`, разделить на бесконечность `Infinity`? Это легко! `0`. А что если вещественное отрицательное число `number`, разделить на бесконечность `Infinity`? Об этом в следующей серии, продолжайте читать!\n\n#### Нули\n\nЭто может смутить математически-думающего читателя, но в JavaScript есть два значения `0`: нормальный ноль (также известный как положительный ноль `+0`) *и* отрицательный ноль `-0`. Прежде чем объяснять почему существует `-0`, мы должны посмотреть как это работает в JS, потому что это может сбить с толку.\n\nКроме того что значение `-0` может быть буквально присвоено, отрицательный ноль может быть результатом математических операций. Например:\n\n```js\nvar a = 0 / -3; // -0\nvar b = 0 * -3; // -0\n```\n\nОтрицательный ноль не может быть получен в результате сложения или вычитания.\n\nОтрицательный ноль при выводе в консоль разработчика обычно покажет `-0`, хотя до недавнего времени это не было общепринятым, вы можете узнать что некоторые старые браузеры до сих пор выводят `0`.\n\nКак бы там ни было, при попытке преобразования отрицательного нуля в строку, всегда будет выведено `\"0\"`, согласно спецификации.\n\n```js\nvar a = 0 / -3;\n\n// (некоторые браузеры) выводят в консоль правильное значение\na;\t\t\t\t\t\t\t// -0\n\n// но спецификация лжет вам на каждом шагу!\na.toString();\t\t\t\t// \"0\"\na + \"\";\t\t\t\t\t\t// \"0\"\nString( a );\t\t\t\t// \"0\"\n\n// странно, даже JSON введен в заблуждение\nJSON.stringify( a );\t\t// \"0\"\n```\n\nИнтересно, что обратная операция (преобразование из строки `string` в число `number`) не врет:\n\n```js\n+\"-0\";\t\t\t\t// -0\nNumber( \"-0\" );\t\t// -0\nJSON.parse( \"-0\" );\t// -0\n```\n\n**Предупреждение:** Поведение `JSON.stringify( -0 )` по отношению к `\"0\"` странное лишь частично, если вы заметите то обратная операция: `JSON.parse( \"-0\" )` выведет `-0` как вы и ожидаете.\n\nВ дополнение к тому что преобразование в строку скрывает реальное значение отрицательного нуля, операторы сравнения также (намеренно) настроены *лгать*.\n\n```js\nvar a = 0;\nvar b = 0 / -3;\n\na == b;\t\t// true\n-0 == 0;\t// true\n\na === b;\t// true\n-0 === 0;\t// true\n\n0 > -0;\t\t// false\na > b;\t\t// false\n```\n\nОчевидно, если вы хотите различать `-0` от `0` в вашем коде, вы не можете просто полагаться на то, что выведет консоль разработчика, так что придется поступить немного хитрее:\n\n```js\nfunction isNegZero(n) {\n\tn = Number( n );\n\treturn (n === 0) && (1 / n === -Infinity);\n}\n\nisNegZero( -0 );\t\t// true\nisNegZero( 0 / -3 );\t// true\nisNegZero( 0 );\t\t\t// false\n```\n\nИтак, зачем нам нужен отрицательный ноль, вместо обычного значения?\n\nЕсть определенные случаи где разработчики используют величину значения для определения одних данных (например скорость перемещения анимации в кадре) а знак этого числа `number` для представления других данных (например направление перемещения).\n\nВ этих случаях, как в примере выше, если переменная достигнет нуля и потеряет знак, тогда, вы потеряете информацию о том, откуда она пришла, до того как достигла нулевого значения. Сохранение знака нуля предупреждает потерю этой информации.\n\n### Специальное равенство\n\nКак мы заметили ранее, значения `NaN` и `-0` имеют особенное поведение в случае сравнения. `NaN` никогда не равно самому себе, поэтому необходимо использовать функцию из ES6 `Number.isNaN(..)` (или же полифил). Аналогично, `-0` *лжет* и притворяется равным (даже `===` строго равным -- см. Главу 4) положительному `0`, поэтому необходимо использовать хитрый способ `isNegZero(..)`, который мы предложили выше.\n\nВ ES6 появилась новая возможность, которую мы можем использовать для тестирования двух значений на абсолютное равенство без вышеперечисленных исключений. Она называется `Object.is(..)`:\n\n```js\nvar a = 2 / \"foo\";\nvar b = -3 * 0;\n\nObject.is( a, NaN );\t// true\nObject.is( b, -0 );\t\t// true\n\nObject.is( b, 0 );\t\t// false\n```\n\nЕсть достаточно простой полифил для `Object.is(..)` для браузеров, не поддерживающих ES6:\n\n```js\nif (!Object.is) {\n\tObject.is = function(v1, v2) {\n\t\t// test for `-0`\n\t\tif (v1 === 0 && v2 === 0) {\n\t\t\treturn 1 / v1 === 1 / v2;\n\t\t}\n\t\t// test for `NaN`\n\t\tif (v1 !== v1) {\n\t\t\treturn v2 !== v2;\n\t\t}\n\t\t// everything else\n\t\treturn v1 === v2;\n\t};\n}\n```\n\n`Object.is(..)`, вероятно, не должен использоваться в случаях, где `==` и `===` достоверно *безопасны* (см. Главу 4 \"Coercion\"), поскольку данные операторы скорее более эффективны и определенно более идиоматичны/распространены. `Object.is(..)` необходим для особенных случаев равенства.\n\n## Значения и ссылки\n\nВо многих языках значения могут присваиваться/передаваться по значению или по ссылке в зависимости от используемого синтаксиса.\n\nНапример, если в С++ вы хотите обновить значение числовой переменной, передаваемой функции, то можете объявить параметр функции вида `int& myNum`. Тогда при передаче переменной (например `x`) `myNum` будет содержать **ссылку на `x`**; ссылки работают как специальная разновиднось указателей (то есть фактически *синонимы* для других переменных). Если же не объявить ссылочный параметр, то передаваемое значение *всегда* будет копироваться, даже если это сложный объект.\n\nВ JavaScript указатели не существуют, а ссылки работают несколько иначе. Одна переменная JS не может хранить ссылку на другую переменную -- это попросту невозможно.\n\nСсылка в JS указывает на (общее) **значение**, так что, если вы создаете 10 разных ссылок, они всегда будут указывать на одно общее значение; **они никогда не ссылаются/не указывают друг на друга.**\n\nБолее того, в JavaScript не существует синтаксических подсказок, управляющие способом передачи (по ссылке или по значению). Вместо этого *тип* значения управляет только тем, как будет выполняться присваивание -- копированием значения или копированние ссылки.\n\nПример:\n\n```js\nvar a = 2;\nvar b = a; // `b` всегда содержит копию значения из `a`\nb++;\na; // 2\nb; // 3\n\nvar c = [1,2,3];\nvar d = c; // `d` - ссылка на общее значение `[1,2,3]`\nd.push( 4 );\nc; // [1,2,3,4]\nd; // [1,2,3,4]\n```\n\nПростые значения (то есть скалярные примитивы) *всегда* присваиваются/передаются копированием значения: это `null`, `undefined`, `string`, `number`, `boolean` и `symbol` из ES6.\n\nСоставные значения -- `объекты` (включая `массивы` и все объектные обертки -- см. главу 3) и `функции` -- при присваивании или передаче *всегда* создают копию ссылки.\n\nВ приведенном примере, поскольку `2` является скалярным примитивом, `a` содержит одну исходную копию значения, а `b` присваивается другая *копия* значения.\n\nНо **`c` и `d`** представляют собой разные ссылки на одно общее значение `[1,2,3]`, которое является составным. Важно заметить, что значение `[1, 2, 3]` не \"принадлежит\" ни `c`, ни `d` -- это просто равноправные ссылки на значение. Итак, при использовании любой ссылки для изменения общего `массива` ((`.push(4)`)) изменения распространяются на единственное общее значение, а обе ссылки будут указывать на измененное значение `[1, 2, 3, 4]`.\n\nТак как ссылки указывают на сами значения, а не на переменные, одна ссылка не может использоваться для изменения того, на что ссылается другая ссылка:\n\n```js\nvar a = [1,2,3];\nvar b = a;\na; // [1,2,3]\nb; // [1,2,3]\n\n// позднее\nb = [4,5,6];\na; // [1,2,3]\nb; // [4,5,6]\n```\n\nВыполняя присваивание `b = [4,5,6]`, мы абсолютно ничего не делаем для изменения того, на что сейчас ссылается `a` (`[1,2,3]`). Чтобы это произошло, переменная `b` должна быть указателем, а не ссылкой на массив, но в JS такой возможности нет.\n\nЧаще всего такие недоразумения происходят с параметрами функций:\n\n```js\nfunction foo(x) {\n\tx.push( 4 );\n\tx; // [1,2,3,4]\n\n\t// позднее\n\tx = [4,5,6];\n\tx.push( 7 );\n\tx; // [4,5,6,7]\n}\n\nvar a = [1,2,3];\n\nfoo( a );\n\na; // [1,2,3,4], а не  [4,5,6,7]\n```\n\nПри передаче аргумента `a` копия ссылки `a` присваивается `x`. `x` и `a` -- разные ссылки, указывающие на одно значение `[1,2,3]`. Теперь внутри функции можно использовать эту ссылку для изменения самого значения (`push(4)`). Но когда мы выполняем присваивание `x = [4,5,6]`, оно никак не влияет на то, на что указывает исходная ссылка, она все еще указывает на (уже измененный) `[1,2,3,4]`.\n\nСсылка `x` не может использоваться для изменения того, на что указывает `a`. Можно только изменить содержимое общего значения, на которое указывает как `a`, так и `x`.\n\nЧтобы переменная `a` изменилась и содержала `[4,5,6,7]`, вам не удастся создать новый `массив` и выполнить присваивание, необходимо изменить существующее значение `массива`:\n\n```js\nfunction foo(x) {\n\tx.push( 4 );\n\tx; // [1,2,3,4]\n\n\t// позднее\n\tx.length = 0; // очистить существующий массив на месте\n\tx.push( 4, 5, 6, 7 );\n\tx; // [4,5,6,7]\n}\n\nvar a = [1,2,3];\n\nfoo( a );\n\na; // [4,5,6,7], а не  [1,2,3,4]\n```\n\nКак видите, `x.length = 0` и `x.push(4,5,6,7)` не создает новый `массив`, а изменяет существующий общий `массив`. И конечно, `a` ссылается на новое содержимое `[4,5,6,7]`.\n\nПомните: вы не можете напрямую контролировать/переопределять используемый механизм передачи (копирование значения или копирование ссылки) -- эта семантика определяется исключительно типом используемого значения.\n\nЧтобы передать составное значение (например, `массив`) посредством копирования значения, необходимо создать его копию вручную, чтобы переданная ссылка не продолжала указывать на оригинал. Пример:\n\n```js\nfoo( a.slice() );\n```\n\n`slice(..)` без параметров по умолчанию создает совершенно новую (поверхностную) копию `массива`. Таким образом, передается ссылка только на скопированный `массив`, а значит `foo(..)` не сможет повлиять на содержимое `a`.\n\nЧтобы решить обратную задачу -- передать скалярное примитивное значение так, чтобы его значение обновлялось как ссылка -- необходимо \"завернуть\" значение в другое составное значение (`объект`, `массив`, и т. д.), которое *может* быть передано копированием ссылки:\n\n```js\nfunction foo(wrapper) {\n\twrapper.a = 42;\n}\n\nvar obj = {\n\ta: 2\n};\n\nfoo( obj );\n\nobj.a; // 42\n```\n\nЗдесь `obj` является оберткой для скалярного примитивного свойства `a`. При передаче `foo(..)` передается копия ссылки `obj`, которая присваивается параметру `wrapper`. После этого ссылка `wrapper` может использоваться для обращения к общему объекту и обновлению его свойства. После завершения функции `obj.a` \"увидит\" обновленное значение `42`.\n\nИ тут возникает другая мысль: если вы хотите передать ссылку на скалярное примитивное значение (например, `2`), нельзя ли упаковать значение в объектную обертку `Number` (см. главу 3)?\n\nДействительно, функции *будет* передана копия ссылки на объект `Number`, но, к сожалению, наличие ссылки на общий объект не даст вам возможности изменить общее примитивное значение, как можно было бы ожидать:\n\n```js\nfunction foo(x) {\n\tx = x + 1;\n\tx; // 3\n}\n\nvar a = 2;\nvar b = new Number( a ); // эквивалентно `Object(a)`\n\nfoo( b );\nconsole.log( b ); // 2, не 3\n```\n\nПроблема в том, что нижележащее скалярное примитивное значение является *неизменяемым* (то же относится к `String` и `Boolean`). Если объект `Number` содержит скалярное примитивное значение `2`, этот конкретный объект `Number` не удастся изменить так, чтобы он содержал другое значение, можно только создать совершенно новый объект `Number` с другим значением.\n\nПри использовании `x` в выражении `x + 1` нижележащее скалярное примитивное значение `2` распаковывается (извлекается) из объекта `Number` автоматически, так что строка `x = x + 1` совершенно незаметно превращает `x` из общей ссылки на объект `Number` в простое хранилище для скалярного примитивного значения `3` в результате операции сложения `2 + 1`. Следовательно, `b` снаружи продолжает ссылаться на исходный неизмененный/неизменяемый объект `Number`, содержащий значение `2`.\n\nК объекту `Number` *можно* добавлять новые свойства (только не изменяя его внутреннее примитивное значение), так что вы сможете организовать непрямую передачу информации через эти дополнительные свойства.\n\nВпрочем, такие ситуации встречаются довольно редко. Пожалуй, мало кто из разработчиков сочтет такой трюк хорошей практикой программирования.\n\nВместо того чтобы использовать объектную обертку `Number` подобным образом, лучше использовать \"ручное\" решение с объектной оберткой (`obj`) из предыдущего фрагмента. Это вовсе не означает, что для таких объектных оберток, как `Number`, нельзя найти творческое применение. Это значит, что в большинстве случаев лучше использовать форму со скалярным примитивным значением.\n\nСсылки обладают мощными возможностями, но иногда они начинают мешать, а иногда они нужны там, где их нет. Управлять поведением ссылок (выбирать между копированием значений и копированием ссылок) можно только при помощи типа самого значения, так что вам придется косвенно влиять на поведение присваивания/передачи выбором типов используемых значений.\n\n## Обзор\n\nВ JavaScript массивы `array` являются численно индексированными коллекциями для любых типов значений. Строки `string` несколько \"массивоподобны\", но обладают отличительными особенностями, и нужно быть аккуратным, если вы хотите рассматривать их в роли массивов `array`. Значения чисел в JavaScript включают \"целые\" (\"integers\") и с плавающей точкой.\n\nВ примитивах определено несколько специальных значений.\n\nТип `null` имеет одно значение: `null`, аналогично тип `undefined` имеет лишь значение `undefined`. `undefined` в целом является значением по умолчанию для любой переменной или свойства, если не указано иного значения. Оператор `void` позволяет вернуть значение `undefined` из любого другого значения.\n\nЧисла `number` включают несколько специальных значений, например `NaN` (условно \"НЕ число\", но на самом деле скорее \"неправильное число\"); `+Infinity` и `-Infinity`; и `-0`.\n\nПростые скалярные примитивы (строки `string`, числа `number`, и т.д.) присваиваются/передаются копированием значения, однако сложные значения (объекты `object` и т.д.) присваиваются/передаются копированием ссылки. Ссылки не похожи на ссылки/указатели в других языках -- они никогда не указывают на другие переменные/ссылки, а только на основные значения.\n"
  },
  {
    "path": "types & grammar/ch3.md",
    "content": "# Вы не знаете JS: Типы и грамматика\n# Глава 3: Стандартные встроенные объекты\n\nНесколько раз в первой и второй главах этой книги мы упоминали различные нативные объекты, такие как `String` и `Number`. Давай рассмотрим их детальнее.\n\nВот список часто используемых стандартных объектов:\n\n* `String()`\n* `Number()`\n* `Boolean()`\n* `Array()`\n* `Object()`\n* `Function()`\n* `RegExp()`\n* `Date()`\n* `Error()`\n* `Symbol()` -- добавлено в ES6!\n\nКак вы можете заметить, на деле все они являются встроенными функциями.\n\nЕсли вы пришли в JS из языков подобных Java, то, наверное, заметили, что выражение `String()` схоже с конструктором `String(..)`, используемым в Java для создания строк. Скоро станет понятно, что можно делать подобные вещи:\n\n```js\nvar s = new String( \"Hello World!\" );\n\nconsole.log( s.toString() ); // \"Hello World!\"\n```\n\nНа самом деле каждый из этих встроенных объектов может быть использован в качестве конструктора. Но продукт его вызова может быть не таким, как вам кажется.\n\n```js\nvar a = new String( \"abc\" );\n\ntypeof a; // \"object\" ... не \"String\"\n\na instanceof String; // true\n\nObject.prototype.toString.call( a ); // \"[object String]\"\n```\n\nРезультатом создания значений с помощью вызова конструктора (`new String(\"abc\")`) является объект-обертка над примитивным (`\"abc\"`) значением.\n\nВызов `typeof` показывает, что эти объекты не имеют какой-то уникальный `тип`, точнее определить их подтипами типа `object`.\n\nЭту обертку над значением можно наблюдать с помощью:\n\n```js\nconsole.log( a );\n```\n\nРезультаты вывода могут отличаться в разных браузерах, так как консоли разработчика вправе выбирать как сериализировать объекты для инспектирования их разработчиками.\n\n**Замечание:** В момент написания этой книги последняя версия Chrome печатает что-то вроде этого: `String {0: \"a\", 1: \"b\", 2: \"c\", length: 3, [[PrimitiveValue]]: \"abc\"}`. Но старые версии Chrome печатали просто строку: `String {0: \"a\", 1: \"b\", 2: \"c\"}`. Последний Firefox на данный момент выводит `String [\"a\", \"b\", \"c\"]`, но до этого печатал курсивом `\"abc\"`, на который можно было кликнуть и открыть окно инспектора. Конечно, все это быстро меняется, и ваш опыт может сильно разниться с приведенным в книге.\n\nЦель создания обертки над строчкой `\"abc\"` с помощью `new String(\"abc\")` - не только примитивное значение `\"abc\"`.\n\n## Внутреннее свойство `[[Class]]`\n\nЗначения, для которых `typeof` возвращает `\"object\"` (как, например, массив), дополнительно помечаются внутренним свойством `[[Class]]` (думайте об этом больше как о внутренней *класс*ификации, нежели о классах из традиционного ООП). Это свойство не имеет прямого доступа, но его его можно обнаружить, одолжив стандартный метод `Object.prototype.toString()` и вызвав его с желаемым значением. К примеру:\n\n```js\nObject.prototype.toString.call( [1,2,3] );\t\t\t// \"[object Array]\"\n\nObject.prototype.toString.call( /regex-literal/i );\t// \"[object RegExp]\"\n```\n\nВидно, что для массива в этом примере, внутренний `[[Class]]` имеет значение `\"Array\"`, а для регулярного выражения `\"RegExp\"`. В большинстве случаев, значение внутреннего свойства `[[Class]]` соответствует стандартному встроенному конструктору (см. ниже), связанного со значением, хотя это не всегда так.\n\nА что насчет примитивных значений? Рассмотрим, `null` и `undefined`:\n\n```js\nObject.prototype.toString.call( null );\t\t\t// \"[object Null]\"\nObject.prototype.toString.call( undefined );\t// \"[object Undefined]\"\n```\n\nВы заметите, что нет собственных конструкторов Null() или Undefined(), но Null и Undefined, тем не менее, являются внутренними общедоступными значениями `[[Class]]`.\n\nНо для других простых примитивов, таких как `string`, `number` и `boolean`, на самом деле срабатывает другое поведение, которое обычно называется \"упаковкой\" (см. раздел \"Обертки упаковки\" далее):\n\n```js\nObject.prototype.toString.call( \"abc\" );\t// \"[object String]\"\nObject.prototype.toString.call( 42 );\t\t// \"[object Number]\"\nObject.prototype.toString.call( true );\t\t// \"[object Boolean]\"\n```\n\nВ этом фрагменте каждый из простых примитивов автоматически упаковывается соответствующими объектными оболочками, поэтому `\"String\"`, `\"Number\"` и `\"Boolean\"` раскрываются как соответствующие внутренние `[[Class]]` значения.\n\n**Примечание:** Поведение `toString()` и `[[Class]]`, как показано здесь, немного изменилось с ES5 на ES6, но мы рассмотрим эти детали в заголовке *ES6 и далее* этой серии. .\n\n## Обертки\n\nЭти оболочки объектов служат очень важной цели. Примитивные значения не имеют свойств или методов, поэтому для доступа к `.length` или `.toString()` вам нужна оболочка объекта вокруг значения. К счастью, JS автоматически *упаковывает* (или обертывает) примитивное значение для выполнения таких обращений.\n\n```js\nvar a = \"abc\";\n\na.length; // 3\na.toUpperCase(); // \"ABC\"\n```\n\nИтак, если вы собираетесь регулярно обращаться к этим свойствам/методам строковых значений, например, к условию `i < a.length` в цикле `for`, может показаться, что имеет смысл просто иметь объектную форму значения с самого начала, поэтому движку JS не нужно неявно создавать его для вас.\n\nНо оказывается, это плохая идея. Браузеры уже давно оптимизировали производительность в таких распространенных случаях, как `.length`, что означает, что ваша программа *фактически будет работать медленнее*, если вы попытаетесь \"предварительно оптимизировать\" непосредственно с помощью формы объекта (которая не есть путём к оптимизации).\n\nВ общем, нет никакой причины использовать форму объекта напрямую. Лучше просто позволить боксу происходить неявно там, где это необходимо. Другими словами, никогда не делайте такие вещи, как `new String(\"abc\")`, `new Number(42)` и т. д. Всегда предпочитайте использовать литеральные примитивные значения `\"abc\"` и `42`.\n\n### Ошибки объектной оболочки\n\nЕсть некоторые подводные камни, связанные с непосредственным использованием объектов-оболочек, о которых вам следует знать, если вы *решите* когда-либо их использовать.\n\nНапример, рассмотрите `Boolean` обёртку:\n\n```js\nvar a = new Boolean( false );\n\nif (!a) {\n\tconsole.log( \"Oops\" ); // никогда не запустится\n}\n```\n\nПроблема в том, что вы создали объектную оболочку вокруг значения `false`, но сами объекты являются \"истинными\" (см. главу 4), поэтому использование объекта ведет себя противоположно использованию самого лежащего в основе значения `false`, что весьма вопреки обычному ожиданию.\n\nЕсли вы хотите вручную упаковать примитивное значение, вы можете использовать функцию `Object(..)` (без ключевого слова `new`):\n\n```js\nvar a = \"abc\";\nvar b = new String( a );\nvar c = Object( a );\n\ntypeof a; // \"string\"\ntypeof b; // \"object\"\ntypeof c; // \"object\"\n\nb instanceof String; // true\nc instanceof String; // true\n\nObject.prototype.toString.call( b ); // \"[object String]\"\nObject.prototype.toString.call( c ); // \"[object String]\"\n```\n\nОпять же, прямое использование упакованных объектов-оболочек (например, `b` и `c` выше) обычно не рекомендуется, но могут быть некоторые редкие случаи, когда вы столкнетесь с тем, что они могут быть полезны.\n\n## Распаковка\n\nЕсли у вас есть оболочка объекта и вы хотите получить базовое примитивное значение, вы можете использовать метод `valueOf()`:\n\n```js\nvar a = new String( \"abc\" );\nvar b = new Number( 42 );\nvar c = new Boolean( true );\n\na.valueOf(); // \"abc\"\nb.valueOf(); // 42\nc.valueOf(); // true\n```\n\nРаспаковка также может происходить неявно, при использовании значения оболочки объекта способом, требующим примитивного значения. Этот процесс (принуждение) будет рассмотрен более подробно в главе 4, но кратко:\n\n```js\nvar a = new String( \"abc\" );\nvar b = a + \"\"; // `b` имеет распакованное примитивное значение \"abc\"\n\ntypeof a; // \"object\"\ntypeof b; // \"string\"\n```\n\n## Встроенные объекты как конструкторы\n\nДля `массива`, `объекта`, `функции` и значений регулярных выражений почти повсеместно предпочтительно использовать литеральную форму для создания значений, но литеральная форма создает тот же тип объекта, что и форма конструктора ( то есть нет неупакованного значения).\n\nКак мы видели выше с другими стандартными объектами, этих форм-конструкторов обычно следует избегать, если вы действительно не уверены, что они вам нужны, в основном потому, что они вводят исключения и ловушки, с которыми вы, вероятно, не *хотите* иметь дело.\n\n### `Array(..)`\n\n```js\nvar a = new Array( 1, 2, 3 );\na; // [1, 2, 3]\n\nvar b = [1, 2, 3];\nb; // [1, 2, 3]\n```\n\n**Примечание:** Конструктор `Array(..)` не требует ключевого слова `new` перед ним. Если вы его опустите, он будет вести себя так, как будто вы его все равно использовали. Таким образом, «Массив (1,2,3)» — это тот же результат, что и «новый массив (1,2,3)».\n\nКонструктор `Array` имеет специальную форму, в которой, если передается только один аргумент `number`, вместо того, чтобы предоставлять это значение как *содержимое* массива, оно берется как длина для «предварительного размера массива» (ну, вроде как).\n\nЭто ужасная идея. Во-первых, вы можете случайно споткнуться об эту форму, так как ее легко забыть.\n\nНо что еще более важно, нет такой вещи, как предварительное определение размера массива. Вместо этого вы создаете пустой массив, но устанавливаете для свойства `length` массива указанное числовое значение.\n\nМассив, который не имеет явных значений в своих слотах, но имеет свойство `length`, которое *подразумевает*, что слоты существуют, является странным экзотическим типом структуры данных в JS с очень странным и запутанным поведением. Возможность создания такого значения исходит исключительно из старых, устаревших, исторических функций («массивоподобные объекты», такие как объект «аргументы»).\n\n**Примечание.** Массив, в котором есть хотя бы один «пустой слот», часто называют «разреженным массивом».\n\nДело не в том, что это еще один пример, когда консоли разработчиков браузера различаются в зависимости от того, как они представляют такой объект, что порождает еще большую путаницу.\n\nНапример:\n\n```js\nvar a = new Array( 3 );\n\na.length; // 3\na;\n```\nСериализация `a` в Chrome (на момент написания): `[ undefined x 3 ]`. **Это действительно прискорбно.** Это означает, что в слотах этого массива есть три `неопределенных` значения, хотя на самом деле слоты не существуют (так называемые \"пустые слоты\" - тоже плохое название!)\n\nЧтобы визуализировать разницу, попробуйте следующее:\n\n```js\nvar a = new Array( 3 );\nvar b = [ undefined, undefined, undefined ];\nvar c = [];\nc.length = 3;\n\na; // [empty × 3]\nb; // [undefined, undefined, undefined]\nc; // [empty × 3]\n```\n\n**Примечание:** Как видно из `c` в этом примере, пустые слоты в массиве могут появиться после создания массива. Изменяя «длину» массива так, чтобы он превышал количество фактически определенных значений слотов, вы неявно вводите пустые слоты. На самом деле, вы могли бы даже вызвать `delete b[1]` в приведенном выше фрагменте, и это добавит пустой слот в середину `b`.\n\nДля `b` (в настоящее время в Chrome) вы найдете `[ undefined, undefined, undefined ]` в качестве сериализации, в отличие от `[ undefined x 3 ]` для `a` и `c`. Озадачены? Да, как и все остальные.\n\nХуже того, на момент написания Firefox сообщает `[ , , , ]` для `a` и `c`. Вы поняли, почему это так запутанно? Посмотрите внимательно. Три запятые означают четыре слота, а не три слота, как мы ожидали.\n\n**Что!?** Firefox добавляет здесь дополнительный `,` в конце своей сериализации, потому что начиная с ES5 разрешены конечные запятые в списках (значения массива, списки свойств и т. д.) (и, таким образом, отбрасываются и игнорируются). Таким образом, если бы вы ввели значение `[ , , ]` в свою программу или консоль, вы фактически получили бы базовое значение, похожее на `[ , , ]` (то есть массив с тремя пустыми слотами). Этот выбор, хотя и сбивает с толку при чтении консоли разработчика, защищается тем, что вместо этого делает поведение копирования и вставки точным.\n\nЕсли вы сейчас качаете головой или закатываете глаза, вы не одиноки! Пожимает плечами.\n\nК сожалению, это становится хуже. `a` и `b` из приведенного выше фрагмента кода больше, чем просто сбивающий с толку вывод консоли, на самом деле ведут себя одинаково в некоторых случаях **но по-разному в других**:\n\n```js\na.join( \"-\" ); // \"--\"\nb.join( \"-\" ); // \"--\"\n\na.map(function(v,i){ return i; }); // [ undefined x 3 ]\nb.map(function(v,i){ return i; }); // [ 0, 1, 2 ]\n```\n\n**Фу.**\n\nВызов `a.map(..)` *терпит неудачу*, потому что слоты на самом деле не существуют, поэтому `map(..)` нечего перебирать. `join(..)` работает по-другому. По сути, мы можем думать о его реализации примерно так:\n\n```js\nfunction fakeJoin(arr,connector) {\n\tvar str = \"\";\n\tfor (var i = 0; i < arr.length; i++) {\n\t\tif (i > 0) {\n\t\t\tstr += connector;\n\t\t}\n\t\tif (arr[i] !== undefined) {\n\t\t\tstr += arr[i];\n\t\t}\n\t}\n\treturn str;\n}\n\nvar a = new Array( 3 );\nfakeJoin( a, \"-\" ); // \"--\"\n```\n\nКак видите, `join(..)` работает, просто *предполагая*, что слоты существуют, и зацикливается до значения `length`. Что бы ни делала `map(..)` внутри, она (очевидно) не делает такого предположения, поэтому результат от странного массива \"пустых слотов\" является неожиданным и, вероятно, приведет к сбою.\n\nИтак, если вы хотите *на самом деле* создать массив фактических «неопределенных» значений (а не просто «пустых слотов»), как вы можете это сделать (кроме как вручную)?\n\n```js\nvar a = Array.apply( null, { length: 3 } );\na; // [ undefined, undefined, undefined ]\n```\n\nОзадачены? Ага. Вот примерно как это работает.\n\n`apply(..)` - это утилита, доступная для всех функций, которая вызывает функцию, с которой она используется, но особым образом.\n\nПервый аргумент — это привязка объекта `this` (описанная в заголовке *this & Object Prototypes* этой серии), которая нам здесь не нужна, поэтому мы устанавливаем для нее значение `null`. Предполагается, что второй аргумент должен быть массивом (или чем-то *подобным* массиву, также известному как \"array-like object\"). Содержимое этого «массива» «распространяется» как аргументы рассматриваемой функции.\n\nТаким образом, `Array.apply(..)` вызывает функцию `Array(..)` и распределяет значения (значения объекта `{length: 3 }`) в качестве аргументов.\n\nВнутри `apply(..)` мы можем представить себе еще один цикл `for` (что-то вроде `join(..)` выше), который идет от `0` до `length` (`3` в нашем случае).\n\nДля каждого индекса он извлекает этот ключ из объекта. Таким образом, если бы параметр объекта массива был назван `arr` внутри функции `apply(..)`, доступ к свойству был бы: `arr[0]`, `arr[1]` и `arr[2]. ]`. Конечно, ни одно из этих свойств не существует в значении объекта `{ length: 3 }`, поэтому все три доступа к этим свойствам вернут значение `undefined`.\n\nДругими словами, это заканчивается вызовом `Array(..)` в основном следующим образом: `Array(undefined,undefined,undefined)`, так мы получаем массив, заполненный `undefined` значениями, а не этими (сумасшедшими) пустыми слотами.\n\nХотя `Array.apply( null, {length: 3 } )` - это странный и многословный способ создания массива, заполненного `неопределенными` значениями, он **значительно** лучше и надежнее, чем то, что вы получаете с ножным ружьем `Array(3)` пустые слоты.\n\nИтог: **никогда, ни при каких обстоятельствах** вы не должны намеренно создавать и использовать эти экзотические массивы пустых слотов. Просто не делай этого. Они сумасшедшие.\n\n### `Object(..)`, `Function(..)`, and `RegExp(..)`\n\nКонструкторы `Object(..)`/`Function(..)`/`RegExp(..)` также обычно необязательны (и поэтому их обычно следует избегать, если они специально не требуются):\n\n```js\nvar c = new Object();\nc.foo = \"bar\";\nc; // { foo: \"bar\" }\n\nvar d = { foo: \"bar\" };\nd; // { foo: \"bar\" }\n\nvar e = new Function( \"a\", \"return a * 2;\" );\nvar f = function(a) { return a * 2; };\nfunction g(a) { return a * 2; }\n\nvar h = new RegExp( \"^a*b+\", \"g\" );\nvar i = /^a*b+/g;\n```\n\nПрактически нет причин когда-либо использовать форму конструктора `new Object()`, тем более, что она вынуждает вас добавлять свойства одно за другим, а не многие сразу в литеральной форме объекта.\n\nКонструктор `Function` полезен только в самых редких случаях, когда вам нужно динамически определить параметры функции и/или ее тело функции. **Не рассматривайте `Function(..)` просто как альтернативную форму `eval(..)`.** Вам почти никогда не потребуется динамически определять функцию таким образом.\n\nРегулярные выражения, определенные в литеральной форме (`/^a*b+/g`), настоятельно предпочтительнее не только из-за простоты синтаксиса, но и из соображений производительности - механизм JS предварительно компилирует и кэширует их перед выполнением кода. В отличие от других форм конструктора, которые мы видели до сих пор, `RegExp(..)` имеет разумную полезность: для динамического определения шаблона для регулярного выражения.\n\n```js\nvar name = \"Kyle\";\nvar namePattern = new RegExp( \"\\\\b(?:\" + name + \")+\\\\b\", \"ig\" );\n\nvar matches = someText.match( namePattern );\n```\n\nТакой сценарий время от времени возникает в программах JS, поэтому вам нужно использовать форму `new RegExp(\"pattern\",\"flags\")`.\n\n### `Date(..)` and `Error(..)`\n\nСобственные конструкторы `Date(..)` и `Error(..)` намного полезнее, чем другие нативные конструкторы, потому что ни для одного из них нет литеральной формы.\n\nЧтобы создать значение объекта даты, вы должны использовать `new Date()`. Конструктор `Date(..)` принимает необязательные аргументы для указания используемой даты/времени, но если они опущены, предполагается текущая дата/время.\n\nНа сегодняшний день наиболее распространенной причиной создания объекта даты является получение текущего значения метки времени (целое число со знаком в миллисекундах с 1 января 1970 года). Вы можете сделать это, вызвав `getTime()` для экземпляра объекта даты.\n\nНо еще более простой способ — просто вызвать статическую вспомогательную функцию, определенную в ES5: `Date.now()`. А полифилить это для pre-ES5 довольно просто:\n\n```js\nif (!Date.now) {\n\tDate.now = function(){\n\t\treturn (new Date()).getTime();\n\t};\n}\n```\n\n**Примечание:** Если вы вызываете `Date()` без `new`, вы получите строковое представление даты/времени в этот момент. Точная форма этого представления не указана в спецификации языка, хотя браузеры, как правило, соглашаются на что-то близкое к: «Пт, 18 июля 2014 г., 00:31:02 GMT-0500 (CDT)».\n\nКонструктор `Error(..)` (очень похожий на `Array()` выше) ведет себя одинаково с ключевым словом `new`, присутствующим или опущенным.\n\nОсновная причина, по которой вы хотите создать объект ошибки, заключается в том, что он захватывает текущий контекст стека выполнения в объект (в большинстве JS-движков после создания он раскрывается как свойство `.stack`, доступное только для чтения). Этот контекст стека включает в себя стек вызовов функций и номер строки, в которой был создан объект ошибки, что значительно упрощает отладку этой ошибки.\n\nОбычно вы используете такой объект ошибки с оператором `throw`:\n\n```js\nfunction foo(x) {\n\tif (!x) {\n\t\tthrow new Error( \"x wasn't provided\" );\n\t}\n\t// ..\n}\n```\n\nЭкземпляры объекта ошибки обычно имеют как минимум свойство `message`, а иногда и другие свойства (которые следует рассматривать как доступные только для чтения), например `type`. Однако, помимо проверки вышеупомянутого свойства `stack`, обычно лучше просто вызвать `toString()` для объекта ошибки (либо явно, либо неявно с помощью приведения – см. главу 4), чтобы получить сообщение об ошибке в понятном формате. сообщение.\n\n**Совет:** Технически, в дополнение к общему нативному коду `Error(..)`, есть несколько других нативных типов для конкретных ошибок: `EvalError(..)`, `RangeError(..)`, `ReferenceError(..)`, `SyntaxError(..)`, `TypeError(..)` и `URIError(..)`. Но очень редко можно вручную использовать эти конкретные ошибки. Они автоматически используются, если ваша программа действительно страдает от реального исключения (например, ссылка на необъявленную переменную и получение ошибки `ReferenceError`).\n\n### `Symbol(..)`\n\nВ ES6 добавлен дополнительный примитивный тип значения, который называется «Символ». Символы — это специальные «уникальные» (не строго гарантированные!) значения, которые можно использовать в качестве свойств объектов, практически не опасаясь каких-либо столкновений. В первую очередь они предназначены для специального встроенного поведения конструкций ES6, но вы также можете определить свои собственные символы.\n\nСимволы можно использовать в качестве имен свойств, но вы не можете увидеть или получить доступ к фактическому значению символа из своей программы или из консоли разработчика. Если вы оцениваете символ в консоли разработчика, то, что показано, выглядит, например, как `Symbol(Symbol.create)`.\n\nВ ES6 есть несколько предопределенных символов, доступ к которым осуществляется как к статическим свойствам функционального объекта `Symbol`, например, `Symbol.create`, `Symbol.iterator` и т.д. Чтобы использовать их, сделайте что-то вроде:\n\n```js\nobj[Symbol.iterator] = function(){ /*..*/ };\n```\n\nЧтобы определить свои собственные символы, используйте родной `Symbol(..)`. Собственный \"конструктор\" `Symbol(..)` уникален тем, что вам не разрешено использовать с ним `new`, так как это вызовет ошибку.\n\n```js\nvar mysym = Symbol( \"my own symbol\" );\nmysym;\t\t\t\t// Symbol(my own symbol)\nmysym.toString();\t// \"Symbol(my own symbol)\"\ntypeof mysym; \t\t// \"symbol\"\n\nvar a = { };\na[mysym] = \"foobar\";\n\nObject.getOwnPropertySymbols( a );\n// [ Symbol(my own symbol) ]\n```\n\nХотя символы на самом деле не являются приватными (`Object.getOwnPropertySymbols(..)` отражает объект и раскрывает символы довольно публично), их использование для приватных или специальных свойств, вероятно, является их основным вариантом использования. Для большинства разработчиков они могут заменить имена свойств с префиксами подчеркивания `_`, которые почти всегда по соглашению означают: «Эй, это частное/специальное/внутреннее свойство, так что не трогайте его!»\n\n**Примечание:** \"Символы\" *не* \"объекты\", это простые скалярные примитивы.\n\n### Прототипы встроенных объектов\n\nКаждый из встроенных нативных конструкторов имеет свой собственный объект `.prototype` -- `Array.prototype`, `String.prototype` и т.д.\n\nЭти объекты содержат поведение, уникальное для их конкретного подтипа объекта.\n\nНапример, все строковые объекты, а также расширенные (через упаковку) примитивы `string`, имеют доступ к поведению по умолчанию как методы, определенные в объекте `String.prototype`.\n\n**Примечание:** По соглашению, принятому в документации, String.prototype.XYZ сокращается до String#XYZ, и аналогично для всех остальных `.prototype`.\n\n* `String#indexOf(..)`: найти позицию в строке другой подстроки\n* `String#charAt(..)`:  получить доступ к символу в позиции в строке\n* `String#substr(..)`, `String#substring(..)`, and `String#slice(..)`: извлечь часть строки как новую строку\n* `String#toUpperCase()` and `String#toLowerCase()`: создать новую строку, которая преобразуется в верхний или нижний регистр\n* `String#trim()`: создать новую строку, лишенную всех конечных или начальных пробелов\n\nНи один из методов не изменяет строку *на месте*. Модификации (такие как преобразование регистра или обрезка) создают новое значение из существующего значения.\n\nБлагодаря делегированию прототипам (см. заголовок *this & Object Prototypes* в этой серии) любое строковое значение может получить доступ к этим методам:\n\n```js\nvar a = \" abc \";\n\na.indexOf( \"c\" ); // 3\na.toUpperCase(); // \" ABC \"\na.trim(); // \"abc\"\n```\n\nДругие прототипы конструкторов содержат поведение, соответствующее их типам, например `Number#toFixed(..)` (строка числа с фиксированным количеством десятичных цифр) и `Array#concat(..)` (объединение массивов). Все функции имеют доступ к `apply(..)`, `call(..)` и `bind(..)`, поскольку они определены в `Function.prototype`.\n\nНо некоторые нативные прототипы не являются *просто* простыми объектами:\n\n```js\ntypeof Function.prototype;\t\t\t// \"function\"\nFunction.prototype();\t\t\t\t// Пустая функция!\n\nRegExp.prototype.toString();\t\t// \"/(?:)/\" -- пустая регулярка\n\"abc\".match( RegExp.prototype );\t// [\"\"]\n```\n\nОсобенно плохая идея, вы даже можете изменить эти собственные прототипы (а не просто добавить свойства, с которыми вы, вероятно, знакомы):\n\n```js\nArray.isArray( Array.prototype );\t// true\nArray.prototype.push( 1, 2, 3 );\t// 3\nArray.prototype;\t\t\t\t\t// [1,2,3]\n\n// не оставляйте так, иначе ждите странностей!\n// сбрасываем `Array.prototype` на пустой\nArray.prototype.length = 0;\n```\n\nКак видите, Function.prototype — это функция, RegExp.prototype — регулярное выражение, а Array.prototype — массив. Интересно и круто, да?\n\n#### Прототипы по умолчанию\n\n`Function.prototype` – пустая функция, `RegExp.prototype` – \"пустое\" (например, несоответствующее) регулярное выражение, а `Array.prototype` – пустой массив, сделайте для них все приятные значения \"по умолчанию\" для присвоения к переменным, если эти переменные еще не имели значения надлежащего типа.\n\nНапример:\n\n```js\nfunction isThisCool(vals,fn,rx) {\n\tvals = vals || Array.prototype;\n\tfn = fn || Function.prototype;\n\trx = rx || RegExp.prototype;\n\n\treturn rx.test(\n\t\tvals.map( fn ).join( \"\" )\n\t);\n}\n\nisThisCool();\t\t// true\n\nisThisCool(\n\t[\"a\",\"b\",\"c\"],\n\tfunction(v){ return v.toUpperCase(); },\n\t/D/\n);\t\t\t\t\t// false\n```\n\n**Примечание:** Начиная с ES6, нам не нужно использовать `vals = vals || ..` трюк с синтаксисом значения по умолчанию (см. главу 4) больше не используется, потому что значения по умолчанию могут быть установлены для параметров с помощью собственного синтаксиса в объявлении функции (см. главу 5).\n\nОдним из незначительных побочных преимуществ этого подхода является то, что `.prototype`\nуже созданы и встроены, поэтому создаются *только один раз*. Напротив, использование самих значений `[]`, `function(){}` и `/(?:)/` для этих значений по умолчанию (вероятно, в зависимости от реализации движка) будет воссоздавать эти значения (и, возможно, выполнять сборку мусора). их позже) для *каждого вызова* `isThisCool(..)`. Это может быть расточительно по памяти/ЦП.\n\nКроме того, будьте очень осторожны, чтобы не использовать `Array.prototype` в качестве значения по умолчанию, **которое впоследствии будет изменено**. В этом примере vals используется только для чтения, но если бы вы вместо этого вносили изменения в vals на месте, вы фактически модифицировали бы сам Array.prototype, что привело бы к подводным камням, упомянутым ранее!\n\n**Примечание.** Хотя мы указываем на эти нативные прототипы и на некоторую их полезность, будьте осторожны, полагаясь на них, и еще более осторожны, не изменяя их каким-либо образом. См. Приложение A «Родные прототипы» для более подробного обсуждения.\n\n## Обзор\n\nJavaScript предоставляет объектные оболочки вокруг примитивных значений, известных как стандартные объекты (String, Number, Boolean и т. д.). Эти оболочки объектов предоставляют значениям доступ к поведению, подходящему для каждого подтипа объекта (`String#trim()` и `Array#concat(..)`).\n\nЕсли у вас есть простое скалярное примитивное значение, такое как `\"abc\"`, и вы обращаетесь к его свойству `length` или какому-то методу `String.prototype`, JS автоматически \"упаковывает\" значение (оборачивает его в соответствующую оболочку объекта), чтобы доступы к свойствам/методам могли быть выполнены.\n"
  },
  {
    "path": "types & grammar/ch4.md",
    "content": "# Вы не знаете JS: Типы и грамматика\n# Глава 4: Приведение\n\nТеперь, когда мы гораздо более полно понимаем типы и значения Javascript, мы обратим наше внимание на очень спорную тему: приведение.\n\nКак мы упоминали в Главе 1, споры о том, является ли приведение полезной возможностью или недостатком языка (или чем-то посередине!) бушевали с первого дня. Если вы читали другие популярные книги по JS, вы знаете, что в подавляющем большинстве случаев распространено *мнение* о том, что приведение - это волшебство, зло, путаница и просто совершенно плохая идея.\n\nСледуя духу этой серии книг, вместо того, чтобы убегать от приведения значений, потому что так делают все остальные, или потому, что вас укусила какая-то муха, я думаю, вам следует заняться тем, чего вы не понимаете, и попытаться лучше *схватить* это.\n\nНаша цель - полностью изучить плюсы и минусы (да, *есть* плюсы!) приведения, чтобы вы могли принять обоснованное решение о его целесообразности в вашем коде.\n\n## Конвертация значений\n\nКонвертация значения из одного типа в другой часто называется \"преобразованием типа\", когда делается явно, и \"приведением\", когда выполняется неявно (диктуется правилами использования значения).\n\n**Примечание:** Это может быть неочевидно, но результат приведения в JavaScript это всегда значение скалярного примитива (см. Главу 2), например, `string`, `number`, или `boolean`. Не существует приведения, которое бы приводило к созданию сложного значения, такого как `object` или `function`. Глава 3 посвящена \"упаковке\", которая помещает скалярные примитивные значения в их `object`-аналоги, но на самом деле это не приведение в строгом смысле слова.\n\nДругой распространенный способ различения этих терминов состоит в следующем: \"преобразование типов\" (или \"конвертация типов\") выполняется в статически типизированных языках во время компиляции, а \"приведение типов\" - это преобразование во время выполнения в динамически типизированных языках.\n\nОднако в JavaScript большинство людей называют все эти виды преобразований *приведением*, поэтому я предпочитаю обозначать их как \"неявное приведение\" и \"явное приведение\".\n\nРазница должна быть очевидной: \"явное приведение\" - это когда при взгляде на код ясно, что преобразование типа выполняется намеренно, тогда как \"неявное приведение\" - это когда преобразование - это менее очевидный побочный эффект какой-либо другой намеренной операции.\n\nДля примера рассмотрим эти два способа приведения:\n\n```js\nvar a = 42;\n\nvar b = a + \"\";\t\t\t// неявное приведение\n\nvar c = String( a );\t// явное приведение\n```\n\nВ случае с `b` возникающее приведение происходит неявно, потому что оператор `+` в сочетании с одним из операндов, являющимся строковым значением (`\"\"`), будет настаивать на том, что это операция конкатенации строк (сложения двух `string` вместе), что *в качестве (скрытого) побочного эффекта* приведет к тому, что значение `42` в `a` будет приведено к его строковому эквиваленту: `\"42\"`.\n\nНапротив, функция `String(..)` делает конвертацию очевидной, так как она явно берёт значение в `a` и приводит его к `string` представлению.\n\nОба подхода приводят к одному и тому же результату: из `42` получается `\"42\"`. Но именно то, как это делается, лежит в основе жарких дебатов о приведении в JavaScript.\n\n**Примечание**: Технически, здесь, помимо стилистических различий, есть и нюансы в разном поведении. Мы рассмотрим их более подробно позже в разделе \"Неявно: Строки <--> Числа\".\n\nТермины \"явный\" и \"неявный\", или \"очевидный\" и \"скрытый побочный эффект\", *относительны*.\n\nЕсли вы точно знаете, что делает `a + \"\"`, и вы намеренно пишете это, чтобы привести к `string`, вы можете воспринимать эту операцию достаточно \"явной\". И наоборот, если вы никогда не видели функцию `String(..)`, используемую для приведения к `string`, ее поведение может показаться достаточно скрытым, чтобы стать для вас \"неявным\".\n\nНо мы ведем это обсуждение \"явного\" и \"неявного\" с точки зрения *среднего, достаточно информированного разработчика, но не эксперта или поборника JS спецификации*. В какой бы степени такое описание ни подходило вашему мироощущению, вам необходимо сделать поправку на наш угол обзора здесь.\n\nПросто помните: часто бывает так, что мы пишем наш код и являемся единственными, кто его читает. Даже если вы являетесь экспертом во всех тонкостях JS, подумайте, что почувствуют ваши менее опытные товарищи по команде, когда прочтут ваш код. Будет ли он \"явным\" или \"неявным\" для них так же, как и для вас?\n\n## Абстрактные операции со значениями\n\nПрежде чем мы сможем приступить к *явному* и *неявному* приведению, нам нужно изучить базовые правила, которые определяют, как значения *становятся* `string`, `number` или `boolean`. Спецификация ES5 в разделе 9 определяет несколько \"абстрактных операций\" (затейливо обозначенные как \"исключительно внутренние операции\") с правилами конвертации значений. Мы специально обратим внимание на: `ToString`, `ToNumber`, `ToBoolean` и, в меньшей степени, на `ToPrimitive`.\n\n### `ToString`\n\nКогда любое не строковое значение приводится в `string`-представление, преобразование выполняется абстрактной операцией `ToString` из раздела 9.8 спецификации.\n\nВстроенные примитивные значения имеют естественную строковое отображение: `null` становится `\"null\"`, `undefined` превращается в `\"undefined\"`, а `true` конвертируется в `\"true\"`. Числа (`number`) обычно представляются ожидаемым вами образом, но, как мы обсуждали в Главе 2, очень маленькие или очень большие числа представляются в экспоненциальной форме:\n\n```js\n// умножим `1.07` на `1000` семь раз\nvar a = 1.07 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000;\n\n// семь раз по три цифры => 21 цифра\na.toString(); // \"1.07e21\"\n```\n\nДля обычных объектов, если вы не укажете свой собственный, по умолчанию используется `toString()` (находится в `Object.prototype.toString()`), который вернет *внутренний `[[Class]]`* (см. Главу 3). Например, `\"[object Object]\"`.\n\nНо, как было показано ранее, если у объекта есть свой собственный метод `toString()`, и вы используете этот объект как `string`, автоматически будет вызван его `toString()`, и вместо объекта будет использован `string`-результат этого метода.\n\n**Примечание:** Технически путь приведения объекта к `string` пролегает через абстрактную операцию `ToPrimitive` (Спецификация ES5, раздел 9.1), но эти нюансы более подробно рассматриваются позже в разделе `ToNumber`, поэтому мы пропустим их здесь.\n\nУ массивов базовый метод `toString()` переопределён и представляет собой сцепление всех его значений в виде строк через разделитель `\",\"` (строковое представление каждого значения формируется индивидуально):\n\n```js\nvar a = [1,2,3];\n\na.toString(); // \"1,2,3\"\n```\n\nОпять же, `toString()` может быть либо вызван явно, либо он будет вызван автоматически, если не строковое значение используется в `string`-контексте.\n\n#### Строковое преобразование JSON\n\nДругая задача, которая, казалось бы, плохо связанна с `ToString`, - это когда вы используете утилиту `JSON.stringify(..)` для сериализации значения в строковый вид, совместимый с JSON.\n\nВажно отметить, что это строковое преобразование - не совсем то же самое, что приведение. Но поскольку оно связано с приведенными выше правилами `ToString`, мы сделаем небольшое отступление, чтобы рассмотреть логику строкового преобразования JSON.\n\nОбычно для большинства простых значений строковое преобразование JSON  ведет себя так же, как `toString()`, за исключением того, что результатом сериализации *всегда является `string`*:\n\n```js\nJSON.stringify( 42 );\t// \"42\"\nJSON.stringify( \"42\" );\t// \"\"42\"\" (строка с закавыченным строковым значением)\nJSON.stringify( null );\t// \"null\"\nJSON.stringify( true );\t// \"true\"\n```\n\nЛюбое *безопасное для JSON* значение может быть преобразовано в строку с помощью `JSON.stringify(..)`. Но что такое *безопасное для JSON*? Любое значение, которое может быть корректно отображено в представлении JSON.\n\nВероятно, проще будет назвать значения, которые **не** являются безопасными для JSON. Некоторые примеры: `undefined`, `function`, `symbol` (ES6+) и `object` с циклическими ссылками (где ссылки на свойства объекта создают замкнутый круг, указывая друг на друга). Все это недопустимые значения для стандартной структуры JSON, главным образом потому, что они не переносимы на другие языки, которые используют JSON-данные.\n\nУтилита `JSON.stringify(..)` автоматически опустит значения `undefined`, `function` и `symbol`, когда столкнется с ними. Если такое значение окажется в `array`, то оно заменяется на `null` (чтобы сохранить информацию о местоположении элементов в массиве). Если любое из них хранится в свойстве `object`, это свойство будет просто исключено.\n\nРассмотрим:\n\n```js\nJSON.stringify( undefined );\t\t\t\t\t// undefined\nJSON.stringify( function(){} );\t\t\t\t\t// undefined\n\nJSON.stringify( [1,undefined,function(){},4] );\t// \"[1,null,null,4]\"\nJSON.stringify( { a:2, b:function(){} } );\t\t// \"{\"a\":2}\"\n```\n\nНо если вы попытаетесь передать в `JSON.stringify(..)` любой `object` с циклическими ссылками, то будет выдана ошибка.\n\nСтроковое преобразование JSON ведет себя иначе, если в передаваемом ему `object` определен метод `toJSON()`. Этот метод будет вызван первым, чтобы получить сериализованное значение.\n\nЕсли вы собираетесь преобразовывать в JSON строку объект, который может содержать недопустимые JSON-значения, или если у вас в `object` есть значения, которые не подходят для сериализации, то вам следует определить для него метод `toJSON()`, который возвратит *безопасную для JSON* версию `object`.\n\nНапример:\n\n```js\nvar o = { };\n\nvar a = {\n\tb: 42,\n\tc: o,\n\td: function(){}\n};\n\n// создадим циклическую ссылку в `a`\no.e = a;\n\n// выдаст ошибку о циклической ссылке\n// JSON.stringify( a );\n\n// определим пользовательскую сериализацию в JSON\na.toJSON = function() {\n\t// при сериализации включать только свойство `b`\n\treturn { b: this.b };\n};\n\nJSON.stringify( a ); // \"{\"b\":42}\"\n```\n\nЭто очень распространенное заблуждение, что `toJSON()` должен возвращать строковое представление JSON. Вероятно, это неправильно до тех пор, пока вы не захотите сделать сериализацию самой `string` (обычно такого желания нет!). В действительности `toJSON()` должен возвращать обычное значение (любого подходящего типа), а `JSON.stringify(..)` сам преобразует его в строку.\n\nДругими словами, `toJSON()` следует интерпретировать как \"к JSON-безопасному значению, подходящему для превращения в строку\", а не \"к строке JSON\", как ошибочно предполагают многие разработчики.\n\nРассмотрим:\n\n```js\nvar a = {\n\tval: [1,2,3],\n\n\t// вероятно, правильно!\n\ttoJSON: function(){\n\t\treturn this.val.slice( 1 );\n\t}\n};\n\nvar b = {\n\tval: [1,2,3],\n\n\t// вероятно, неправильно!\n\ttoJSON: function(){\n\t\treturn \"[\" +\n\t\t\tthis.val.slice( 1 ).join() +\n\t\t\"]\";\n\t}\n};\n\nJSON.stringify( a ); // \"[2,3]\"\n\nJSON.stringify( b ); // \"\"[2,3]\"\"\n```\n\nВо втором вызове мы сериализовали возвращаемый `string`, а не `array`, что, вероятно, было не тем, что мы хотели сделать.\n\nПока мы говорим о `JSON.stringify(..)`, давайте обсудим некоторые менее известные возможности, которые тем не менее могут быть очень полезными.\n\n В `JSON.stringify(..)` может быть передан необязательный второй аргумент, который называется *replacer*. Он может быть либо `array`, либо `function`. Аргумент используется для настройки рекурсивной сериализации `object`, предоставляя механизм фильтрации, какие свойства должны включаться или исключаться, аналогично тому, как `toJSON()` может готовить значение для сериализации.\n\nЕсли *replacer* - `array`, то он должен быть массивом строк, каждая из которых будет содержать имя свойства, которое разрешено включать в сериализацию объекта. Если в `object` есть свойство, которого нет в этом списке, оно будет пропущено.\n\nЕсли *replacer* - `function`, то она будет вызвана один раз для самого `object`, а затем по разу для каждого свойства в `object`. Каждый раз передается два аргумента, *key* (ключ) и *value* (значение). Чтобы пропустить *key* при сериализации, верните значение `undefined`. В противном случае верните указанное *value*.\n\n```js\nvar a = {\n\tb: 42,\n\tc: \"42\",\n\td: [1,2,3]\n};\n\nJSON.stringify( a, [\"b\",\"c\"] ); // \"{\"b\":42,\"c\":\"42\"}\"\n\nJSON.stringify( a, function(k,v){\n\tif (k !== \"c\") return v;\n} );\n// \"{\"b\":42,\"d\":[1,2,3]}\"\n```\n\n**Примечание:** Когда *replacer* - это `function`, при первом вызове (где передается сам объект `a`) аргумент `k` равен `undefined`. Оператор `if` **отфильтровывает** свойство с именем `\"c\"`. Строковое преобразование рекурсивное, поэтому в массиве `[1,2,3]` каждое из его значений (`1`, `2`, `3`) передается как аргумент `v`, а индексы (`0`, `1`, `2`) - как аргумент `k`.\n\nВ `JSON.stringify(..)` также может быть передан третий необязательный аргумент, называемый *space*, который используется в качестве отступа для более наглядного и читаемого вывода. *space* может быть положительным целым числом, говорящим, сколько пробелов следует использовать на каждом уровне отступа. *space*  может быть и `string`. В этом случае для каждого уровня отступа будут использоваться первые десять символов его значения.\n\n```js\nvar a = {\n\tb: 42,\n\tc: \"42\",\n\td: [1,2,3]\n};\n\nJSON.stringify( a, null, 3 );\n// \"{\n//    \"b\": 42,\n//    \"c\": \"42\",\n//    \"d\": [\n//       1,\n//       2,\n//       3\n//    ]\n// }\"\n\nJSON.stringify( a, null, \"-----\" );\n// \"{\n// -----\"b\": 42,\n// -----\"c\": \"42\",\n// -----\"d\": [\n// ----------1,\n// ----------2,\n// ----------3\n// -----]\n// }\"\n```\n\nПомните, что `JSON.stringify(..)` напрямую не является формой приведения. Однако мы рассмотрели его здесь по двум причинам, которые связывают его действие с приведением `ToString`:\n\n1. Значения `string`, `number`, `boolean` и `null` - все они в основном преобразуются JSON-строки так же, как приводятся в `string`-значения с помощью правил абстрактной операции `ToString`.\n\n2. Если вы передаете `object`-значение в `JSON.stringify(..)`, и в этом `object` есть метод `toJSON()`, то `toJSON()` автоматически вызывается, чтобы (как бы) \"привести\" значение в *безопасное для JSON значение* перед началом преобразования в строку.\n\n### `ToNumber`\n\nЕсли любое не `number` значение используется в контексте, требующем, чтобы оно было `number`, например, в математической операции, то спецификация ES5 определяет абстрактную операцию `ToNumber` в разделе 9.3.\n\nНапример, `true` становится `1`, `false` - `0`, а `undefined` превращается в `NaN`, но (что любопытно) `null` преобразуется в `0`.\n\n`ToNumber` для `string` значения, по сути, работает по большей части так же, как правила/синтаксис для числовых литералов (см. Главу 3). В случае неудачи, результатом будет `NaN` (вместо синтаксической ошибки, как в случае с `number`-литералами). Один из примеров отличий - в этой операции восьмеричные числа с `0`-префиксом обрабатываются не как восьмеричные (с основанием 8) а, как обычные десятичные числа (с основанием 10), хотя такие восьмеричные являются корректным `number` литералом (см. Главу 2).\n\n**Примечание:** Различия между грамматикой `number`-литерала и `string`-значением в `ToNumber` тонкие и с многими нюансами, поэтому здесь они не будут рассматриваться. Для получения дополнительной информации обратитесь к разделу 9.3.1 спецификации ES5.\n\nОбъекты (и массивы) сначала преобразуются в их эквивалент примитивного значения, а результирующее значение (если оно примитив, но еще не `number`) преобразуется в `number` в соответствии с выше описанными правилами `ToNumber`.\n\nДля преобразования в этот эквивалент примитивного значения, абстрактная операция `ToPrimitive` (спецификация ES5, раздел 9.1) использует внутреннюю операцию `DefaultValue` (спецификация ES5, раздел 8.12.8), чтобы определить, есть ли у значения метод `valueOf()`. Если `valueOf()` доступен, и он возвращает примитивное значение, то *это* значение используется для приведения. Если нет, но доступен `toString()`, он обеспечивает значение для приведения.\n\nЕсли ни одна из операций не может предоставить примитивное значение, выбрасывается ошибка `TypeError`.\n\nНачиная с ES5, вы можете создавать такой неприводимый объект - без `valueOf()` и `toString()` - если его скрытое свойство `[[Prototype]]` равно `null`. Обычно он создаётся с помощью `Object.create(null)`. Обратитесь к книге *This и Прототипы Объектов* из этой же серии для получения дополнительной информации о `[[Prototype]]`.\n\n**Примечание:** Позже в этой главе мы подробно рассмотрим, как приводить `number`, но для следующего фрагмента кода просто предположите, что это выполняет функция `Number(..)`.\n\nРассмотрим:\n\n```js\nvar a = {\n\tvalueOf: function(){\n\t\treturn \"42\";\n\t}\n};\n\nvar b = {\n\ttoString: function(){\n\t\treturn \"42\";\n\t}\n};\n\nvar c = [4,2];\nc.toString = function(){\n\treturn this.join( \"\" );\t// \"42\"\n};\n\nNumber( a );\t\t\t// 42\nNumber( b );\t\t\t// 42\nNumber( c );\t\t\t// 42\nNumber( \"\" );\t\t\t// 0\nNumber( [] );\t\t\t// 0\nNumber( [ \"abc\" ] );\t// NaN\n```\n\n### `ToBoolean`\n\nДалее, давайте немного поговорим о том, как ведут себя `boolean` значения в JS. Вокруг этой темы **много путаницы и неправильных представлений**, так что будьте бдительны!\n\nПрежде всего, в JS есть реальные ключевые слова `true` и `false`, и они ведут себя точно так, как вы ожидаете от `boolean` значений. Распространенное заблуждение, что значения `1` и `0` идентичны `true`/`false`. Хотя это может быть верно для других языков, в JS `number` - это `number`, а `boolean` - это `boolean`. Вы можете привести `1` в `true` (и наоборот) или `0` в `false` (и наоборот). Но это не одно и то же.\n\n#### Ложные значения\n\nНо это еще не конец истории. Нам нужно обсудить, как ведут себя значения, отличные от двух `boolean`, когда вы приводите их *к* `boolean` эквиваленту.\n\nВ JavaScript все значения можно разделить на две категории:\n\n1. значения, которые станут `false`, если их привести в `boolean`\n2. все остальное (которые, очевидно, станет `true`)\n\nЯ не шучу. Спецификация JS определяет конкретный, узкий список значений, которые становятся `false` при приведении в `boolean`.\n\nКак мы узнаем, что это за список значений? В спецификации ES5 раздел 9.2 определяет абстрактную операцию `ToBoolean`, которая точно определяет, что происходит для всех возможных значений, когда вы пытаетесь привести их \"к булевому (логическому) значению\".\n\nИз этой таблицы мы получаем список так называемых \"ложных\" значений:\n\n* `undefined`\n* `null`\n* `false`\n* `+0`, `-0` и `NaN`\n* `\"\"`\n\nЭто он. Если значение находится в этом списке, это \"ложное\" значение, и оно будет равно `false`, если вы приведёте его к `boolean`.\n\nСогласно логике, если значение *отсутствует* в этом списке, то оно должно быть в *другом списке*, который мы называем списком \"правдивых\" значений. Но JS спецификация на самом деле не определяет \"правдивый\" список как таковой. Она приводит отдельные примеры, как, например, явное указание, что все объекты - правдивые. Спецификация просто подразумевает: **все, что явно не указано в списке ложных, является правдивым**.\n\n#### Ложные объекты\n\nПогодите минутку, название этого раздела даже звучит противоречиво. Я буквально *только что сказал*, что спецификация называет все объекты правдивыми, верно? Такого понятия, как \"ложный объект\", не должно быть.\n\nЧто бы это вообще могло значить?\n\nУ вас может возникнуть соблазн подумать, что это объект-обертка (см. Главу 3) вокруг ложного значения (такого как `\"\"`, `0` или `false`). Но не попадайтесь на эту *удочку*.\n\n**Примечание:** Это тонкая шутка с уточнением, которую некоторые из вас смогут понять.\n\nРассмотрим:\n\n```js\nvar a = new Boolean( false );\nvar b = new Number( 0 );\nvar c = new String( \"\" );\n```\n\nМы знаем, что все три значения здесь являются объектами (см. Главу 3), обернутыми вокруг явно ложных значений. Но ведут ли себя эти объекты как `true` или как `false`? На это легко ответить:\n\n```js\nvar d = Boolean( a && b && c );\n\nd; // true\n```\n\nИтак, все три ведут себя как `true`, ибо только так `d` может оказаться `true`.\n\n**Совет:** Обратите внимание на `Boolean( .. )`, обернутое вокруг выражения `a && b && c` - вы можете задаться вопросом, зачем оно там. Мы вернемся к этому позже, так что запомните это. Для краткости (с точки зрения мелочей) попробуйте узнать сами, каким будет `d`, если вы просто выполните `d = a && b && c` без вызова `Boolean( .. )`!\n\nИтак, если \"ложные объекты\" - это **не просто объекты, обернутые вокруг ложных значений**, то что же это такое, черт возьми?\n\nСложность заключается в том, что они могут появляться в вашем JS коде, но на самом деле они не являются частью самого JavaScript.\n\n**Что!?**\n\nЕсть конкретные ситуации, когда браузеры изобрели свой вид поведения *экзотических* значений, а именно идею \"ложных объектов\" поверх обычной семантики JS.\n\n\"Ложный объект\" - это значение, которое выглядит и действует как обычный объект (свойства и т.д.). Но, когда вы приводите его значение к `boolean`, оно превращается в `false`.\n\n**Почему!?**\n\nСамым известным примером является `document.all`: массивоподобный (объект), предоставляемый вашей JS программе *DOM*-ом (не самим движком JS), который отражает элементы страницы для вашей программы. Он *вёл* себя как обычный объект - действовал бы он правдиво. Но больше это не так.\n\n`document.all` само по себе никогда не было по-настоящему \"стандартным\" и уже давно признано устаревшим и стало неподдерживаемым.\n\n\"Не могут ли они просто удалить это тогда?\" Извини, хорошая попытка. Жаль, что они не могут. Существует слишком много старого JS кода, который использует его.\n\nТак, зачем заставлять его действовать ложно? Потому что приведение `document.all` к `boolean` (например, в операторе `if`) почти всегда использовалось как средство обнаружения старого, нестандартного IE.\n\nIE уже давно соответствует стандартам и во многих случаях продвигает веб вперед не меньше, а то и больше, чем любой другой браузер. Но весь этот старый код `if (document.all) { /* это IE */ }` все еще работает, и большая его часть, вероятно, никогда не уйдёт. Всё это наследие из старого кода по-прежнему предполагает, что он работает в IE десятилетней давности, что попросту приводит к некорректной работе страниц у пользователей IE.\n\nИтак, мы не можем удалить `document.all` полностью, но IE не хочет, чтобы код `if (document.all) { .. }` больше работал. Он хочет, чтобы пользователи современного IE получали новую, соответствующую стандартам логику кода.\n\n**\"Что нам делать?\"** \"Я знаю! Давайте уничтожим систему типов JS и притворимся, что `document.all` - ложный!\"\n\nФу. Это отстой. Это сумасшедшая уловка, которую большинство разработчиков JS не понимают. Но альтернатива (ничего не делать с вышеупомянутыми проблемами) - *еще больший отстой*.\n\nИтак... вот что мы имеем: сумасшедшие, нестандартные \"ложные объекты\", добавленные браузерами в JavaScript. Ура!\n\n#### Правдивые значения\n\nВернемся к правдивому списку. Какие именно значения правдивые? Помните: **значение правдивое, если его нет в списке ложных**.\n\nРассмотрим:\n\n```js\nvar a = \"false\";\nvar b = \"0\";\nvar c = \"''\";\n\nvar d = Boolean( a && b && c );\n\nd;\n```\n\nПо вашему мнению, какое значение будет иметь `d` здесь? Это должно быть либо `true`, либо `false`.\n\nЭто будет `true`. Почему? Потому что, хотя содержимое этих `string` выглядит как ложные значения, сами `string` значения являются истинными, потому что в списке ложных `string` есть единственное значение - это `\"\"`.\n\nА эти?\n\n```js\nvar a = [];\t\t\t\t// пустой array -- правдивое или ложное?\nvar b = {};\t\t\t\t// пустой object -- правдивое или ложное?\nvar c = function(){};\t// пустая function -- правдивое или ложное?\n\nvar d = Boolean( a && b && c );\n\nd;\n```\n\nДа, вы уже догадались, `d` здесь по-прежнему `true`. Почему? Та же причина, что и раньше. Несмотря на то, чем это может казаться, `[]`, `{}` и `function(){}` *отсутствуют* в списке ложных значений и, следовательно, являются истинными значениями.\n\nДругими словами, правдивый список бесконечно длинен. Составить такой список невозможно. Вы можете только составить конечный список ложных значений и сверяться *с ним*.\n\nПотратьте пять минут, напишите ложный список на стикере для монитора или запомните его, если хотите. Тогда, вы легко сможете воспроизвести виртуальный правдивый список, когда это вам понадобится, просто спросив, есть ли он в ложном списке или нет.\n\nВажность правдивости и ложности заключается в понимании того, как будет вести себя значение, если вы его приведёте (явно или неявно) к `boolean` значению. Теперь, когда у вас есть эти два списка, мы можем углубиться в примеры приведения.\n\n## Явное приведение\n\n*Явное* приведение относится к преобразованиям типов, которые являются очевидными и явными. Существует широкий спектр применений преобразования типов, которое соответствует категории *явного* приведения у большинства разработчиков.\n\nЦель заключается в том, чтобы выявить в нашем коде шаблоны - ясного и очевидного преобразования значения из одного типа в другой - так, чтобы не оставлять ям, в которые могут угодить будущие разработчики. Чем более демонстративны мы будем, тем больше вероятность, что кто-то после сможет прочитать и понять наш код без излишних усилий, какие у нас были намерения.\n\nДумается, не будет каких-либо существенных разногласий относительно *явного* приведения, поскольку оно наиболее точно соответствует общепринятой практике преобразования типов, сложившейся в языках со статической типизацией. Таким образом, мы примем как должное (на данный момент), что *явное* приведение едино в том, чтобы не быть злонамеренным или противоречивым. Однако мы вернемся к этому позже.\n\n### Явно: Строки <--> Числа\n\nМы начнем с самой простой и, возможно, наиболее распространенной операции приведения: преобразование значений между  `string` и `number` представлениями.\n\nДля приведения между `string` и `number` мы используем встроенные функции `String(..)` и `Number(..)` (которые мы назвали \"собственными конструкторами\" в Главе 3), при этом **очень важно**, мы не используем ключевое слово `new` перед ними. Таким образом, мы не создаем объекты-обёртки.\n\nВместо этого мы на самом деле выполняем *явное приведение* между двумя этими типами:\n\n```js\nvar a = 42;\nvar b = String( a );\n\nvar c = \"3.14\";\nvar d = Number( c );\n\nb; // \"42\"\nd; // 3.14\n```\n\n`String(..)` преобразует любое значение в примитивное значение `string`, используя ранее рассмотренные правила операции `ToString`. `Number(..)` преобразует любое значение в примитивное значение `number`, используя ранее описанные правила операции `ToNumber`.\n\nЯ называю это *явным* приведением, потому что в целом для большинства разработчиков довольно очевидно, что конечным результатом этих операций является приемлемое преобразование типа.\n\nДействительно, это очень похоже на то, как это работает в некоторых других статически типизированных языках.\n\nНапример, в C/C++ вы можете написать либо `(int)x`, либо `int(x)`, и оба они преобразуют значение в `x` в целое число. Обе формы допустимы, но многие предпочитают последнюю, которая выглядит как вызов функции. В JavaScript, когда вы пишете `Number(x)`, это выглядит ужасно похоже. Имеет ли значение, что это *на самом деле* вызов функции в JS? Не совсем.\n\nПомимо `String(..)` и `Number(..)`, существуют другие способы \"явного\" приведения значений между `string` и `number`:\n\n```js\nvar a = 42;\nvar b = a.toString();\n\nvar c = \"3.14\";\nvar d = +c;\n\nb; // \"42\"\nd; // 3.14\n```\n\nВызов `a.toString()` считается явным (довольно ясно, что \"toString\" означает \"к строке\"), но здесь есть определенная скрытая неявность. `toString()` не может быть вызван для *примитивного* значения, такого как `42`. Поэтому JS автоматически \"упаковывает\" (см. Главу 3) `42` в объект-обёртку, так что `toString()` может быть вызван. Другими словами, вы могли бы назвать это \"явно неявным\".\n\n`+c` здесь демонстрирует форму *унарного оператора* `+` (оператор только с одним операндом). Однако вместо выполнения математического сложения (или сцепления строк - см. ниже) унарный символ `+` явно приводит свой операнд (`c`) в значение `number`.\n\nЯвляется ли `+c` *явным* приведением? Зависит от вашего опыта и точки зрения. Если вы знаете (а вы теперь знаете!), что унарный `+` явно предназначен для приведения к `number`, то это достаточно явно и очевидно. Однако, если вы никогда не видели этого раньше, это может показаться ужасно запутанным, неявным, со скрытыми побочными эффектами и т.д.\n\n**Примечание:** Общепринятая точка зрения JS-сообщества с открытым исходным кодом заключается в том, что унарный `+` является приемлемой формой *явного* приведения.\n\nДаже если вам действительно нравится форма `+c`, определенно есть места, где она может выглядеть ужасно запутанной. Рассмотрим пример:\n\n```js\nvar c = \"3.14\";\nvar d = 5+ +c;\n\nd; // 8.14\n```\n\nУнарный оператор `-` также выполняет приведение, как и `+`, но он ещё меняет знак числа. При этом вы не можете поместить два оператора рядом с друг другом `--`, чтобы отменить смену знака, так как это интерпретируется как оператор уменьшения. Вместо этого вам нужно было бы сделать: `- -\"3.14\"` с пробелом между ними, тогда бы это вызвало приведение к `3.14`.\n\nВероятно, вы можете придумать всевозможные отвратительные комбинации двоичных операторов (подобно `+` для сложения) рядом с унарной формой оператора. Вот еще один безумный пример:\n\n```js\n1 + - + + + - + 1;\t// 2\n```\n\nВам следует настойчиво избегать приведения с унарным `+` (или `-`), когда он примыкает к другим операторам. Хотя пример выше работает, такое почти везде считается плохой идеей. Даже `d = +c` (или `d = + c`, если уж на то пошло!) слишком легко спутать с `d + = c`, что совершенно другое!\n\n**Примечание:** Другим чрезвычайно запутанным случаем использования унарного `+` - это помещение его рядом с операторами инкремента `++` и декремента `--`. Например: `a +++b`, `a + ++b` и `a + + +b`. Больше подробностей о `++` смотрите в разделе \"Побочные эффекты выражений\" в Главе 5.\n\nПомните, мы пытаемся явно выразить свои намерения и **уменьшить** путаницу, а не усугублять ее!\n\n#### `Date` в `number`\n\nДругим распространенным случаем использования унарного оператора `+` является приведение объекта `Date` в `number`, так как в результате мы получаем метку времени unix (миллисекунды, прошедшие с 1 января 1970 года 00:00:00 UTC), представляющую значение даты/времени:\n\n```js\nvar d = new Date( \"Mon, 18 Aug 2014 08:53:06 CDT\" );\n\n+d; // 1408369986000\n```\nСамым распространенным применением этой идиомы является фиксация времени *текущего времени* в виде метки времени, например, так:\n\n```js\nvar timestamp = +new Date();\n```\n\n**Примечание:** Некоторые разработчики знают о специфическом синтаксическом \"трюке\" в JavaScript, который заключается в том, что `()` при вызове конструктора (функция, вызываемая с `new`), являются *необязательными*, если нет аргументов для передачи. Поэтому, вы можете встретить такой вариант: `var timestamp = +new Date;`. Однако не все разработчики согласны с тем, что отсутствие `()` улучшает читаемость, поскольку это необычное синтаксическое исключение применяется только к форме вызова `new fn()`, а не к обычной форме вызова `fn()`.\n\nНо приведение - это не единственный способ получить метку времени из объекта `Date`. Вариант без приведения, возможно, даже предпочтительнее, поскольку он более явный:\n\n```js\nvar timestamp = new Date().getTime();\n// var timestamp = (new Date()).getTime();\n// var timestamp = (new Date).getTime();\n```\n\nНо *еще более* предпочтительным вариантом без приведения является использование появившейся в ES5 статической функции `Date.now()`:\n\n```js\nvar timestamp = Date.now();\n```\n\nВ старых браузерах вы можете использовать полифил `Date.now()`, он довольно простой:\n\n```js\nif (!Date.now) {\n\tDate.now = function() {\n\t\treturn +new Date();\n\t};\n}\n```\n\nЯ бы рекомендовал избегать приведений, связанных с датами. Используйте `Date.now()` для метки времени *текущего момента* и `new Date( .. ).getTime()` для получения метки времени *не текущего момента*, который можно указать в виде даты/времени.\n\n#### Любопытный случай с `~`\n\nОдним из операторов приведения, который часто упускается из виду и обычно сбивает с толку, является оператор тильды `~` (\"побитовое НЕ\"). Многие из тех, кто даже понимает, что он делает, часто избегают его. Но, придерживаясь духа этой книги и серии, давайте углубимся в него, чтобы выяснить, может ли `~` дать нам что-нибудь полезное.\n\nВ разделе \"32-битные целые числа (со знаком)\" Главы 2 мы писали, что в JS побитовые операторы работают только как 32-разрядные операторы, то есть они требуют от своих операндов иметь значение в 32-разрядном представлении. Правила того, как это происходит, управляется абстрактной операцией `ToInt32` (спецификация ES5, раздел 9.5).\n\n`ToInt32` сначала выполняет приведение `ToNumber`, что означает, что, если значение равно `\"123\"`, оно сначала станет `123`, прежде чем будут применены правила `ToInt32`.\n\nХотя *технически* это не приведение (поскольку тип не меняется!), использование побитовых операторов (такого как `|` или `~`) с определенными специальными значениями `number` дает эффект приведения и другое значение `number`.\n\nНапример, давайте сначала рассмотрим оператор `|` - \"побитовое ИЛИ\", используемый в идиоме `0 | x`, которая (как показано в Главе 2) по сути выполняет лишь преобразование `ToInt32`:\n\n```js\n0 | -0;\t\t\t// 0\n0 | NaN;\t\t// 0\n0 | Infinity;\t// 0\n0 | -Infinity;\t// 0\n```\n\nЭти специальные числа нельзя представить в 32-разрядном виде (поскольку они взяты из 64-разрядного стандарта IEEE 754 - см. Главу 2), поэтому `ToInt32` просто указывает `0` как результат этих значений.\n\nСпорно, является ли `0 | __` *явной* формой приведения операции `ToInt32` или она всё же *неявная*. С точки зрения спецификации, она безусловно *явная*, но если вы не понимаете побитовые операции, то она вероятно может показаться *неявной* и волшебной. Тем не менее, в соответствии с другими утверждениями в этой главе, мы будем называть приведение *явным*.\n\nИтак, давайте опять обратим наше внимание на `~`. Оператор `~` сначала \"приводит\" к 32-разрядному значению `number`, а затем выполняет побитовое отрицание (инвертируя каждый бит).\n\n**Примечание:** Это очень похоже на то, как `!` не только преобразует значение в `boolean`, но и инвертирует его значение (см. обсуждение \"унарного `!`\" ниже).\n\nНо... что?! Почему нас волнует, что биты инвертируются? Это довольно специфичная тема. JS-разработчикам довольно редко приходится задумываться об отдельных битах.\n\nИной смысл сущности `~` даёт информатика старой школы / дискретная математика: здесь `~` - это операция дополнения двойки. Отлично, спасибо, это совершенно ясно!\n\nДавайте попробуем еще раз: `~x` примерно совпадает с `-(x+1)`. Это странно, но рассуждать об этом немного легче. Итак:\n\n```js\n~42;\t// -(42+1) ==> -43\n```\n\nВы, вероятно, все еще задаетесь вопросом, к чему, черт возьми, вся эта ерунда с `~`, или почему это действительно важно в обсуждении приведения? Давайте сразу перейдем к делу.\n\nРассмотрим `-(x+1)`. Какое единственное значение, с которым вы можете выполнить эту операцию и получить результат `0` (или `-0` технически!)? `-1`. Другими словами, `~`, используемая с разными значениями `number`, даст ложное значение `0` (легко приводимое к `false`) для входного значения `-1`. В любом другом случае мы значение `number` будет правдивым.\n\nКакое отношение это имеет к делу?\n\n`-1` обычно зовётся \"контрольным значением\" - это значение, которому придается определенный семантический смысл в наборе данных того же типа (`number`). Язык C использует контрольные значения `-1` во многих функциях, которые возвращают значения `>= 0` в случае \"успеха\" и `-1` для \"неудач\".\n\nJavaScript заимствовал этот подход для `string` операции `indexOf(..)`, которая ищет подстроку и, если найдена, возвращает ее индекс-позицию или `-1`, если она не найдена.\n\nДовольно часто пытаются использовать `indexOf(..)` не только для поиска позиции, но и как `boolean` проверку наличия/отсутствия подстроки в другой `string`. Вот как обычно выполняют такие проверки:\n\n```js\nvar a = \"Hello World\";\n\nif (a.indexOf( \"lo\" ) >= 0) {\t// true\n\t// нашёл!\n}\nif (a.indexOf( \"lo\" ) != -1) {\t// true\n\t// нашёл\n}\n\nif (a.indexOf( \"ol\" ) < 0) {\t// true\n\t// не нашёл!\n}\nif (a.indexOf( \"ol\" ) == -1) {\t// true\n\t// не нашёл!\n}\n```\n\nЯ нахожу довольно неэстетичным видеть в коде `>= 0` или `== -1`. По сути, это \"дырявая абстракция\", поскольку она выставляет наружу, в мой код, свою внутреннюю реализацию - использование контрольного `-1` для \"сбоя\". Я бы предпочел, чтобы такие детали были скрыты.\n\nНаконец, мы видим, как `~` могла бы нам помочь! Использование `~` с `indexOf()` \"приводит\" (на самом деле просто преобразует) результат **к значению, которое можно привести к `boolean`**:\n\n```js\nvar a = \"Hello World\";\n\n~a.indexOf( \"lo\" );\t\t\t// -4   <-- правдивое!\n\nif (~a.indexOf( \"lo\" )) {\t// true\n\t// нашёл!\n}\n\n~a.indexOf( \"ol\" );\t\t\t// 0    <-- ложное!\n!~a.indexOf( \"ol\" );\t\t// true\n\nif (!~a.indexOf( \"ol\" )) {\t// true\n\t// не нашёл!\n}\n```\n\n`~` принимает возвращаемое значение `indexOf(..)` и преобразует его: для `-1` \"сбоя\" мы получаем ложный `0`, а все остальные значения являются правдивыми.\n\n**Примечание:** Псевдоалгоритм `-(x + 1)` для `~` подразумевает, что `~-1` равно `-0`, но на самом деле тильда выдает `0`, потому что операция на самом деле побитовая, а не математическая.\n\nТехнически, `if (~a.indexOf(..))` использует *неявное* приведение результирующего значения `0` к `false` или ненулевого значения к `true`. Но в целом, мне кажется, `~` больше похожа на *явное* приведение, если вы знаете, цель этого оператора в этой идиоме.\n\nЯ считаю, что это более ясный код, чем беспорядок с `>= 0` / `== -1`.\n\n##### Отбрасывание битов\n\nЕщё одно место, где `~` может появиться в коде, с которым вы сталкиваетесь: некоторые разработчики используют двойную тильду `~~`, чтобы отбросить десятичную часть `number` (т.е. \"привести\" его к целому числу \"integer\"). Часто утверждается (хотя и ошибочно), что это тот же самое, что и вызов `Math.floor(..)`.\n\nКак работает `~~`: первая `~` выполняет \"приведение\" `ToInt32`  и побитовую инверсию, затем вторая `~` выполняет еще одно побитовое переключение, возвращая все биты обратно в исходное состояние. Итог - просто \"приведение\" `ToInt32` (оно же усечение/отбрасывание).\n\n**Примечание:** Побитовая двойная инверсия `~~` очень похожа на действие двойного отрицания `!!`, которое рассматривается ниже в разделе \"Явно: * --> Булево значение\".\n\nОднако `~~` нуждается в некотором предостережении/разъяснении. Во-первых, он корректно работает только с 32-разрядными значениями. Но что еще более важно, с отрицательными числами она действует не так, как `Math.floor (..)`!\n\n```js\nMath.floor( -49.6 );\t// -50\n~~-49.6;\t\t\t\t// -49\n```\n\nОставляя в стороне отличие `Math.floor(..)`, `~~x` усекает до (32-разрядного) целого числа. Но то же самое делает и `x | 0`, и, по-видимому, с (немного) *меньшими усилиями*.\n\nИтак, почему же тогда вы могли бы выбрать `~~x` вместо `x | 0`? Приоритет операторов (см. Главу 5):\n\n```js\n~~1E20 / 10;\t\t// 166199296\n\n1E20 | 0 / 10;\t\t// 1661992960\n(1E20 | 0) / 10;\t// 166199296\n```\n\nКак и во всех других советах здесь, используйте `~` и `~~` в качестве явного механизма \"приведения\" и преобразования значений только в том случае, если каждый, кто читает/пишет такой код, в курсе, как работают эти операторы! \n\n### Явно: Парсинг числовых строк\n\nАналогичный приведению `string` к `number` результат можно получить путем выявления чисел в символах строки. Однако есть явные различия между таким парсингом и преобразованием типов, рассмотренным ранее.\n\nВзгляните:\n\n```js\nvar a = \"42\";\nvar b = \"42px\";\n\nNumber( a );\t// 42\nparseInt( a );\t// 42\n\nNumber( b );\t// NaN\nparseInt( b );\t// 42\n```\n\nПарсинг числового значения из строки *терпим* к нечисловым символам - он просто прекращает синтаксический анализ слева направо при их обнаружении. Приведение же *не терпимо* и приводит к значению `NaN`.\n\nПарсинг не следует рассматривать как замену приведению. Эти две задачи, хотя и схожи, имеют разные цели. Разбирайте `string` как `number`, когда вы не знаете / неважно, появятся ли нечисловые символы с правой стороны. Приводите `string` (к `number`), когда допустимы лишь числовые значения, а что-то вроде `\"42px\"` должно быть отклонено.\n\n**Совет:** `parseInt(..)` имеет двойника, `parseFloat(..)`, который (как понятно) извлекает из строки число с плавающей запятой.\n\nНе забывайте, что `parseInt(..)` работает со значениями `string`. Нет абсолютно никакого смысла передавать значение `number` в `parseInt(..)`. Также не имеет смысла передавать значение любого другого типа, например, `true`, `function(){..}` или `[1,2,3]`.\n\nЕсли вы передаете значение, отличное от `string`, то оно сначала автоматически приводится в `string` (см. \"`ToString`\" выше), что очевидно своего рода скрытое *неявное* приведение. Это действительно плохая идея полагаться на такое поведение в вашей программе, поэтому никогда не используйте `parseInt(..)` со значением, отличным от `string`.\n\nДо ES5 была другая ошибка с `parseInt(..)`, которая служила источником ошибок во многих программах на JS. Если вы не передавали второй аргумент (radix), чтобы обозначить, какую систему счисления использовать для интерпретации строки, `parseInt(..)` анализировала первые символы строки и делала предположения.\n\nЕсли первые два символа `\"0x\"` или `\"0X\"`, предполагалось (по соглашению), что вы хотели интерпретировать `string` как шестнадцатеричное `number` (основание - 16). Иначе, если первый символ `\"0\"`, предполагалось (опять же, по соглашению), что вы хотели интерпретировать `string` как восьмеричное `number` (основание - 8).\n\nШестнадцатеричную строку (с начальным значением `0x` или `0X`) не так-то просто перепутать. Но угадывание восьмеричных чисел оказалось дьявольским явлением. Например:\n\n```js\nvar hour = parseInt( selectedHour.value );\nvar minute = parseInt( selectedMinute.value );\n\nconsole.log( \"The time you selected was: \" + hour + \":\" + minute);\n```\n\nВыглядит безобидным, правда? Попробуйте взять `08` для часа и `09` для минуты. Вы получите `0:0`. Почему? потому что ни `8`, ни `9` не являются допустимыми символами в восьмеричной системе.\n\nДо ES5 заплатка была простой, но её так легко забыть: **всегда передавайте `10` в качестве второго аргумента**. Это было абсолютно безопасно:\n\n```js\nvar hour = parseInt( selectedHour.value, 10 );\nvar minute = parseInt( selectedMiniute.value, 10 );\n```\n\nНачиная с ES5, `parseInt(..)` больше не угадывает восьмеричные числа. Если вы не скажете обратное, он предполагает базу - 10 (или базу - 16 для префиксов `\"0x\"`). Это гораздо приятнее. Просто будьте осторожны, если ваш код должен выполняться в окружении до ES5.В этом случае вам нужно передать `10` в radix (основание).\n\n#### Парсинг не строк\n\nОдин печально известный пример поведения `parseInt(..)` был опубликован в саркастически-шутливом посте несколько лет назад:\n\n```js\nparseInt( 1/0, 19 ); // 18\n```\n\nПредположительное (но совершенно неверное) утверждение гласило: \"Если я передам Infinity и разберу её в целое число, то я должен получить Infinity, а не 18\". Вероятно, JS совсем без ума раз дает такой результат, верно?\n\nХотя этот пример явно надуман и нереален, давайте на мгновение предадимся безумию и посмотрим, действительно ли JS настолько дурацкий.\n\nВо-первых, самый очевидный грех, совершенный здесь, заключается в передаче не-`string` в `parseInt(..)`. Этого не должно быть. Делая так, ты напрашиваешься на неприятности. Но даже совершая такое, JS вежливо приведет то, что вы передаете, в `string`, которую он затем может попытаться распарсить.\n\nНекоторые могут возразить, что это неоправданное поведение, и что `parseInt(..)` должен отказаться работать со значением, отличным от `string`. Возможно, это должно выдавать ошибку? Честно говоря, это было бы очень похоже на Java. Я содрогаюсь при мысли, что JS должен начать выдавать ошибки повсюду, так что `try..catch` требуется почти в каждой строке.\n\nДолжен ли он возвращать `NaN`? Может быть. Но... как насчет:\n\n```js\nparseInt( new String( \"42\") );\n```\n\nПотерпит ли это тоже неудачу? Это значение, отличное от `string`. Если вы хотите, чтобы объект-обёртка `String` был распакован в `\"42\"`, то действительно ли так необычно, что `42` сначала становится `\"42\"`, чтобы потом превратиться в `42`?\n\nЯ бы сказал, что это наполовину *явное* и наполовину *неявное* приведение, которое может иметь место, и может быть очень полезным. Например:\n\n```js\nvar a = {\n\tnum: 21,\n\ttoString: function() { return String( this.num * 2 ); }\n};\n\nparseInt( a ); // 42\n```\n\nТот, что `parseInt(..)` принудительно приводит значение к `string` перед парсингом, вполне разумно. Если вы кладёте мусор и вынимаете его обратно, не вините мусорное ведро - оно просто добросовестно выполняло свою работу.\n\nИтак, если вы передаете значение типа `Infinity` (очевидный результат `1 / 0`), какое `string`-представление имеет наибольший смысл для его дальнейшего приведения? На ум приходят только два разумных варианта: `\"Infinity\"` и `\"∞\"`. JS выбрал `\"Infinity\"` и я рад, что он так поступил.\n\nЯ думаю, это хорошо, что **все значения** в JS имеют какое-то `string` представление по умолчанию, поэтому они не таинственные черные ящики, которые мы не можем отлаживать и анализировать их.\n\nХорошо, что насчет основания 19? Очевидно, совершенно фальшивая и надуманная. Никакие реальные JS-программы не используют основание 19. Это абсурд. Но опять же, давайте предадимся нелепице. В системе с основанием 19 допустимыми числовыми символами являются `0` - `9` и `a` - `i` (без учета регистра).\n\nИтак, вернемся к нашему примеру `parseInt( 1/0, 19 )`. По сути, это `parseInt( \"Infinity\", 19 )`. Как это анализируется? Первый символ - `\"I\"` - в глупой девятнадцатеричной системе имеет значение `18`. Второй символ `\"n\"` в допустимом наборе числовых символов отсутствует, и поэтому анализ просто вежливо останавливается, точно так же, как когда он наткнулся на `\"p\"` в `\"42px\"`.\n\nРезультат? `18`. Получилось именно так, как и должно быть. Логика привела нас сюда, а не к ошибке или к `Infinity`, что **очень важно** для JS, и поэтому его не следует так легко отбрасывать.\n\nПриведём ещё примеры такого поведения `parseInt(..)`, которые могут показаться удивительными, но которые вполне разумные:\n\n```js\nparseInt( 0.000008 );\t\t// 0   (\"0\" из \"0.000008\")\nparseInt( 0.0000008 );\t\t// 8   (\"8\" из \"8e-7\")\nparseInt( false, 16 );\t\t// 250 (\"fa\" из \"false\")\nparseInt( parseInt, 16 );\t// 15  (\"f\" из \"function..\")\n\nparseInt( \"0x10\" );\t\t\t// 16\nparseInt( \"103\", 2 );\t\t// 2\n```\n\n`parseInt(..)` на самом деле довольно предсказуем и последователен в своем поведении. Если вы будете использовать его правильно, вы получите разумные результаты. Если вы используете его неправильно, сумасшедшие результаты, которые вы получаете, не являются ошибкой JavaScript.\n\n### Явно: * --> Булево значение\n\nТеперь давайте рассмотрим приведение любого значения, не являющегося `boolean`, к `boolean`.\n\nТочно так же, как со `String(..)` и `Number(..)` выше, `Boolean(..)` (без `new`, конечно!) - это явный способ приведения `ToBoolean`.:\n\n```js\nvar a = \"0\";\nvar b = [];\nvar c = {};\n\nvar d = \"\";\nvar e = 0;\nvar f = null;\nvar g;\n\nBoolean( a ); // true\nBoolean( b ); // true\nBoolean( c ); // true\n\nBoolean( d ); // false\nBoolean( e ); // false\nBoolean( f ); // false\nBoolean( g ); // false\n```\n\nХотя `Boolean (..)` явно выражает намерение, он мало распространен или не идиоматичен.\n\nТочно так же, как унарный оператор `+` преобразует значение в `number` (см. выше), унарный оператор отрицания `!` явно преобразует значение в `boolean`. *Проблема* заключается в том, что он также меняет значение с истинного на ложное или наоборот. Поэтому, самый популярный способ явного приведения к `boolean`, к которому прибегают JS разработчики, - это оператор двойного отрицания `!!`. В нём второй `!` вернет исходный `true`/`false`:\n\n```js\nvar a = \"0\";\nvar b = [];\nvar c = {};\n\nvar d = \"\";\nvar e = 0;\nvar f = null;\nvar g;\n\n!!a;\t// true\n!!b;\t// true\n!!c;\t// true\n\n!!d;\t// false\n!!e;\t// false\n!!f;\t// false\n!!g;\t// false\n```\n\nЛюбое приведение `ToBoolean` выполняется *неявно* без `Boolean(..)` или `!!`, если используется в `boolean` контексте, таком как оператор `if (..) ..`. Но наша цель - это явное приведение значения к `boolean`, чтобы было понятно, что мы используем намеренное приведение `ToBoolean`.\n\nДругой пример использования явного приведения `ToBoolean` - это, когда вы хотите выполнить приведение к `true`/`false` при сериализации структуры данных в формате JSON:\n\n```js\nvar a = [\n\t1,\n\tfunction(){ /*..*/ },\n\t2,\n\tfunction(){ /*..*/ }\n];\n\nJSON.stringify( a ); // \"[1,null,2,null]\"\n\nJSON.stringify( a, function(key,val){\n\tif (typeof val == \"function\") {\n\t\t// выполнить приведение `ToBoolean` для функции\n\t\treturn !!val;\n\t}\n\telse {\n\t\treturn val;\n\t}\n} );\n// \"[1,true,2,true]\"\n```\n\nЕсли вы пришли в JavaScript из Java, вы можете узнать эту идиому:\n\n```js\nvar a = 42;\n\nvar b = a ? true : false;\n```\n\nТернарный оператор `? :` проверит `a` на правдивость и на основе этого присвоит `b` либо `true`, либо `false`.\n\nНа первый взгляд эта идиома выглядит как форма *явного* приведения `ToBoolean`, поскольку, очевидно, операция выдает `true` или `false`.\n\nОднако присутствует скрытое *неявное* приведение, заключающееся в том, что выражение `a` сначала должно быть приведено в `boolean` для прохождения теста на правдивость. Я бы назвал эту идиому \"явно неявной\". Кроме того, я бы посоветовал вам **всегда избегайте эту идиому** в JavaScript. Это не дает никакой пользы, но, что куда хуже, выдает себя за то, чем оно не является.\n\n`Boolean(a)` и `!!a` намного лучше в качестве *явных* вариантов приведения.\n\n## Неявное приведение\n\n*Неявное* приведение относится к скрытым преобразованиям типов с неочевидными побочными эффектами, которые неявно возникают в результате других действий. Другими словами, *неявные приведения* - это любые преобразования типов, которые не очевидны (для вас).\n\nЕсли цель *явного* приведения ясна (сделать код однозначным и более понятным), то также понятно, что *неявное* приведение преследует противоположную цель: усложнить понимание кода.\n\nЕсли принять всё за чистую монету, то, я полагаю, это источник большей части гнева по отношению к приведению. Большинство жалоб на \"приведение JavaScript\" на самом деле касаются (осознано или нет) *неявного* приведения.\n\n**Примечание:** Дуглас Крокфорд, автор книги *\"JavaScript: сильные стороны\"*, утверждал во многих выступлениях на конференциях и в статьях, что следует избегать приведения в JavaScript. Но что он, по-видимому, имеет в виду, так это то, что *неявное* приведение - это плохо (по его мнению). Однако, если вы прочтете его собственный код, вы найдете множество примеров приведения, как *неявного*, так и *явного*! По правде говоря, его беспокойство, похоже, в первую очередь направлено на операцию `==`, но, как вы увидите в этой главе, это только часть механизма приведения.\n\nИтак, **является ли скрытое приведение** злом? Это опасно? Является ли это недостатком в дизайне JavaScript? Должны ли мы избегать этого любой ценой?\n\nБьюсь об заклад, большинство из вас, читатели, склонны с энтузиазмом воскликнуть: \"Да!\"\n\n**Не так быстро**. Выслушай меня.\n\nДавайте взглянем с другой точки зрения на то, что такое *неявное* приведение и каким оно может быть, а не просто заявить, что оно \"противоположность хорошему явному виду приведения\". Это слишком узко и упускает важный нюанс.\n\nДавайте определим цель *неявного* приведения как: уменьшить многословие, шаблонность и/или ненужные детали реализации, которые загрязняют наш код шумом, отвлекающим от более важной цели.\n\n### Упрощение неявного\n\nПрежде чем мы перейдем к JavaScript, позвольте мне предложить что-нибудь псевдокодовое из какого-нибудь теоретического строго типизированного языка для иллюстрации:\n\n```js\nSomeType x = SomeType( AnotherType( y ) )\n```\n\nВ этом примере у меня есть некоторый произвольный тип значения в `y`, который я хочу преобразовать в тип `SomeType`. Проблема в том, что этот язык не может перейти непосредственно от того, чем в данный момент является `y`, к `SomeType`. Ему нужен промежуточный шаг, на котором он сначала преобразуется в `AnotherType`, а затем из `AnotherType` в `SomeType`.\n\nТеперь, что, если бы этот язык просто позволил вам написать:\n\n```js\nSomeType x = SomeType( y )\n```\n\nРазве вы в целом не согласились бы с тем, что мы упростили преобразование типов, чтобы уменьшить ненужный \"шум\" промежуточного этапа преобразования? Я имею в виду, *действительно* ли так важно, прямо здесь, на этом этапе кода, увидеть и смириться с тем фактом, что `y` сначала переходит в `AnotherType`, а затем в `SomeType`? \n\nКто-то мог бы возразить, что, по крайней мере, при некоторых обстоятельствах, да. Но я думаю, что во многих других обстоятельствах можно привести равный аргумент в пользу того, что здесь упрощение **на самом деле способствует удобочитаемости кода** путем абстрагирования или сокрытия таких деталей в самом ли языке, или в наших собственных абстракциях.\n\nНесомненно, где-то за кулисами все еще происходит промежуточный этап преобразования. Но если здесь эта деталь скрыта от глаз, мы можем просто рассуждать о том, что преобразуем `y` в `SomeType` в виде стандартной операции, скрывая ненужные детали.\n\nХотя это и не идеальная аналогия, я собираюсь утверждать на протяжении всей остальной части этой главы, что *неявное* приведение JS можно рассматривать как оказание аналогичной помощи вашему коду.\n\nНо, **и это очень важно**, это не безграничное, абсолютное утверждение. Определенно, вокруг *неявного* приведения скрывается множество *пороков*, которые нанесут вашему коду гораздо больший вред, чем любые потенциальные улучшения читаемости. Очевидно, что мы должны научиться избегать таких конструкций, чтобы не отравлять наш код всевозможными ошибками.\n\nМногие разработчики считают, что если механизм может делать какую-то полезную вещь **A**, но также может быть использован не по назначению для совершения какой-то ужасной вещи **Z**, то мы должны полностью отказаться от него, просто на всякий случай.\n\nМой совет вам таков: не соглашайтесь на это. Не \"выплескивайте ребенка вместе с водой\". Не думайте, что *неявное* приведение - это плохо, потому что все, что, по вашему мнению, вы когда-либо видели, - это его \"плохие стороны\". Я думаю, что здесь есть \"сильные стороны\", и я хочу помочь и вдохновить большинство из вас найти и принять их!\n\n### Неявно: Строки <--> Числа\n\nРанее в этой главе мы исследовали *явное* приведение между значениями `string` и `number`. Теперь давайте рассмотрим ту же задачу, но с использованием методов *неявного* приведения. Но прежде чем мы это сделаем, мы должны изучить некоторые нюансы операций, которые *неявно* приведут к приведению.\n\nОператор `+` очень занятой. Он и складывает `number`, и сцепляет `string`. Итак, как JS догадывается, какой тип операции вы хотите использовать? Взгляните:\n\n```js\nvar a = \"42\";\nvar b = \"0\";\n\nvar c = 42;\nvar d = 0;\n\na + b; // \"420\"\nc + d; // 42\n```\n\nГде та разница, которая формирует либо `\"420\"`, либо `42`? Распространенное заблуждение, что разница в том, является ли один или оба операнда `string`, поскольку это означает, что `+` предполагает сцепление `string`. Хотя это отчасти верно, но все гораздо сложнее.\n\nРассмотрим:\n\n```js\nvar a = [1,2];\nvar b = [3,4];\n\na + b; // \"1,23,4\"\n```\n\nНи один из этих операндов не является `string`, но очевидно, что они оба были приведены к `string`, а затем произошло сцепление `string`. Так что же происходит на самом деле?\n\n(**Предупреждение:** грядет очень подробный разбор спецификации, так что пропустите следующие два абзаца, если это вас пугает!)\n\n-----\n\nСогласно разделу 11.6.1 спецификации ES5, алгоритм `+` (когда `object`-значение является операндом) будет сцеплять, если любой из операндов либо уже является `string`, либо если следующие шаги ведут к `string`. Итак, когда `+` получает `object` (включая `array`) для любого из операндов, он для значения сначала вызывает абстрактную операцию `ToPrimitive` (раздел 9.1), которая затем вызывает алгоритм `[[DefaultValue]]` (раздел 8.12.8) с контекстной подсказкой `number`.\n\nЕсли вы будете внимательны, то заметите, что эта операция теперь идентична тому, как абстрактная операция `ToNumber` обрабатывает `object` (см. раздел \"`ToNumber`\"\" выше). Операция `valueOf()` над `array` не приведет к созданию простого примитива, поэтому затем он переходит к `toString()`. Так, два массива становятся `\"1,2\"` и `\"3,4\"` соответственно. Теперь `+` сцепляет две `string` так, как вы ожидаете: `\"1,23,4\"`.\n\n-----\n\nДавайте оставим в стороне эти запутанные детали и вернемся к более раннему, упрощенному объяснению: если любой из операндов `+` является `string` (или становится таковым с помощью описанных выше шагов!), операция будет сцеплением `string`. В противном случае это всегда числовое сложение.\n\n**Примечание:** Часто цитируемый пример приведения - `[] + {}` против `{} + []`, которые приводят, соответственно, к `\"[object Object]\"` и `0`. Однако это еще не все, и мы рассмотрим эти детали в разделе \"Блоки\" в Главе 5.\n\nЧто это значит для *неявного* приведения?\n\nВы можете привести `number` к `string`, просто \"добавив\" `number` и `\"\"` - пустую `string`:\n\n```js\nvar a = 42;\nvar b = a + \"\";\n\nb; // \"42\"\n```\n\n**Совет:** Числовое сложение с помощью оператора `+` является коммутативным, что означает, что `2 + 3` совпадает с `3 + 2`. Объединение строк с помощью `+`, очевидно, обычно не является коммутативным, **но** в конкретном случае `\"\"` оно эффективно коммутативно, так как `a + \"\"` и `\"\" + a` приведут к одному и тому же результату.\n\nЧрезвычайно популярно / идиоматично (*неявно*) приводить `number` к `string` с помощью операции `+ \"\"`. Интересно, что даже некоторые из самых ярых критиков *неявного* приведения все еще используют этот подход в своем собственном коде вместо одной из его *явных* альтернатив.\n\n**Я думаю, что это отличный пример** полезной формы в *неявном* приведении, несмотря на то, как часто этот способ подвергается критике!\n\nСравнивая *неявное* приведение `a + \"\"` с предыдущим примером *явного* приведения `String(a)`, необходимо учитывать еще одну особенность. Следуя логике работы абстрактной операции `ToPrimitive`, сначала `a + \"\"` вызывает `valueOf()` для значения `a`, затем возвращаемое значение преобразуется в `string` с помощью внутренней абстрактной операции `ToString`. В то же время `String(a)` просто вызывает `toString()` напрямую.\n\nОба способа в конечном итоге приводят к `string`, но если вы используете `object` вместо обычного примитивного `number`, вы не обязательно можете получить *такое же* значение `string`!\n\nРассмотрим:\n\n```js\nvar a = {\n\tvalueOf: function() { return 42; },\n\ttoString: function() { return 4; }\n};\n\na + \"\";\t\t\t// \"42\"\n\nString( a );\t// \"4\"\n```\n\nКак правило, такого рода уловки вам не вредят, если вы только действительно не пытаетесь создавать запутанные структуры данных и методы, но вам следует быть осторожным, если вы пишете свои собственные методы `valueOf()` и `toString()` для какого-то `object`, поскольку то, как вы приводите значение, может повлиять на результат.\n\nА как насчет другого направления? Как мы можем *неявно привести* из `string` в `number`?\n\n```js\nvar a = \"3.14\";\nvar b = a - 0;\n\nb; // 3.14\n```\n\nОператор `-` определен только для числового вычитания, поэтому `a - 0` вызывает приведение значения `a` к `number`. Куда менее распространенные, `a * 1` и `a / 1` также приводят к тому же результату, ибо эти операторы предназначены только для числовых операций.\n\nКак насчет значений `object` с оператором `-`? Аналогичная история, как и для `+` выше:\n\n```js\nvar a = [3];\nvar b = [1];\n\na - b; // 2\n```\n\nОба значения `array` должны стать `number`, но сначала они преобразуются в `strings` (с использованием ожидаемой сериализации `toString()`), а затем преобразуются в `number` для выполнения вычитания `-`.\n\nИтак, является ли *неявное* приведение к `string` и `number` тем уродливым злом, о котором вы слышите в страшилках? Лично я так не думаю.\n\nСравните `b = String(a)` (*явный*) с `b = a + \"\"` (*неявный*). Я думаю, что можно привести примеры того, что оба подхода полезны в вашем коде. Конечно, `b = a + \"\"` немного чаще встречается в JS программах, демонстрируя свою полезность, невзирая на *чувства* по поводу достоинств или опасностей *неявного* приведения в целом.\n\n### Неявно: Булевы значения --> Числа\n\nПо-моему, ситуация, когда *неявное* приведение может проявить свои лучшие стороны, - это случай упрощения определенных типов сложной `boolean` логики в виде простого числового сложения. Конечно, это не техника общего назначения, а конкретное решение для особых случаев.\n\nРассмотрим:\n\n```js\nfunction onlyOne(a,b,c) {\n\treturn !!((a && !b && !c) ||\n\t\t(!a && b && !c) || (!a && !b && c));\n}\n\nvar a = true;\nvar b = false;\n\nonlyOne( a, b, b );\t// true\nonlyOne( b, a, b );\t// true\n\nonlyOne( a, b, a );\t// false\n```\n\nФункция `onlyOne(..)` должна возвращать `true` только в том случае, если лишь один из её аргументов является `true` / правдивым. Она использует *неявное* приведение в проверках на правдивость и *явное* приведение в остальных случаях, включая возвращаемое итоговое значение.\n\nНо что, если нам нужно, чтобы эта утилита могла обрабатывать четыре, пять или двадцать флагов одним и тем же способом? Довольно сложно представить реализацию кода, который обрабатывал бы все эти перестановки сравнений.\n\nВот где приведение `boolean` значений к `number` (очевидно, `0` или `1`) может сильно помочь:\n\n```js\nfunction onlyOne() {\n\tvar sum = 0;\n\tfor (var i=0; i < arguments.length; i++) {\n        // пропускаем ложные значения,\n\t\t// считая их 0, но избегайте NaN.\n\t\tif (arguments[i]) {\n\t\t\tsum += arguments[i];\n\t\t}\n\t}\n\treturn sum == 1;\n}\n\nvar a = true;\nvar b = false;\n\nonlyOne( b, a );\t\t\t\t// true\nonlyOne( b, a, b, b, b );\t\t// true\n\nonlyOne( b, b );\t\t\t\t// false\nonlyOne( b, a, b, b, b, a );\t// false\n```\n\n**Примечание:** Конечно, вместо цикла `for` в `onlyOne(..)` вы могли бы более лаконично использовать функцию ES5 `reduce(..)`, но я не хотел затуманивать концепцию.\n\nТо, что мы здесь делаем, - это полагаемся на `1` для `true`/правдивых приведений и численно складываем их. `sum + = arguments[i]` использует *неявное* приведение, чтобы это произошло. Если одно и только одно значение в списке `arguments` равно `true`, то числовая сумма будет равна `1`, в противном случае сумма не будет равна `1` и, таким образом, желаемое условие не выполняется.\n\nКонечно, мы могли бы сделать тоже самое с помощью *явного* приведения:\n\n```js\nfunction onlyOne() {\n\tvar sum = 0;\n\tfor (var i=0; i < arguments.length; i++) {\n\t\tsum += Number( !!arguments[i] );\n\t}\n\treturn sum === 1;\n}\n```\n\nМы сначала используем `!!arguments[i]`, побуждая привести значения к `true` или `false`. Это для того, чтобы вы могли передавать значения, отличные от `boolean`, например, `onlyOne( \"42\", 0 )`, и утилита работала бы так, как ожидается (в противном случае вы получили бы сцепление `string`, и логика была бы неверной).\n\nПосле того, как мы чётко знаем, что это `boolean`, мы выполняем еще одно *явное* приведение с помощью `Number(..)`, чтобы получить `0` или `1`.\n\nЯвляется ли *явная* форма приведения в этой утилите \"лучше\"? Она позволяет избежать ловушки `NaN`, как описано в комментариях к коду. Но, в конечном счете, это зависит от ваших потребностей. Лично я считаю, что первая версия, опирающаяся на *неявное* приведение, более элегантна (если вы не будете передавать `undefined` или `NaN`), а *явная* версия излишне многословна.\n\nНо, как и почти во всем, то, что мы здесь обсуждаем, это субъективные решения.\n\n**Примечание:** Независимо от подхода, *явного* или *неявного*, вы можете легко создать варианты `onlyTwo(..)` или `onlyFive(..)`, просто изменив итоговое сравнение с `1` на `2` или `5` соответственно. Это значительно проще, чем добавлять кучу выражений `&&` и `||`. Так что, в общем, приведение в данном случае очень полезно.\n\n### Неявно: * --> Булево значение\n\nТеперь давайте обратим наше внимание на *неявное* приведение к `boolean` значениям, поскольку оно, безусловно, самое распространенное, а также всё ещё самое потенциально проблемное.\n\nПомните, *неявное* приведение - это то, что возникает, когда вы используете значение так, что приходится преобразовать значение. Для `number` и `string` операций довольно легко увидеть ситуации вынужденного приведения.\n\nНо какие операции требуют/заставляют (*неявно*) приводить к `boolean`?\n\n1. Проверяемое выражение в операторе `if (..)`.\n2. Проверяемое выражение (второе) в `for ( .. ; .. ; .. )`.\n3. Проверяемое выражение в циклах `while (..)` и `do..while(..)`.\n4. Проверяемое выражение (первое) в тернарном операторе `? :`.\n5. Левый операнд (является проверяемым выражением - см. ниже!) в операторах `||` (\"логическое или\") и `&&` (\"логическое и\").\n\nЛюбое значение, используемое в этих контекстах, которое еще не является `boolean`, будет *неявно* преобразовано в `boolean` с использованием правил абстрактной операции `ToBoolean`, рассмотренной выше в этой главе.\n\nДавайте взглянем на примеры:\n\n```js\nvar a = 42;\nvar b = \"abc\";\nvar c;\nvar d = null;\n\nif (a) {\n\tconsole.log( \"угу\" );\t\t// угу\n}\n\nwhile (c) {\n\tconsole.log( \"нет, никогда не выполнится\" );\n}\n\nc = d ? a : b;\nc;\t\t\t\t\t\t\t\t// \"abc\"\n\nif ((a && d) || c) {\n\tconsole.log( \"угу\" );\t\t// угу\n}\n```\n\nВо всех этих контекстах значения, не являющиеся `boolean`, *неявно приводятся* к их `boolean` эквивалентам для выполнения проверки.\n\n### Операторы `||` и `&&`\n\nВероятно, вы видели операторы `||` (\"логическое или\") и `&&` (\"логическое и\") в большинстве или во всех других языках, которые вы использовали. Поэтому было бы естественно предположить, что в JavaScript они работают в основном так же, как и в других подобных языках.\n\nЕсть очень малоизвестный, но очень важный нюанс.\n\nНа самом деле, я бы сказал, что эти операторы даже не следует называть \"логическими ___ операторами\", поскольку такое название неполно описывает то, что они делают. Если бы я давал им более точное (хотя и более неуклюжее) название, я бы назвал их \"операторами выбора\" или, более полно, \"операторами выбора операндов\".\n\nПочему? Потому что в JavaScript они на самом деле не приводят к *логическому* значению (`boolean`), как это происходит в некоторых других языках.\n\nТак, к чему *они* приводят? Они приводят к значению одного (и только одного) из их двух операндов. Другими словами, **они выбирают одно из  значений двух операндов**.\n\nЦитирую раздел 11.11 спецификации ES5:\n\n> Значение, создаваемое оператором && или ||, не обязательно имеет тип Boolean. Полученное значение всегда будет значением одного из выражений двух операндов.\n\nДавайте проиллюстрирую:\n\n```js\nvar a = 42;\nvar b = \"abc\";\nvar c = null;\n\na || b;\t\t// 42\na && b;\t\t// \"abc\"\n\nc || b;\t\t// \"abc\"\nc && b;\t\t// null\n```\n\n**Подождите, что!?** Подумайте об этом. В таких языках, как C и PHP, эти выражения приводят к `true` или `false`, но в JS (и Python, и Ruby, если уж на то пошло!) результат определяется самими значениями.\n\nОба оператора `||` и `&&` выполняют `boolean` тест для **первого операнда** (`a` или `c`). Если операнд еще не является `boolean` (а здесь это не так), происходит обычное приведение `ToBoolean`, и проверка может быть выполнена.\n\nДля оператора `||`, если итог проверки `true`, выражение `||` возвращает значение *первого операнда* (`a` или `c`). Если итог проверки `false`, выражение `||` возвращает значение *второго операнда* (`b`).\n\nИ наоборот для оператора `&&`. Если итог проверки `true`, выражение `&&` возвращает значение *второго операнда* (`b`). Если итог проверки `false`, выражение `&&` возвращает значение *первого операнда* (`a` или `c`).\n\nРезультатом выражения `||` или `&&` всегда является значение одного из операндов, **а не** результат проверки (возможно, приведенный). В `c && b`, `c` равно `null` и, следовательно, является ложным. Но само выражение `&&` возвращает `null` (значение `c`), а не приведённый `false`, использованный при проверке.\n\nТеперь вы понимаете, что эти операторы действуют как \"селекторы операндов\"?\n\nДругой взгляд на эти операторы:\n\n```js\na || b;\n// примерно эквивалентно:\na ? a : b;\n\na && b;\n// примерно эквивалентно:\na ? b : a;\n```\n\n**Примечание:** Я говорю `a || b` \"примерно эквивалентно\" `a ? a : b` потому что результат идентичен, но есть определённая разница. В `а ? a : b`, если бы `a` было более сложным выражением (например, которое могло бы иметь побочные эффекты, такие как вызов `function` и т.д.), то выражение `a`, возможно, было бы вычислено дважды (если первая оценка была правдивой). В `a || b`, напротив, выражение `a` вычисляется лишь один раз, а это значение используется и для проверки, и в качестве результата (если требуется). Тот же нюанс и в выражениях `a && b` и `a ? b : a`.\n\nЧрезвычайно распространенным и полезным применением данного поведения, которое вы, вероятно, уже использовали и не до конца поняли, следующее:\n\n```js\nfunction foo(a,b) {\n\ta = a || \"hello\";\n\tb = b || \"world\";\n\n\tconsole.log( a + \" \" + b );\n}\n\nfoo();\t\t\t\t\t// \"hello world\"\nfoo( \"yeah\", \"yeah!\" );\t// \"yeah yeah!\"\n```\n\nИдиома `a = a || \"hello\"` (иногда говорят, что это JavaScript-версия \"оператора нулевого слияния\" из C#) проверяет `a` и, если у переменной нет значения (или оно нежелательное ложное), то возвращает резервное значение по умолчанию (`\"hello\"`).\n\nНо **будь осторожен**!\n\n```js\nfoo( \"That's it!\", \"\" ); // \"That's it! world\" <-- Ой!\n```\n\nВидите проблему? `\"\"` во втором аргументе - это ложное значение (см. `ToBoolean` ранее в этой главе). Поэтому проверка в `b = b || \"world\"` терпит неудачу и замещается значением по умолчанию `\"world\"`, хотя цель, вероятно, состояла в том, чтобы явно переданная пустая строка `\"\"` была присвоена `b`.\n\nЭта идиома `||` чрезвычайно распространена и весьма полезна, но вы должны использовать ее только в тех случаях, когда *все ложные значения* должны быть проигнорированы. В противном случае вам следует быть более точным в своей проверке и, возможно, прибегнуть к тернарному оператору `? :`.\n\nЭта идиома *присвоения значения по умолчанию* настолько распространена (и полезна!), что даже те, кто публично и яростно осуждает приведение в JavaScript, часто используют ее в своем собственном коде!\n\nА как насчет `&&`?\n\nЕсть еще одна идиома, которая несколько реже создается вручную, но которая часто используется JS минификаторами. Оператор `&&` \"выбирает\" второй операнд тогда и только тогда, когда первый операнд признаётся правдивым, и этот подход иногда называют \"защитным оператором\" (также см. \"Короткое замыкание\" в Главе 5) - проверка первого выражения \"защищает\" второе выражение:\n\n```js\nfunction foo() {\n\tconsole.log( a );\n}\n\nvar a = 42;\n\na && foo(); // 42\n```\n\n`foo()` вызывается только потому, что `a` определяется, как правдивый. Если результат проверки ложный, то выполнение оператора в выражении `a && foo()` молча остановится - это называют \"коротким замыканием\" - и `foo()` никогда не будет вызван.\n\nОпять же, люди не так часто пишут подобные вещи. Обычно вместо этого они выбирают `if (a) { foo(); }`. Но минификаторы JS предпочитают `a && foo()`, потому что это намного короче. Итак, теперь, если вам когда-нибудь придется расшифровывать такой код, вы будете знать, что он делает и почему.\n\nХорошо, итак, у `||` и `&&` есть несколько изящных трюков в рукаве, если вы готовы допустить *неявное* приведение в своей работе.\n\n**Примечание:** Обе идиомы `a = b || \"something\"` и `a && b()` опираются на короткое замыкание, которое мы более подробно рассмотрим в Главе 5.\n\nТот факт, что эти операторы на самом деле не приводят к `true` и `false`, возможно, уже немного заморочил вам голову. И вы, вероятно, удивляетесь, как вообще работали все ваши операторы `if` и циклы `for`, если в них были сложносоставные логические выражения, такие как `a && (b || c)`.\n\nНе волнуйся! Мир не рушится. С вашим кодом (возможно) всё хорошо. Просто вы, наверное, никогда раньше не осознавали, что **после того, как** было вычислено составное выражение, происходило *неявное* приведение к `boolean`.\n\nВзгляните:\n\n```js\nvar a = 42;\nvar b = null;\nvar c = \"foo\";\n\nif (a && (b || c)) {\n\tconsole.log( \"yep\" );\n}\n```\n\nЭтот код по-прежнему работает так, как вы всегда думали, за исключением одной незначительной дополнительной детали. Выражение `a && (b || c)` *на самом деле* возвращает `\"foo\"`, а не `true`. Итак, оператор `if` *затем* приводит значение `foo` к `boolean`, которое, конечно же, будет `true`.\n\nВидите? Нет причин для паники. Ваш код, вероятно, все еще в безопасности. Но теперь вы знаете больше о том, как он делает то, что делает.\n\nИ теперь вы также понимаете, что такой код использует *неявное* приведение. Если вы все еще в лагере \"избегайте (неявного) приведения\", вам нужно будет вернуться к своему коду и сделать все эти проверки *явными*:\n\n```js\nif (!!a && (!!b || !!c)) {\n\tconsole.log( \"yep\" );\n}\n```\n\nУдачи вам в этом! ... Извините, просто подтруниваю.\n\n### Приведение Symbol\n\nДо сего момента не было почти никакой заметной разницы в результатах между *явным* и *неявным* приведением - на кону была только читаемость кода.\n\nНо Symbol из ES6 вносят подвох в систему приведения, который нам нужно кратко обсудить. По причинам, которые выходят далеко за рамки того, что мы обсуждаем в этой книге, допускается *явное* преобразование `symbol` в `string`, но *неявное* приведение того же самого запрещено и выкидывает ошибку.\n\nРассмотрим:\n\n```js\nvar s1 = Symbol( \"cool\" );\nString( s1 );\t\t\t\t\t// \"Symbol(cool)\"\n\nvar s2 = Symbol( \"not cool\" );\ns2 + \"\";\t\t\t\t\t\t// TypeError\n```\n\nЗначения `symbol` вообще нельзя привести к `number` (всегда выдает ошибку), но, как ни странно, их можно как *явно*, так и *неявно* приводить к `boolean` (всегда `true`).\n\nСогласованной системе всегда легче научиться, а с исключениями всегда невесело иметь дело. Нам просто нужно быть осторожными с новыми `symbol` из ES6 и с тем, как их приводить.\n\nХорошая новость: вероятно, вам крайне редко понадобится приводить значение `symbol`. То, как они обычно используются (см. Главу 3), не требует их приведения на постоянной основе.\n\n## Обычное равенство vs. Строгое равенство\n\nОбычное равенство - это оператор `==`, а строгое равенство - это оператор `===`. Оба оператора используются для сравнения двух значений на \"равенство\". Это размежевание на \"обычное\" и \"строгое\" указывает на **очень важную** разницу в поведении между ними, в частности, в том, как они определяют \"равенство\".\n\nОчень распространенное заблуждение относительно этих двух операторов таково: \"`==` проверяет значения на равенство, а `===` проверяет как значения, так и типы на равенство\". Хотя это звучит красиво и разумно, но неточно. Бесчисленные уважаемые книги и блоги по JavaScript говорят именно об этом, но, к сожалению, все они *неправы*.\n\nПравильное описание таково: \"`==` допускает приведение при сравнении на равенство, а `===` запрещает приведение\".\n\n### Быстродействие равенства\n\nОстановитесь и подумайте о разнице между первым (неточным) и этим вторым (точным) объяснением.\n\nВ первом объяснении кажется очевидным, что `===` *выполняет больше работы*, чем `==`, потому что он должен *также* проверять тип. Во втором объяснении `==` - это то, что *выполняет больше работы*, потому что он должен выполнять приведение, если типы разные.\n\nНе попадайтесь в эту ловушку, думая как большинство, что это как-то связано с производительностью - будто бы `==` медленнее, чем `===`. Действительно это можно замерить и увидеть, что приведение действительно занимает *некоторое* время, но это всего лишь микросекунды (да, это миллионные доли секунды!).\n\nЕсли вы сравниваете два значения одного и того же типа, `==` и `===` используют идентичный алгоритм, и поэтому, за исключением незначительных различий в реализации движка, они делают одну и ту же работу.\n\nЕсли вы сравниваете два значения разных типов, производительность не является важным фактором. Что вы должны спросить себя: сравнивая эти две величины, нужно ли мне приведение или нет?\n\nЕсли вам нужно приведение, используйте `==` обычного равенства, но, если вы не хотите приведения, используйте `===` строгого равенства.\n\n**Примечание:** Здесь подразумевается, что и `==`, и `===` проверяют типы своих операндов. Разница заключается в том, как они реагируют, если типы не совпадают.\n\n### Абстрактное равенство\n\nПоведение оператора `==` определено в разделе 11.9.3 \"Абстрактный алгоритм сравнения равенства\" спецификации ES5. То, что там перечислено, - это всеобъемлющий, но простой алгоритм, в котором явно указаны все возможные комбинации типов и то, как приведения (при необходимости) должны выполняться для каждой комбинации.\n\n**Предупреждение:** Когда (*неявное*) приведение поносят как слишком сложное и ущербное, чтобы быть \"полезной сильной стороной\", осуждаются именно эти правила \"абстрактного равенства\". Как правило, говорят, что они слишком сложны и неинтуитивны для практического изучения и использования разработчиками, и что они больше склонны вызывать ошибки в программах JS, чем обеспечивать большую читаемость кода. Я считаю, что это ошибочная предпосылка - что вы, читатели, являетесь компетентными разработчиками, которые пишут (читают и понимают!) алгоритмы (он же код) весь день напролет. Итак, далее следует простое изложение \"абстрактного равенства\" в простых терминах. Но я умоляю вас также прочитать раздел 11.9.3 спецификации ES5. Я думаю, вы будете удивлены тем, насколько это разумно.\n\nПо сути, в первом пункте (11.9.3.1) говорится, что, если два сравниваемых значения имеют один и тот же тип, они просто и естественно сравниваются на Идентичность, как и следовало ожидать. Например, `42` равно только `42`, а `\"abc\"` равно только `\"abc\"`.\n\nНекоторые незначительные исключения из обычных ожиданий, о которых следует знать:\n\n* `NaN` никогда не равен самому себе (см. Главу 2)\n* `+0` и `-0` равны друг другу (см. Главу 2)\n\nПоследнее положение пункта 11.9.3.1 описывает обычное равенство `==` для `object` значений (включая `function` и `array`). Два таких значения *равны* только в том случае, если они оба являются ссылками на *одно и то же значение*. Здесь не происходит никакого приведения.\n\n**Примечание:** Алгоритм сравнения для строгого равенства `===` определен идентично пункту 11.9.3.1, включая положение о двух значениях `object`. Это совсем малоизвестный факт, что **`==` и `===` ведут себя одинаково** в случае, когда сравниваются два `object`!\n\nОстальная часть алгоритма в 11.9.3 говорит, что, если вы используете обычное равенство `==` для сравнения двух значений разных типов, одно или оба значения должны быть *неявно* приведены. Это приведение выполняется таким образом, что оба значения в конечном итоге оказываются одного типа, и могут быть напрямую сопоставлены на Идентичность значений.\n\n**Примечание:** Операция `!=` обычного неравенства определяется точно так, как вы ожидаете, в том смысле, что это буквально выполнение операция `==`, а затем отрицание (инверсия) результата. То же самое относится и к строгой операции неравенства `!==`.\n\n#### Сравнение: `string` и `number`\n\nЧтобы проиллюстрировать приведение `==`, давайте сначала рассмотрим примеры `string` и `number`, приведенные ранее в этой главе:\n\n```js\nvar a = 42;\nvar b = \"42\";\n\na === b;\t// false\na == b;\t\t// true\n```\n\nКак и следовало ожидать, `a === b` терпит неудачу, потому что никакое приведение не допускается, и действительно, значения `42` и `\"42\"` различные.\n\nОднако второе сравнение `a == b` использует обычное равенство, что означает, что если типы окажутся разными, то алгоритм сравнения выполнит *неявное* приведение одного или обоих значений.\n\nНо какой вид приведения здесь выполняется? Приводится ли значение `a`, равное `42`, к `string`, или значение `b`, равное `\"42\"`, становится `number`?\n\nВ спецификации ES5 в пунктах 11.9.3.4-5 говорится:\n\n> 4. Если Type(x) -- Number, а Type(y) -- String,\n> вернуть результат сравнения x == ToNumber(y).\n> 5. Если Type(x) -- String, а Type(y) -- Number,\n> вернуть результат сравнения ToNumber(x) == y.\n\n**Предупреждение:** Спецификация использует `Number` и `String` в качестве формальных имен для типов, а эта книга предпочитает `number` и `string` для обозначения примитивных типов. Не позволяйте заглавным буквам `Number` в спецификации ввести вас в заблуждение и принять это за функцию `Number()`. Для наших целей заглавные буквы в названии типа не имеют значения - в целом они имеют одно и то же значение.\n\nОчевидно, что спецификация говорит, что для сравнения значение `\"42\"` приведено к `number`. *Как* приведено - ранее было рассмотрено - с помощью абстрактной операции `ToNumber`. В этом случае совершенно очевидно, что результирующие два значения `42` равны.\n\n#### Сравнение: Любого с `boolean`\n\nОдна из самых больших ошибок с *неявным* приведением в обычном равенстве `==` возникает, когда вы пытаетесь напрямую сравнить значение с `true` или `false`.\n\nРассмотрим:\n\n```js\nvar a = \"42\";\nvar b = true;\n\na == b;\t// false\n```\n\nПодождите, что здесь произошло!? Мы знаем, что `\"42\"` - это истинное значение (см. выше в этой главе). Итак, как вышло что в `==` оно не равно `true`?\n\nПричина одновременно проста и обманчиво хитра. Это так легко неправильно понять, что многие разработчики JS никогда не уделяют достаточно пристального внимания, чтобы полностью понять это.\n\nДавайте еще раз процитируем спецификацию, пункты 11.9.3.6-7:\n\n> 6. Если Type(x) -- Boolean,\n> вернуть результат сравнения ToNumber(x) == y.\n> 7. Если Type(y) -- Boolean,\n> вернуть результат сравнения x == ToNumber(y).\n\nДавайте разберемся с этим. Во-первых:\n\n```js\nvar x = true;\nvar y = \"42\";\n\nx == y; // false\n```\n\n`Type(x)` действительно `Boolean`, поэтому выполняется `ToNumber(x)`, которое приводит `true` в `1`. Следом анализируется `1 == \"42\"`. Типы по-прежнему разные, поэтому (по сути, рекурсивно) мы прибегаем к алгоритму, который, как и выше, преобразует `\"42\"` в `42`, а `1 == 42` явно является `false`.\n\nПоменяем направление на противоположное, и мы все равно получим тот же результат:\n\n```js\nvar x = \"42\";\nvar y = false;\n\nx == y; // false\n```\n\nНа этот раз `Type(y)` является `Boolean`, поэтому `ToNumber(y)` дает `0`, а `\"42\" == 0` рекурсивно становится `42 == 0`, что, конечно же, является `false`.\n\nДругими словами, **значение `\"42\"` не является ни `== true`, ни `== false`**. На первый взгляд это утверждение может показаться безумным. Как значение может быть ни правдивым, ни ложным?\n\nНо в этом-то и проблема! Вы задаете совершенно неправильный вопрос. На самом деле это не твоя вина. Твой мозг обманывает тебя.\n\n`\"42\"` действительно правдивое, но `\"42\" == true` **вообще не выполняет логический тест/приведение**, независимо от того, что говорит ваш мозг. `\"42\"` *не* приводится к `boolean` (`true`), а вместо этого `true` преобразуется в `1`, а затем `\"42\"` конвертируется в `42`.\n\nНравится нам это или нет, `ToBoolean` здесь даже не задействован, поэтому правдивость или ложность `\"42\"` не имеет отношения к операции `==`!\n\nЕдинственно, что *важно*, - это понять, как алгоритм `==` сравнения ведет себя с разными комбинациями типов. Поскольку это относится и к `boolean` по обе стороны от `==`, запомните - `boolean` всегда *сначала* приводится к `number`.\n\nЕсли вам это кажется странным, вы не одиноки. Лично я рекомендовал бы ни при каких обстоятельствах не использовать `== true` или `== false`. Никогда.\n\nНо помните, я говорю только о `==`. `=== true` и `=== false` не делают приведения типа, поэтому они защищены от этого скрытого приведения `ToNumber`.\n\nРассмотрим:\n\n```js\nvar a = \"42\";\n\n// плохо (не пройдет проверку!):\nif (a == true) {\n\t// ..\n}\n\n// тоже плохо (не пройдет проверку!):\nif (a === true) {\n\t// ..\n}\n\n// приемлемо (неявное приведение):\nif (a) {\n\t// ..\n}\n\n// лучше (явное приведение):\nif (!!a) {\n\t// ..\n}\n\n// тоже хорошо (явное приведение):\nif (Boolean( a )) {\n\t// ..\n}\n```\n\nЕсли вы будете избегать в своем коде `== true` или `== false` (обычное равенство с `boolean`), вам никогда не придется беспокоиться об этой ментальной ловушки правдивости/ложности.\n\n#### Сравнение: `null` с `undefined`\n\nДругой пример *неявного* приведения можно наблюдать в случае обычного равенства `==` между значениями `null` и `undefined`. Еще раз цитирую спецификацию ES5, пункты 11.9.3.2-3:\n\n> 2. Если x равно `null`, а y -- `undefined`, вернуть значение `true`.\n> 3. Если x равно `undefined`, а y -- `null`, вернуть значение `true`.\n\n`null` и `undefined` при обычном равенстве `==` приравниваются (приводятся) друг к другу (а также к самим себе, очевидно) и к никаким другим значениям языка.\n\nЭто означает, что `null` и `undefined` могут рассматриваться как неразличимые для целей сравнения, если вы используете оператор обычного равенства `==` для их взаимного *неявного* приведения.\n\n```js\nvar a = null;\nvar b;\n\na == b;\t\t// true\na == null;\t// true\nb == null;\t// true\n\na == false;\t// false\nb == false;\t// false\na == \"\";\t// false\nb == \"\";\t// false\na == 0;\t\t// false\nb == 0;\t\t// false\n```\n\nПриведение между `null` и `undefined` безопасно и предсказуемо, и никакие другие значения не могут давать ложных срабатываний при такой проверке. Я рекомендую использовать это приведение, чтобы `null` и `undefined` были неразличимы и, таким образом, рассматривались как одно и то же значение.\n\nНапример:\n\n```js\nvar a = doSomething();\n\nif (a == null) {\n\t// ..\n}\n```\n\nПроверка `a == null` пройдет только в том случае, если `doSomething()` возвращает либо `null`, либо `undefined`, и завершится ошибкой с любым другим значением, даже с другими ложными значениями, такими как `0`, `false` и `\"\"`.\n\n*Явная* форма проверки, запрещающее любое такое приведение, (на мой взгляд) неоправданно сильно уродливее (и, возможно, чуть менее производительна!):\n\n```js\nvar a = doSomething();\n\nif (a === undefined || a === null) {\n\t// ..\n}\n```\n\nПо-моему, форма `a == null` - это еще один пример, когда *неявное* приведение улучшает читаемость кода, и делает это безопасным способом.\n\n#### Сравнение: `object` с не-`object`\n\nПункты 11.9.3.8-9 спецификация ES5 гласят, что, если `object`/`function`/`array` сравнивается с простым скалярным примитивом (`string`, `number` или `boolean`), то:\n\n> 8. Если Type(x) является String или Number, а Type(y) - Object,\n> вернуть результат сравнения x == ToPrimitive(y).\n> 9. Если Type(x) - Object, а Type(y) - String или Number,\n> вернуть результат сравнения ToPrimitive(x) == y.\n\n**Примечание:** Вы можете заметить, что в этих положениях упоминаются только `String` и `Number`, но не `Boolean`. Это потому, что пункты 11.9.3.6-7 (см. выше) позаботятся о том, чтобы сначала привести `Boolean` операнд к `Number`.\n\nРассмотрим:\n\n```js\nvar a = 42;\nvar b = [ 42 ];\n\na == b;\t// true\n```\n\nДля значения `[ 42 ]` вызывается абстрактная операция `ToPrimitive` (см. выше раздел \"Абстрактные операции со значениями\"), результатом которой станет `\"42\"`. Теперь это просто `42 == \"42\"`, которое, как мы уже видели, становится `42 == 42`, так что `a` и `b` оказываются приведённо равными.\n\n**Совет:** Все особенности абстрактной операции `ToPrimitive`, которые мы обсуждали ранее в этой главе (`toString()`, `valueOf()`), применимы здесь, как и следовало ожидать. Это может быть весьма полезно, если у вас сложная структура данных, для которой вы хотите определить пользовательский метод `valueOf()`, чтобы предоставить простое значение для сравнения на равенство.\n\nВ Главе 3 мы рассматривали \"распаковку\", когда `object`-обёртка вокруг примитивного значения (например, из `new String(\"abc\")`) разворачивается, и возвращается базовое примитивное значение (`\"abc\"`). Такое поведение связано с `ToPrimitive`-приведением в алгоритме `==`:\n\n```js\nvar a = \"abc\";\nvar b = Object( a );\t// same as `new String( a )`\n\na === b;\t\t\t\t// false\na == b;\t\t\t\t\t// true\n```\n\n`a == b` является `true`, потому что `b` принудительно (он же \"unboxed\", развернутый) через `ToPrimitive` к его простому скалярному примитивному значению `abc`, которое совпадает со значением в `a`.\n\nОднако есть некоторые значения, для которых это не так, из-за других переопределяющих правил в алгоритме `==`. Посмотрите:\n\n```js\nvar a = null;\nvar b = Object( a );\t// same as `Object()`\na == b;\t\t\t\t\t// false\n\nvar c = undefined;\nvar d = Object( c );\t// same as `Object()`\nc == d;\t\t\t\t\t// false\n\nvar e = NaN;\nvar f = Object( e );\t// same as `new Number( e )`\ne == f;\t\t\t\t\t// false\n```\n\nЗначения `null` и `undefined` не могут быть \"упакованы\" - у них нет эквивалента объектной обёртки - поэтому `Object(null)` аналогичен `Object()` в том смысле, что оба они просто создают обычный объект.\n\n`NaN` может быть упакован в эквивалент объектной оболочки `Number`, но когда `==` вызывает распаковку, сравнение `NaN == NaN` завершается неудачей, потому что `NaN` никогда не равен самому себе (см. Главу 2).\n\n### Граничные случаи\n\nТеперь, когда мы тщательно изучили, как работает *неявное* приведение обычного равенства `==` (как логичным, так и неожиданным образом), давайте попробуем назвать худшие, самые безумные граничные случаи, чтобы мы могли понять, чего нам надо избегать, чтобы не быть нокаутированным ошибками приведения.\n\nВо-первых, давайте рассмотрим, как модификация встроенных прототипов может привести к сумасшедшим результатам:\n\n#### Number из любого другого значения будет...\n\n```js\nNumber.prototype.valueOf = function() {\n\treturn 3;\n};\n\nnew Number( 2 ) == 3;\t// true\n```\n\n**Предупреждение:** `2 == 3` не попало бы в эту ловушку, потому что ни `2`, ни `3` не вызвали бы встроенный метод `Number.prototype.valueOf()`, потому что оба уже являются примитивными значениями `number` и могут быть сравнены напрямую. Однако `new Number(2)` должно пройти через приведение `ToPrimitive` и, таким образом, вызвать `valueOf()`.\n\nЗло, да? Конечно. Никто никогда не должен делать ничего подобного. Тот факт, что вы *можете* сделать это, иногда используется как критика приведения и `==`. Но это беспочвенное разочарование. JavaScript не *плох*, потому что вы можете делать такие вещи, разработчик *плох*, **если он делает такие вещи**. Не впадайте в заблуждение \"мой язык программирования должен защищать меня от самого себя\".\n\nДавайте рассмотрим другой хитрый пример, который выводит зло предыдущего примера на новый уровень:\n\n```js\nif (a == 2 && a == 3) {\n\t// ..\n}\n```\n\nВы могли подумать, что это невозможно, потому что `a` никогда не может быть равно как `2`, так и `3` *одновременно*. Но \"в то же время\" неточно, поскольку первое выражение `a == 2` происходит строго *перед* `a == 3`.\n\nИтак, что, если мы заставим `a.valueOf()` иметь побочные эффекты при каждом его вызове, так что при первом вызове он вернет `2`, а при втором - `3`? Это довольно просто:\n\n```js\nvar i = 2;\n\nNumber.prototype.valueOf = function() {\n\treturn i++;\n};\n\nvar a = new Number( 42 );\n\nif (a == 2 && a == 3) {\n\tconsole.log( \"Да, это случилось.\" );\n}\n```\n\nОпять же, это злые уловки. Не делайте так. И не используйте их для жалоб на приведение. Потенциальные злоупотребления механизмом не являются достаточными доказательствами для осуждения механизма. Просто избегайте этих безумных трюков и придерживайтесь только корректного и надлежащего использования приведения.\n\n#### False-сравнения\n\nНаиболее частая жалоба на *неявное* приведение при обычном равенстве `==` исходит из того, что ложные значения ведут себя неожиданно, когда сравниваются друг с другом.\n\nЧтобы проиллюстрировать это, давайте посмотрим на список граничных случаев сравнения ложных значений, и увидим, какие из них обоснованы, а какие источник проблем:\n\n```js\n\"0\" == null;\t\t\t// false\n\"0\" == undefined;\t\t// false\n\"0\" == false;\t\t\t// true -- О-О-О!\n\"0\" == NaN;\t\t\t\t// false\n\"0\" == 0;\t\t\t\t// true\n\"0\" == \"\";\t\t\t\t// false\n\nfalse == null;\t\t\t// false\nfalse == undefined;\t\t// false\nfalse == NaN;\t\t\t// false\nfalse == 0;\t\t\t\t// true -- О-О-О!\nfalse == \"\";\t\t\t// true -- О-О-О!\nfalse == [];\t\t\t// true -- О-О-О!\nfalse == {};\t\t\t// false\n\n\"\" == null;\t\t\t\t// false\n\"\" == undefined;\t\t// false\n\"\" == NaN;\t\t\t\t// false\n\"\" == 0;\t\t\t\t// true -- О-О-О!\n\"\" == [];\t\t\t\t// true -- О-О-О!\n\"\" == {};\t\t\t\t// false\n\n0 == null;\t\t\t\t// false\n0 == undefined;\t\t\t// false\n0 == NaN;\t\t\t\t// false\n0 == [];\t\t\t\t// true -- О-О-О!\n0 == {};\t\t\t\t// false\n```\n\nВ этом списке 17 из 24 сравнений вполне разумны и предсказуемы. Например, мы знаем, что `\"\"` и `NaN` вовсе не являются приравниваемыми значениями, и действительно, они не приводятся обычным равенством, тогда как `\"0\"` и `0` разумно приравниваемы и *действительно* приводятся обычным равенством.\n\nОднако семь сравнений отмечены знаком \"О-О-О!\", потому что, будучи ложнопозитивными, они скорее являются ошибками, которые могут сбить с толку. `\"\"` и `0` совершенно разные значения, и редко, когда есть необходимость считать их равнозначными. Поэтому их взаимное приведение вызывает проблемы. Обратите внимание, что здесь нет никаких ложнонегативных случаев.\n\n#### Самые сумасшедшие из них\n\nОднако мы не должны останавливаться на достигнутом. Мы можем продолжать искать еще более неприятные способы приведения:\n\n```js\n[] == ![];\t\t// true\n```\n\nОооо, это кажется более высоким уровнем сумасшествия, верно!? Ваш мозг, скорее всего, может обмануть вас, что вы сравниваете правдивое и ложное значения, поэтому результат `true` удивителен, поскольку мы *знаем*, что значение никогда не может быть правдивым и ложным одновременно!\n\nНо это не то, что происходит на самом деле. Давайте разберем это по полочкам. Что мы знаем об унарном операторе `!`? Он явно приводит к `boolean`, используя правила `ToBoolean` (он также инвертирует значение). Таким образом, еще до того, как `[] == ![]` будет обработано, оно фактически уже переведено в `[] == false`. Мы уже видели эту в нашем списке выше (`false == []`), поэтому неожиданный результат *не новый* для нас.\n\nКак насчет других граничных случаев?\n\n```js\n2 == [2];\t\t// true\n\"\" == [null];\t// true\n```\n\nКак мы говорили ранее в нашем обсуждении `ToNumber`, значения справа `[2]` и `[null]` подвергнутся приведению `ToPrimitive`, поэтому их будет легче сравнить с простыми примитивами (`2` и `\"\"` соответственно) слева. Поскольку `valueOf()` для значений `array` просто возвращает сам `array`, приведение сводится к превращению `array` в строку.\n\n`[2]` станет `\"2\"`, которая затем приводится `ToNumber` к `2` справа в первом сравнении. `[null]` просто прямо становится `\"\"`.\n\nПоэтому `2 == 2` и `\"\" == \"\"` вполне понятны.\n\nЕсли вам по-прежнему инстинктивно не нравятся эти результаты, то на самом деле ваше разочарование вызвано не приведением, как вы вероятно думаете. На самом деле это недовольство значением по умолчанию для  `array`, когда приведение `ToPrimitive` возвращает значение `string`. Скорее всего, вы бы просто хотели, чтобы `[2].toString()` не возвращал `\"2\"`, и `[null].toString()` возвращал бы не `\"\"`.\n\nНо что *должны* возвращать эти приведения к `string`? Я действительно не могу придумать ничего более подходящего для `[2]` приводимой к `string`, кроме `\"2\"`, за исключением, возможно, `\"[2]\"` - но это может оказаться очень странным в других контекстах!\n\nВы могли бы справедливо утверждать, что поскольку `String(null)` становится `\"null\"`, то `String([null])` также должна стать `\"null\"`. Это разумное утверждение. Итак, вот кто настоящий виновник.\n\n*Неявное* приведение само по себе здесь не является злом. Даже *явное* приведение `[null]` к `string` приводит к `\"\"`. Что вызывает разногласия, так это, разумно ли вообще `array` приводить к строковому эквиваленту его содержимого, и как именно это делать. Итак, направьте свое разочарование на правила для `String( [..] )`, потому что именно отсюда рождается сумасшествие. Возможно, вообще не должно быть приведения `array` к строке? Но это дало бы много других нехороших последствий в других частях языка.\n\nЕще одно часто цитируемое недоумение:\n\n```js\n0 == \"\\n\";\t\t// true\n```\n\nКак мы обсуждали выше пустые `\"\"`, `\"\\n\"` (`\" \"` или любая другая комбинация пробелов) приводится через `ToNumber`, и результат этого - `0`. К какому другому значению `number` вы хотели привести пробел? Вас беспокоит, что *явное* `Number(\" \")` дает `0`?\n\nНа самом деле единственное другое разумное значение `number`, к которому можно привести пустые строки или строки с пробелами, - это `NaN`. Но действительно ли это было бы лучше? Сравнение `\" \" == NaN`, конечно же, потерпело бы неудачу, но неясно, действительно ли бы мы *исправили* какие-либо из проблем.\n\nВероятность того, что реальная JS-программа выйдет из строя из-за `0 == \"\\n\"`, ужасно редка, и таких граничных случаев легко избежать.\n\nПреобразования типов **всегда** имеют граничные случаи на любом языке - ничего специфичного для приведения. Проблемы здесь заключаются в последующих сомнениях о конкретных граничных случаях (и, возможно, это правильно!?), но это не является весомым аргументом против общего механизма приведения.\n\nИтог: почти любое сумасшедшее приведение между *нормальными значениями*, с которым вы вероятно столкнетесь (кроме намеренных хаков `valueOf()` и `toString()` выше), будет сводиться к короткому списку из семи пунктов, которые мы определили выше.\n\nВ противовес этим 24-м частым подозреваемым в странном приведении, рассмотрим другой список:\n\n```js\n42 == \"43\";\t\t\t\t\t\t\t// false\n\"foo\" == 42;\t\t\t\t\t\t// false\n\"true\" == true;\t\t\t\t\t\t// false\n\n42 == \"42\";\t\t\t\t\t\t\t// true\n\"foo\" == [ \"foo\" ];\t\t\t\t\t// true\n```\n\nВ этих не ложных, не граничных случаях (а существует буквально бесконечное число сравнений, которые мы могли бы включить в этот список) результаты приведения абсолютно безопасны, разумны и объяснимы.\n\n#### Проверка на здравомыслие\n\nЛадно, мы действительно нашли какие-то сумасшедшие вещи, когда глубоко погрузились в *неявное* приведение. Неудивительно, что большинство разработчиков заявляют, что приведение - это зло, и его следует избегать, верно!?\n\nНо давайте сделаем шаг назад и проведем проверку на здравомыслие.\n\nДля оценки масштабов: у нас есть *список* из семи проблематичных приведений, и есть *другой список* (по крайней мере, 17, но на самом деле бесконечный) приведений, которые полностью вменяемы и объяснимы.\n\nЕсли вы ищете хрестоматийный пример \"выплёскивания вместе с водой ребёнка\", то вот он: отказ от любого приведения (бесконечно большой список безопасных и полезных средств) из-за буквально семи ошибок.\n\nБолее разумной реакцией было бы спросить: \"Как я могу использовать бесчисленные *сильные стороны* приведения, и избежать немногих *недостатков*?\"\n\nДавайте еще раз посмотрим на список \"недостатков\":\n\n```js\n\"0\" == false;\t\t\t// true -- О-О-О!\nfalse == 0;\t\t\t\t// true -- О-О-О!\nfalse == \"\";\t\t\t// true -- О-О-О!\nfalse == [];\t\t\t// true -- О-О-О!\n\"\" == 0;\t\t\t\t// true -- О-О-О!\n\"\" == [];\t\t\t\t// true -- О-О-О!\n0 == [];\t\t\t\t// true -- О-О-О!\n```\n\nЧетыре из семи пунктов в этом списке включают сравнение `== false`, которого, как мы говорили ранее, вам следует **всегда, всегда** избегать. Это довольно простое правило для запоминания.\n\nТеперь список сократился до трех.\n\n```js\n\"\" == 0;\t\t\t\t// true -- О-О-О!\n\"\" == [];\t\t\t\t// true -- О-О-О!\n0 == [];\t\t\t\t// true -- О-О-О!\n```\n\nБудет ли применение таких приведений в обычной JS-программе разумным? В каких обстоятельствах они действительно могут случиться?\n\nЯ не думаю, что высока вероятность того, что вы буквально будете использовать `== []` в вашей программе. По крайней мере, намеренно. Более вероятно, вы бы написали `== \"\"` или `== 0`, как тут:\n\n```js\nfunction doSomething(a) {\n\tif (a == \"\") {\n\t\t// ..\n\t}\n}\n```\n\nУ вас бы случился большой ОЙ, если бы вы случайно вызвали `doSomething(0)` или `do Something([])`. Другой сценарий:\n\n```js\nfunction doSomething(a,b) {\n\tif (a == b) {\n\t\t// ..\n\t}\n}\n```\n\nОпять же, это может сломаться, если вы сделаете что-то вроде `doSomething(\"\",0)` или `doSomething([],\"\")`.\n\nТаким образом, хотя *могут* существовать ситуации, когда эти приведения доставят вам беспокойство, и вы захотите быть осторожными с ними, они, вероятно, не очень распространены в вашей кодовой базе.\n\n#### Безопасное использование неявного приведения\n\nСамый важный совет, который я могу вам дать: изучите свою программу и подумайте о том, какие значения могут оказаться по обе стороны от сравнения `==`. Чтобы эффективно избежать проблем с такими сравнениями, вот несколько эвристических правил, которым надо следовать:\n\n1. Если любая из сторон сравнения может иметь значения `true` или `false`, никогда, НИКОГДА не используйте `==`.\n2. Если любая из сторон сравнения может иметь `[]`, `\"\"`, или значения `0`, серьезно подумайте о том, чтобы не использовать `==`.\n\nВ этих случаях почти наверняка лучше использовать `===` вместо `==`, чтобы избежать нежелательного приведения. Следуйте этим двум простым правилам, и вы избежите практически все ошибки приведения, которые могут навредить вам.\n\n**Для большей ясности - это избавит вас от множества головных проблем.**\n\nВопрос `==` vs. `===` в действительности формулируется так: следует ли допускать приведение для сравнения или нет?\n\nЕсть много случаев, когда такое приведение может быть полезным, позволяя вам более кратко выразить некоторую логику сравнения (например, с `null` и `undefined`).\n\nВ совокупном порядке вещей существует относительно немного случаев, когда *неявное* приведение действительно опасно. Но в этих ситуациях, в целях безопасности, обязательно используйте `===`.\n\n**Совет:** Еще один случай, где приведение гарантированно *не* причинит вам вреда, - это оператор `typeof`. `typeof` всегда будет возвращать вам одну из семи строк (см. Главу 1), и ни одна из них не является пустой строкой `\"\"`. Соответственно, нет ни одного случая, когда проверка типа какого-либо значения натолкнется на *неявное* приведение. `typeof x == \"function\"` на 100% так же безопасен и надежен, как `typeof x === \"function\"`. В спецификации буквально говорится, что алгоритм будет идентичен в этих случаях. Итак, не используйте `===` слепо везде просто потому, что так говорит ваша среда разработки, или (что хуже всего) потому, что в какой-то книге вам сказали **не думать об этом**. Вы сами отвечаете за качество своего кода.\n\nЯвляется ли *неявное* приведение злом и опасным? В некоторых случаях - да, но в подавляющем большинстве - нет.\n\nБудьте ответственным и зрелым разработчиком. Изучите, как эффективно и безопасно применять мощь приведения (как *явного*, так и *неявного*). И научите окружающих делать то же самое.\n\nВот удобная таблица, составленная Алексом Дори (@dorey на GitHub) для визуализации различных сравнений:\n\n<img src=\"fig1.png\" width=\"600\">\n\nИсточник: https://github.com/dorey/JavaScript-Equality-Table\n\n## Абстрактное сравнение отношений\n\nХотя этой части *неявного* приведения часто уделяется гораздо меньше внимания, тем не менее важно подумать о том, что происходит со сравнениями `a < b` (аналогично тому, как мы только что подробно рассмотрели `a == b`).\n\nАлгоритм \"Абстрактного сравнения отношений\" в разделе 11.8.5 ES5 по существу делится на две части: что делать, если в сравнении оба значения `string` (вторая половина) или иное (первая половина).\n\n**Примечание:** Алгоритм определен только для `a < b`. Поэтому `a > b` обрабатывается как `b < a`.\n\nСначала алгоритм инициирует приведение `ToPrimitive` для обоих значений, и если любой из возвращаемых результатов не `string`, то оба значения преобразуются в `number` с использованием правил операции `ToNumber` и затем сравниваются численно.\n\nНапример:\n\n```js\nvar a = [ 42 ];\nvar b = [ \"43\" ];\n\na < b;\t// true\nb < a;\t// false\n```\n\n**Примечание:** Здесь действуют те же оговорки о `-0` и `NaN`, как и в рассмотренном ранее алгоритме `==`.\n\nОднако, если в сравнении `<` оба значения `string`, выполняется простое лексикографическое (в натуральном алфавите) сравнение символов:\n\n```js\nvar a = [ \"42\" ];\nvar b = [ \"043\" ];\n\na < b;\t// false\n```\n\n`a` и `b` *не* приводятся к `number`, потому что оба `array` после `ToPrimitive` приведения становятся `string`. Следовательно, `\"42\"` посимвольно сравнивается с `\"043\"`, начиная с первых символов `\"4\"` и `\"0\"` соответственно. Поскольку `\"0\"` лексикографически *меньше*, чем `\"4\"`, сравнение возвращает `false`.\n\nТочно такое же поведение и рассуждения наблюдаем здесь:\n\n```js\nvar a = [ 4, 2 ];\nvar b = [ 0, 4, 3 ];\n\na < b;\t// false\n```\n\nЗдесь `a` становится `\"4,2\"`, а `b` становится `\"0,4,3\"`, и они лексикографически сравниваются идентично предыдущему коду.\n\nКак насчет этого:\n\n```js\nvar a = { b: 42 };\nvar b = { b: 43 };\n\na < b;\t// ??\n```\n\n`a < b` также `false`, потому что `a` становится `[object Object]`, и `b` становится `[object Object]`. Поэтому очевидно, что `a` лексикографически не меньше `b`.\n\nНо вот странный случай:\n\n```js\nvar a = { b: 42 };\nvar b = { b: 43 };\n\na < b;\t// false\na == b;\t// false\na > b;\t// false\n\na <= b;\t// true\na >= b;\t// true\n```\n\nПочему `a == b` не `true`? Это же одно и то же `string` значение (`\"[object Object]\"`), поэтому кажется они должны быть равны, верно? Нет. Вспомним предыдущее обсуждение того, как `==` работает со ссылками на `object`.\n\nНо тогда как `a <= b` и `a >= b` становятся `true`, если **и** `a < b`, **и** `a == b`, **и** `a > b` - все равны `false`?\n\nПотому что в спецификации сказано, что для `a <= b`, на самом деле сначала вычисляется `b < a`, а затем её результат инвертируется. Так как `b < a` *тоже* `false`, то результат `a <= b` это `true`.\n\nЭто, вероятно, ужасно противоречит тому, как до настоящего момента вы вероятно интерпретировали действие `<=` - скорее буквально: \"меньше, чем *или* равно\". JS интерпретирует `<=` как \"не больше, чем\" (`!(a > b)`, которое JS трактует как `!(b < a)`). Более того, `a >= b` также сначала интерпретируется как `b <= a`, а затем в ход идёт та же логика.\n\nК сожалению, не существует \"строгого сравнения отношения\", как для равенства. Другими словами, нет никакого способа предотвратить *неявное* приведение при сравнении отношений, таких как `a < b`, кроме как явно убедиться, что `a` и `b` имеют один и тот же тип, перед выполнением сравнения.\n\nСледуйте той же логике проверки на здравомыслие, что и в нашем предыдущем обсуждении `==` vs. `===`. Если приведение полезно и достаточно безопасно, как в сравнении `42 < \"43\"`, **используйте его**. С другой стороны, если вам нужна безопасность сравнении отношений, то сначала *явно приведите* значения, прежде чем использовать `<` (или его аналоги).\n\n```js\nvar a = [ 42 ];\nvar b = \"043\";\n\na < b;\t\t\t\t\t\t// false -- сравнение строк!\nNumber( a ) < Number( b );\t// true -- сравнение чисел!\n```\n\n## Итоги\n\nВ этой главе мы обратили наше внимание на то, как происходит преобразование типов в JavaScript, называемое **приведением**, которое можно описать либо *явным*, либо *неявным*.\n\nПриведение пользуется дурной славой, но в действительности во многих случаях оно весьма полезно. Важной задачей для ответственного разработчика JS становится изучение всех тонкостей приведения, чтобы решить, какие вещи помогут улучшить его код, а чего на самом деле следует избегать.\n\n*Явное* приведение - это код, из которого очевидно, что целью является преобразование значения из одного типа в другой. Его преимущество - улучшение читаемости и поддержки кода путем сокращения недоумений.\n\n*Неявное* приведение - это \"скрытое\" преобразование типа, являющееся побочным эффектом какой-либо другой операции, где не так очевидно, что произойдет конвертация типа. Хотя может показаться, что *неявное* приведение противопоставляется *явному* и, поэтому вредно (и действительно, многие так думают!), на самом деле *неявное* приведение также служит улучшению читаемости кода.\n\nПриведение должно использоваться ответственно и осознано, особенно это касается *неявного* приведения. Знайте, почему вы пишете тот код, который вы пишете, и как он работает. Стремитесь писать код, который другие также легко смогут изучить и понять.\n"
  },
  {
    "path": "types & grammar/ch5.md",
    "content": "# Вы не знаете JS: Типы и грамматика\n# Глава 5: Грамматика\n\nПоследняя важная тема, которую мы хотим затронуть, - это то, как работает синтаксис языка JavaScript (он же его грамматика). Вы можете думать, что знаете, как писать JS, но в различных частях грамматики языка ужасно много нюансов, которые приводят к путанице и неправильному пониманию, поэтому мы хотим углубиться в эти части и прояснить некоторые вещи.\n\n**Примечание:** Термин \"грамматика\" может быть немного менее знаком читателям, чем термин \"синтаксис\". Во многих отношениях это схожие термины, описывающие *правила* того, как работает язык. У них есть небольшие различия, но они в основном не имеют значения для нашего здесь обсуждения. Грамматика для JavaScript - это структурированный способ описания того, как синтаксис (операторы, ключевые слова и т.д.) компонуется в правильно и корректно разработанные программы. Иными словами, обсуждение синтаксиса без грамматики упустило бы многие важные детали. Поэтому, в этой главе наше внимание акцентируется на том, что наиболее точно описывается как \"грамматика\", хотя разработчики непосредственно оперируют с синтаксисом языка.\n\n## Инструкции и выражения\n\nРазработчики довольно часто предполагают, что термины \"инструкция\" и \"выражение\" примерно эквивалентны. Но здесь нам нужно разделить их, потому что в наших JS программах есть некоторые очень важные различия.\n\nЧтобы провести различие, давайте позаимствуем терминологию, с которой вы, возможно, более знакомы: английский язык.\n\n\"Предложение\" - это одно законченное высказывание из слов, выражающее мысль. Оно состоит из одной или нескольких \"фраз\", каждая из которых может быть связана знаками препинания или союзами (\"и\", \"или\" и т.д.). Сама фраза может состоять из более мелких фраз. Некоторые фразы являются неполными и сами по себе мало чего значат, в то время как другие фразы могут быть самостоятельными. Эти правила в совокупности называются *грамматикой* английского языка.\n\nТак же обстоит дело с грамматикой JavaScript. Инструкции - это предложения, выражения - это фразы, а операторы - это союзы/знаки препинания.\n\nКаждое выражение в JS может быть вычислено вплоть до одного конкретного значения. Например:\n\n```js\nvar a = 3 * 6;\nvar b = a;\nb;\n```\n\nВ этом фрагменте `3 * 6` является выражением (вычисляется до значения `18`). `a` во второй строке также является выражением, как и `b` в третьей строке. Оба выражения `a` и `b` вычисляются в соответствии со значениями, хранящимися в этих переменных в данный момент, которые равны `18`.\n\nБолее того, каждая из трех строк представляет собой инструкцию, содержащую выражения. `var a = 3 * 6` и `var b = a` называются \"операторами объявления\", потому что каждый из них объявляет переменную (и необязательно присваивает ей значение). Присваивания `a = 3 * 6` и `b = a` (откидывая `var`) называются выражениями присваивания.\n\nТретья строка содержит только выражение `b`, и это также инструкция сама по себе (хотя и не очень интересная!). Обычно это называется \"оператор выражения\".\n\n### Значение завершения инструкции\n\nЭто весьма малоизвестный факт, что все инструкции имеют значения завершения (даже если это просто `undefined`).\n\nКак бы вы отнеслись к тому, чтобы взглянуть на значение завершения?\n\nНаиболее очевидный путь - ввести инструкцию в консоль разработчика вашего браузера, потому что, когда вы ее выполняете, консоль по умолчанию сообщает значение завершения самой последней инструкции, которую она выполнила.\n\nДавайте рассмотрим `var b = a`. Каково значение завершения этой инструкции?\n\nВыражение присваивания `b = a` возвращает значение, которое было присвоено (`18` см. выше), но сама инструкция `var` возвращает `undefined`. Почему? Потому что так инструкция `var` определена в спецификации. Если вы введете `var a = 42;` в свою консоль, вы увидите сообщение `undefined` вместо `42`.\n\n**Примечание:** Технически всё немного сложнее. В спецификации ES5, раздел 12.2 \"Инструкция переменной\", алгоритм `VariableDeclaration` действительно *возвращает* значение (`string`, содержащая имя объявленной переменной - странно, да!?), но это значение обычно поглощается (кроме цикла `for..in`) алгоритмом `VariableStatement`, который выдает пустое (известное как `undefined`) значение завершения.\n\nНа самом деле, если вы много экспериментировали с кодом в своей консоли (или в JS среде REPL -- read /evaluate /print / loop), вы, вероятно, видели сообщение `undefined` после множества разных инструкций и, возможно, никогда не понимали, что бы это было. Проще говоря, консоль просто сообщает значение завершения инструкции.\n\nНо то, что консоль выводит как значение завершения, - это не то, что мы можем использовать внутри нашей программы. Итак, как мы можем зафиксировать значение завершения?\n\nЭто гораздо более сложная задача. Прежде чем мы объясним *как*, давайте рассмотрим *почему* вам хотелось бы это сделать?\n\nНам нужно рассмотреть другие типы значений завершения инструкции. Например, любой обыденный блок `{ .. }` имеет значение завершения, равное значению завершения его последней инструкции/выражения.\n\nРассмотрим:\n\n```js\nvar b;\n\nif (true) {\n\tb = 4 + 38;\n}\n```\n\nЕсли бы вы ввели это в своей REPL-консоли, вы, вероятно, увидели бы сообщение `42`, поскольку `42` - это значение завершения блока `if`, который принял значение завершения своей последней инструкции выражения присваивания `b = 4 + 38`.\n\nДругими словами, значение завершения блока похоже на *неявный return* значения последней инструкции в блоке.\n\n**Примечание:** Это концептуально известно в таких языках, как CoffeeScript, которые имеют неявные `return` значения из `function`, которые совпадают со значением последней инструкции в функции.\n\nНо есть очевидная проблема. Такой код не работает:\n\n```js\nvar a, b;\n\na = if (true) {\n\tb = 4 + 38;\n};\n```\n\nМы не можем зафиксировать значение завершения инструкции и присвоить его другой переменной каким-либо простым синтаксическим/грамматическим способом (по крайней мере, пока!).\n\nИтак, что мы можем сделать?\n\n**Предупреждение**: только для демонстрационных целей -- пожалуйста, не делайте нижеприведенное в вашем реальном коде!\n\nМы можем использовать сильно оклеветанную функцию `eval(..)` (иногда произносится как \"evil\" - \"злой\"), чтобы зафиксировать это значение завершения.\n\n```js\nvar a, b;\n\na = eval( \"if (true) { b = 4 + 38; }\" );\n\na;\t// 42\n```\n\nДааааааааа. Это ужасно некрасиво. Но это работает! И это иллюстрирует тот факт, что значения завершения инструкции - это реальная вещь, которая может быть зафиксирована не только в нашей консоли, но и в наших программах.\n\nЕсть предложение для ES7 под названием \"выражение исполнения\" (do-выражение). Вот как это может сработать:\n\n```js\nvar a, b;\n\na = do {\n\tif (true) {\n\t\tb = 4 + 38;\n\t}\n};\n\na;\t// 42\n```\n\nВыражение `do { .. }` выполняет блок (с одним или несколькими операторами в нем), и значение завершения последней инструкции внутри блока становится значением завершения *`do`-выражения*, которое, как показано, затем может быть присвоено `a`.\n\nОбщая идея состоит в том, чтобы иметь возможность обрабатывать инструкции как выражения -- они могут отображаться внутри других инструкций -- без необходимости оборачивать их в функциональные выражения и делать явный `return ..`.\n\nНа данный момент значения завершения инструкций - это не больше, чем пустяки. Но они, возможно, будут приобретать все большее значение по мере развития JS, и, надеюсь, выражения `do { .. }` уменьшат соблазн использовать такие вещи, как `eval (..)`.\n\n**Предупреждение:** Повторяю мое предыдущее увещевание: избегайте `eval (..)`. Серьезно. За дополнительными деталями обращайтесь к книге этой же серии *Область Видимости и Замыкания*.\n\n### Побочные эффекты выражений\n\nБольшинство выражений не имеют побочных эффектов. Например:\n\n```js\nvar a = 2;\nvar b = a + 3;\n```\n\nВыражение `a + 3` не имело *собственного* побочного эффекта, как, например, изменение `a`. У него был результат, равный `5`, и этот итог был присвоен `b` в инструкции `b = a + 3`.\n\nНаиболее распространенным примером выражения с (возможными) побочными эффектами является выражение вызова функции:\n\n```js\nfunction foo() {\n\ta = a + 1;\n}\n\nvar a = 1;\nfoo();\t\t// результат: `undefined`, сторонний эффект: изменённое `a`\n```\n\nОднако есть и другие побочные эффекты выражений. Например:\n\n```js\nvar a = 42;\nvar b = a++;\n```\n\nВыражение `a++` выполняет два отдельных действия. *Сначала* оно возвращает текущее значение `a`, которое равно `42` (которое следом присваивается `b`). Но *затем* оно изменяет само значение `a`, увеличивая его на единицу.\n\n```js\nvar a = 42;\nvar b = a++;\n\na;\t// 43\nb;\t// 42\n```\n\nМногие разработчики ошибочно полагают, что `b` равно `43` так же, как и `a`. Неразбериха возникает из-за того, что не полностью учитывается, *когда* происходит побочный эффект оператора `++`.\n\nОператоры инкремента `++` и оператор декремента `--` являются унарными операторами (см. Главу 4), которые могут использоваться либо в постфиксной (\"после\") позиции, либо в префиксной (\"до\") позиции.\n\n```js\nvar a = 42;\n\na++;\t// 42\na;\t\t// 43\n\n++a;\t// 44\na;\t\t// 44\n```\n\nКогда `++` используется в префиксной позиции, как в `++a`, его побочный эффект (увеличение `a` на единицу) происходит *до* возврата значения из выражения, а не *после*, как в случае `a++`.\n\n**Примечание:** Считаете ли вы, что `++a++` - это корректный синтаксис? Если вы попробуете, то получите ошибку `ReferenceError`, но почему? Потому что операторы с побочным эффектом **требуют ссылки на переменную**, на которую нацелены их побочные эффекты. Для `++a++` сначала вычисляется часть `a++` (из-за приоритета оператора - см. ниже), которая возвращает значение `a` _до_ инкремента. Но затем он пытается вычислить `++42`, что (если вы попытаетесь это сделать) даст ту же ошибку `ReferenceError`, поскольку `++` не может иметь побочного эффекта непосредственно для значения `42`.\n\nИногда ошибочно полагают, что вы можете инкапсулировать побочный эффект *после* `a++`, заключив его в пару скобок `( )`, например:\n\n```js\nvar a = 42;\nvar b = (a++);\n\na;\t// 43\nb;\t// 42\n```\n\nК сожалению, `( )` сами по себе не определяют новое обёрнутое выражение, которое вычисляется следом *за побочным эффектом* выражения `a++`, как мы могли бы надеяться. Фактически, даже если бы это произошло, `a++` сначала возвращает `42`, и, если у вас нет другого выражения, которое повторно вычисляет `a` после побочного эффекта `++`, вы не получите `43` из этого выражения, поэтому `b` не будет присвоен `43`.\n\nОднако есть вариант: `,` - инструкция серии операторов запятой. Этот оператор позволяет вам объединить несколько автономных выражений в одну инструкцию:\n\n```js\nvar a = 42, b;\nb = ( a++, a );\n\na;\t// 43\nb;\t// 43\n```\n\n**Примечание:** Здесь требуется `( .. )` вокруг `a++, a`. Причина в приоритете операторов, о котором мы поговорим позже в этой главе.\n\nВыражение `a++, a` означает, что второе выражение инструкции `a` вычисляется следом *за побочным эффектом* первого выражения инструкции `a++`, что означает, что оно возвращает значение `43` для выполнения присваивания `b`.\n\nДругим примером оператора с побочным действием, является `delete`. Как мы показали в Главе 2, `delete` используется для удаления свойства из `object` или ячейки из `array`. Но обычно он просто вызывается как отдельный оператор:\n\n```js\nvar obj = {\n\ta: 42\n};\n\nobj.a;\t\t\t// 42\ndelete obj.a;\t// true\nobj.a;\t\t\t// undefined\n```\n\nРезультирующее значение оператора `delete` равно `true`, если запрошенная операция является допустимой, или `false` в противном случае. Но побочный эффект оператора заключается в том, что он удаляет свойство объекта (или ячейку массива).\n\n**Примечание:** Что мы подразумеваем под допустимым? Несуществующие свойства или свойства, которые существуют и конфигурируемы (см. Главу 3 из книги этой серии *This и Прототипы Объектов*), вернут `true` из оператора `delete`. В противном случае результат будет `false` или ошибка.\n\nПоследним примером оператора с побочным эффектом, который может быть одновременно и очевидным, и неочевидным, является оператор присваивания `=`.\n\nВзгляните:\n\n```js\nvar a;\n\na = 42;\t\t// 42\na;\t\t\t// 42\n```\n\nМожет показаться, что `=` в инструкции `a = 42` не является оператором с побочным действием. Но, если мы посмотрим на результирующее значение инструкции `a = 42`, то увидим - это только что присвоенное значение (`42`), поэтому присвоение в `a` значения по сути является побочным эффектом.\n\n**Совет:** Те же рассуждения о побочных эффектах применимы к составным операторам присваивания, таким как `+=`, `-=`, и т.д. Например, `a = b += 2` сначала обрабатывается как `b += 2` (то есть `b = b + 2`), а результат *этого* `=` затем присваивается `a`.\n\nТакое поведение, при котором выражение присваивания (или инструкция) завершается присвоенным значением, в первую очередь полезно для цепочек присвоений, таких как:\n\n```js\nvar a, b, c;\n\na = b = c = 42;\n```\n\nЗдесь `c = 42` вычисляется как `42` (с побочным эффектом присваивания `42` в `c`), затем `b = 42` вычисляется как `42` (с побочным эффектом присваивания `42` в `b`), и, наконец, вычисляется `a = 42` (с побочным эффектом присваивания `42` в `a`).\n\n**Предупреждение:** Распространенная ошибка, которую разработчики допускают при выполнении цепочки присваиваний выглядит так: `var a = b = 42`. Хотя это смотрится как одно и то же, но это не так. Если эта инструкция выполняется без наличия отдельной инструкции `var b` (где-то в области видимости), которая официально декларирует переменную `b`, то `var a = b = 42` не объявляет переменную `b` напрямую. В зависимости от `strict` режима это приведёт либо к ошибке, либо к случайной глобальной переменной (см. книгу этой серии *Область Видимости и Замыкания*).\n\nДругой пример для рассмотрения:\n\n```js\nfunction vowels(str) {\n\tvar matches;\n\n\tif (str) {\n\t\t// выбрать все гласные\n\t\tmatches = str.match( /[aeiou]/g );\n\n\t\tif (matches) {\n\t\t\treturn matches;\n\t\t}\n\t}\n}\n\nvowels( \"Hello World\" ); // [\"e\",\"o\",\"o\"]\n```\n\nЭто работает, и многие разработчики предпочитают именно такой вариант. Но мы можем упростить функцию, объединив два оператора `if` в один, если применим идиому, в которой побочный эффект присваивания будет работать на пользу:\n\n```js\nfunction vowels(str) {\n\tvar matches;\n\n\t// выбрать все гласные\n\tif (str && (matches = str.match( /[aeiou]/g ))) {\n\t\treturn matches;\n\t}\n}\n\nvowels( \"Hello World\" ); // [\"e\",\"o\",\"o\"]\n```\n\n**Примечание:** `( .. )` вокруг `matches = str.match..` обязательны. Причина - приоритет операторов, который мы рассмотрим позже в разделе \"Приоритет операторов\" этой главы.\n\nЯ предпочитаю этот более короткий стиль, так как он, по-моему, проясняет, что два условных выражения на самом деле связаны, а не разделены. Но, как и в случае с большинством стилистических вариантов в JS, это лишь мнение, какой вариант *лучше*.\n\n### Контекстуальные правила\n\nВ правилах грамматики JavaScript есть довольно много мест, где один и тот же синтаксис означает разные вещи в зависимости от того, где / как он используется. Такого рода вещи сами по себе могут вызвать немалую путаницу.\n\nЗдесь мы не перечислим исчерпывающе все подобные случаи, а просто назовем несколько самых распространенных.\n\n#### `{ .. }` Фигурные скобки\n\nЕсть два основных случая (их будет больше по мере развития JS!), когда в вашем коде появляется пара фигурных скобок `{ .. }`. Давайте взглянем на каждый из них.\n\n##### Объектные литералы\n\nВо-первых, как литерал `object`:\n\n```js\n// предположим, что определена функция `bar()`\n\nvar a = {\n\tfoo: bar()\n};\n```\n\nОткуда мы знаем, что это литерал `object`? Потому что пара `{ .. }` - это значение, которое присваивается `a`.\n\n**Примечание:** Эта ссылка `a` называется \"L-значение\" (значение левой стороны), поскольку она является целью присваивания. Пара `{ .. }` является \"R-значением\" (значение правой стороны), поскольку она используется *просто* как значение (в данном случае как источник присваивания).\n\n##### Метки\n\nЧто произойдет, если мы удалим `var a =` из приведенного выше фрагмента?\n\n```js\n// предположим, что определена функция `bar()`\n\n{\n\tfoo: bar()\n}\n```\n\nМногие разработчики предполагают, что пара `{ .. }` - это просто отдельный литерал `object`, который ничему не присваивается. Но на самом деле все совсем по-другому.\n\nЗдесь `{ .. }` - это просто обычный блок кода. В JavaScript не очень идиоматично (тем более в других языках!) иметь такой автономный блок `{ .. }`, но это вполне допустимая грамматика JS. Это может быть особенно полезно в сочетании с объявлениями переменных через `let` с областью видимости блока (см. книгу этой серии *Область Видимости и Замыкания*).\n\nБлок кода `{ .. }` здесь в значительной степени функционально идентичен блоку кода, сопутствующему некой инструкции, такой как циклы `for`/`while`, условного ветвления `if` и т.д.\n\nНо, если это обычный блок кода, тогда, что это за странный синтаксис `foo: bar()` и насколько это корректно?\n\nЭтот обескураживающе малоизвестный инструмент в JavaScript называется \"инструкцией с меткой\". Здесь `foo` - это метка для инструкции `bar()` (у которой опущена завершающая `;` - см. далее в этой главе \"Автоматические точки с запятой\"). Но в чем смысл инструкции с меткой?\n\nЕсли бы в JavaScript был оператор `goto`, вы теоретически могли бы написать `goto foo` и заставить перейти сюда, продолжить выполнять код с этого места. Обычно `goto` считаются ужасными идиомами программирования, поскольку они значительно затрудняют понимание кода (он же \"спагетти-код\"), поэтому *очень хорошо*, что в JavaScript нет привычного `goto`.\n\nОднако JS *действительно* поддерживает ограниченную, специальную форму `goto`: переходы по метке. Обе инструкции `continue` и `break` могут опционально принимать указанную метку, и в этом случае поток программы \"прыгает\" подобно `goto`. Рассмотрим:\n\n```js\n// `foo` labeled-loop\nfoo: for (var i=0; i<4; i++) {\n\tfor (var j=0; j<4; j++) {\n\t\t// всякий раз, когда встречается, продолжить внешний цикл\n\t\tif (j == i) {\n\t\t\t// перейти к следующей итерации\n\t\t\t// цикла, помеченного `foo`\n\t\t\tcontinue foo;\n\t\t}\n\n\t\t// пропускать нечетные числа\n\t\tif ((j * i) % 2 == 1) {\n\t\t\t// обычный (безметочный) `continue` внутреннего цикла\n\t\t\tcontinue;\n\t\t}\n\n\t\tconsole.log( i, j );\n\t}\n}\n// 1 0\n// 2 0\n// 2 1\n// 3 0\n// 3 2\n```\n\n**Примечание:** `continue foo` не означает \"перейти к позиции с меткой 'foo', чтобы продолжить\", а \"продолжить цикл с меткой \"foo\" со следующей итерации\". Итак, это *на самом деле* не произвольное `goto`.\n\nКак вы видите, мы пропустили итерацию с нечетным произведением `3 1`, а переход с меткой также пропустил итерации `1 1` и `2 2`.\n\nВозможно, немного более полезная форма перехода с меткой - это `break __` из внутреннего цикла, чтобы выбраться из внешнего цикла. Эту логику довольно громоздко реализовывать с помощью `break` без метки:\n\n```js\n// `foo` labeled-loop\nfoo: for (var i=0; i<4; i++) {\n\tfor (var j=0; j<4; j++) {\n\t\tif ((i * j) >= 3) {\n\t\t\tconsole.log( \"останавливаемся!\", i, j );\n\t\t\t// прервать цикл помеченный меткой `foo`\n\t\t\tbreak foo;\n\t\t}\n\n\t\tconsole.log( i, j );\n\t}\n}\n// 0 0\n// 0 1\n// 0 2\n// 0 3\n// 1 0\n// 1 1\n// 1 2\n// останавливаемся! 1 3\n```\n\n**Примечание:** `break foo` не означает \"перейти к позиции с меткой 'foo', чтобы продолжить\", а \"выйти из цикла/блока с надписью 'foo' и продолжить *после* него\". Не совсем `goto` в традиционном понимании, да?\n\nБезметочная альтернатива `break` вышеописанному, вероятно, потребовала бы задействовать одну или несколько функций, доступ к переменной из общей области видимости и т.д. Скорее всего, это было бы более запутанным, чем `break` с меткой, поэтому использование `break` с меткой здесь, вероятно, является лучшим вариантом.\n\nМетка может применяться к блоку без цикла, но только `break` может сослаться на такую метку. Вы можете сделать `break ___` из любого блока с меткой, но вы не можете использовать `continue ___` или использовать `break` без метки из блока.\n\n```js\nfunction foo() {\n\t// блок с меткой `bar`\n\tbar: {\n\t\tconsole.log( \"Привет\" );\n\t\tbreak bar;\n\t\tconsole.log( \"никогда не выводится\" );\n\t}\n\tconsole.log( \"Мир\" );\n}\n\nfoo();\n// Привет\n// Мир\n```\n\nЦиклы/блоки с метками крайне редки, и к ним часто относятся неодобрительно. Если это возможно, то лучше всего избегать их; например, используя вызовы функций вместо переходов из цикла. Но, возможно, есть редкие случаи, когда они могут быть полезны. Если вы собираетесь использовать переход по метке, обязательно задокументируйте то, что вы делаете, с подробными объяснениями!\n\nОчень распространено мнение, что JSON является корректным подмножеством JS, поэтому строка JSON (например, `{\"a\":42}` - обратите внимание на кавычки вокруг имени свойства, как того требует JSON!) считается допустимым кодом JavaScript. **Неправда!** Попробуйте ввести `{\"a\":42}` в вашу консоль JS, и вы получите сообщение об ошибке.\n\nИнструкция с меткой не может быть заключена в кавычки, поэтому `\"a\"` не является допустимой меткой, и, следовательно, `:` не может идти сразу после нее.\n\nИтак, JSON действительно является подмножеством синтаксиса JS, но JSON сам по себе не является допустимой грамматикой JS.\n\nОдно из чрезвычайно распространенных заблуждений из этой области заключается в том, что, если бы вы загрузили файл JS через тег `<script src = ..>`, в котором содержится только содержимое JSON (например, результат вызова API), данные были бы прочитаны как действительный JavaScript, но просто были бы недоступны для программы. Обычно заявляют, что JSON-P (практика оборачивания JSON данных в вызов функции, например, `foo({\"a\":42})`) решает проблему их недоступности, отправляя значение в одну из функций вашей программы.\n\n**Неправда!** Полностью допустимое значение JSON `{\"a\":42}` само по себе выдало бы ошибку JS, поскольку оно было бы интерпретировано как блок инструкций с недопустимой меткой. Но `foo({\"a\":42})` является допустимым JS, потому что в нем `{\"a\":42}` является литеральным значением `object`, передаваемым в `foo (..)`. Итак, правильно сказать, **JSON-P превращает JSON в допустимую JS грамматику**!\n\n##### Блоки\n\nДругая часто цитируемая JS нелепица (связанная с приведением - см. Главу 4) - это:\n\n```js\n[] + {}; // \"[object Object]\"\n{} + []; // 0\n```\n\nКазалось бы, это говорит, что оператор `+` дает разные результаты в зависимости от того, является ли первый операнд `[]` или `{}`. Но на самом деле это не имеет к оператору никакого отношения!\n\nВ первой строке `{}` появляется в выражении оператора `+` и поэтому интерпретируется как фактическое значение (пустой `object`). В главе 4 объясняется, что `[]` преобразуется в `\"\"` и, следовательно, `{}` также преобразуется в значение `string`: `\"[object Object]\"`.\n\nНо во второй строке `{}` интерпретируется как отдельный пустой блок `{}` (который ничего не делает). Блокам не нужны точки с запятой, так что отсутствие точки с запятой здесь не является проблемой. Наконец, `+ []` - это выражение, которое *явно приводит* `[]` в `number` (см. Главу 4), которое равно `0`.\n\n##### Деструктуризация объекта\n\nНачиная с ES6, есть еще одна ситуация, когда вы увидите пару `{ .. }`, - это \"деструктурирующее присваивание\" (за дополнительной информацией обратитесь к книге этой серии *ES6 и не только*), в частности, к деструктурированию `object`. Рассмотрим:\n\n```js\nfunction getData() {\n\t// ..\n\treturn {\n\t\ta: 42,\n\t\tb: \"foo\"\n\t};\n}\n\nvar { a, b } = getData();\n\nconsole.log( a, b ); // 42 \"foo\"\n```\n\nКак вы, наверное, можете сказать, `var { a , b } = ..` является формой деструктурирующего присваивания в ES6, что приблизительно эквивалентно:\n\n```js\nvar res = getData();\nvar a = res.a;\nvar b = res.b;\n```\n\n**Примечание:** в ES6 `{ a, b }` на самом деле является сокращенной формой деструктурирования `{ a: a, b: b }`, поэтому оба будут работать, но предполагается, что более краткая `{ a, b }` будет предпочтительным вариантом.\n\nДеструктурирование объекта с помощью пары `{ .. }` также может использоваться для именованных аргументов функции, что является сахаром для такого же рода неявного присваивания свойств объекта:\n\n```js\nfunction foo({ a, b, c }) {\n\t// нет необходимости в:\n\t// var a = obj.a, b = obj.b, c = obj.c\n\tconsole.log( a, b, c );\n}\n\nfoo( {\n\tc: [1,2,3],\n\ta: 42,\n\tb: \"foo\"\n} );\t// 42 \"foo\" [1, 2, 3]\n```\n\nИтак, контекст, в котором мы используем пару `{ .. }`, полностью определяет, что она означает. Это иллюстрирует разницу между синтаксисом и грамматикой. Очень важно понимать эти нюансы, чтобы избежать неожиданных интерпретаций JS движком.\n\n#### `else if` и необязательные блоки\n\nЭто распространенное заблуждение, что в JavaScript есть условие `else if`, потому что вы можете сделать так:\n\n```js\nif (a) {\n\t// ..\n}\nelse if (b) {\n\t// ..\n}\nelse {\n\t// ..\n}\n```\n\nНо здесь есть скрытая особенность грамматики JS: здесь нет `else if`. Но инструкциям `if` и `else` разрешается опускать `{ }` вокруг прикрепленного к ним блока, если они содержат только одну инструкцию. Несомненно, ранее вы видели это много раз:\n\n```js\nif (a) doSomething( a );\n```\n\nМногие руководства по JS стилю будут настаивать на том, чтобы вы всегда использовали `{ }` вокруг блока с единственной инструкцией, например:\n\n```js\nif (a) { doSomething( a ); }\n```\n\nОднако точно такое же грамматическое правило применяется к условию `else`, поэтому форма `else if`, которую вы, вероятно, всегда писали, *на самом деле* интерпретируется так:\n\n```js\nif (a) {\n\t// ..\n}\nelse {\n\tif (b) {\n\t\t// ..\n\t}\n\telse {\n\t\t// ..\n\t}\n}\n```\n\n`if (b) { .. } else { .. }` - это единственная инструкция, которая следует за `else`, поэтому вы можете либо вставить обрамляющие `{ }`, либо нет. Другими словами, когда вы используете `else if`, вы технически нарушаете общее правило из руководства по стилю и просто определяете свое `else` с помощью одного оператора `if`.\n\nКонечно, идиома `else if` чрезвычайно распространена и приводит к уменьшению отступа на один уровень, поэтому она так привлекательна. Какой бы способ вы ни выбрали, просто пишите явно в своем собственном руководстве по стилю/правилах и не предполагайте, что такие вещи, как `else if`, являются прямыми грамматическими правилами.\n\n## Приоритет оператора\n\nКак мы рассмотрели в Главе 4, `&&` и `||` в Javascript интересны тем, что они выбирают и возвращают один из своих операндов, а не просто приводят к `true` или `false`. Это легко анализировать, если есть только два операнда и один оператор.\n\n```js\nvar a = 42;\nvar b = \"foo\";\n\na && b;\t// \"foo\"\na || b;\t// 42\n```\n\nА, если задействованы два оператора и три операнда, что тогда?\n\n```js\nvar a = 42;\nvar b = \"foo\";\nvar c = [1,2,3];\n\na && b || c; // ???\na || b && c; // ???\n```\n\nЧтобы понять, какой результат этих выражений, нам нужно понять, какие правила регламентируют обработку операторов, когда их в выражении более одного.\n\nЭти правила называются \"приоритетом операторов\".\n\nБьюсь об заклад, большинство читателей считают, что они неплохо разбираются в приоритете операторов. Но, как и во всем остальном, что мы рассмотрели в этой серии книг, мы собираемся испытать это понимание на прочность, и, надеемся, узнать новое на этом пути.\n\nВспомним приведенный выше пример:\n\n```js\nvar a = 42, b;\nb = ( a++, a );\n\na;\t// 43\nb;\t// 43\n```\n\nА какой будет результат, если убрать `( )`?\n\n```js\nvar a = 42, b;\nb = a++, a;\n\na;\t// 43\nb;\t// 42\n```\n\nПогодите! Почему это изменило значение, присвоенное `b`?\n\nПотому что оператор `,` имеет более низкий приоритет, чем оператор `=`. Поэтому, `b = a++, a` интерпретируется как `(b = a++), a`. Поскольку (как мы выяснили ранее) `a++` имеет *пост-побочные эффекты*, `b` присвоено значение `42` до того, как `++` изменит `a`.\n\nЭто простейший пример необходимости понимать приоритет оператора. Если вы планируете использовать `,` в качестве инструкции серии операторов, то важно знать, что он имеет наименьший приоритет. Любой другой оператор будет использован раньше, чем `,`.\n\nТеперь вспомним другой рассмотренный ранее пример:\n\n```js\nif (str && (matches = str.match( /[aeiou]/g ))) {\n\t// ..\n}\n```\n\nМы говорили, что `( )` вокруг присваивания обязательны, но почему? Потому что `&&` имеет более высокий приоритет, чем `=`. Поэтому без принудительной группировки `( )` выражение интерпретировалось бы как `(str && matches) = str.match..`. И это инициировало бы ошибку, потому что результат `(str && matches)` будет не переменной, а значением (в данном случае `undefined`), и поэтому оно не может быть левой частью присваивания `=`!\n\nХорошо, итак, вы, вероятно, думаете, что эта проблема с приоритетом оператора у вас решена.\n\nТогда, давайте перейдем к более сложному примеру (который мы рассмотрим в следующих разделах этой главы), чтобы *действительно* проверить ваше понимание:\n\n```js\nvar a = 42;\nvar b = \"foo\";\nvar c = false;\n\nvar d = a && b || c ? c || b ? a : c && b : a;\n\nd;\t\t// ??\n```\n\nЛадно, я признаю, - это зло. Никто не стал бы писать подобную строку набора инструкций, верно? *Вероятно*, нет, но мы используем её для изучения различных проблем, связанных с объединением нескольких операторов в цепочку, что *является* очень распространенной задачей.\n\nРезультат выражения выше равен `42`. Но это не так интересно, как то, как мы нашли ответ, не запуская JS программу, дав ей его посчитать.\n\nДавайте копнём.\n\nПервый вопрос - который вам, возможно, даже не пришёл в голову - в том, ведет ли себя первая часть (`a && b || c`) как `(a && b) || c` или как `a && (b || c)`? Вы уверены? Можете ли вы хотя бы себя убедить, что они действительно разные?\n\n```js\n(false && true) || true;\t// true\nfalse && (true || true);\t// false\n```\n\nИтак, доказано, что они разные. И все же, как ведет себя `false && true || true`? Ответ:\n\n```js\nfalse && true || true;\t\t// true\n(false && true) || true;\t// true\n```\n\nТеперь у нас есть ответ. Оператор `&&` вычисляется первым, а оператор `||` вычисляется вторым.\n\nНо вызвано ли это обработкой слева направо? Давайте поменяем порядок операторов на обратный:\n\n```js\ntrue || false && false;\t\t// true\n\n(true || false) && false;\t// false -- нет\ntrue || (false && false);\t// true -- победитель!\n```\n\nТеперь мы доказали, что сначала вычисляется `&&`, а затем `||`, и в данном случае это шло явно в разрез с привычно ожидаемой обработкой слева направо.\n\nТак что же вызвало такое поведение? **Приоритет оператора**.\n\nКаждый язык определяет свой список приоритетов операторов. То, насколько уникален он, приводит в отчаяние, так как JS разработчикам приходится лезть в него и читать.\n\nЕсли бы вы хорошо его знали, то приведенные выше примеры ничуть не сбили бы вас с толку, потому что вы бы уже знали, что `&&` более приоритетен, чем `||`. Но, я уверен, изрядному числу читателей пришлось задуматься над этим.\n\n**Примечание:** К сожалению, в спецификации JS нет списка приоритетов операторов в одном удобном списке. Вы должны прошерстить и понять все правила грамматики. Поэтому мы постараемся описать здесь наиболее типичные и полезные ситуации в более удобной подаче. Полный список приоритетов операторов см. в разделе \"Приоритет операторов\" на сайте MDN *(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence)*.\n\n### Короткий цикл вычислений\n\nВ дополнительном примечании Главы 4 мы упоминали о \"коротком цикле вычислений\" (short circuiting) таких операторов, как `&&` и `||`. Давайте вернемся к нему более подробно.\n\nДля обоих операторов `&&` и `||` правый операнд **не будет вычислен**, если для определения результата операции достаточно левого операнда. Отсюда и название \"короткий цикл\" (в том смысле, что возможно досрочное завершение).\n\nНапример, в `a && b` значение `b` не вычисляется, если `a` ложное, потому что результат операнда `&&` уже понятен, и нет смысла беспокоиться о проверке `b`. Аналогично, с `a || b`, если `a` правдиво, результат операнда также понятен, и нет резона проверять `b`.\n\nЭтот короткий цикл бывает очень полезным и широко используется:\n\n```js\nfunction doSomething(opts) {\n\tif (opts && opts.cool) {\n\t\t// ..\n\t}\n}\n```\n\n`opts` в проверке `opts && opts.cool` действует как предохранитель, потому что, если `opts` не установлен (или не `object`), то `opts.cool` выдаст ошибку. При отрицательном результате проверки `opts` короткий цикл отменит проверку `opts.cool`, и никакой ошибки не возникнет!\n\nАналогично, вы можете использовать короткий цикл `||`:\n\n```js\nfunction doSomething(opts) {\n\tif (opts.cache || primeCache()) {\n\t\t// ..\n\t}\n}\n```\n\nЗдесь мы сначала проверяем наличие `opts.cache`, и если он есть, то не вызываем функцию `prime Cache()`, избегая таким образом потенциально лишней работы.\n\n### Более тесная связка\n\nНо давайте вновь обратим наше внимание на тот предыдущий пример инструкции с цепочкой операторов, в частности на тернарные операторы `? :`. Имеет ли оператор `? :` больший или меньший приоритет, чем `&&` и `||`?\n\n```js\na && b || c ? c || b ? a : c && b : a\n```\n\nИдентичен ли он этому:\n\n```js\na && b || (c ? c || (b ? a : c) && b : a)\n```\n\nили этому?\n\n```js\n(a && b || c) ? (c || b) ? a : (c && b) : a\n```\n\nПравильный ответ второй. Но почему?\n\nПотому что `&&` более приоритетный, чем `||`, а `||` более приоритетный, чем `? :`.\n\nПоэтому *первым* вычисляется выражение `(a && b || c)`, а затем `? :`, частью которого он является. Другой популярный вариант объяснения следующий: `&&` и `||` \"более тесно связаны\", чем `? :`. Если бы было верно обратное, то `c ? c...` было бы более тесно связано, и работал бы первый вариант - `a && b || (c ? c..)`.\n\n### Ассоциативность\n\nИтак, сначала группируются `&&` и `||`, затем оператор `? :`. Но как быть в ситуации нескольких операторов с одинаковым приоритетом? Обрабатываются ли они всегда слева направо или справа налево?\n\nОператоры обычно бывают либо левоассоциативными, либо правоассоциативными, в зависимости от этого **группировка выполняется слева или справа**.\n\nВажно отметить, что ассоциативность - это *не* то же самое, что обработка слева направо или справа налево.\n\nПочему же тогда так важно, выполняется ли обработка слева направо или справа налево? Потому что выражения могут иметь побочные эффекты, как, например, при вызове функций:\n\n```js\nvar a = foo() && bar();\n```\n\nЗдесь сначала вычисляется `foo()`, а затем в зависимости от результата `foo()`, возможно, `bar()`. Это безусловно могло бы сказаться на поведении программы, если бы `bar()` вызывался перед `foo()`.\n\nНо здесь обработка идет *просто* слева направо (поведение по умолчанию в JavaScript!) - здесь не важна ассоциативность `&&`. Поскольку в этом примере есть только одно `&&`, то, следовательно, здесь нет места группировке, ассоциативность даже не вступает в игру.\n\nОднако в выражении `a && b && c` группировка *будет* происходить неявно, что означает, что сначала будет вычислено либо `a && b`, либо `b && c`.\n\nТехнически `a && b && c` будет обрабатываться как `(a && b) && c`, потому что `&&` является левоассоциативным (как и `||`, кстати). Однако правоассоциативная альтернатива `a && (b && c)` ведет себя, очевидно, точно также. Для одних и тех же значений одни и те же выражения вычисляются в одном и том же порядке.\n\n**Примечание:** Гипотетически, если бы `&&` был правоассоциативным, он был бы обработан аналогично ручной группировке `a && (b && c)`. Но это все еще **не означает**, что `c` будет вычислен перед `b`. Правая ассоциативность **не означает** вычисления справа налево, это означает **группировку** справа налево. В любом случае, независимо от группировки / ассоциативности, строгий порядок вычисления будет `a`, затем `b`, затем `c` (то есть слева направо).\n\nПоэтому не так уж важно, что `&&` и `||` являются левоассоциативными, кроме как для точности обсуждаемых определений.\n\nНо это не всегда так. Некоторые операторы будут вести себя очень по-разному в зависимости от лево- и правоассоциативности.\n\nРассмотрим `? :` (\"тернарный\" или \"условный\") оператор:\n\n```js\na ? b : c ? d : e;\n```\n\n`? :` является правоассоциативным. Итак, какая группировка соответствует очерёдности выполнения?\n\n* `a ? b : (c ? d : e)`\n* `(a ? b : c) ? d : e`\n\nОтвет таков: `a ? b : (c ? d : e)`. В отличие от `&&` и `||` выше, правая ассоциативность здесь действительно имеет значение, поскольку `(a ? b : c) ? d : e` *будет* вести себя по-разному для некоторых (но не для всех!) комбинаций значений.\n\nОдин из таких примеров:\n\n```js\ntrue ? false : true ? true : true;\t\t// false\n\ntrue ? false : (true ? true : true);\t// false\n(true ? false : true) ? true : true;\t// true\n```\n\nЕще более тонкие различия скрываются в других комбинациях значений, даже если конечный результат тот же. Взглянем:\n\n```js\ntrue ? false : true ? true : false;\t\t// false\n\ntrue ? false : (true ? true : false);\t// false\n(true ? false : true) ? true : false;\t// false\n```\n\nВ этом случае одинаковые результаты сеют сомнения, какой вариант группировки действует. Однако:\n\n```js\nvar a = true, b = false, c = true, d = true, e = false;\n\na ? b : (c ? d : e); // false, вычисляются только `a` и `b`\n(a ? b : c) ? d : e; // false, вычисляются `a`, `b` и `e`\n```\n\nИтак, мы четко доказали, что `? :` является правоассоциативным, и что это действительно имеет значение в отношении того, как ведет себя оператор в цепочке с самим собой.\n\nДругим примером правой ассоциативности (группировки) является оператор `=`. Вспомните пример с цепочкой присваивания, рассмотренный выше в этой главе:\n\n```js\nvar a, b, c;\n\na = b = c = 42;\n```\n\nРанее мы сказали, что обработка `a = b = c = 42` ведётся, начиная с присваивания `c = 42`, затем `b = ..` и, наконец, `a = ..`. Почему? Из-за правой ассоциативности, которая на самом деле трактует инструкцию следующим образом: `a = (b = (c = 42))`.\n\nПомните наш первый пример присваивания сложного выражения в этой главе?\n\n```js\nvar a = 42;\nvar b = \"foo\";\nvar c = false;\n\nvar d = a && b || c ? c || b ? a : c && b : a;\n\nd;\t\t// 42\n```\n\nВооружившись нашими знаниями о приоритете и ассоциативности, мы теперь способны разбить код на группы, описывающие обработку этой инструкции:\n\n```js\n((a && b) || c) ? ((c || b) ? a : (c && b)) : a\n```\n\nИли с отступами, если это легче понять:\n\n```js\n(\n  (a && b)\n    ||\n  c\n)\n  ?\n(\n  (c || b)\n    ?\n  a\n    :\n  (c && b)\n)\n  :\na\n```\n\nДавайте решим это сейчас:\n\n1. `(a && b)` равно `\"foo\"`.\n2. `\"foo\" || c` равно `\"foo\"`.\n3. В первом `?` проверка `\"foo\"` правдивая.\n4. `(c || b)` равно `\"foo\"`.\n5. Во втором `?` проверка `\"foo\"` правдивая.\n6. `a` равно `42`.\n\nВот и все, мы закончили! Ответ - `42`, как и раньше. На самом деле это было не так уж трудно, не правда ли?\n\n### Избежание двусмысленностей\n\nТеперь вы гораздо лучше понимаете ассоциативность и приоритеты операторов, и чувствуете себя увереннее, понимая, как будет вести себя код с цепочкой операторов.\n\nНо остается важный вопрос: должны ли мы все писать код, понимая и исключительно полагаясь на все правила ассоциативности / приоритета операторов? Следует ли нам использовать ручную группировку `( )` лишь тогда, когда необходимо применить другой порядок обработки?\n\nИли, с другой стороны, принимая, что, хотя эти правила *на самом деле* поддаются изучению, но тут достаточно ловушек, чтобы не полагаться на автоматические приоритеты и ассоциативности? Если да, то должны ли мы тогда, всегда использовать ручную группировку `( )` и полностью отказаться от заложенного механизма поведения?\n\nЭта дискуссия в высшей степени субъективна и аналогична дискуссии в Главе 4 о *неявном* приведении. Большинство разработчиков исповедуют единый подход в обоих случаях: либо они принимают оба варианта поведения и код, ожидающий их, либо они отбрасывают оба варианта поведения и придерживаются ручных / явных идиом.\n\nКонечно, тут я не могу ответить читателю на вопрос более однозначно, чем в Главе 4. Но я показал вам плюсы и минусы и, надеюсь, помог достаточно глубоко понять тему, чтобы вы могли принять обоснованное, а не продиктованное ажиотажем решение.\n\nНа мой взгляд, есть важная золотая середина. Нам следует использовать *и* приоритет операторов/ассоциативность, *и* ручную группировку `( )` в нашем коде. Той же подход я предлагал в Главе 4, выступая за здоровое/безопасное использование *неявного* приведения, и против его повсеместного применения.\n\nНапример, `if (a && b && c) ..` для меня норма, и я не стал бы писать `if ((a && b) && c) ..`, чтобы явно задать ассоциативность, потому что я думаю, это излишне.\n\nС другой стороны, если бы мне нужно было связать два оператора `? :` вместе, я бы, конечно, использовал ручную группировку `( )`, чтобы было абсолютно ясно, какую логику я заложил здесь.\n\nТаким образом, мой совет здесь аналогичен совету из Главы 4: **используйте приоритет операторов/ассоциативность там, где это приводит к более короткому и чистому коду, но используйте ручную группировку `( )` там, где это вносит ясность и уменьшает путаницу**.\n\n## Автоматическая расстановка точки с запятой\n\nASI (автоматическая вставка точки с запятой) - это когда JavaScript подразумевает `;` в определенных местах вашей JS-программы, даже если вы её туда не ставили.\n\nЗачем ему это делать? Потому что, если вы опустите хотя бы одну обязательную `;`, ваша программа завершится сбоем. Не всегда всепрощающе. ASI позволяет JS быть терпимым к определенным местам, где обычно `;` не считается необходимой.\n\nВажно отметить, что ASI работает только при наличии новой строки (она же разрыв строки). Точки с запятой не вставляются в середину строки.\n\nПо существу, если JS-парсер анализирует строку, в которой произошла бы ошибка синтаксического анализа (ожидаемое отсутствие `;`), и он может разумно вставить ее, он это делает. Что разумно для вставки? Только если между концом какого-либо оператора и новой строкой/разрывом строки нет ничего, кроме пробелов и/или комментариев.\n\nРассмотрим:\n\n```js\nvar a = 42, b\nc;\n```\n\nДолжен ли JS рассматривать `c` в следующей строке как часть инструкции `var`? Это, конечно, так и было бы, если бы где-нибудь была `,` (даже в другой строке) между `b` и `c`. Но поскольку её нет, JS вместо этого предполагает, что после `b` есть подразумеваемая `;` (в новой строке). Таким образом, `c;` остается как отдельный оператор выражения.\n\nАналогично:\n\n```js\nvar a = 42, b = \"foo\";\n\na\nb\t// \"foo\"\n```\n\nЭто все еще допустимая программа без ошибок, потому что выражения также признают действие ASI.\n\nЕсть определенные места, где ASI полезен, например:\n\n```js\nvar a = 42;\n\ndo {\n\t// ..\n} while (a)\t// <-- ; ожидается здесь!\na;\n```\n\nГрамматика требует `;` после цикла `do..while`, но не после циклов `while` или `for`. Однако большинство разработчиков этого не помнит! Поэтому ASI услужливо вмешивается и вставляет её.\n\nКак мы говорили ранее в этой главе, блоки операторов не требуют завершающей `;`, поэтому в ASI нет необходимости:\n\n```js\nvar a = 42;\n\nwhile (a) {\n\t// ..\n} // <-- ; не ожидается здесь.\na;\n```\n\nДругой важный случай, когда ASI срабатывает, - это ключевые слова `break`, `continue`, `return` и (ES6) `yield`:\n\n```js\nfunction foo(a) {\n\tif (!a) return\n\ta *= 2;\n\t// ..\n}\n```\n\nОператор `return` не включает выражение следующей строки `a *= 2`, поскольку ASI предполагает завершающую `;` у оператора `return`. Конечно, операторы `return` *можно* легко разбивать на несколько строк, но только не тогда, когда после `return` ничего нет, кроме новой строки/разрыва строки.\n\n```js\nfunction foo(a) {\n\treturn (\n\t\ta * 2 + 3 / 12\n\t);\n}\n```\n\nАналогичные рассуждения применимы к `break`, `continue` и `yield`.\n\n### Исправление ошибок\n\nОдна из самых горячих *религиозных войн* JS-сообщества (помимо табуляции и пробелов) ведётся о том, следует ли сильно/исключительно полагаться на ASI или нет.\n\nБольшинство точек с запятой необязательны, но не все. Две `;` требуется в заголовок цикла `for ( .. ) ..`.\n\nНа стороне сторонников многие разработчики считают, что ASI - это полезный механизм, который позволяет им писать более лаконичный (и более \"красивый\") код, опуская все, кроме строго обязательных `;` (которых очень мало). Часто утверждается, что ASI делает многие `;` необязательными, поэтому правильно написанная программа *без них* ничем не отличается от правильно написанной программы *с ними*.\n\nИз стана противников многие разработчики говорят, что существует *слишком много* мест, способных стать источниками случайных ошибок, особенно для молодых, менее опытных разработчиков, где непреднамеренная, вставленная волшебным образом `;` меняет смысл. Аналогично, некоторые разработчики утверждают, что, если они опускают точку с запятой, это явная ошибка, и они хотят, чтобы их инструменты (линтеры и т.д.) обнаружили ее до того, как движок JS *исправит* ошибку под капотом.\n\nПозвольте мне просто поделиться своей точкой зрения. Строгое прочтение спецификации подразумевает, что ASI - это процедура \"исправления ошибок\". Что это за ошибка, спросите вы? В частности, ошибка **синтаксического анализатора**. Другими словами, в попытке уменьшить количество сбоев парсера ASI позволяет ему быть более терпимым.\n\nНо терпимый к чему? На мой взгляд, единственная причина возникновения ошибки **синтаксического анализа** - это если для анализа дана неправильная программа с ошибками. Таким образом, хотя ASI строго исправляет ошибки синтаксического анализатора, единственный способ получить такие ошибки - это ошибки автора программы - пропуск точек с запятой там, где этого требуют правила грамматики.\n\nИтак, честно говоря, когда я слышу, как кто-то утверждает, что они хотят опустить \"необязательные точки с запятой\", мой мозг переводит это утверждение в \"Я хочу написать максимально неправильную для синтаксического анализатора программу, которая все же будет работать\".\n\nЯ нахожу это нелепым, а аргументы в пользу сокращения нажатий клавиш и получения более \"красивого кода\" в лучшем случае слабыми.\n\nБолее того, я не согласен с тем, что это то же самое, что дебаты о пробелах и табуляциях - что это лишь вопрос оформления. Я считаю, это фундаментальный вопрос: написание кода, соответствующего требованиям грамматики, или код, который полагается на грамматические исключения, чтобы только-только пройти проверку.\n\nЕщё один взгляд на проблему в том, что полагаться на ASI - это, по сути, рассматривать новые строки как значимые \"пробелы\". Другие языки, такие как Python, имеют действительно значимые пробелы. Но уместно ли думать о JavaScript как о языке, имеющем значимые новые строки в том виде, в каком он существует сегодня?\n\nМое мнение: **используйте точки с запятой везде, где вы знаете, что они \"обязательны\", и по минимуму полагайтесь на ASI**.\n\nОднако не верьте мне на слово. Еще в 2012 году создатель JavaScript Брендан Эйх сказал (http://brendaneich.com/2012/04/the-infernal-semicolon /) следующее:\n\n> Мораль этой истории: ASI - это (формально говоря) процедура исправления синтаксических ошибок. Если вы начнете кодировать так, как если бы это было универсальное правило - значимых новый строк, то у вас будут проблемы.\n> ..\n> Жаль, что я не сделал новые строки более значимыми в JS в те десять дней мая 1995 года.\n> ..\n> Будьте осторожны, не используйте ASI так, как если бы у JS новые строки значимы.\n\n## Ошибки\n\nМало того, что JavaScript имеет различные *подтипы* ошибок (`TypeError`, `ReferenceError`, `SyntaxError` и т.д.), но грамматика также определяет перечень ошибок, которые должны быть вызваны во время компиляции, в дополнение ко всем другим ошибкам, которые происходят во время выполнения кода.\n\nВ частности, уже давно существует ряд специфических условий, которые следует отлавливать и сообщать о них как о \"ранних ошибках\" (во время компиляции). Любая прямая синтаксическая ошибка является ранней ошибкой (например, `a = ,`), но также грамматика определяет вещи, которые синтаксически допустимы, но, тем не менее, запрещены.\n\nПоскольку выполнение вашего кода еще не началось, эти ошибки не могут быть перехвачены с помощью `try..catch`; они просто ведут к сбою синтаксического анализа/компиляции вашей программы.\n\n**Совет:** В спецификации нет требования о том, как именно браузеры (и инструменты разработчика) должны сообщать об ошибках. Поэтому вы видите расхождения в сообщениях разных браузеров о подтипе ошибки или её описании.\n\nОдин простой пример - синтаксис внутри литерала регулярного выражения. Здесь нет ничего плохого в синтаксисе JS, но недопустимое регулярное выражение выдаст раннюю ошибку:\n\n```js\nvar a = /+foo/;\t\t// Ошибка!\n```\n\nЦелью присваивания должен быть идентификатор (или выражение деструктурирования ES6, которое создает один или несколько идентификаторов), поэтому значение `42` в этой позиции недопустимо и об этом сразу можно сообщить:\n\n```js\nvar a;\n42 = a;\t\t// Ошибка!\n```\n\n`strict` режим ES5 даёт еще больше ранних ошибок. Например, в `strict` режиме имена параметров функции не могут дублироваться:\n\n```js\nfunction foo(a,b,a) { }\t\t\t\t\t// всё хорошо\n\nfunction bar(a,b,a) { \"use strict\"; }\t// Ошибка!\n```\n\nДругая ранняя ошибка `strict` режима - это литерал объекта, имеющий несколько свойств с одинаковым именем:\n\n```js\n(function(){\n\t\"use strict\";\n\n\tvar a = {\n\t\tb: 42,\n\t\tb: 43\n\t};\t\t\t// Ошибка!\n})();\n```\n\n**Примечание:** С семантической точки зрения, такие ошибки технически не являются *синтаксическими*, а скорее *грамматическими* ошибками - приведенные выше фрагменты являются синтаксически допустимыми. Но поскольку типа `GrammarError` не существует, некоторые браузеры вместо этого используют `SyntaxError`.\n\n### Использование переменных слишком рано\n\nES6 определяет новую (откровенно сбивающую с толку) концепцию, называемую TDZ (\"Временная мертвая зона\").\n\nTDZ относится к местам в коде, где ещё нельзя использовать переменную, поскольку она ещё не была должным образом инициализирована.\n\nНаиболее наглядный пример этого -- использование `let` блоковой области действия в ES6:\n\n```js\n{\n\ta = 2;\t\t// ReferenceError!\n\tlet a;\n}\n```\n\nПрисвоение `a = 2` обращается к переменной `a` (которая ограничена областью действия блока `{ .. }`) до того, как она была объявлена `let a`, поэтому `a` находится в TDZ и появляется ошибка.\n\nИнтересно, что если для `typeof` сделано исключение, он безопасно работает с необъявленными переменными (см. Главу 1), для TDZ такого исключения безопасности не сделано:\n\n```js\n{\n\ttypeof a;\t// undefined\n\ttypeof b;\t// ReferenceError! (TDZ)\n\tlet b;\n}\n```\n\n## Аргументы фунции\n\nДругой пример ошибки TDZ можно увидеть в значениях по умолчанию ES6 для параметров функции (см. книгу этой серии *ES6 и не только*):\n\n```js\nvar b = 3;\n\nfunction foo( a = 42, b = a + b + 5 ) {\n\t// ..\n}\n```\n\nСсылка на `b` в присваивании параметра `b` будет в TDZ (ссылка на внешнюю `b` не будет действовать), поэтому она выдаст ошибку. Однако с `a` в присваивании всё в порядке, так как к этому моменту для параметра `a` TDZ уже закончилась.\n\nПри использовании значений по умолчанию параметров (ES6) это значение применяется, если вы либо опускаете аргумент, либо передаете `undefined`:\n\n```js\nfunction foo( a = 42, b = a + 1 ) {\n\tconsole.log( a, b );\n}\n\nfoo();\t\t\t\t\t// 42 43\nfoo( undefined );\t\t// 42 43\nfoo( 5 );\t\t\t\t// 5 6\nfoo( void 0, 7 );\t\t// 42 7\nfoo( null );\t\t\t// null 1\n```\n\n**Примечание:** `null` в выражении `a + 1` приводится к значению `0`. За дополнительной информацией обращайтесь к Главе 4.\n\nС точки зрения значений по умолчанию параметров (ES6), нет никакой разницы между пропуском аргумента и передачей значения `undefined`. Однако в отдельных случаях эту разницу можно обнаружить:\n\n```js\nfunction foo( a = 42, b = a + 1 ) {\n\tconsole.log(\n\t\targuments.length, a, b,\n\t\targuments[0], arguments[1]\n\t);\n}\n\nfoo();\t\t\t\t\t// 0 42 43 undefined undefined\nfoo( 10 );\t\t\t\t// 1 10 11 10 undefined\nfoo( 10, undefined );\t// 2 10 11 10 undefined\nfoo( 10, null );\t\t// 2 10 null 10 null\n```\n\nНесмотря на то, что параметры `a` и `b` используют значения по умолчанию, если для них не было передано никаких аргументов, массив `arguments` не будет содержать записей.\n\nИ наоборот, если вы передадите аргумент `undefined` явно, в массиве `arguments` будет запись для этого аргумента, она будет `undefined` и не обязательно будет совпадать со значением по умолчанию, которое было применено к данному именованному параметру.\n\nТакже как значения по умолчанию параметров могут расходиться с ячейками массива `arguments` и соответствующей именованной переменной в ES6, такое же расхождение может возникать сложными способами и в ES5:\n\n```js\nfunction foo(a) {\n\ta = 42;\n\tconsole.log( arguments[0] );\n}\n\nfoo( 2 );\t// 42 (связано)\nfoo();\t\t// undefined (не связано)\n```\n\nЕсли вы передаете аргумент, слот `arguments` и именованный параметр связаны, чтобы всегда иметь одно и то же значение. Если вы опустите аргумент, такая связь не возникнет.\n\nОднако в `strict` режиме такой связи нет в любом случае:\n\n```js\nfunction foo(a) {\n\t\"use strict\";\n\ta = 42;\n\tconsole.log( arguments[0] );\n}\n\nfoo( 2 );\t// 2 (не связано)\nfoo();\t\t// undefined (не связано)\n```\n\nОпределённо это плохая идея - когда-либо полагаться на любую такую привязку. На самом деле связка это хлипкая абстракция, которая показывает внутреннюю реализацию движка, а не правильно спроектированную возможность.\n\nИспользование массива `arguments` объявлено устаревшим (в пользу остаточных параметров ES6 `...` - см. книгу этой серии *ES6 и не только*), но это не значит, что всё это неправильно.\n\nДо ES6 `arguments` был единственным способом получить массив всех переданных аргументов для передачи другим функциям, что было весьма полезным. Вы также можете смешивать именованные параметры и массив `arguments` и оставаться в безопасности, если будете следовать одному простому правилу: **никогда не ссылайтесь на именованный параметр *и* соответствующий ему слот `arguments` одновременно**. Если вы избежите этой плохой практики, вы никогда не столкнётесь с потерей связи.\n\n```js\nfunction foo(a) {\n\tconsole.log( a + arguments[1] ); // безопасно!\n}\n\nfoo( 10, 32 );\t// 42\n```\n\n## `try..finally`\n\nВы, вероятно, знакомы с тем, как работает блок `try..catch`. Но задумывались ли вы когда-нибудь над `finally`, которое может быть вместе с ним? Действительно, знаете ли вы, что `try` требуется только `catch` или `finally`, хотя при необходимости могут присутствовать и то, и другое.\n\nКод в `finally` выполняется *всегда* (что бы ни случилось), и он всегда выполняется сразу после `try` (и `catch`, если присутствует), перед запуском любого другого кода. В каком-то смысле вы можете думать о коде в `finally` как о функции обратного вызова, которая всегда будет вызываться независимо от того, как ведет себя остальная часть блока.\n\nИтак, что произойдет, если внутри предложения `try` есть оператор `return`? Очевидно, что это вернет значение, верно? Но выполняется ли код, который получает это значение, до или после `finally`?\n\n```js\nfunction foo() {\n\ttry {\n\t\treturn 42;\n\t}\n\tfinally {\n\t\tconsole.log( \"Hello\" );\n\t}\n\n\tconsole.log( \"никогда не выполнится\" );\n}\n\nconsole.log( foo() );\n// Hello\n// 42\n```\n\n`return 42` выполняется сразу, устанавливая значение завершения вызова `foo()`. Это действие завершает `try`, поэтому следом немедленно выполняется `finally`. И только тогда завершается `foo()`, возвращая значение завершения, которое используется в инструкции `console.log(..)`.\n\nТочно такое же поведение верно для `throw` внутри `try`:\n\n```js\n function foo() {\n\ttry {\n\t\tthrow 42;\n\t}\n\tfinally {\n\t\tconsole.log( \"Hello\" );\n\t}\n\n\tconsole.log( \"никогда не выполнится\" );\n}\n\nconsole.log( foo() );\n// Hello\n// Uncaught Exception: 42\n```\n\nТеперь, если инициируется исключение (случайно или намеренно) внутри `finally`, оно переопределит завершение функции. Если вышестоящий `return` в блоке `try` установил значение завершения функции, то это значение будет отброшено.\n\n```js\nfunction foo() {\n\ttry {\n\t\treturn 42;\n\t}\n\tfinally {\n\t\tthrow \"Oops!\";\n\t}\n\n\tconsole.log( \"никогда не выполнится\" );\n}\n\nconsole.log( foo() );\n// Uncaught Exception: Oops!\n```\n\nНеудивительно, что другие операторы нелинейного управления, такие как `continue` и `break`, действуют аналогично `return` и `throw`:\n\n```js\nfor (var i=0; i<10; i++) {\n\ttry {\n\t\tcontinue;\n\t}\n\tfinally {\n\t\tconsole.log( i );\n\t}\n}\n// 0 1 2 3 4 5 6 7 8 9\n```\n\nИнструкция `console.log(i)` выполняется в конце итерации, который инициируется инструкцией `continue`. Однако она по-прежнему длится до оператора обновления итерации `i++`, поэтому печатаются значения `0..9` вместо `1..10`.\n\n**Примечание:** ES6 добавляет оператор `yield` в генераторах (см. книгу этой серии *Асинхронность и Производительность*), который в некотором смысле можно рассматривать как промежуточный оператор `return`. Однако, в отличие от `return`, `yield` не завершен до тех пор, пока генератор не будет возобновлен, что означает, что `try { .. yield .. }` не завершен. Таким образом, прикрепленное `finally` не будет выполняться сразу после `yield`, как это происходит с `return`.\n\n`return` внутри `finally` обладает специальной способностью переопределять предыдущий `return` из предложения `try` или `catch`, но только если `return` вызывается явно:\n\n```js\nfunction foo() {\n\ttry {\n\t\treturn 42;\n\t}\n\tfinally {\n\t\t// здесь нет `return ..`, поэтому нет переопределения\n\t}\n}\n\nfunction bar() {\n\ttry {\n\t\treturn 42;\n\t}\n\tfinally {\n\t\t// переопределяет вышестоящий `return 42`\n\t\treturn;\n\t}\n}\n\nfunction baz() {\n\ttry {\n\t\treturn 42;\n\t}\n\tfinally {\n\t\t// переопределяет вышестоящий `return 42`\n\t\treturn \"Hello\";\n\t}\n}\n\nfoo();\t// 42\nbar();\t// undefined\nbaz();\t// \"Hello\"\n```\n\nОбычно пропуск `return` в функции идентично `return;` или даже `return undefined;`, но пропуск `return` внутри блока `finally` не действует как переопределяющий `return undefined`; он просто оставляет в силе вышестоящий `return`.\n\nНа самом деле, мы действительно можем усилить безумие, если объединим `finally` с `break` (обсуждалось ранее в этой главе):\n\n```js\nfunction foo() {\n\tbar: {\n\t\ttry {\n\t\t\treturn 42;\n\t\t}\n\t\tfinally {\n\t\t\t// выйти из блока с меткой `bar`\n\t\t\tbreak bar;\n\t\t}\n\t}\n\n\tconsole.log( \"Crazy\" );\n\n\treturn \"Hello\";\n}\n\nconsole.log( foo() );\n// Crazy\n// Hello\n```\n\nНо... не делайте так. Серьезно. Используя `finally` + `break` с меткой, чтобы отменить `return`, вы делаете всё, чтобы создать максимально запутанный код. Я спорю, что никакое количество комментариев не сделает этот код понятнее.\n\n## `switch`\n\nДавайте кратко взглянем на оператор `switch`, своего рода синтаксическое сокращение цепочки операторов `if..else if..else..`.\n\n```js\nswitch (a) {\n\tcase 2:\n\t\t// выполнить что-нибудь\n\t\tbreak;\n\tcase 42:\n\t\t// выполнить что-то другое\n\t\tbreak;\n\tdefault:\n\t\t// здесь запасной вариант\n}\n```\n\nКак вы видите, `a` вычисляется один раз, а затем результирующее значение сопоставляется с каждым `case` (здесь выражения только простых значений). Если совпадение найдено, выполняется код в этом `case` и будет продолжаться либо пока не будет встречен `break`, либо пока не встретится конец блока `switch`.\n\nВозможно, вас это не сильно удивит, но в `switch` есть несколько особенностей, которые вы вероятно раньше не замечали.\n\nВо-первых, сравнение, которое происходит между `a` и каждым `case`, идентично алгоритму `===` (см. Главу 4). Часто `switch` используются с абсолютными значениями в операторах `case`, как показано выше, поэтому строгое равенство уместно.\n\nОднако вы можете захотеть разрешить равенство с приведением (оно же `==`, см. Главу 4), но для этого вам нужно немного \"взломать\" оператор `switch`:\n\n```js\nvar a = \"42\";\n\nswitch (true) {\n\tcase a == 10:\n\t\tconsole.log( \"10 или '10'\" );\n\t\tbreak;\n\tcase a == 42:\n\t\tconsole.log( \"42 или '42'\" );\n\t\tbreak;\n\tdefault:\n\t\t// никогда сюда не попадёте\n}\n// 42 или '42'\n```\n\nЭто работает, потому что `case` может содержать любое выражение (не только простые значения), что означает, что оно будет строго сравнивать результат выражения и тестовое значение (`true`). Поскольку `a == 42` здесь превращается в `true`, совпадение найдено.\n\nНесмотря на `==`, сам поиск в `switch` ведётся на строгое равенство, между `true` и `true`. Если выражение `case` приводит к чему-то правдивому, а не к строго `true` (см. Главу 4), то это не сработает. Это может ударить по вам, если, например, вы используете \"логический оператор\", такой как `||` или `&&` в вашем выражении:\n\n```js\nvar a = \"hello world\";\nvar b = 10;\n\nswitch (true) {\n\tcase (a || b == 10):\n\t\t// никогда сюда не попадём\n\t\tbreak;\n\tdefault:\n\t\tconsole.log( \"Oops\" );\n}\n// Oops\n```\n\nПоскольку результатом `(a || b == 10)` является `\"hello world\"`, а не `true`, строгое сравнение завершается неудачей. В данном случае решением проблемы было бы в том, чтобы заставить выражение стать явно `true` или `false`, например, `case !!(a || b == 10):` (см. Главу 4).\n\nНаконец, вариант `default` опционален, поэтому он и не обязан присутствовать (хотя это рекомендуемая практика). Даже к `default` применяются те же правила, что и при обнаружении `break` или его отсутствии:\n\n```js\nvar a = 10;\n\nswitch (a) {\n\tcase 1:\n\tcase 2:\n\t\t// никогда не окажемся здесь\n\tdefault:\n\t\tconsole.log( \"default\" );\n\tcase 3:\n\t\tconsole.log( \"3\" );\n\t\tbreak;\n\tcase 4:\n\t\tconsole.log( \"4\" );\n}\n// default\n// 3\n```\n\n**Примечание:** Как обсуждалось ранее о `break` с меткой, `break` внутри `case` также может быть с меткой.\n\nЭтот фрагмент работает так: сначала обходятся все `case` в поиске совпадения, и когда их не находит, возвращается к варианту `default` и выполняет его. Но, поскольку в нём нет `break`, он продолжает работу в ранее пропущенном `case 3` до того, как встретит `break`.\n\nХотя такого рода логика действительно возможна в JavaScript, нет почти никаких шансов, что это даст оправданный или понятный код. Будьте самокритичны, если поймаете себя на мысли воспользоваться такой завёрнутой логикой работы. И если вы всё же решитесь на это, не забудьте сопроводить код подробными комментариями, чтобы объяснить, что вы задумали!\n\n## Итоги\n\nГрамматика JavaScript имеет множество нюансов, на которые нам, разработчикам, следует потратить немного больше времени, уделяя им более пристальное внимание, чем мы обычно делаем. Лёгкое усилие имеет большое значение для укрепления наших знаний языка.\n\nИнструкции и выражения имеют аналоги в английском языке - инструкции похожи на предложения, а выражения - на фразы. Выражения могут быть ясными/самодостаточными, или они могут иметь побочные эффекты.\n\nГрамматика JavaScript накладывает правила семантического использования (они же контекст) поверх чистого синтаксиса. Например, пара `{ }`, используемая в различных местах вашей программы, может означать блоки инструкций, литералы `object`, (ES6) деструктурирующие присваивание или (ES6) именованные аргументы функции.\n\nВсе операторы JavaScript имеют четкие правила приоритета (какие из них выполняются первыми, а какие следом) и ассоциативности (как операторы неявно группируются, если их несколько). Изучив эти правила, вы сможете сами решить, *слишком ли неявен* приоритет/ассоциативность, чтобы пользоваться ими для написания более короткого и понятного кода.\n\nASI (Автоматическая вставка точки с запятой) - это механизм исправления ошибок синтаксического анализа, встроенный в движок JS, который позволяет ему в определенных обстоятельствах вставлять ожидаемую `;` в местах, где она требуется, но была опущена, *и*, где вставка исправляет ошибку синтаксического анализа. Ведутся споры о том, подразумевает ли этот механизм, что большинство `;` являются необязательными (и могут/должны быть опущены ради более чистого кода), или это означает, что их пропуск ведёт к ошибкам, которые движок JS просто исправляет за вас.\n\nВ JavaScript есть несколько типов ошибок, но менее известно, что в нём есть две категории: \"ранние\" ошибки (неперехватываемые ошибки компилятора) и ошибки \"выполнения\" (перехватываемые `try..catch`). Все синтаксические ошибки, очевидно, являются ранними, которые останавливают программу ещё до ее запуска, но есть и другие.\n\nАргументы функции имеют интересную взаимосвязь с их формально объявленными именованными параметрами. В частности, массив `arguments` имеет ряд ловушек, связанных утечкой внутренней реализации языка, если вы не будете осторожны. Избегайте `arguments`, если можете, но если вы должны его использовать, всеми способами избегайте одновременного использования ячейки `arguments` и его именованного параметра.\n\nБлок `finally`, прикрепленный к `try` (или `try ..catch`), предлагает несколько очень интересных особенностей с точки зрения очерёдности выполнения. Некоторые из них могут быть полезны, но могут принести и много путаницы особенно в сочетании с блоками с метками. Общее правило: используйте `finally`, чтобы сделать код лучше и понятнее, а не заумным или запутанным.\n\n`switch` предлагает приятную компактную замену для инструкций `if..else if..`, но остерегайтесь распространенных упрощенных предположений о его поведении. Тут есть причуды, которые могут сбить вас с толку, если вы не будете осторожны, но есть также несколько искусно скрытых трюков, которые у `switch` припасены в рукаве!\n"
  },
  {
    "path": "types & grammar/foreword.md",
    "content": "# Вы не знаете JS: Типы и грамматика\n# Предисловие\n\nКак было однажды сказано, \"JavaScript — это единственный язык, который разработчики не учат перед тем, как работать с ним.\"\n\nЯ смеюсь каждый раз, когда слышу эту цитату, потому что так было у меня, и, я подозреваю, у многих других разработчиков. JavaScript и, возможно, даже CSS и HTML не были основными языками компьютерных наук, преподававшимися в колледжах в первые дни Интернета, поэтому личное развитие было в значительной степени основано на поиске толкового разработчика и возможности посмотреть исходный код, чтобы собрать воедино эти основные веб-языки.\n\nЯ до сих пор помню свой первый проект веб-сайта из средней школы. Задача заключалась в создании любого интернет-магазина, и я, будучи поклонником Джеймса Бонда, решил создать магазин «Золотой глаз». В нём было всё: заглавная midi-песня из «Золотого глаза», играющая на фоне, мишень на JavaScript, двигающаяся за мышью по экрану и звук выстрела, который воспроизводился при каждом клике. Q гордился бы этим шедевром.\n\nЯ рассказываю эту историю, потому что я сделал тогда то, что делают многие разработчики сегодня: я скопировал и вставил куски JavaScript-кода в свой проект, не имея понятия, что там на самом деле происходит. Широкое использование JavaScript-инструментов, таких как jQuery, некоторым образом увековечило эту модель незнания основ JavaScript.\n\nЯ не пренебрегаю использованием JavaScript-инструментов; в конце концов, я являюсь членом команды MooTools! Но причина, по которой инструменты для JavaScript настолько сильны, в том, что их разработчики знают основы и их подводные камни и великолепно их применяют. Как бы ни были полезны эти инструменты, всё ещё невероятно важно знать основы языка, а с такими книгами, как серия *Вы не знаете JS* Кайла Симпсона, нет оправдания, чтобы не изучать их.\n\n*Типы и грамматика*, третий выпуск серии — это отличный взгляд на основы JavaScript, которым копипаст и сторонние библиотеки не учат и никогда не смогут вас научить. Приведение типов и его подводные камни, примитивы как конструкторы и весь диапазон основ JavaScript подробно объясняются детальными примерами кода. Как и в других книгах этой серии, Кайл объясняет чётко и по делу: никакой воды и пустословия — та самая категория технических книг, которую я люблю.\n\nНаслаждайтесь \"Типами и грамматикой\" и держите её поближе к вашему рабочему столу!\n\nДэвид Уолш<br>\n[http://davidwalsh.name](http://davidwalsh.name), [@davidwalshblog](http://twitter.com/davidwalshblog)<br>\nSenior Web Developer, Mozilla\n"
  },
  {
    "path": "types & grammar/toc.md",
    "content": "# Вы не знаете JS: Типы и грамматика\n\n## Содержание\n\n* Предисловие\n* Введение\n* Глава 1: Типы\n\t* Тип, как бы он ни назывался...\n\t* Встроенные типы\n\t* Значения как типы\n* Chapter 2: Values\n\t* Arrays\n\t* Strings\n\t* Numbers\n\t* Special Values\n\t* Value vs Reference\n* Chapter 3: Natives\n\t* Internal `[[Class]]`\n\t* Boxing Wrappers\n\t* Unboxing\n\t* Natives as Constructors\n* Chapter 4: Coercion\n\t* Converting Values\n\t* Abstract Value Operations\n\t* Explicit Coercion\n\t* Implicit Coercion\n\t* Loose Equals vs Strict Equals\n\t* Abstract Relational Comparison\n* Chapter 5: Grammar\n\t* Statements & Expressions\n\t* Operator Precedence\n\t* Automatic Semicolons\n\t* Errors\n\t* Function Arguments\n\t* `try..finally`\n\t* `switch`\n* Appendix A: Mixed Environment JavaScript\n* Appendix B: Acknowledgments\n\n"
  },
  {
    "path": "up & going/README.md",
    "content": "# Вы не знаете JS: Начните и Совершенствуйтесь\n\n<img src=\"cover.jpg\" width=\"300\">\n\n-----\n\n**[Купить цифровую или печатную книгу от издательства O'Reilly (англ.)](http://shop.oreilly.com/product/0636920039303.do)**\n\n-----\n\n[Оглавление](toc.md)\n\n* [Введение](foreword.md) (от [Jenn Lukas](http://jennlukas.com))\n* [Предисловие](../preface.md)\n* [Глава 1: Введение в программирование](ch1.md)\n* [Глава 2: Введение в JavaScript](ch2.md)\n* [Глава 3: Введение в \"Вы не знаете JavaScript\"](ch3.md)\n* [Приложение A: Благодарности!](apA.md)\n"
  },
  {
    "path": "up & going/apA.md",
    "content": "# Вы не знаете JS: Начните и Совершенствуйтесь\n# Приложение A: Благодарности!\n\nЕсть много людей, которых я хотел бы поблагодарить за помощь в том, что эта книга и вся серия появились.\n\nВо-первых, Я должен поблагодарить мою жену Кристен Симпсон (Christen Simpson) и двух моих детей: Итана (Ethan) и Эмили (Emily), за примирение с тем, что папа всегда \"зависал\" на компьютере. Даже когда не пишу книги, моя одержимость JavaScript приклеивает мои глаза к экрану гораздо больше, чем следует. То время,которое я одалживал у своей семьи — это и есть причина того, что эти книги могут столь глубоко полно разъяснить JavaScript вам, читатель. Я в долгу перед моей семьей во всем.\n\nЯ бы хотел поблагодарить моих редакторов в O'Reilly, а именно Симона Сэн-Лорана (Simon St.Laurent) и Брайана МакДональда (Brian MacDonald), так же как и остальную команду редакторов и специалистов по маркетингу. Работать с ними — одно удовольствие, в том числе и в том, что особенно шли навстречу во время этого эксперимента в написании, редактировании и выпуске \"open source\" книги.\n\nБлагодарю многих людей, кто участвовал в улучшении этой серии книг предоставляя редакторские советы и исправления, включая Shelley Powers, Tim Ferro, Evan Borden, Forrest L. Norvell, Jennifer Davis, Jesse Harlin, Kris Kowal, Rick Waldron, Jordan Harband, Benjamin Gruenbaum, Vyacheslav Egorov, David Nolen и многих других. Большое спасибо Jenn Lukas за написание предисловия для этой книги.\n\nСпасибо бессчетному количеству людей в сообществе, включая членов комитета TC39, которые поделились столькими знаниями со всеми нами и особенно спокойно относились к моим бесконечным вопросам и исследованиям с терпением и вниманием к деталям. John-David Dalton, Juriy \"kangax\" Zaytsev, Mathias Bynens, Axel Rauschmayer, Nicholas Zakas, Angus Croll, Reginald Braithwaite, Dave Herman, Brendan Eich, Allen Wirfs-Brock, Bradley Meck, Domenic Denicola, David Walsh, Tim Disney, Peter van der Zee, Andrea Giammarchi, Kit Cambridge, Eric Elliott и многие другие, я даже не могу перечислить всех.\n\nПоскольку серия книг \"Вы не знаете JS\" родилась на Kickstarter, я также хочу поблагодарить всех моих (почти) 500 щедрых спонсоров, без которых эта серия книг не появилась бы:\n\n> Jan Szpila, nokiko, Murali Krishnamoorthy, Ryan Joy, Craig Patchett, pdqtrader, Dale Fukami, ray hatfield, R0drigo Perez [Mx], Dan Petitt, Jack Franklin, Andrew Berry, Brian Grinstead, Rob Sutherland, Sergi Meseguer, Phillip Gourley, Mark Watson, Jeff Carouth, Alfredo Sumaran, Martin Sachse, Marcio Barrios, Dan, AimelyneM, Matt Sullivan, Delnatte Pierre-Antoine, Jake Smith, Eugen Tudorancea, Iris, David Trinh, simonstl, Ray Daly, Uros Gruber, Justin Myers, Shai Zonis, Mom & Dad, Devin Clark, Dennis Palmer, Brian Panahi Johnson, Josh Marshall, Marshall, Dennis Kerr, Matt Steele, Erik Slagter, Sacah, Justin Rainbow, Christian Nilsson, Delapouite, D.Pereira, Nicolas Hoizey, George V. Reilly, Dan Reeves, Bruno Laturner, Chad Jennings, Shane King, Jeremiah Lee Cohick, od3n, Stan Yamane, Marko Vucinic, Jim B, Stephen Collins, Ægir Þorsteinsson, Eric Pederson, Owain, Nathan Smith, Jeanetteurphy, Alexandre ELISÉ, Chris Peterson, Rik Watson, Luke Matthews, Justin Lowery, Morten Nielsen, Vernon Kesner, Chetan Shenoy, Paul Tregoing, Marc Grabanski, Dion Almaer, Andrew Sullivan, Keith Elsass, Tom Burke, Brian Ashenfelter, David Stuart, Karl Swedberg, Graeme, Brandon Hays, John Christopher, Gior, manoj reddy, Chad Smith, Jared Harbour, Minoru TODA, Chris Wigley, Daniel Mee, Mike, Handyface, Alex Jahraus, Carl Furrow, Rob Foulkrod, Max Shishkin, Leigh Penny Jr., Robert Ferguson, Mike van Hoenselaar, Hasse Schougaard, rajan venkataguru, Jeff Adams, Trae Robbins, Rolf Langenhuijzen, Jorge Antunes, Alex Koloskov, Hugh Greenish, Tim Jones, Jose Ochoa, Michael Brennan-White, Naga Harish Muvva, Barkóczi Dávid, Kitt Hodsden, Paul McGraw, Sascha Goldhofer, Andrew Metcalf, Markus Krogh, Michael Mathews, Matt Jared, Juanfran, Georgie Kirschner, Kenny Lee, Ted Zhang, Amit Pahwa, Inbal Sinai, Dan Raine, Schabse Laks, Michael Tervoort, Alexandre Abreu, Alan Joseph Williams, NicolasD, Cindy Wong, Reg Braithwaite, LocalPCGuy, Jon Friskics, Chris Merriman, John Pena, Jacob Katz, Sue Lockwood, Magnus Johansson, Jeremy Crapsey, Grzegorz Pawłowski, nico nuzzaci, Christine Wilks, Hans Bergren, charles montgomery, Ariel בר-לבב Fogel, Ivan Kolev, Daniel Campos, Hugh Wood, Christian Bradford, Frédéric Harper, Ionuţ Dan Popa, Jeff Trimble, Rupert Wood, Trey Carrico, Pancho Lopez, Joël kuijten, Tom A Marra, Jeff Jewiss, Jacob Rios, Paolo Di Stefano, Soledad Penades, Chris Gerber, Andrey Dolganov, Wil Moore III, Thomas Martineau, Kareem, Ben Thouret, Udi Nir, Morgan Laupies, jory carson-burson, Nathan L Smith, Eric Damon Walters, Derry Lozano-Hoyland, Geoffrey Wiseman, mkeehner, KatieK, Scott MacFarlane, Brian LaShomb, Adrien Mas, christopher ross, Ian Littman, Dan Atkinson, Elliot Jobe, Nick Dozier, Peter Wooley, John Hoover, dan, Martin A. Jackson, Héctor Fernando Hurtado, andy ennamorato, Paul Seltmann, Melissa Gore, Dave Pollard, Jack Smith, Philip Da Silva, Guy Israeli, @megalithic, Damian Crawford, Felix Gliesche, April Carter Grant, Heidi, jim tierney, Andrea Giammarchi, Nico Vignola, Don Jones, Chris Hartjes, Alex Howes, john gibbon, David J. Groom, BBox, Yu 'Dilys' Sun, Nate Steiner, Brandon Satrom, Brian Wyant, Wesley Hales, Ian Pouncey, Timothy Kevin Oxley, George Terezakis, sanjay raj, Jordan Harband, Marko McLion, Wolfgang Kaufmann, Pascal Peuckert, Dave Nugent, Markus Liebelt, Welling Guzman, Nick Cooley, Daniel Mesquita, Robert Syvarth, Chris Coyier, Rémy Bach, Adam Dougal, Alistair Duggin, David Loidolt, Ed Richer, Brian Chenault, GoldFire Studios, Carles Andrés, Carlos Cabo, Yuya Saito, roberto ricardo, Barnett Klane, Mike Moore, Kevin Marx, Justin Love, Joe Taylor, Paul Dijou, Michael Kohler, Rob Cassie, Mike Tierney, Cody Leroy Lindley, tofuji, Shimon Schwartz, Raymond, Luc De Brouwer, David Hayes, Rhys Brett-Bowen, Dmitry, Aziz Khoury, Dean, Scott Tolinski - Level Up, Clement Boirie, Djordje Lukic, Anton Kotenko, Rafael Corral, Philip Hurwitz, Jonathan Pidgeon, Jason Campbell, Joseph C., SwiftOne, Jan Hohner, Derick Bailey, getify, Daniel Cousineau, Chris Charlton, Eric Turner, David Turner, Joël Galeran, Dharma Vagabond, adam, Dirk van Bergen, dave ♥♫★ furf, Vedran Zakanj, Ryan McAllen, Natalie Patrice Tucker, Eric J. Bivona, Adam Spooner, Aaron Cavano, Kelly Packer, Eric J, Martin Drenovac, Emilis, Michael Pelikan, Scott F. Walter, Josh Freeman, Brandon Hudgeons, vijay chennupati, Bill Glennon, Robin R., Troy Forster, otaku_coder, Brad, Scott, Frederick Ostrander, Adam Brill, Seb Flippence, Michael Anderson, Jacob, Adam Randlett, Standard, Joshua Clanton, Sebastian Kouba, Chris Deck, SwordFire, Hannes Papenberg, Richard Woeber, hnzz, Rob Crowther, Jedidiah Broadbent, Sergey Chernyshev, Jay-Ar Jamon, Ben Combee, luciano bonachela, Mark Tomlinson, Kit Cambridge, Michael Melgares, Jacob Adams, Adrian Bruinhout, Bev Wieber, Scott Puleo, Thomas Herzog, April Leone, Daniel Mizieliński, Kees van Ginkel, Jon Abrams, Erwin Heiser, Avi Laviad, David newell, Jean-Francois Turcot, Niko Roberts, Erik Dana, Charles Neill, Aarson Holmes, Grzegorz Ziółkowski, Nathan Youngman, Timothy, Jacob Mather, Michael Allan, Mohit Seth, Ryan Ewing, Benjamin Van Treese, Marcelo Santos, Denis Wolf, Phil Keys, Chris Yung, Timo Tijhof, Martin Lekvall, Agendine, Greg Whitworth, Helen Humphrey, Dougal Campbell, Johannes Harth, Bruno Girin, Brian Hough, Darren Newton, Craig McPheat, Olivier Tille, Dennis Roethig, Mathias Bynens, Brendan Stromberger, sundeep, John Meyer, Ron Male, John F Croston III, gigante, Carl Bergenhem, B.J. May, Rebekah Tyler, Ted Foxberry, Jordan Reese, Terry Suitor, afeliz, Tom Kiefer, Darragh Duffy, Kevin Vanderbeken, Andy Pearson, Simon Mac Donald, Abid Din, Chris Joel, Tomas Theunissen, David Dick, Paul Grock, Brandon Wood, John Weis, dgrebb, Nick Jenkins, Chuck Lane, Johnny Megahan, marzsman, Tatu Tamminen, Geoffrey Knauth, Alexander Tarmolov, Jeremy Tymes, Chad Auld, Sean Parmelee, Rob Staenke, Dan Bender, Yannick derwa, Joshua Jones, Geert Plaisier, Tom LeZotte, Christen Simpson, Stefan Bruvik, Justin Falcone, Carlos Santana, Michael Weiss, Pablo Villoslada, Peter deHaan, Dimitris Iliopoulos, seyDoggy, Adam Jordens, Noah Kantrowitz, Amol M, Matthew Winnard, Dirk Ginader, Phinam Bui, David Rapson, Andrew Baxter, Florian Bougel, Michael George, Alban Escalier, Daniel Sellers, Sasha Rudan, John Green, Robert Kowalski, David I. Teixeira (@ditma, Charles Carpenter, Justin Yost, Sam S, Denis Ciccale, Kevin Sheurs, Yannick Croissant, Pau Fracés, Stephen McGowan, Shawn Searcy, Chris Ruppel, Kevin Lamping, Jessica Campbell, Christopher Schmitt, Sablons, Jonathan Reisdorf, Bunni Gek, Teddy Huff, Michael Mullany, Michael Fürstenberg, Carl Henderson, Rick Yoesting, Scott Nichols, Hernán Ciudad, Andrew Maier, Mike Stapp, Jesse Shawl, Sérgio Lopes, jsulak, Shawn Price, Joel Clermont, Chris Ridmann, Sean Timm, Jason Finch, Aiden Montgomery, Elijah Manor, Derek Gathright, Jesse Harlin, Dillon Curry, Courtney Myers, Diego Cadenas, Arne de Bree, João Paulo Dubas, James Taylor, Philipp Kraeutli, Mihai Păun, Sam Gharegozlou, joshjs, Matt Murchison, Eric Windham, Timo Behrmann, Andrew Hall, joshua price, Théophile Villard\n\nЭта серия книг выпускается в виде open source, включая редактирование и выпуск. У нас есть долг благодарности перед GitHub за предоставление такого рода возможности для сообщества!\n\nСнова спасибо всем бесчисленным людям, которых я не перечислил поименно, но кого я несмотря на это должен поблагодарить. Пусть эта серия книг будет \"принадлежать\" всем нам и помогать делать вклад в увеличивающиеся осведомленность и понимание языка JavaScript, к выигрышу всех настоящих и будущих участников сообщества, вносящих свой вклад.\n"
  },
  {
    "path": "up & going/ch1.md",
    "content": "# Вы не знаете JS: Начните и Совершенствуйтесь\n# Глава 1: Введение в программирование\n\nДобро пожаловать в серию книг *Вы не знаете JS* (*You don't know JS - YDKJS*).\n\nКнига *Начните и Совершенствуйтесь* является введением в некоторые базовые концепции программирования, конечно, с намеренным уклоном в JavaScript (часто сокращаемый до JS), также она о том, как подступиться к оставшимся книгам серии и понять их. Эта книга кратко описывает все необходимое, чтобы начать программировать, в том числе на JavaScript.\n\nКнига начинается с объяснения базовых принципов программирования на самом высоком уровне. Она в основном предназначена для тех из вас, кто начинает *YDKJS*, имея малый или не имея вовсе опыта в программировании, а также тех, кто рассчитывает, что эти книги помогут встать на путь понимания программирования сквозь призму JavaScript.\n\nГлаву 1 можно представить как быстрый обзор того, что вам следует изучить поподробнее и с чем попрактиковаться, дабы быстрее войти *в программирование*. Кроме того, есть много других фантастических ресурсов по основам программирования, которые помогут вам изучить во всех подробностях затрагиваемые темы, и я призываю вас изучить их в дополнение к этой главе.\n\nЕсли вы хорошо знаете общие основы программирования, глава 2 подтолкнет вас к более близкому знакомству с духом программирования на JavaScript. Глава 2 знакомит с тем, что такое JavaScript, но, обращаю ваше внимание еще раз: это не подробное руководство — за это выступают остальные книги *YDKJS*!\n\nЕсли вы уже довольно комфортно чувствуете себя с JavaScript, сначала ознакомьтесь с главой 3 для беглого знакомства с тем, чего ожидать от *YDKJS*, а затем приступайте!\n\n## Код\n\nНачнем с начала.\n\nПрограмма, часто упоминаемая как *исходный код* или просто *код* — это набор особых инструкций, сообщающих компьютеру, какие задачи нужно сделать. Обычно код сохраняют в текстовый файл, хотя в случае c JavaScript можно писать код прямо в консоли разработчика в браузере, чего мы кратко коснемся далее.\n\nПравила допустимого формата и комбинаций операторов, называемые *языком программирования*, иногда соотносят с его *синтаксисом*, аналогично  английскому языку, где правила говорят вам, как произносить слова и как составлять правильные предложения, используя слова и знаки препинания.\n\n### Операторы\n\nВ языке программирования группа слов, чисел и операций, которые выполняют определенную задачу, называются *оператором*. В JavaScript, оператор может выглядеть так:\n\n```js\na = b * 2;\n```\n\nСимволы `a` и `b` называются *переменными* (см. «Переменные»), которые примерно как обычные коробки, в которых вы можете хранить что угодно. В программах переменные хранят значения (например, число `42`), используемые программой. Представляйте их как символьную подмену для самих значений.\n\nВ противоположность им, `2` — это само значение, называемое *литеральным значением*, поскольку оно само по себе не хранится в переменной.\n\nСимволы `=` и `*` — это *операции* (см. «Операции»): они выполняют действия, такие как присваивание и математическое умножение, со значениями и переменными.\n\nБольшинство операторов в JavaScript заканчиваются точкой с запятой (`;`).\n\nОператор `a = b * 2;` сообщает компьютеру, грубо говоря, взять текущее значение из переменной `b`, умножить это значение на `2`, а затем сохранить результат в другую переменную, которую мы назвали `a`.\n\nПрограммы — это всего лишь набор стольких операторов, сколько необходимо для того, чтобы описать все шаги для достижения цели вашей программы.\n\n### Выражения\n\nОператоры состоят из одного или более *выражений*. Выражение — это любая ссылка на переменную или значение, или набор переменных и значений, объединенных операциями.\n\nНапример:\n\n```js\na = b * 2;\n```\n\nУ этого оператора 4 выражения:\n\n* `2` — это *выражение литерального значения*\n* `b` — это *выражение переменной*, которое тут означает извлечение его текущего значения\n* `b * 2` — это *арифметическое выражение*, в данном случае выполнение умножения\n* `a = b * 2` — это *выражение присваивания*, в данном случае это присвоить результат выражения `b * 2` переменной `a` (подробнее о выражениях далее)\n\nТипичное выражение, которое является законченным, называется *оператор-выражение*, например, такое как это:\n\n```js\nb * 2;\n```\n\nЭтот пример оператора-выражения не является типовым или полезным, и в целом не оказывает никакого эффекта на выполнение программы — он всего лишь извлекает значение `b` и умножает его на `2`, но затем ничего не делает с результатом.\n\nБолее распространенный оператор-выражение — это *оператор-выражение вызова*  (см. «Функции»), поскольку весь оператор — это выражение вызова функции:\n\n```js\nalert( a );\n```\n\n### Выполнение программы\n\nТак как же эти наборы программных операторов сообщают компьютеру, что нужно делать? Программу нужно *выполнить*, также говорят *запуск программы*.\n\nОператоры, подобные `a = b * 2`, понятны для разработчиков как при чтении, так и записи, но фактически в такой форме они не понятны напрямую компьютеру. Поэтому используется специальная утилита в компьютере (либо *интерпретатор*, либо *компилятор*) для перевода кода, который вы пишете, в команды, понятные компьютеру.\n\nВ некоторых языках программирования перевод команд обычно выполняется сверху вниз, строка за строкой, каждый раз когда программа запускается, что обычно называется *интерпретацией* кода.\n\nВ других языках перевод, выполняемый заранее, называется *компиляцией* кода, поэтому, когда позднее программа *запускается*, то что запускается — это по факту уже скомпилированные инструкции компьютера, готовые к выполнению.\n\nОбычно утверждают, что JavaScript — *интерпретируемый*, так как ваш исходный код на JavaScript обрабатывается каждый раз, когда запускается. Но это не совсем точно. Движок JavaScript на самом деле *компилирует* программу на лету и затем сразу же запускает скомпилированный код.\n\n**Примечание:** Подробнее о компиляции JavaScript смотрите в первых двух главах книги *Область видимости и замыкания* этой серии.\n\n## Попробуйте сами\n\nЭта глава проиллюстрирует каждое понятие из программирования простыми примерами кода, полностью написанными на JavaScript (очевидно!).\n\nНельзя не отметить, что пока вы продвигаетесь по этой главе, вам может понадобиться перечитать её несколько раз, и вам следует практиковаться в каждом из понятий, набирая код самостоятельно. Простейший способ сделать это - открыть консоль в средствах разработчика в ближайшем браузере (Firefox, Chrome, IE и т.п.).\n\n**Подсказка:** Обычно вы можете запустить консоль разработчика с помощью горячих клавиш или из меню. Подробнее о запуске и использовании консоли в вашем любимом браузере см. “Mastering The Developer Tools Console” (http://blog.teamtreehouse.com/mastering-developer-tools-console). Чтобы ввести несколько строк в консоли за раз, используйте `<shift> + <enter>`, чтобы переместиться на новую строку. Как только вы просто нажмете `<enter>`, консоль выполнит всё, что вы написали.\n\nДавайте познакомимся с процессом запуска кода в консоли. Сперва я предлагаю открыть пустую вкладку в браузере. Я предпочитаю делать это, набирая `about:blank` в адресной строке. Затем убедитесь, что ваша консоль разработчика, о которой мы только что упоминали, открылась.\n\nТеперь наберите этот код и посмотрите, как он выполняется:\n\n```js\na = 21;\n\nb = a * 2;\n\nconsole.log( b );\n```\n\nНабрав в консоли вышеуказанный код в браузере Chrome, мы увидим что-то вроде этого:\n\n<img src=\"fig1.png\" width=\"500\">\n\nВперед, попробуйте! Наилучший путь обучения программированию — это начать писать код!\n\n### Вывод\n\nВ предыдущем кусочке кода мы использовали`console.log(..)`. Давайте взглянем вкратце о чем же эта строка кода.\n\nВозможно вы это предполагали, но это и в самом деле то, как мы печатаем текст  (т.е. *вывод* для пользователя) в консоли разработчика. Есть две характеристики этого оператора, которые нам следует пояснить.\n\nПервая часть, `log( b )`, указывает на вызов функции (см. «Функции»). Здесь получается, что мы передаем переменную `b` в эту функцию, которая берет значение `b` и печатает его в консоли.\n\nВторая часть, `console.`, является ссылкой на объект, где расположена функция `log(..)`. Мы рассмотрим объекты и их свойства более детально в главе 2.\n\nЕще один путь вывести информацию — запустить оператор `alert(..)`. Например:\n\n```js\nalert( b );\n```\n\nЕсли вы запустите этот оператор, то заметите, что вместо вывода значения в консоль он показывает всплывающее окно с кнопкой «OK» и содержимым переменной `b`. Однако использование `console.log(..)` обычно лучше помогает кодировать и запускать программы в консоли, чем использование `alert(..)`, потому что вы можете вывести несколько значений за раз без остановки в интерфейсе браузера.\n\nВ этой книге мы будем использовать для вывода `console.log(..)`.\n\n### Ввод\n\nПока мы обсуждаем вывод, вы попутно могли задаться вопросом о *вводе* (т.е. о получении информации от пользователя).\n\nСамый распространенный путь — показать элементы формы на HTML-странице  (например, строки ввода) для пользователя, чтобы он мог вводить туда данные, а затем, используя JS, считать эти значения в переменные программы.\n\nНо есть более простой путь получать входные данные в целях обучения и демонстрации, который вы будете использовать на протяжении всей этой книги. Используйте функцию `prompt(..)`:\n\n```js\nage = prompt( \"Please tell me your age:\" );\n\nconsole.log( age );\n```\n\nКак вы уже могли догадаться, сообщение, которое вы передаете в  `prompt(..)`, в данном случае `\"Please tell me your age:\"` ('\"Пожалуйста сообщите мне свой возраст:\"'), выводится во всплывающем окне.\n\nЭто может выглядеть примерно так:\n\n<img src=\"fig2.png\" width=\"500\">\n\nКак только вы подтвердите ввод текста, щелкнув по «OK», вы заметите, что введенное значение теперь хранится в переменной `age`, которую мы затем  *выводим* с помощью `console.log(..)`:\n\n<img src=\"fig3.png\" width=\"500\">\n\nДля упрощения, пока мы изучаем основные понятия программирования, примеры в этой книге не потребуют ввода. Зато теперь вы увидели как пользоваться `prompt(..)`. Если вы хотите проверить себя, то можете попробовать использовать ввод в порядке экспериментов с примерами.\n\n## Операции\n\nОперации — это действия, которые мы выполняем над переменными и значениями. Мы уже видели две операции в JavaScript: `=` и `*`.\n\nОперация `*` выполняет математическое умножение. Достаточно просто, не так ли?\n\nОперация `=` используется для *присваивания* — сначала мы вычисляем значение с *правой стороны* (исходное значение) от `=`, а затем записываем его в переменную, которую мы указываем с *левой стороны* (переменная назначения).\n\n**Предупреждение:** Такой обратный порядок для присваивания может выглядеть немного странно. Вместо `a = 42` кто-то может предпочесть поменять порядок, чтобы исходное значение было слева, а переменная назначения — справа, например `42 -> a` (это неправильный JavaScript!). К сожалению, форма `a = 42` и похожие на нее практически полностью превалируют в современных языках программирования. Если вам такой порядок присваивания кажется неестественным, потратьте некоторое время на привыкание к нему.\n\nПример:\n\n```js\na = 2;\nb = a + 1;\n```\n\nТут мы присваиваем значение `2` переменной `a`. Затем мы получаем значение переменной `a` (пока еще `2`), прибавляем к нему `1` получая в результате `3`, потом сохраняем это значение в переменной `b`.\n\nХотя оно технически не является операцией, вам необходимо ключевое слово `var` в любой программе, поскольку это основной способ, с помощью которого вы *объявляете* (т.е. *создаете*) переменные (сокращение от *var*iables) (см. «Переменные»).\n\nВы всегда должны объявить переменную с именем до того, как начнете её использовать. Но вам достаточно объявить переменную всего раз для каждой *области видимости* (см. «Область видимости»), а затем пользоваться ею столько раз, сколько нужно. Например:\n\n```js\nvar a = 20;\n\na = a + 1;\na = a * 2;\n\nconsole.log( a );\t// 42\n```\n\nВот несколько самых базовых операций в JavaScript:\n\n* Присваивание: `=` как в `a = 2`.\n* Математические: `+` (сложение), `-` (вычитание), `*` (умножение) и `/` (деление), как в `a * 3`.\n* Составное присваивание: `+=`, `-=`, `*=` и `/=` — это составные операции, которые объединяют математическую операцию с присваиванием, как в `a += 2` (эквивалентно `a = a + 2`).\n* Инкремент/Декремент: `++` (инкремент), `--` (декремент), как в `a++` (эквивалентно `a = a + 1`).\n* Доступ к свойству объекта: `.` как в `console.log()`.\n\n   Объекты — это значения, которые хранят другие значения под своими именами, называемые свойства. `obj.a` означает значение из объекта  `obj` из его свойства `a`. Еще один способ доступа к свойствам — `obj[\"a\"]`. См. главу 2.\n* Равенство: `==` (нестрогое), `===` (строгое), `!=` (нестрогое неравенство), `!==` (строгое неравенство), как в `a == b`.\n\n   См. «Значения и типы» и главу 2.\n* Сравнение: `<` (меньше чем), `>` (больше чем), `<=` (меньше или нестрого равно), `>=` (больше или нестрого равно), как в `a <= b`.\n\n   См. «Значения и типы» и главу 2.\n* Логические: `&&` (и), `||` (или), как в `a || b`, которое выбирает или `a`, *или* (*or*) `b`.\n\n   Эти операции используются для создания составных условных конструкций (см. «Условные конструкции»), например: если либо `a` *либо (*or*)* `b` — истина.\n\n**Примечание:** Для более детального рассмотрения и охвата операций, не рассмотренных здесь, см. the Mozilla Developer Network (MDN)'s “Expressions and Operators“ (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators).\n\n## Значения и типы\n\nЕсли вы спросите сотрудника в магазине сотовой связи, сколько стоит определенный телефон, и он ответит: «девяносто девять, девяносто девять» (т.е. 99.99), таким образом он дает вам точную информацию о сумме денег, которую вам необходимо заплатить, чтобы купить телефон. Если вы хотите купить два таких телефона, вы легко сможете в уме удвоить стоимость, получив 199.98 в качестве общей стоимости.\n\nЕсли тот же сотрудник возьмет другой аналогичный телефон и скажет, что он «бесплатный» (конечно, в кавычках), он не скажет вам сумму, но взамен предоставит другую форму представления ожидаемой стоимости (0.00) — слово «бесплатный».\n\nЕсли затем вы спросите, включено ли в комплект поставки телефона зарядное устройство, то ответ может быть только «да» или «нет».\n\nВесьма схожим образом, когда вы указываете значения в программе, вы выбираете разные представления для этих значений в зависимости от того, что вы планируете делать с ними.\n\nЭти разнообразные представления для значений называются *типами* в терминологии программирования. В JavaScript есть встроенные типы для каждого из этих так называемых *примитивных* значений:\n\n* когда вам нужно работать с математикой, вам нужно `число`.\n* когда вам нужно вывести значение на экран, вам нужна `строка` (один или несколько символов, слов, предложений).\n* когда вам нужно принять решение в своей программе, вам нужно  `логическое значение` (`true` (`истина`) или `false` (`ложь`)).\n\nЗначения, непосредственно включаемые в исходный код, называются *литералами*. `строковые` литералы заключаются в двойные `\"...\"` или одинарные `'...'` кавычки — единственная разница в них — это ваши стилистические предпочтения. Литералы `числа` и `логического значения` пишутся как есть (т.е., `42`, `true` и т.д.).\n\nПример:\n\n```js\n\"Я - строка\";\n'Я - тоже строка';\n\n42;\n\ntrue;\nfalse;\n```\n\nКроме типов значений `строка`/`число`/`логическое значение` для языков программирования привычно предоставлять такие типы, как  *массивы*, *объекты*, *функции* и многое другое. Мы рассмотрим детально значения и типы на протяжении этой и следующей глав.\n\n### Преобразование между типами\n\nЕсли у вас есть `число` и вам нужно вывести его на экран, то необходимо преобразовать его значение в `строку`. В JavaScript такая конвертация называется «приведением типов (coercion)». Аналогично, если кто-то вводит серию цифр в форму на веб-странице, это `строка`, но если нужно потом использовать это значение для выполнения математических операций, то вам понадобится *приведение* его к `числу`.\n\nJavaScript предоставляет несколько различных возможностей принудительного приведения между *типами*. Например:\n\n```js\nvar a = \"42\";\nvar b = Number( a );\n\nconsole.log( a );\t// \"42\"\nconsole.log( b );\t// 42\n```\n\nИспользование `Number(..)` (встроенная функция), как было показано выше, это *явное* приведение из любого другого типа в тип `число`. Это выглядит достаточно очевидно.\n\nНо каверзный вопрос заключается в том, что произойдет, если вы попытаетесь сравнить два значения разных типов, которые могут потребовать *неявного* приведения.\n\nПри сравнении строки `\"99.99\"` с числом `99.99` многие согласятся, что они равны. Но они ведь не совсем одно и то же, не так ли? Это одно и то же значение в двух разных представлениях двух разных *типов*. Вы могли бы сказать, что они «нестрого равны», разве нет?\n\nЧтобы помочь вам в таких стандартных ситуациях, JavaScript иногда вмешивается и *неявно* приводит значения к подходящим типам.\n\nПоэтому если вы используете операцию нестрогого равенства `==` для сравнения `\"99.99\" == 99.99`, JavaScript преобразует с левой стороны `\"99.99\"` в его `числовой` эквивалент `99.99`. После этого сравнение превращается в `99.99 == 99.99`, которое, конечно, является `истинным`.\n\nНесмотря на то, что неявное приведение было задумано, чтобы помочь вам, оно может привести в замешательство, если вы не уделили достаточно времени изучению правил, которые определяют его поведение.  У большинства JS-разработчиков никогда его нет, поэтому общее отношение выражается в том, что неявное приведение сбивает с толку и вредит программам, внося непредвиденные ошибки, и поэтому следует его избегать. Иногда его даже называют изъяном дизайна языка.\n\nОднако, неявное приведение — это механизм, который *может* и, даже более того, *должен быть изучен* каждым, кто хочет серьезно заниматься программированием на JavaScript. Не только потому, что после изучения его правил оно не будет смущать вас, оно может в самом деле улучшить ваши программы! Усилия того стоят!\n\n**Примечание:** Для получения более подробной информации о приведении типов см. главу 2 этой книги и главу 4 книги *«Типы и синтаксис»* этой серии.\n\n## Комментарии в коде\n\nСотрудник салона сотовой связи может набросать некоторые заметки о возможностях только что выпущенных телефонов или о новых тарифных планах, которые предлагает его компания. Эти заметки только для самого сотрудника — они не предназначены для чтения покупателями. Тем не менее эти заметки помогают сотруднику улучшить свою работу, документируя все \"как\" и \"почему\" того, что ему следует рассказать покупателям.\n\nОдин из самых важных уроков, который вы можете освоить при изучении программирования - код не только для компьютера. Каждый бит кода также, если не больше, важен для программиста, как и для компилятора.\n\nВаш компьютер заботится только о машинном коде, последовательности бинарных 0 и 1, которые появляются после *компиляции*. Почти бесконечное количество программ можно написать таким образом, что они скомпилируются в одинаковую последовательность 0 и 1. Выбор, который вы делаете о том, как написать программу, имеет значение не только для вас, но и для других членов вашей команды и даже для будущего вас.\n\nНужно стремиться писать программы, не только правильно работающие, но и понятные при чтении. Вы можете пройти долгий путь в этом направлении, к примеру, выбирая понятные имена для своих переменных (см. «Переменные») и функций (см. «Функции»).\n\nНо еще одна важная часть этого процесса — это комментарии в коде. Это кусочки текста в вашей программе, которые вставляются именно для того, чтобы пояснить какие-то вещи для человека. Интерпретатор/компилятор всегда игнорирует эти комментарии.\n\nЕсть масса мнений о том, что делает код хорошо документируемым; тяжело определить на самом деле абсолютно универсальные правила. Но некоторые соображения и рекомендации будут весьма полезны:\n\n* Код без комментариев не оптимален.\n* Слишком много комментариев (по одному на каждую строку кода, например), возможно, является признаком плохо написанного кода.\n* Комментарии должны объяснять *почему*, а не *что*. Они могут дополнительно объяснять *как*, когда код особенно сложен.\n\nВ JavaScript есть два типа комментариев: однострочный и многострочный.\n\nПример:\n\n```js\n// Это - однострочный комментарий\n\n/* А это\n       многострочный\n             комментарий.\n                      */\n```\n\nОднострочный комментарий `//` подходит, если вы собираетесь разместить комментарий прямо над одиночным оператором или даже в конце строки. Всё что написано в строке после `//` интерпретируется как комментарий (и потому игнорируется компилятором) до самого конца строки. Нет никаких ограничений на то, что может находиться внутри однострочного комментария.\n\nПример:\n\n```js\nvar a = 42;\t\t// 42 - смысл жизни\n```\n\nМногострочный комментарий `/* .. */` подходит в случае, если у вас есть несколько строк пояснений для вашего кода.\n\nВот типичный пример использования многострочного комментария:\n\n```js\n/* Нижеприведенное значение используется, поскольку\n   выяснилось, что оно отвечает\n   на любой вопрос во вселенной. */\nvar a = 42;\n```\n\nОн может появляться в любом месте строки, даже в середине, поскольку есть `*/`, обозначающий его окончание. Например:\n\n```js\nvar a = /* произвольное значение */ 42;\n\nconsole.log( a );\t// 42\n```\n\nЕдинственное, что не может появляться в многострочном комментарии — это `*/`, так как это будет означать конец комментария.\n\nВам, несомненно, следует изучать программирование, параллельно вырабатывая привычку комментировать код. На всем протяжении оставшейся части этой главы вы увидите, что я использую комментарии для пояснения кода, поэтому и вы делайте также в вашей собственной практике написания кода. Поверьте, все, кто будут читать ваш код, скажут вам спасибо!\n\n## Переменные\n\nБольшинству программ нужно отслеживать то, как меняется то или иное значение на протяжении выполнения программы, проходя через различные операции, вызываемые для соответствующих задач вашей программы.\n\nСамый простой путь сделать это в программе — это присвоить значение символьному контейнеру, называемому *переменной*, называющейся так потому, что значение в этом контейнере может *меняться* с течением времени при необходимости.\n\nВ некоторых языках программирования вы определяете переменную (контейнер), чтобы хранить определенный тип значения, такой как `число` или `строка`. *Статическая типизация*, также известная как *контроль типов*, обычно упоминается как преимущество в корректности программы, предотвращая непредусмотренные преобразования значений.\n\nДля других языков больше важны типы для значений нежели переменных. *Слабая типизация*, также известная как *динамическая типизация*, позволяет переменной хранить значения любого типа в любое время. Это обычно упоминается как преимущество в гибкости программы, позволяющее одной переменной представлять значения разного типа в разные моменты выполнения программы.\n\nJavaScript использует второй подход, *динамическую типизацию*. Это означает, что переменные могут хранить значения любого *типа* без какого-либо контроля над ними.\n\nКак уже упоминалось ранее, мы объявляем переменную, используя оператор `var` -- заметьте, при этом нет никакой другой информации о *типе* в объявлении. Обратите внимание на эту простую программу:\n\n```js\nvar amount = 99.99;\n\namount = amount * 2;\n\nconsole.log( amount );\t\t// 199.98\n\n// преобразует `amount` в строку и\n// добавляет \"$\" в начало\namount = \"$\" + String( amount );\n\nconsole.log( amount );\t\t// \"$199.98\"\n```\n\nПеременная `amount` начинает свой жизненный цикл с хранения числа `99.99`, а затем хранит `числовой` результат `amount * 2`, который равен `199.98`.\n\nПервая команда `console.log(..)` должна *неявно* привести это `числовое` значение к `строке`, чтобы вывести его в консоль.\n\nЗатем оператор `amount = \"$\" + String(amount)` *явно* приводит значение `199.98` к `строке` и добавляет символ `\"$\"` в начало. С этого момента, `amount` хранит `строковое` значение `\"$199.98\"`, поэтому второму оператору `console.log(..)` не нужно выполнять никакого приведения, чтобы вывести его в консоль.\n\nРазработчики на JavaScript отметят гибкость использования переменной  `amount` для каждого из значений `99.99`, `199.98` и `\"$199.98\"`. Энтузиасты статической типизации предпочтут отдельную переменную, например `amountStr`, чтобы хранить окончательное представление значения `\"$199.98\"`, поскольку оно уже будет другого типа.\n\nВ любом случае, вы заметите, что `amount` хранит текущее значение, которое меняется по ходу выполнения программы, иллюстрируя первичную цель переменных: управление *состоянием* программы.\n\nДругими словами, *состояние* отслеживает изменения значений при выполнении программы.\n\nЕще одно распространенное использование переменных — централизация установки значений. Обычно это называется *константами*, когда вы объявляете переменную со значением и предполагаете, что это значение не будет меняться в течение работы программы.\n\nВы объявляете эти *константы* чаще всего в начале программы таким образом, чтобы иметь всего одно место для изменения значений при необходимости. По общепринятым соглашениям переменные в JavaScript, являющиеся константами, обычно пишутся большими буквами, с подчеркиваниями `_` между словами.\n\nВот глупый пример:\n\n```js\nvar TAX_RATE = 0.08;\t// 8% налог с продаж\n\nvar amount = 99.99;\n\namount = amount * 2;\n\namount = amount + (amount * TAX_RATE);\n\nconsole.log( amount );\t\t\t\t// 215.9784\nconsole.log( amount.toFixed( 2 ) );\t// \"215.98\"\n```\n\n**Примечание:** Также как в выражении `console.log(...)` функция `log(..)` доступна как свойство объекта `console`, в этом примере `toFixed(..)` — это функция, которая может быть доступна у `числовых` значений. `Число` в JavaScript не форматируется автоматически со знаком валюты — среда выполнения не знает ваших намерений, плюс к этому не существует типа для валюты. `toFixed(..)` позволяет нам указать, до скольких знаков после запятой мы хотим округлить `число`, и при необходимости возвращает `строку`.\n\nПеременная `TAX_RATE` является *константой* лишь по соглашению - в этой программе нет ничего, что могло бы предотвратить ее изменение. Но если ставка налога повысится до 9%, мы все еще можем легко обновить нашу программу, присвоив `TAX_RATE` значение равное `0.09` всего в одном месте, вместо поиска и изменения всех вхождений значения `0.08`,разбросанных по программе.\n\nНовейшая версия JavaScript на момент написания этих строк (обычно называемая \"ES6\") включает в себя новый способ объявления *констант*, использующий `const` вместо `var`:\n\n```js\n// согласно ES6:\nconst TAX_RATE = 0.08;\n\nvar amount = 99.99;\n\n// ..\n```\n\nКонстанты полезны также как и переменные с неизменяемыми значениями, за исключением того, что константы также предотвращают случайное изменение где-либо после начальной установки значения. Если вы попытаетесь присвоить любое значение в `TAX_RATE` после её объявления, ваша программа отвергнет это изменение (а в строгом (strict) режиме, прервется с ошибкой, см. \"Строгий режим\" в главе 2).\n\nКстати, такой тип «защиты» от ошибок похож на контроль типов статической типизации, так что вы в какой-то степени поймете, почему статические типы в других языках могут быть привлекательными!\n\n**Примечание:** Для получения более подробной информации о том, как различные значения в переменных могут использоваться в программах, см. книгу *Типы и синтаксис* этой серии.\n\n## Блоки\nКогда вы покупаете новый телефон, сотрудник салона сотовой связи должен пройти последовательность шагов для завершения оформления покупки.\n\nПримерно также в коде нам часто нужно сгруппировать последовательности операторов вместе, которые мы часто называем *блоками*. В JavaScript блок определяется обрамлением одного или более операторов парой фигурных скобок `{ .. }`. Пример:\n\n```js\nvar amount = 99.99;\n\n// отдельный блок\n{\n\tamount = amount * 2;\n\tconsole.log( amount );\t// 199.98\n}\n```\n\nТакой вид отдельного блока `{ .. }` вполне допустим, но не часто встречается в JS-программах. Обычно блоки присоединяются к другим управляющим операторам, таким как оператор `if` (см. «Условные конструкции») или цикл (см. «Циклы»). Например:\n\n```js\nvar amount = 99.99;\n\n// сумма достаточно велика?\nif (amount > 10) {\t\t\t// <-- блок прикрепляется к `if`\n\tamount = amount * 2;\n\tconsole.log( amount );\t// 199.98\n}\n```\n\nМы расскажем об операторе `if` в следующем разделе, но как вы видите блок `{ .. }` с двумя операторами присоединен к `if (amount > 10)`. Операторы внутри этого блока будут выполнены только при истинности выражения в условной конструкции.\n\n**Примечание:** В отличие от многих других операторов, таких как `console.log(amount);`, блоковый оператор не требует точки с запятой (`;`) в конце.\n\n## Условные конструкции\n\n«Хотите ли вы добавить дополнительную защитную пленку за $9.99 в вашу покупку?». Любезный сотрудник магазина попросил вас принять решение. И вам может сначала понадобиться проинспектировать текущее *состояние* вашего кошелька или банковского счета, чтобы ответить на этот вопрос. Но, очевидно, что это всего лишь простой вопрос из разряда «да или нет».\n\nЕсть несколько способов выражения *условных конструкций* (т.е. выбора) в наших программах.\n\nСамый распространенный из них — это оператор `if`. По сути, вы говорите, «*Если* (*if*) это условие истинно, сделать следующее...». Например:\n\n```js\nvar bank_balance = 302.13;\nvar amount = 99.99;\n\nif (amount < bank_balance) {\n\tconsole.log( \"Я хочу купить этот телефон\" );\n}\n```\n\nОператор `if` требует выражение между скобками `( )`, которое может быть интерпретировано либо как `истина` (`true`), либо как `ложь` (`false`). В этой программе мы написали выражение `amount < bank_balance`, которое конечно же будет вычислено как `true` или `false` в зависимости от значения переменной `bank_balance`.\n\nВы даже можете предоставить альтернативу программе, в случае если условие не будет истинным, описываемую оператором `else`. Пример:\n\n```js\nconst ACCESSORY_PRICE = 9.99;\n\nvar bank_balance = 302.13;\nvar amount = 99.99;\n\namount = amount * 2;\n\n// может ли мы позволить себе дополнительную покупку?\nif ( amount < bank_balance ) {\n\tconsole.log( \"Я возьму этот аксессуар!\" );\n\tamount = amount + ACCESSORY_PRICE;\n}\n// иначе:\nelse {\n\tconsole.log( \"Нет, спасибо.\" );\n}\n```\n\nЕсли `amount < bank_balance` - `истинно`, выведем `\"Я возьму этот аксессуар!\"` и добавим `9.99` в нашу переменную `amount`. В противном случае, оператор `else` говорит, что мы вежливо ответим `\"Нет, спасибо.\"` и оставим переменную `amount` без изменений.\n\nКак мы уже обсуждали ранее в главе «Значения и типы», значения, которые не совпадают с ожидаемым типом, часто приводятся к этому типу. Оператор `if` ожидает `логическое значение`, но если вы передадите что-либо отличное от `логического значения`, произойдет неявное приведение типов.\n\nJavaScript определяет список особых значений, которые считаются «как бы ложными», так как при приведении к `логическому значению` они примут значение `false`; такой список включает в себя `0` и `\"\"`. Любое другое значение, не входящее в список «как бы ложных», автоматически считается «как бы истинным»: при приведении к `логическому значению` оно становится равным `true`. Истинными, например, являются значения `99.99` и `\"free\"`. См. «Истинный и ложный» в главе 2 для получения более детальной информации.\n\n*Условные конструкции* существуют и в других формах, отличных от `if`. Например, оператор `switch` может использоваться в качестве сокращения для последовательности операторов `if..else` (см. главу 2). Циклы (см. «Циклы») используют *условную конструкцию*, чтобы определить завершать выполнение или нет.\n\n**Примечание:** Детальную информацию о приведениях типов, которые происходят неявно в проверочных выражениях *условных конструкций*, см. главу 4 книги *Типы и синтаксис* этой серии.\n\n## Циклы\n\nПри большой занятости магазина образуется очередь из покупателей, которым нужно поговорить с сотрудником магазина. Пока в этой очереди есть люди, сотруднику нужно продолжать обслуживать очередного покупателя.\n\nПовторение набора действий пока не нарушится определенное условие, или другими словами, повторение только пока соблюдается условие — это как раз работа для циклов. Циклы могут принимать различные формы, но все они удовлетворяют этому базовому поведению.\n\nЦикл включает в себя проверяемое условие и блок (обычно в виде `{ .. }`). Процесс каждого выполнения блока в цикле называется *итерацией*.\n\nНапример, цикл `while` и цикл `do..while` иллюстрируют принцип повторения блока выражений до тех пор, пока условие не перестанет быть равным `true`:\n\n```js\nwhile (numOfCustomers > 0) {\n\tconsole.log( \"Чем я могу вам помочь?\" );\n\n\t// помощь покупателю...\n\n\tnumOfCustomers = numOfCustomers - 1;\n}\n\n// против:\n\ndo {\n\tconsole.log( \"Чем я могу вам помочь?\" );\n\n\t// помощь покупателю...\n\n\tnumOfCustomers = numOfCustomers - 1;\n} while (numOfCustomers > 0);\n```\n\nЕдинственной разницей между этими циклами является проверка условия до первой итерации (`while`) или после первой итерации (`do..while`).\n\nЕсли в любом из этих циклов условная конструкция возвратит `false`, то следующая итерация не будет выполнена. Это означает, что, если условие изначально будет `false`, цикл `while` никогда не будет выполнен, а цикл `do..while` выполнится только один раз.\n\nИногда вы используете цикл для подсчета определенного набора чисел, например, от `0` до `9` (десять чисел). Это можно сделать присвоением переменной итерации, например, `i` значения `0`, а затем увеличением ее на `1` в каждой итерации.\n\n**Предупреждение:** По множеству исторических причин языки программирования почти всегда ведут подсчет, начиная с `0` вместо `1`. Если вы не знакомы с таким типом подсчета, поначалу это может сбивать с толку. Уделите некоторое время тому, чтобы попрактиковаться в подсчете, начинающимся с `0`, чтобы освоиться в нем!\n\nУсловная конструкция проверяется на каждой итерации, как если бы был неявный оператор `if` внутри цикла.\n\nДля выхода из цикла можно использовать оператор `break`. К тому же, можно обнаружить, что ужасно легко можно создать цикл, который без механизма  `break` будет работать вечно.\n\nПроиллюстрируем:\n\n```js\nvar i = 0;\n\n// цикл `while..true` будет выполняться вечно, не так ли?\nwhile (true) {\n\t// прервать цикл?\n\tif ((i <= 9) === false) {\n\t\tbreak;\n\t}\n\n\tconsole.log( i );\n\ti = i + 1;\n}\n// 0 1 2 3 4 5 6 7 8 9\n```\n\n**Предупреждение:** Показанное выше не является практикой, которой вам необходимо придерживаться при реализации ваших циклов. Это представлено только в иллюстративных целях.\n\nЕсли `while` (или `do..while`) может достичь цели вручную, есть еще одна синтаксическая форма, называемая циклом `for`, подходящая именно для такой цели:\n\n```js\nfor (var i = 0; i <= 9; i = i + 1) {\n\tconsole.log( i );\n}\n// 0 1 2 3 4 5 6 7 8 9\n```\n\nКак видите, в обоих случаях условная конструкция `i <= 9` равна `true` для первых 10 итераций (`i` принимает значения от `0` до `9`) для любой из форм цикла, но становится равной `false`, как только переменная `i` становится равной `10`.\n\nУ цикла `for` есть три составных части: инициализация (`var i=0`), проверка условия (`i <= 9`) и обновление значения (`i = i + 1`). Поэтому, если вы собираетесь заниматься выполнением конкретного количества итераций, `for` будет более компактной и зачастую более легкой формой цикла для понимания и записи.\n\nЕсть и другие особые формы циклов, которые предназначены для итерирования по особым значениям, таким как свойства объекта (см. главу 2), где неявная проверка условной конструкции — это все ли свойства уже обработаны. Принцип «цикл работает пока не нарушится условие» соблюдается независимо от формы цикла.\n\n## Функции\n\nСотрудник магазина, возможно, не носит постоянно с собой калькулятор, чтобы учесть налоги и рассчитать окончательную стоимость покупки. Это задача, которую ему нужно определить один раз и использовать раз за разом. Преимущество в том, что у компании есть контрольно-кассовый аппарат (компьютер, планшет и т.п.), в который эти «функции» уже встроены.\n\nПохожим образом и в вашей программе вам определенно захочется разбить задачи в коде на повторно используемые части, вместо того, чтобы снова и снова однообразно повторять себя. Для реализации этого необходимо определить `функцию`.\n\nОбычно функция — это именованная секция кода, которая может быть «вызвана» по имени, и код внутри нее будет при этом запускаться при каждом вызове. Пример:\n\n```js\nfunction printAmount() {\n\tconsole.log( amount.toFixed( 2 ) );\n}\n\nvar amount = 99.99;\n\nprintAmount(); // \"99.99\"\n\namount = amount * 2;\n\nprintAmount(); // \"199.98\"\n```\n\nУ функций могут быть аргументы (т.е. параметры) — это значения, которые вы ей передаете. А также функции могут возвращать значение.\n\n```js\nfunction printAmount(amt) {\n\tconsole.log( amt.toFixed( 2 ) );\n}\n\nfunction formatAmount() {\n\treturn \"$\" + amount.toFixed( 2 );\n}\n\nvar amount = 99.99;\n\nprintAmount( amount * 2 );\t\t// \"199.98\"\n\namount = formatAmount();\nconsole.log( amount );\t\t\t// \"$99.99\"\n```\n\nФункция `printAmount(..)` принимает параметр, который мы назвали `amt`. Функция `formatAmount()` возвращает значение. Конечно, вы можете комбинировать параметры и возвращаемое значение в одной и той же функции.\n\nФункции часто используются для кода, который вы планируете вызывать несколько раз, но они также полезны для организации связанных частей кода в именованные наборы, даже если вы вызовете их всего лишь раз.\n\nПример:\n\n```js\nconst TAX_RATE = 0.08;\n\nfunction calculateFinalPurchaseAmount(amt) {\n\t// вычисляем новую сумму с налогом\n\tamt = amt + (amt * TAX_RATE);\n\n\t// возвращаем новую сумму\n\treturn amt;\n}\n\nvar amount = 99.99;\n\namount = calculateFinalPurchaseAmount( amount );\n\nconsole.log( amount.toFixed( 2 ) );\t\t// \"107.99\"\n```\n\nХотя `calculateFinalPurchaseAmount(..)` вызывается только один раз, выделение её поведения в отдельную именованную функцию делает код, использующий её логику (оператор `amount = calculateFinal...`), яснее. Если в функции есть несколько операторов, то её преимущества будут более очевидны.\n\n### Область видимости\n\nЕсли вы попросите у продавца модель телефона, которой у магазина нет в продаже, то он не сможет продать вам телефон, который вы хотите. У него есть доступ только к телефонам, которые есть в наличии в магазине. Вам нужно найти другой магазин, чтобы посмотреть, есть ли в нем нужный вам телефон.\n\nВ программировании есть термин для этого принципа: *область видимости* (технически называемая *лексическая область видимости*). В JavaScript каждая функция получает свою собственную область видимости. Областью видимости является коллекция переменных и правила доступа к этим переменным по имени. Только код внутри функции имеет доступ к переменным, *определенным в ее области видимости*.\n\nИмя переменной должно быть уникальным в рамках одной и той же области видимости: не может быть двух различных переменных `a`, расположенных рядом друг с другом. Но одно и тоже имя переменной `a` может появляться в разных областях видимости.\n\n```js\nfunction one() {\n\t// эта `a` принадлежит только функции `one()`\n\tvar a = 1;\n\tconsole.log( a );\n}\n\nfunction two() {\n\t// эта `a` принадлежит только функции `two()`\n\tvar a = 2;\n\tconsole.log( a );\n}\n\none();\t\t// 1\ntwo();\t\t// 2\n```\n\nТакже, область видимости может быть вложена внутрь другой области видимости, прямо как клоун на дне рождения надувает один шарик внутри другого. Если одна область вложена в другую, для кода внутри самой внутренней области доступны переменные из окружающей области.\n\nПример:\n\n```js\nfunction outer() {\n\tvar a = 1;\n\n\tfunction inner() {\n\t\tvar b = 2;\n\n\t\t// здесь у нас есть доступ и к `a`, и к `b`\n\t\tconsole.log( a + b );\t// 3\n\t}\n\n\tinner();\n\n\t// здесь у нас есть доступ только к  `a`\n\tconsole.log( a );\t\t\t// 1\n}\n\nouter();\n```\n\nПравила лексической области видимости говорят, что код в одной области может иметь доступ к переменным как её самой, так и к переменным любой области снаружи этой области.\n\nТаким образом, код внутри функции `inner()` имеет доступ к обеим переменным `a` и `b`, но у кода в `outer()` есть доступ только к `a` — у него нет доступа к `b`, потому что эта переменная внутри `inner()`.\n\nВспомните этот код, который появлялся выше:\n\n```js\nconst TAX_RATE = 0.08;\n\nfunction calculateFinalPurchaseAmount(amt) {\n\t// вычисляем новую сумму с налогом\n\tamt = amt + (amt * TAX_RATE);\n\n\t// возвращаем новую сумму\n\treturn amt;\n}\n```\n\nКонстанта (переменная) `TAX_RATE` доступна внутри функции `calculateFinalPurchaseAmount(..)`, даже несмотря на то, что мы не передавали её внутрь, из-за лексической области видимости.\n\n**Примечание:** Подробная информация о лексической области видимости есть в первых трех главах книги *Область видимости и замыкания* этой серии.\n\n## Практика\n\nНет абсолютно никакой равноценной замены практике при обучении программированию. Никакое, даже самое ясное, описание с моей стороны само по себе не сделает из вас программиста.\n\nДержа это в уме, давайте попробуем попрактиковаться в некоторых принципах, которые мы изучили в этой главе. Я дам вам «требования», а вы попробуете их реализовать. Затем сверьтесь с кодом, приведенным ниже, чтобы увидеть, как реализовал их я.\n\n* Напишите программу для вычисления общей стоимости покупки телефона. Вы будете продолжать покупать телефоны (подсказка: циклы!), пока у вас не закончатся деньги на банковском счете. Вы также будете покупать аксессуары для каждого из телефонов до тех пор, пока сумма покупки не превысит ваш мысленный предел трат.\n* После того, как вы посчитаете сумму покупки, прибавьте налог, затем выведите на экран вычисленную сумму покупки, правильно отформатировав её.\n* Наконец, сверьте сумму с балансом вашего банковского счета, чтобы понять можете вы себе это позволить или нет.\n* Вы должны настроить некоторые константы для «ставки налога», «цены телефона», «цены аксессуара» и «предела трат», также как и переменную для вашего «баланса банковского счета».\n* Вам следует определить функции для вычисления налога и для форматирования цены со знаком валюты и округлением до двух знаков после запятой.\n* **Бонусная задача:** Попробуйте включить ввод данных в вашу программу, например с помощью функции `prompt(..)`, рассмотренной ранее в разделе «Ввод». Вы можете, например, запросить у пользователя баланс банковского счета. Развлекайтесь и будьте изобретательны!\n\nХорошо, вперед. Попробуйте. Не подсматривайте в мой код, пока сами не попробуете!\n\n**Примечание:** Так как это книга о JavaScript, очевидно, что я буду решать практические упражнения на JavaScript. Но вы можете сделать это на другом языке, если чувствуете себя в нем более уверенно.\n\nВот мое решение для этого упражнения, написанное на JavaScript:\n\n```js\nconst SPENDING_THRESHOLD = 200;\nconst TAX_RATE = 0.08;\nconst PHONE_PRICE = 99.99;\nconst ACCESSORY_PRICE = 9.99;\n\nvar bank_balance = 303.91;\nvar amount = 0;\n\nfunction calculateTax(amount) {\n\treturn amount * TAX_RATE;\n}\n\nfunction formatAmount(amount) {\n\treturn \"$\" + amount.toFixed( 2 );\n}\n\n// продолжаем покупать телефоны пока у нас остаются деньги\nwhile (amount < bank_balance) {\n\t// покупаем новый телефон!\n\tamount = amount + PHONE_PRICE;\n\n\t// можем ли мы позволить себе аксессуар?\n\tif (amount < SPENDING_THRESHOLD) {\n\t\tamount = amount + ACCESSORY_PRICE;\n\t}\n}\n\n// не забудьте заплатить налог\namount = amount + calculateTax( amount );\n\nconsole.log(\n\t\"Ваша покупка: \" + formatAmount( amount )\n);\n// Ваша покупка: $334.76\n\n// можете ли вы в самом деле позволить себе эту покупку?\nif (amount > bank_balance) {\n\tconsole.log(\n\t\t\"Вы не можете позволить себе эту покупку. :(\"\n\t);\n}\n// Вы не можете позволить себе эту покупку. :(\n```\n\n**Примечание:** Простейший способ запустить эту JavaScript программу — набрать её в консоли разработчика в вашем браузере.\n\nКак ваши успехи? Не помешало бы попробовать еще раз после того, как вы увидели мой код. Также попробуйте поиграть с изменением констант, чтобы увидеть работу программы с разными значениями.\n\n## Резюме\n\nОбучение программированию не такой уж сложный и непреодолимый процесс. Есть всего несколько базовых принципов, которые вам нужно уложить у себя в голове.\n\nОни действуют подобно строительным блокам. Чтобы построить высокую башню, вы начинаете класть блок на блок, блок на блок. То же самое и в программировании. Вот несколько необходимых строительных блоков в программировании:\n\n* Вам нужны *операции* для выполнения действий над значениями.\n* Вам нужны значения и *типы* для выполнения различного рода действий, например, математических с `числом` или вывод со `строкой`.\n* Вам нужны *переменные* для хранения данных (т.е. *состояния*) в процессе выполнения программы.\n* Вам нужны *условные конструкции*, такие как оператор `if`, чтобы делать выбор.\n* Вам нужны *циклы*, чтобы повторять действия, пока заданное условие не прекратит быть истинным.\n* Вам нужны *функции* для организации вашего кода в логические и повторно используемые части программы.\n\nКомментарии к коду — это весьма эффективный путь к написанию более читаемого кода; они сделают вашу программу понятнее, легче для разработки и поддержания в будущем.\n\nНаконец, не пренебрегайте мощью практики. Лучший способ научиться как писать код — это писать код.\n\nЯ рад, что вы теперь на верном пути к изучению написания кода! Так держать! Не забудьте ознакомиться с другими ресурсами по программированию для начинающих (книги, блоги, онлайн-тренировки и т.д.). Эта глава и эта книга являются хорошим стартом, но они — всего лишь краткое введение.\n\nСледующая глава рассмотрит многие принципы из этой главы, но с более специфичной для JavaScript перспективы. Она осветит многие основные темы, которые будут рассматриваться более детально на протяжении оставшихся книг серии.\n"
  },
  {
    "path": "up & going/ch2.md",
    "content": "# Вы не знаете JS: Начните и Совершенствуйтесь\n# Глава 2: Введение в JavaScript\n\nВ предыдущей главе я представил основные строительные блоки программирования, такие как переменные, циклы, условные операторы и функции. Конечно же, весь код, который был показан, был на JavaScript. Но в этой главе, мы хотим особенно сконцентрироваться на вещах, которые вам необходимо знать о JavaScript, чтобы усиленно изучать JS и стать JS-разработчиком.\n\nМы представим довольно много концепций в этой главе, которые не будут полностью рассмотрены до последующих книг *YDKJS*. Думайте об этой главе как об обзоре тем, раскрытых в деталях на протяжении остальных книг серии.\n\nОсобенно, если вы — новичок в JavaScript, то вам следует потратить достаточно времени на изучение концепций и примеров кода, представленных тут. Любой хороший фундамент закладывается кирпич за кирпичом, поэтому не ждите, что сразу же поймете все с первого раза.\n\nЗдесь начинается ваше путешествие к серьезному изучению JavaScript.\n\n**Примечание:** Как я упоминал в главе 1, вам определенно стоит попробовать весь этот код самим, пока вы читаете и работаете над этой главой. Имейте в виду, что здесь есть код, который предполагает возможности, представленные в последней на момент написания версии JavaScript (обычно упоминаемой как \"ES6\" из-за 6-ой версии ECMAScript — официального названия JS спецификации). Если вы вдруг используете более старый, пред-ES6 браузер, код может не заработать. Следует использовать последние версии современных браузеров (такие как Chrome, Firefox или IE).\n\n## Значения и типы\n\nКак мы условились в главе 1, в JavaScript типизированные значения, а не типизированные переменные. Доступны следующие встроенные типы:\n\n* `string` (строка)\n* `number` (число)\n* `boolean` (логическое значение)\n* `null` и `undefined` (пустое значение)\n* `object` (объект)\n* `symbol` (символ, новое в ES6)\n\nJavaScript предоставляет операцию `typeof`, которая оценивает значение и сообщает вам, какого оно типа:\n\n```js\nvar a;\ntypeof a;\t\t\t\t// \"undefined\"\n\na = \"hello world\";\ntypeof a;\t\t\t\t// \"string\"\n\na = 42;\ntypeof a;\t\t\t\t// \"number\"\n\na = true;\ntypeof a;\t\t\t\t// \"boolean\"\n\na = null;\ntypeof a;\t\t\t\t// \"object\" — черт, ошибка\n\na = undefined;\ntypeof a;\t\t\t\t// \"undefined\"\n\na = { b: \"c\" };\ntypeof a;\t\t\t\t// \"object\"\n\na = Symbol();\ntypeof a;                               // \"symbol\"\n```\n\nЗначение, возвращаемое операцией `typeof`, всегда одно из шести (семи в ES6! - тип \"symbol\") строковых значений. Это значит, что `typeof \"abc\"` вернет `\"string\"`, а не `string`.\n\nОбратите внимание, что в этом коде переменная `a` хранит значения каждого из типов, и несмотря на видимость, `typeof a` спрашивает не \"тип `a`\", а \"тип текущего значения в `a`.\" Только у значений есть типы в JavaScript, переменные являются всего лишь контейнерами для этих значений.\n\n`typeof null` — это интересный случай, так как он ошибочно возвращает `\"object\"`, тогда как вы ожидали бы, что он вернет `\"null\"`.\n\n**Предупреждение:** Это давний баг в JS, но, похоже, он никогда не будет исправлен. Слишком много кода в интернете полагается на него, и его исправление повлечет за собой намного больше ошибок!\n\nТакже обратите внимание на `a = undefined`. Мы явно установили `a` в значение `undefined`, и она по поведению не отличается от переменной, у которой еще не установлено значение, например, как тут `var a;`, в строке в начале блока кода. Переменная может получать такое состояние значения \"undefined\" разными способами, включая функции, которые не возвращают значения, или использованием операции `void`.\n\n### Объекты\n\nТип `object` указывает на составное значение, в котором вы можете устанавливать свойства (именованные области), хранящие свои собственные значения любого типа. Это, может быть, один из самых полезных типов значений во всем JavaScript.\n\n```js\nvar obj = {\n\ta: \"hello world\",\n\tb: 42,\n\tc: true\n};\n\nobj.a;\t\t// \"hello world\"\nobj.b;\t\t// 42\nobj.c;\t\t// true\n\nobj[\"a\"];\t// \"hello world\"\nobj[\"b\"];\t// 42\nobj[\"c\"];\t// true\n```\n\nПолезно представить значение этого `obj` визуально:\n\n<img src=\"fig4.png\">\n\nСвойства могут быть доступны либо через *точечную нотацию* (т.е. `obj.a`), либо через *скобочную нотацию* (т.е. `obj[\"a\"]`). Точечная нотация короче и в целом легче для чтения, и, следовательно, ей следует по возможности отдавать предпочтение.\n\nСкобочная нотация полезна, если у вас есть имя свойства, содержащее спецсимволы, например `obj[\"hello world!\"]` — такие свойства часто называют  *ключами*, когда к ним обращаются с помощью скобочной нотации. Нотация `[ ]` требует либо переменную (поясняется ниже), либо `строковый` *литерал* (который должен быть заключен в `\" .. \"` или `' .. '`).\n\nКонечно, скобочная нотация также полезна, если вы хотите получить доступ к свойству/ключу, но имя хранится в другой переменной, как в этом примере:\n\n```js\nvar obj = {\n\ta: \"hello world\",\n\tb: 42\n};\n\nvar c = \"a\";\n\nobj[c];\t\t\t// \"hello world\"\nobj[\"b\"];\t\t// 42\n```\n\n**Примечание:** Более детальная информация о JavaScript объектах есть в книге *this и прототипы объектов* этой серии, особенно в главе 3.\n\nЕсть пара других типов, с которыми вам предстоит взаимодействовать в JavaScript программах: *array* (массив) и *function* (функция). Точнее, вместо того, чтобы быть полноценными встроенными типами, о них следует думать скорее как о подтипах — особых версиях типа `object`.\n\n#### Массивы\n\nМассив — это `объект`, который хранит значения (любого типа) не в именованных свойствах/ключах, а в ячейках, доступных по числовому индексу. Например:\n\n```js\nvar arr = [\n\t\"hello world\",\n\t42,\n\ttrue\n];\n\narr[0];\t\t\t// \"hello world\"\narr[1];\t\t\t// 42\narr[2];\t\t\t// true\narr.length;\t\t// 3\n\ntypeof arr;\t\t// \"object\"\n```\n\n**Примечание:** Языки, которые начинают счет с нуля, как и JS, используют `0` в качестве индекса первого элемента массива.\n\nПолезно представить `arr` визуально:\n\n<img src=\"fig5.png\">\n\nПоскольку массивы — это особые объекты (как намекает `typeof`), то у них могут быть свойства, включая автообновляемое свойство `length` (длина).\n\nТеоретически, вы можете использовать массив как обычный объект со своими собственными именованными свойствами или использовать `object`, дав ему числовые свойства (`0`, `1` и т.д.) как у массива. Однако, в общем это было бы использованием соответствующих типов не по назначению.\n\nЛучшим и самым естественным подходом является использование массивов для значений, расположенных по числовым позициям, и использовать `object` для именованных свойств.\n\n#### Функции\n\nЕще один подтип `object`, которым вы будете пользоваться во всех ваших JS программах — это функция:\n\n```js\nfunction foo() {\n\treturn 42;\n}\n\nfoo.bar = \"hello world\";\n\ntypeof foo;\t\t\t// \"function\"\ntypeof foo();\t\t// \"number\"\ntypeof foo.bar;\t\t// \"string\"\n```\n\nЕще раз, функции — это подтипы `объектов`: `typeof` вернет `\"function\"`, что говорит о том, что `function` является основным типом, и поэтому у него могут быть свойства, но обычно вы в редких случаях будете пользоваться свойствами функций (к примеру, `foo.bar`).\n\n**Примечание:** Более детальная информация о значениях в JS и их типах есть в первых двух главах книги *Типы и синтаксис* этой серии.\n\n### Методы встроенных типов\n\nВстроенные типы и подтипы, которые мы только что обсудили, содержат логику, отраженную в достаточно мощныx и полезныx свойствах и методах.\n\nНапример:\n\n```js\nvar a = \"hello world\";\nvar b = 3.14159;\n\na.length;\t\t\t\t// 11\na.toUpperCase();\t\t// \"HELLO WORLD\"\nb.toFixed(4);\t\t\t// \"3.1416\"\n```\n\nВозможность вызова `a.toUpperCase()` более сложна и трудоемка, чем факт существования этого метода у значения.\n\nКоротко говоря, есть форма обертки объекта `String` (заглавная `S`), обычно называемая \"родной\" (или \"нативной\"), которая связывается с примитивным типом `string`; именно эта обертка определяет метод `toUpperCase()` в своем прототипе.\n\nКогда вы используете примитивное значение, такое как `\"hello world\"`, подобно объекту, ссылаясь на свойство или метод (к примеру, `a.toUpperCase()` в предыдущем кусочке кода), JS автоматически \"упаковывает\" значение в его обертку-двойника (скрытую внутри).\n\nЗначение типа `string` может быть обернуто объектом `String`, значение типа `number` может быть обернуто объектом `Number`, а `boolean` может быть обернуто объектом `Boolean`. В основном, вам не нужно беспокоиться о прямом использовании этих оберток значений — отдавайте предпочтение примитивным формам значений практически во всех случаях, а об остальном позаботится JavaScript.\n\n**Примечание:** Более детальная информация о родных типах в JS и \"упаковке\" есть в главе 3 книги *Типы и синтаксис* этой серии. Для лучшего понимания прототипов объектов см. главу 5 книги *this и прототипы объектов* этой серии.\n\n### Сравнение значений\n\nЕсть два основных типа сравнения значений, которые могут понадобиться вам в JS программах: *равенство* и *неравенство*. Результатом любого сравнения является только значение типа `boolean` (`true` или `false`), независимо от сравниваемых типов значений.\n\n#### Приведение типов (coercion)\n\nМы немного касались приведения типов в главе 1, давайте освежим информацию в памяти еще раз.\n\nПриведение в JavaScript существует в двух формах: *явное* и *неявное*. Явное приведение — это когда можно явным образом увидеть в коде конвертации из одного типа в другой, в свою очередь, неявное приведение — это когда конвертация происходит в результате менее очевидных побочных эффектов других операций.\n\nВозможно, вы слышали мнения по типу \"приведение типов - зло\", опирающиеся на факт того, что безусловно существуют места, где приведение может привести к удивительным результатам. Конечно, ничто так не расстраивает разработчиков как моменты, когда язык преподносит им сюрпризы.\n\nПриведение — не зло и не должно преподносить сюрпризов. На самом деле, большинство сценариев, которые вы можете построить, используя приведение типов, вполне адекватны и понятны, они даже могут использоваться с целью *увеличить* читаемость вашего кода. Но мы не будем далее вступать в дебаты — глава 4 книги *Типы и синтаксис* этой серии книг раскроет все стороны приведения.\n\nВот пример *явного* приведения:\n\n```js\nvar a = \"42\";\n\nvar b = Number( a );\n\na;\t\t\t\t// \"42\"\nb;\t\t\t\t// 42 — число!\n```\n\nА вот пример *неявного* приведения:\n\n```js\nvar a = \"42\";\n\nvar b = a * 1;\t// здесь \"42\" неявно приводится к 42\n\na;\t\t\t\t// \"42\"\nb;\t\t\t\t// 42 — число!\n```\n\n#### Как бы истинный и ложный\n\nВ главе 1, мы кратко рассмотрели \"как бы истинную\" и \"как бы ложную\" природу значений: когда не-`boolean` значение приводится к `boolean`, становится ли оно `true` или `false`, соответственно?\n\nОсобый список \"как бы ложных\" значений в JavaScript таков:\n\n* `\"\"` (пустая строка)\n* `0`, `-0`, `NaN` (некорректное `число`)\n* `null`, `undefined`\n* `false`\n\nЛюбое значение, не входящее в этот список — \"как бы истинно.\" Вот несколько примеров:\n\n* `\"hello\"`\n* `42`\n* `true`\n* `[ ]`, `[ 1, \"2\", 3 ]` (массивы)\n* `{ }`, `{ a: 42 }` (объекты)\n* `function foo() { .. }` (функции)\n\nВажно помнить, что не-`boolean` значение следует такому приведению \"истинный\"/\"ложный\", только если оно действительно приводится к `boolean`. Это не единственная трудность, которая может смутить вас в ситуации, когда кажется, что значение приводится к `boolean`, хотя на самом деле это не так.\n\n#### Равенство\n\nЕсть четыре операции равенства: `==`, `===`, `!=` и `!==`. Формы с `!` — конечно же, симметричные версии \"не равно\" своих  противоположностей; *не равно* не следует путать с *неравенством*.\n\nРазница между `==` и `===` — обычно состоит в том, что `==` проверяет на равенство значений, а `===` проверяет на равенство и значений, и типов. Однако, это не точно. Подходящий способ охарактеризовать их: `==` проверяет на равенство значений с использованием приведения, а `===` проверяет на равенство, не разрешая приведение. Операцию `===` часто по этой причине называют \"строгое равенство\".\n\nПосмотрите на пример неявного приведения, которое допускается нестрогим равенством `==` и не допускается строгим равенством `===`:\n\n```js\nvar a = \"42\";\nvar b = 42;\n\na == b;\t\t\t// true\na === b;\t\t// false\n```\n\nВ сравнении `a == b` JS замечает, что типы не совпадают, поэтому он делает упорядоченный ряд шагов, чтобы привести одно или оба значения к другим типам, пока типы не совпадут, а затем уже может быть проверено простое равенство значений.\n\nЕсли подумать, то есть два возможных пути, когда `a == b` может стать `true` через приведение. Либо сравнение может закончится на `42 == 42`, либо на `\"42\" == \"42\"`. Так какое же из них?\n\nОтвет: `\"42\"` становится `42`, чтобы сделать сравнение `42 == 42`. В таком простом примере не так уж важно по какому пути пойдет сравнение, в конце результат будет один и тот же. Есть более сложные случаи, где важно не только каков конечный результат сравнения, но и *как* вы к нему пришли.\n\nСравнение `a === b` выдает `false`, так как приведение не разрешено, поэтому простое сравнение значений, очевидно, не завершится успехом. Многие разработчики чувствуют, что операция `===` — более предсказуема, поэтому они советуют всегда использовать эту форму и держаться подальше от `==`. Мне кажется, такая точка зрения очень недальновидна. Я верю, что операция `==` — мощный инструмент, который поможет вашей программе, *если вы уделите время на изучение того, как это работает.*\n\nМы не собираемся рассматривать все скучные мельчайшие подробности того, как работает приведение в сравнениях `==`. Многие из них очень разумные, но есть несколько важных тупиковых ситуаций, с которыми надо быть осторожнее. Чтобы посмотреть точные правила, загляните в раздел 11.9.3 спецификации ES5 (http://www.ecma-international.org/ecma-262/5.1/): вы будете удивлены тем, насколько этот механизм прямолинейный, по сравнению со всей этой негативной шумихой вокруг него.\n\nЧтобы свести целое множество деталей к нескольким простым выводам и помочь вам узнать, использовать `==` или `===` в различных ситуациях, вот мои простые правила:\n\n* Если одно из значений (т.е. сторона) в сравнении может быть значением `true` или `false`, избегайте `==` и используйте `===`.\n* Если одно из значений в сравнении может быть одним из этих особых значений (`0`, `\"\"` или `[]` — пустой массив), избегайте `==` и используйте `===`.\n* Во *всех* остальных случаях вы можете безопасно использовать `==`. Это не только безопасно, но во многих случаях это упрощает ваш код путем повышения читаемости.\n\nЭти правила сводятся к тому, что требуют от вас критически оценивать свой код и думать о том, какого вида значения могут исходить из переменных, проверяемых на равенство. Если вы уверены насчет значений, и сравнение `==` — безопасно, то используйте его! Если вы не уверены насчет значений, используйте `===`. Это просто.\n\nФорма не-равно `!=` идет в паре с `==`, а форма `!==` — в паре с `===`. Все правила и утверждения, которые мы только что обсудили также применимы для этих сравнений на не равно.\n\nВам следует обратить особое внимание на правила сравнения `==` и `===`, когда вы сравниваете два непримитивных значения, таких как `object` (включая `function` и `array`). Так как эти значения на самом деле хранятся по ссылке, оба сравнения `==` и `===` просто проверяет равны ли ссылки, но ничего не сделают касаемо самих значений.\n\nНапример, `массив` по умолчанию приводится к `строке` простым присоединением всех значений с запятыми (`,`) между ними. Можно было бы подумать, что эти два `массива` с одинаковым содержимым будут равны по `==`, но это не так:\n\n```js\nvar a = [1,2,3];\nvar b = [1,2,3];\nvar c = \"1,2,3\";\n\na == c;\t\t// true\nb == c;\t\t// true\na == b;\t\t// false\n```\n\n**Примечание:** Детальную информацию о правилах сравнения равенства `==` можно посмотреть в спецификации ES5 (раздел 11.9.3) а также свериться с главой 4 книги *Типы и синтаксис* этой серии; см. главу 2 для детальной информации о значениях в сравнении с ссылками.\n\n#### Неравенство\n\nОперации `<`, `>`, `<=` и `>=`, использующиеся для неравенств, упоминаются в спецификации как \"относительное сравнение.\" Обычно они используются со значениями, сравниваемыми порядками, как `числа`. Легко понять, что `3 < 4`.\n\nНо `строковые` значения в JavaScript тоже могут участвовать в неравенствах, используя типичные алфавитные правила (`\"bar\" < \"foo\"`).\n\nКак насчет приведения типов? Тут всё похоже на правила в сравнении `==` (хотя и не совсем идентично!). Примечательно, что нет операций \"строгого неравенства\", которые запрещали бы приведение таким же путем как и \"строгое равенство\" `===`.\n\nПример:\n\n```js\nvar a = 41;\nvar b = \"42\";\nvar c = \"43\";\n\na < b;\t\t// true\nb < c;\t\t// true\n```\n\nЧто здесь происходит? В разделе 11.8.5 спецификации ES5 говорится, что, если оба значения в сравнении `<` являются `строками`, как это было в случае с `b < c`, то сравнение производится лексикографически (т.е. в алфавитном порядке, как в словаре), но если одно или оба значения не являются `строками`, как в случае с `a < b`, то оба значения приводятся к `числу`, и происходит типичное числовое сравнение.\n\nСамое большое затруднение, в которое вы можете попасть со сравнениями между потенциально разными типами значений (помните, что нет формы \"строгого неравенства\"?) — это когда одно из значений не может быть превращено в корректное число, например:\n\n```js\nvar a = 42;\nvar b = \"foo\";\n\na < b;\t\t// false\na > b;\t\t// false\na == b;\t\t// false\n```\n\nПодождите-ка, как это все эти три сравнения могут быть `false`? Так как значение `b` приводится к \"некорректному числовому значению\" `NaN` в сравнениях `<` и `>`, а спецификация говорит, что `NaN` не больше и не меньше, чем любое другое значение.\n\nСравнение `==` не проходит по другой причине. `a == b` может быть некорректным, если оно интерпретируется как `42 == NaN` или `\"42\" == \"foo\"` — как мы объяснили ранее, первый вариант — наш случай.\n\n**Примечание:** Более детальная информация о правилах сравнения в неравенствах есть в разделе 11.8.5 спецификации ES5, также сверьтесь с главой 4 книги *Типы и синтаксис* этой серии.\n\n## Переменные\n\nВ JavaScript имена переменных (включая имена функций) должны быть корректными *идентификаторами*. Строгие и полные правила о корректных символах в идентификаторах —  немного сложны, когда вы хотите использовать нестандартные символы, такие как Unicode-символы. Если вы собираетесь использовать только типичные буквенно-цифровые ASCII-символы, то правила просты.\n\nИдентификатор должен начинаться с `a`-`z`, `A`-`Z`, `$` или `_`. Дальше он может содержать любые из этих же символов и цифры `0`-`9`.\n\nВ общем-то, те же правила, как и к идентификатору переменной, применяются и к имени свойства. Однако, определенные слова не могут использоваться как переменные, но могут использоваться в качестве имен свойств. Эти слова называются \"зарезервированными словами\", и включают ключевые слова JS (`for`, `in`, `if` и т.д.), так же как и `null`, `true` и `false`.\n\n**Примечание:** Более детальная информация о зарезервированных словах есть в приложении А книги *Типы и синтаксис* этой серии.\n\n### Области видимости функций\n\nВы используете ключевое слово `var`, чтобы объявить переменную, которая принадлежит области видимости текущей функции или глобальной области, если находится на верхнем уровне вне любой функции.\n\n#### Поднятие переменной (hoisting)\n\nГде бы ни появлялось `var` внутри области видимости, это объявление принадлежит всей области видимости и доступно в любом месте внутри области.\n\nМетафорически это поведение называется *поднятие (hoisting)*, когда объявление `var` концептуально \"перемещается\" на вершину своей объемлющей области видимости. Технически этот процесс более точно объясняется тем, как компилируется код, но сейчас опустим эти подробности.\n\nПример:\n\n```js\nvar a = 2;\n\nfoo();\t\t\t\t\t// работает, так как определение `foo()`\n\t\t\t\t\t\t// \"всплыло\"\n\nfunction foo() {\n\ta = 3;\n\n\tconsole.log( a );\t// 3\n\n\tvar a;\t\t\t\t// определение \"всплыло\"\n\t\t\t\t\t\t// наверх `foo()`\n}\n\nconsole.log( a );\t// 2\n```\n\n**Предупреждение:** Не общепринято и не так уж здраво полагаться на *поднятие* переменной, чтобы использовать переменную раньше в ее области видимости, чем появится ее объявление с `var`: такое может сбить с толку. Общепринято и приемлемо использовать *всплытие* объявлений функций, что мы и делали с вызовом `foo()`, появившемся до ее объявления.\n\n#### Вложенные области видимости\n\nКогда вы объявляете переменную, она доступна везде в ее области видимости, так же как и в более нижних/внутренних областях видимости. Например:\n\n```js\nfunction foo() {\n\tvar a = 1;\n\n\tfunction bar() {\n\t\tvar b = 2;\n\n\t\tfunction baz() {\n\t\t\tvar c = 3;\n\n\t\t\tconsole.log( a, b, c );\t// 1 2 3\n\t\t}\n\n\t\tbaz();\n\t\tconsole.log( a, b );\t\t// 1 2\n\t}\n\n\tbar();\n\tconsole.log( a );\t\t\t\t// 1\n}\n\nfoo();\n```\n\nЗаметьте, что `c` не доступна внутри `bar()`, потому что она объявлена только внутри внутренней области видимости `baz()` и `b` не доступна в `foo()` по той же причине.\n\nЕсли вы попытаетесь получить доступ к значению переменной в области видимости, где она уже недоступна, вы получите `ReferenceError`. Если вы попытаетесь установить значение переменной, которая еще не объявлена, все  либо закончится тем, что переменная создастся в самой верхней глобальной области видимости (плохо!), либо получите ошибку в зависимости от \"строгого режима\" (см. \"Строгий режим\"). Давайте взглянем:\n\n```js\nfunction foo() {\n\ta = 1;\t// `a` формально не объявлена\n}\n\nfoo();\na;\t\t\t// 1 — упс, автоматическая глобальная переменная :(\n```\n\nЭто очень плохая практика. Не делайте так! Всегда явно объявляйте свои переменные.\n\nВ дополнение к созданию объявлений переменных на уровне функций, ES6 *позволяет* вам объявлять переменные, принадлежащие отдельным блокам (пара `{ .. }`), используя ключевое слово `let`. Кроме некоторых едва уловимых деталей, правила области видимости будут вести себя точно так же, как мы видели в функциях:\n\n```js\nfunction foo() {\n\tvar a = 1;\n\n\tif (a >= 1) {\n\t\tlet b = 2;\n\n\t\twhile (b < 5) {\n\t\t\tlet c = b * 2;\n\t\t\tb++;\n\n\t\t\tconsole.log( a + c );\n\t\t}\n\t}\n}\n\nfoo();\n// 5 7 9\n```\n\nИз-за использования `let` вместо `var`, `b` будет принадлежать только оператору `if` и следовательно не всей области видимости функции `foo()`. Точно так же `c` принадлежит только циклу `while`. Блочная область видимости очень полезна для управления областями ваших переменных более точно, что может сделать ваш код более легким в обслуживании в долгосрочной перспективе.\n\n**Примечание:** Более детальная информация об области видимости есть в книге *Область видимости и замыкания* этой серии. См. книгу *ES6 и за его пределами* этой серии, чтобы узнать больше о блочной области видимости `let`.\n\n## Условные операторы\n\nВ дополнение к оператору `if`, который мы кратко представили в главе 1, JavaScript предоставляет несколько других механизмов условных операторов, на которые нам следует взглянуть.\n\nИногда вы ловите себя на том, что пишете серию операторов `if..else..if` примерно как тут:\n\n```js\nif (a == 2) {\n\t// сделать что-то\n}\nelse if (a == 10) {\n\t// сделать что-то еще\n}\nelse if (a == 42) {\n\t// сделать еще одну вещь\n}\nelse {\n\t// резервный вариант\n}\n```\n\nЭта структура работает, но она слишком подробна, поскольку вам нужно указать проверку для `a` в каждом случае. Вот альтернативная возможность, оператор `switch`:\n\n```js\nswitch (a) {\n\tcase 2:\n    // сделать что-то\n\t\tbreak;\n\tcase 10:\n    // сделать что-то еще\n\t\tbreak;\n\tcase 42:\n    // сделать еще одну вещь\n\t\tbreak;\n\tdefault:\n    // резервный вариант\n}\n```\n\nОператор `break` важен, если вы хотите, чтобы выполнились операторы только одного `case`. Если вы опустите `break` в `case` и этот `case` подойдет или выполнится, выполнение продолжится в следующем операторе `case` независимо то того, подходит ли этот `case`. Этот так называемый \"провал (fall through)\" иногда полезен/желателен:\n\n```js\nswitch (a) {\n\tcase 2:\n\tcase 10:\n\t\t// какие-то крутые вещи\n\t\tbreak;\n\tcase 42:\n\t\t// другие вещи\n\t\tbreak;\n\tdefault:\n\t\t// резерв\n}\n```\n\nЗдесь если `a` будет либо `2`, либо `10`, то выполнятся операторы \"какие-то крутые вещи\".\n\nЕще одна форма условного оператора в JavaScript — это \"условная операция\", часто называемая \"тернарная операция\". Это примерно как более краткая форма отдельного оператора `if..else`. Например:\n\n```js\nvar a = 42;\n\nvar b = (a > 41) ? \"hello\" : \"world\";\n\n// эквивалентно этому:\n\n// if (a > 41) {\n//    b = \"hello\";\n// }\n// else {\n//    b = \"world\";\n// }\n```\n\nЕсли проверяемое выражение (здесь `a > 41`) вычисляется как `true`, результатом будет первая часть (`\"hello\"`), в противном случае результатом будет вторая часть (`\"world\"`), а затем независимо от результата он будет присвоен переменной `b`.\n\nУсловная операция не обязательно должна использоваться в присваивании, но это самое распространенное ее использование.\n\n**Примечание:** Более детальная информация об условиях проверки и других шаблонах для `switch` и `? :` есть в книге *Типы и синтаксис* этой серии.\n\n## Строгий режим (Strict Mode)\n\nES5 добавила \"строгий режим\" в язык, который ужесточил правила для определенных сценариев. В общем-то, эти ограничения выглядят как большее соответствие кода более безопасному и более подходящему набору рекомендаций. Также, тяготение к строгому режиму сделает ваш код более оптимизируемым движком. Строгий режим — это большая победа для кода и вам следует использовать его во всех своих программах.\n\nВы можете явно указать его для отдельной функции или целого файла, в зависимости от того, где вы разместите директиву строгого режима:\n\n```js\nfunction foo() {\n\t\"use strict\";\n\n\t// этот код в строгом режиме\n\n\tfunction bar() {\n\t\t// этот код в строгом режиме\n\t}\n}\n\n// этот код в нестрогом режиме\n```\n\nСравните с:\n\n```js\n\"use strict\";\n\nfunction foo() {\n\t// этот код в строгом режиме\n\n\tfunction bar() {\n\t\t// этот код в строгом режиме\n\t}\n}\n\n// этот код в строгом режиме\n```\n\nВсего одно ключевое отличие (улучшение!) строгого режима — запрет автоматического неявного объявления глобальных переменных из-за пропуска`var`:\n\n```js\nfunction foo() {\n\t\"use strict\";\t// включить строгий режим\n\ta = 1;\t\t\t// `var` missing, ReferenceError\n}\n\nfoo();\n```\n\nЕсли вы включаете строгий режим в своем коде и получаете ошибки, или код начинает вести себя ошибочно, у вас может возникнуть соблазн избегать строгого режима. Но потворствовать этому инстинкту — плохая идея. Если строгий режим является причиной проблем в вашей программе, почти определенно это знак того, что в вашей программе есть вещи, которые надо исправить.\n\nСтрогий режим не только способствует безопасности вашего кода и делает ваш код более оптимизируемым, но и заодно показывает будущее направление языка. Вам будет легче привыкнуть к строгому режиму сейчас, чем продолжать откладывать его в сторону — потом код будет сложнее сконвертировать!\n\n**Примечание:** Более детальная информация о строгом режиме есть в главе 5 книги *Типы и синтаксис* этой серии.\n\n## Функции как значения\n\nДо сих пор мы обсуждали функции как основной механизм *области видимости* в JavaScript. Вспомните синтаксис типичного объявления `функции`, указанный ниже:\n\n```js\nfunction foo() {\n\t// ..\n}\n```\n\nХотя это может показаться очевидным из синтаксиса, `foo` — по сути просто переменная во внешней окружающей области видимости, у которой есть ссылка на объявляемую `функцию`. То есть, `функция` сама является значением, так же как `42` или `[1,2,3]`.\n\nЭто может сперва прозвучать как странная идея, поэтому уделим время ее изучению. Вы не только можете передать значение (аргумент) *в* функцию, но и *сама функция может быть значением*, которое может быть присвоено переменным, или передано, или возвращено из других функций.\n\nВ связи с этим, о значении-функции следует думать как о выражении, сродни любому другому значению или выражению.\n\nПример:\n\n```js\nvar foo = function() {\n\t// ..\n};\n\nvar x = function bar(){\n\t// ..\n};\n```\n\nПервое функциональное выражение, присваиваемое переменной `foo`, называется *анонимным* поскольку у него нет `имени`.\n\nВторое функциональное выражение *именованное* (`bar`), несмотря на то, что является ссылкой, также присваивается переменной `x`. *Выражения с именованными функциями* как правило более предпочтительны, хотя *выражения с анонимными функциями* все еще чрезвычайно употребительны.\n\nБолее детальная информация есть в книге *Область видимости и замыкания* этой серии.\n\n### Выражения немедленно вызываемых функций (Immediately Invoked Function Expressions (IIFEs))\n\nВ предыдущем примере ни одно из выражений с функциями не выполнялось, мы могли бы это сделать, включив в код `foo()` или `x()`, например.\n\nЕсть еще один способ выполнить выражение с функцией, на который обычно ссылаются как на *immediately invoked function expression* (IIFE):\n\n```js\n(function IIFE(){\n\tconsole.log( \"Hello!\" );\n})();\n// \"Hello!\"\n```\n\nВнешние `( .. )`, которые окружают выражение функции `(function IIFE(){ .. })`, — это всего лишь нюанс грамматики JS, необходимый для предотвращения  того, чтобы это выражение воспринималось как объявление обычной функции.\n\nПоследние `()` в конце выражения, строка `})();` — это то, что и выполняет выражение с функцией, указанное сразу перед ним.\n\nМожет показаться странным, но это не так уж чужеродно, как кажется на первый взгляд. Посмотрите на сходства между `foo` и `IIFE` тут:\n\n```js\nfunction foo() { .. }\n\n// `foo` выражение со ссылкой на функцию,\n// затем `()` выполняют ее\nfoo();\n\n// Выражение с функцией `IIFE`,\n// затем `()` выполняют ее\n(function IIFE(){ .. })();\n```\n\nКак видите, содержимое `(function IIFE(){ .. })` до ее вызова в `()`  фактически такое же, как включение `foo` до его вызова после `()`. В обоих случаях ссылка на функцию выполняется с помощью `()` сразу после них.\n\nТак как IIFE — просто функция, а функции создают *область видимости* переменных, то использование IIFE таким образом обычно происходит, чтобы объявлять переменные, которые не будут влиять на код, окружающий IIFE снаружи:\n\n```js\nvar a = 42;\n\n(function IIFE(){\n\tvar a = 10;\n\tconsole.log( a );\t// 10\n})();\n\nconsole.log( a );\t\t// 42\n```\n\nФункции IIFE также могут возвращать значения:\n\n```js\nvar x = (function IIFE(){\n\treturn 42;\n})();\n\nx;\t// 42\n```\n\nЗначение `42` `возвращается` из выполненной `IIFE` функции, а затем присваивается в `x`.\n\n### Замыкание\n\n*Замыкание* является одной из самых важных и зачастую наименее понятных концепций в JavaScript. Я не буду вдаваться в подробности сейчас, а вместо этого направляю вас в книгу *Область видимости и замыкания* этой серии. Но я хотел бы сказать несколько слов о замыканиях, чтобы вы понимали общую концепцию. Это будет важной техникой в вашем наборе навыков в JS.\n\nВы можете думать о замыкании как о способе \"запомнить\" и продолжить работу в области видимости функции (с ее переменными) даже когда функция уже закончила свою работу.\n\nПроиллюстрируем:\n\n```js\nfunction makeAdder(x) {\n\t// параметр `x` - внутренняя переменная\n\n\t// внутренняя функция `add()` использует `x`, поэтому\n\t// у нее есть \"замыкание\" на нее\n\tfunction add(y) {\n\t\treturn y + x;\n\t};\n\n\treturn add;\n}\n```\n\nСсылка на внутреннюю функцию `add(..)`, которая возвращается с каждым вызовом внешней `makeAdder(..)`, умеет запоминать какое значение `x` было передано в `makeAdder(..)`. Теперь давайте используем `makeAdder(..)`:\n\n```js\n// `plusOne` получает ссылку на внутреннюю функцию `add(..)`\n// с замыканием на параметре `x`\n// внешней `makeAdder(..)`\nvar plusOne = makeAdder( 1 );\n\n// `plusTen` получает ссылку на внутреннюю функцию `add(..)`\n// с замыканием на параметре `x`\n// внешней `makeAdder(..)`\nvar plusTen = makeAdder( 10 );\n\nplusOne( 3 );\t\t// 4  <-- 1 + 3\nplusOne( 41 );\t\t// 42 <-- 1 + 41\n\nplusTen( 13 );\t\t// 23 <-- 10 + 13\n```\n\nТеперь подробней о том, как работает этот код:\n\n1. Когда мы вызываем `makeAdder(1)`, мы получаем обратно ссылку на ее внутреннюю `add(..)`, которая запоминает `x` как `1`. Мы назвали эту ссылку на функцию `plusOne(..)`.\n2. Когда мы вызываем `makeAdder(10)`, мы получаем обратно ссылку на ее внутреннюю `add(..)`, которая запоминает `x` как `10`. Мы назвали эту ссылку на функцию `plusTen(..)`.\n3. Когда мы вызываем `plusOne(3)`, она прибавляет `3` (свою внутреннюю `y`) к `1` (которая запомнена в `x`), и мы получаем в качестве результата `4`.\n4. Когда мы вызываем `plusTen(13)`, она прибавляет `13` (свою внутреннюю `y`) к `10` (которая запомнена в `x`), и мы получаем в качестве результата `23`.\n\nНе волнуйтесь, если всё это кажется странным и сбивающим по началу с толку — это нормально! Понадобится много практики, чтобы всё это полностью понять.\n\nНо поверьте мне, как только вы это освоите, это будет одной из самых мощных и полезных техник во всем программировании. Определенно стоит приложить усилия, чтобы ваши мозги немного покипели над замыканиями. В следующем разделе, мы немного попрактикуемся с замыканиями.\n\n#### Модули\n\nСамое распространенное использование замыкания в JavaScript — это модульный шаблон. Модули позволяют определять частные детали реализации (переменные, функции), которые скрыты от внешнего мира, а также публичное API, которое *доступно* снаружи.\n\nПредставим:\n\n```js\nfunction User(){\n\tvar username, password;\n\n\tfunction doLogin(user,pw) {\n\t\tusername = user;\n\t\tpassword = pw;\n\n\t\t// сделать остальную часть работы по логину\n\t}\n\n\tvar publicAPI = {\n\t\tlogin: doLogin\n\t};\n\n\treturn publicAPI;\n}\n\n// создать экземпляр модуля `User`\nvar fred = User();\n\nfred.login( \"fred\", \"12Battery34!\" );\n```\n\nФункция `User()` служит как внешняя область видимости, которая хранит переменные `username` и `password`, а также внутреннюю функцию `doLogin()`. Всё это частные внутренние детали этого модуля `User`, которые недоступны из внешнего мира.\n\n**Предупреждение:** Мы не вызываем тут `new User()` намеренно, несмотря на тот факт, что это будет более естественно для большинства читателей. `User()` — просто функция, а не класс, поэтому она вызывается обычным образом. Использование `new` было бы неуместной тратой ресурсов.\n\nПри выполнении `User()` создается *экземпляр* модуля `User`: новая область видимости и также совершенно новая копия каждой из внутренних переменных/функций. Мы присваиваем этот экземпляр в `fred`. Если мы запустим `User()` снова, то получим новый экземпляр, никак не связанный с `fred`.\n\nУ внутренней функции `doLogin()` есть замыкание на `username` и `password`, что значит, что она сохранит свой доступ к ним даже после того, как функция `User()` завершит свое выполнение.\n\n`publicAPI` — это объект с одним свойством/методом, `login`, который является ссылкой на внутреннюю функцию `doLogin()`. Когда мы возвращаем  `publicAPI` из `User()`, он становится экземпляром, который мы назвали `fred`.\n\nНа данный момент внешняя функция `User()` закончила выполнение. Как правило, вы думаете, что внутренние переменные, такие как `username` и `password`, при этом исчезают. Но они никуда не деваются, потому что есть замыкание в функции `login()`, хранящее их.\n\nВот поэтому мы можем вызвать `fred.login(..)`, что подобно вызову внутренней `doLogin(..)`, и у нее все еще будет доступ ко внутренним переменным `username` и `password`.\n\nНе исключено, что после краткого обзора замыканий и модульных шаблонов для вас что-то останется неясным. Ничего страшного! Понадобится практика, чтобы намотать всё это на ус.\n\nПочитайте книгу этой серии *Область видимости и замыкания* для получения более детальных объяснений.\n\n## Идентификатор `this`\n\nЕще одна очень часто неверно понимаемая концепция в JavaScript — это идентификатор `this`. Опять таки, есть пара глав по нему в книге *this и прототипы объектов* этой серии, поэтому здесь мы только кратко его рассмотрим.\n\nПри том что может часто казаться, что ключевое слово `this` связано с \"объектно-ориентированным шаблонами\", в JS `this` — это другой механизм.\n\nЕсли у функции есть внутри ссылка `this`, эта ссылка `this` обычно указывает на `объект`. Но на какой `объект` она указывает зависит от того, как эта функция была вызвана.\n\nВажно понимать, что `this` *не* ссылается на саму функцию, хотя это самое распространенное неверное представление.\n\nВот краткая иллюстрация:\n\n```js\nfunction foo() {\n\tconsole.log( this.bar );\n}\n\nvar bar = \"global\";\n\nvar obj1 = {\n\tbar: \"obj1\",\n\tfoo: foo\n};\n\nvar obj2 = {\n\tbar: \"obj2\"\n};\n\n//--------\n\nfoo();\t\t\t\t// \"global\"\nobj1.foo();\t\t\t// \"obj1\"\nfoo.call( obj2 );\t// \"obj2\"\nnew foo();\t\t\t// undefined\n```\n\nЕсть четыре правила того, как устанавливается `this`, и они показаны в этих четырех последних строках кода.\n\n1. `foo()` присваивает в `this` ссылку на глобальный объект в нестрогом режиме. В строгом режиме, `this` будет `undefined`, и вы получите ошибку при доступе к свойству `bar`, поэтому `\"global\"` — это значение для `this.bar`.\n2. `obj1.foo()` устанавливает `this` в объект `obj1`.\n3. `foo.call(obj2)` устанавливает `this` в объект `obj2`.\n4. `new foo()` устанавливает `this` в абсолютно новый пустой объект.\n\nРезюме: чтобы понять, на что указывает `this`, вам нужно проверить, как именно вызывалась функция. Это будет один из тех четырех вышеописанных способов, таким образом вы поймете, что будет в `this`.\n\n**Примечание:** Более детальная информация о ключевом слове `this` есть в главах 1 и 2 книги *this и прототипы объектов* этой серии.\n\n## Прототипы\n\nМеханизм прототипов в JavaScript довольно сложен. Здесь мы только немного взглянем на него. Вам потребуется потратить много времени, изучая главы 4-6 книги *this и прототипы объектов* этой серии, чтобы получить детальную информацию.\n\nЕсли вы ссылаетесь на свойство объекта, и этого свойства не существует, то JavaScript автоматически использует ссылку на внутренний прототип этого объекта, с целью найти это свойство там. Можете думать об этом механизме как о резервном варианте, когда свойство отсутствует.\n\nСвязывание ссылки на внутренний прототип объекта к его резервному варианту происходит в момент создания объекта. Простейшим способом проиллюстрировать это является вызов встроенной функции `Object.create(..)`.\n\nПример:\n\n```js\nvar foo = {\n\ta: 42\n};\n\n// создаем `bar` и связываем его с `foo`\nvar bar = Object.create( foo );\n\nbar.b = \"hello world\";\n\nbar.b;\t\t// \"hello world\"\nbar.a;\t\t// 42 <-- делегируется в `foo`\n```\n\nСледующая картинка поможет визуально показать объекты `foo` и `bar` и их связь:\n\n<img src=\"fig6.png\">\n\nСвойства `a` на самом деле не существует в объекте `bar`, но поскольку  `bar` прототипно связан с `foo`, JavaScript автоматически прибегает к поиску `a` в объекте `foo`, где оно и находится.\n\nТакая связь может показаться странной возможностью языка. Самым распространенным способом ее использования (я бы поспорил об его правильности) является эмулирование \"классового наследование\".\n\nНо более естественный способ применения прототипов — шаблон, называемый  \"делегированием поведения\", когда вы намеренно проектируете свои связанные объекты так, чтобы они могли *делегировать* от одного к другому части необходимого поведения.\n\n**Примечание:** Более детальная информация о прототипах и делегировании поведения есть в главах 4-6 книги *this & прототипы объектов* этой серии.\n\n## Старый и новый\n\nНекоторые из возможностей JS, которые мы уже рассмотрели, и, конечно, многие возможности, рассмотренные в остальных книгах серии, являются достаточно новыми дополнениями и не всегда будут доступны в более старых браузерах. На самом деле, некоторые новейшие возможности в спецификации еще не реализованы ни в одной из стабильных версий браузеров.\n\nТак что же вам делать со всеми этими новыми вещами? Нужно ли ждать годы или десятилетия, чтобы все старые браузеры канули в лету?\n\nХотя именно так думают многие люди, это совсем не здравый подход к JS.\n\nЕсть две основные техники, которыми можно пользоваться, чтобы \"привнести\" более новые возможности JavaScript в старые браузеры: полифиллинг (polyfilling) и транспиляция (transpiling).\n\n### Полифиллинг (polyfilling)\n\nСлово \"polyfill\", введенный Реми Шарпом термин (https://remysharp.com/2010/10/08/what-is-a-polyfill), означает определение новой функции с помощью кода, реализующего эквивалентное поведению, но с возможностью запуска в более старых окружениях JS.\n\nНапример, ES6 определяет функцию, называемую `Number.isNaN(..)`, для обеспечения точной, безошибочной проверки на значения `NaN`, отменяя устаревшую первоначальную функцию `isNaN(..)`. Но очень легко заполифиллить новую функцию, с целью пользования ею в вашем коде независимо от того, поддерживает браузер ES6 или нет.\n\nПример:\n\n```js\nif (!Number.isNaN) {\n\tNumber.isNaN = function isNaN(x) {\n\t\treturn x !== x;\n\t};\n}\n```\n\nОператор `if` защищает против применения полифильного определения в браузерах, поддерживающих ES6 синтаксис. Если же функция не существует, то мы определяем `Number.isNaN(..)`.\n\n**Примечание:** Проверка, которую мы тут выполняем, использует преимущество причудливости значения `NaN`, которое заключается в том, что оно является единственным не равным самому себе значением во всем языке.  Поэтому значение `NaN` — единственное, делающее условие `x !== x` `истинным`.\n\nНе все новые функции возможно полностью заполифиллить. Зачастую большая часть поведения может быть сполифиллена, хотя есть и небольшие отступления. Вы должны быть очень, очень осторожны, реализовывая полифиллинг самостоятельно; следите за тем, чтобы придерживаться спецификации настолько строго, насколько возможно.\n\nА лучше используйте уже проверенный набор полифиллов, которому вы можете доверять, вроде тех, что предоставляются ES5-Shim (https://github.com/es-shims/es5-shim) и ES6-Shim (https://github.com/es-shims/es6-shim).\n\n### Транспиляция (Transpiling)\n\nНе существует возможности полифиллить новый синтаксис, который был добавлен в язык. Новый синтаксис вызовет ошибку в старом движке JS, как нераспознанный/невалидный.\n\nПоэтому лучшим выбором будет использовать утилиту, которая конвертирует ваш более новый код в эквивалент более старого. Этот процесс обычно называют \"транспиляцией\", как объединение терминов трансформация и компиляция (transforming + compiling).\n\nПо большому счету, исходный код написан в новом синтаксисе, но то, что развертывают в браузере является транспилированным кодом со старым синтаксисом. Обычно вставляют транспилятор в процесс сборки, примерно так же как linter или minifier.\n\nВам может стать интересно, а зачем идти на неприятности: зачем писать в новом синтаксисе, чтобы потом транспилить его в старый код? Почему бы просто не писать напрямую в старом синтаксисе?\n\nЕсть несколько важных причин, по которым вам следует транспилить код:\n\n* Новый синтаксис, добавленный в язык, разрабатывается, с целью сделать ваш код более читаемым и поддерживаемым. Старые эквиваленты часто намного более запутаны. Следует писать с помощью более нового и ясного синтаксиса, не только для себя, но и для всех остальных членов команды разработки.\n* Если вы транспилите только для старых браузеров, но используете новый синтаксис в новейших браузерах, вы получаете преимущество оптимизации производительности браузера с помощью нового синтаксиса. Это также позволяет разработчикам браузеров делать код более приближенным к жизни для проверки их реализаций и оптимизаций.\n* Использование нового синтаксиса как можно раньше позволяет ему быть протестированным более тесно в реальном мире, что обеспечивает более ранние отзывы в комитет JavaScript (TC39). Если проблемы обнаружены достаточно рано, то их можно изменить/устранить до того, как эти ошибки дизайна языка станут постоянными.\n\nВот небольшой пример транспиляции. ES6 добавляет возможность, называемую  \"значения параметров по умолчанию\". Это выглядит примерно так:\n\n```js\nfunction foo(a = 2) {\n\tconsole.log( a );\n}\n\nfoo();\t\t// 2\nfoo( 42 );\t// 42\n```\n\nПросто, правда? Еще и полезно! Но это как раз новый синтаксис, который будет считаться невалидным в до-ES6 движках. Так что же транспилятор сделает с этим кодом, чтобы заставить его работать в более старых движках?\n\n```js\nfunction foo() {\n\tvar a = arguments[0] !== (void 0) ? arguments[0] : 2;\n\tconsole.log( a );\n}\n```\n\nКак видите, он проверяет, равно ли значение `arguments[0]` значению `void 0` (т.е. `undefined`); если да, то предоставляет значение по умолчанию `2`, иначе он присваивает то, что было передано.\n\nВ дополнение к тому, что теперь можно использовать привлекательный синтаксис даже в старых браузерах, транспилированный код фактически делает заданное поведение яснее.\n\nВозможно, просто глядя на версию ES6, вы не задумывались, что `undefined` — единственное значение, которое не может быть явно задано значением по умолчанию для параметра, но транспилированный код показывает это гораздо яснее.\n\nПоследняя важная деталь о транспиляторах: о них следует думать как о стандартной части экосистемы и процесса разработки. JavaScript будет продолжать эволюционировать намного быстрее, чем прежде, поэтому каждые несколько месяцев будут добавляться новый синтаксис и новые возможности.\n\nЕсли вы по умолчанию используете транспилятор, вы в любой момент времени можете переключиться на новый синтаксис, нежели годами ждать выхода сегодняшних браузеров из использования.\n\nЕсть довольно много отличных транспиляторов на выбор. Вот несколько из них на момент написания этого текста:\n\n* Babel (https://babeljs.io) (бывший 6to5): Транспилирует из ES6+ в ES5\n* Traceur (https://github.com/google/traceur-compiler): Транспилирует из  ES6, ES7 и далее в ES5\n\n## Не-JavaScript\n\nНа данный момент, мы рассмотрели только вещи, касающиеся самого языка JS. Реальность такова, что большая часть JS написана для запуска и взаимодействия с такими средами как браузеры. Добрая часть вещей, которые вы пишете в своем коде, строго говоря, не контролируется напрямую JavaScript. Возможно это звучит несколько странно.\n\nСамый распространенный не-JavaScript JavaScript, с которым вы столкнетесь — это DOM API. Например:\n\n```js\nvar el = document.getElementById( \"foo\" );\n```\n\nПеременная `document` существует как глобальная переменная, когда ваш код выполняется в браузере. Она ни обеспечивается движком JS, ни особенно  контролируется спецификацией JavaScript. Она принимает форму чего-то ужасно похожего на обычный JS `объект`, но не является им на самом деле. Это специальный `объект,` часто называемый \"хост-объектом.\"\n\nБолее того, метод `getElementById(..)` в `document` выглядит как обычная функция JS, но это всего лишь кое-как открытый интерфейс к встроенному методу, предоставлeнному DOM из вашего браузера. В некоторых браузерах (нового поколения) этот слой может быть на JS, но традиционно DOM и его поведение реализовано на чем-то вроде C/C++.\n\nЕще один пример с вводом/выводом (I/O).\n\nВсеобщее любимое всплывающее окно `alert(..)` в пользовательском окне браузера. `alert(..)` предоставляется вашей JS программе браузером, а не самим движком JS. Вызов, который вы делаете, отправляет сообщение во внутренности браузера, и уже браузер обрабатывают отрисовку и отображение окна с сообщением.\n\nТо же происходит и с `console.log(..)`: ваш браузер предоставляет подобные механизмы и подключает их к средствам разработчика.\n\nЭта книга, да и вся эта серия, фокусируется на языке JavaScript. Поэтому вы не увидите какого-либо подробного раскрытия деталей об этих не-JavaScript механизмах JavaScript. Как бы то ни было, вам не нужно забывать о них, поскольку они будут в каждой написанной вами JS программе!\n\n## Обзор\n\nПервым шагом в изучении духа программирования на JavaScript является получение первичного представления о его внутренних структурах, таких как значения, типы, замыкания функций, `this` и прототипы.\n\nКонечно, каждая из этих тем заслуживает большего раскрытия, чем вы видели здесь, но именно поэтому есть главы и книги, посвященные им, на протяжении остальных книг серии. После того как вы почувствуете себя более уверенно в концепциях и примерах кода в этой главе, оставшиеся книги серии ждут вас, чтобы по-настоящему погрузиться и узнать язык основательно.\n\nПоследняя глава этой книги даст короткое описание тем оставшихся книг серии и принципов, которые они раскрывают в дополнение к тем, что мы уже изучили.\n"
  },
  {
    "path": "up & going/ch3.md",
    "content": "# Вы не знаете JS: Начните и Совершенствуйтесь\n# Глава 3: Введение в \"Вы не знаете JS\"\n\nО чем вся эта серия? Проще говоря, она о том как взяться серьезно за задачу изучения *всех частей JavaScript*, а не только некоторого подмножества языка, которое кто-то называет \"основными частями\", и не только совсем минимального количества, необходимого вам, чтобы сделать свою работу.\n\nСерьезные разработчики в других языках обычно планируют приложить усилия для изучения большей части или всего языка, на котором они в основном пишут, но разработчики на JS похоже стоят в стороне от всех в том смысле, что типично не изучают многого в языке. Это не так уж и хорошо, и это не то, что и дальше должно считаться нормой.\n\nСерия *Вы не знаете JS* (*YDKJS*) представляет разительный контраст с типичными подходами к изучению языка и непохожа почти на все другие книги о JS, которые вы прочтете. Она требует от вас выйти из зоны комфорта и задать серьезные вопросы \"почему?\" для всех до единой функциональных возможностей, с которыми вы столкнетесь. Вы готовы заняться этой задачей?\n\nЯ использую эту последнюю главу, чтобы кратко подвести итог того, что ждать от остальных книг серии, и как наиболее эффективно приняться за постройку основы обучения JS, держа в своих руках *YDKJS*.\n\n## Область действия и замыкания\n\nНаверное, одна из самых фундаментальных вещей, которые понадобятся вам, чтобы быстрее подобраться к этим терминам — это понимание как именно создание области действия переменных на самом деле работает в JavaScript. Недостаточно иметь анекдотичные расплывчатые *представления* об области действия.\n\nКнига *Область действия и замыкания* начинается с развенчания общего ложного представления, что JS — \"интерпретируемый язык\", и потому он не компилируется. А вот и нет!\n\nДвижок JS компилирует ваш код прямо перед выполнением (а иногда и во время выполнения!). Поэтому мы пойдем путем более глубокого понимания подхода компилятора к вашему коду, чтобы понять, как он находит и разбирается с объявлениями переменных и функций. Попутно мы посмотрим типичную схему JS по управлению областью действия переменных, \"Всплытие (hoisting)\".\n\nИменно это критическое понимание \"лексической области действия\" является тем, на чем мы потом будем основывать наше исследование замыкания в последней главе этой книги. Замыкание — возможно, единственное самое важное понятие во всем JS, но если вы сперва не разберетесь плотно с механизмом области действия, то замыкание скорее всего останется вне вашего понимания.\n\nОдно важное применение замыкания — это модульный шаблон, который мы уже кратко представили в этой книге в главе 2. Модульный шаблон, возможно, самый преобладающий шаблон организации кода во всем JavaScript; его глубокое понимание должно быть одним из самых высоких ваших приоритетов.\n\n## this и прототипы объектов\n\nПожалуй, одним из самых распространенных и устойчивых ложных фактов о JavaScript является то, что ключевое слово `this` указывает на функцию, в которой оно появляется. Ужасное заблуждение!\n\nКлючевое слово `this` динамически привязывается, основываясь на том, как выполняется функция; выясняется, что есть четыре простых правила, помогающих понять и полностью определить привязку `this`.\n\nТесно связан с ключевым словом `this` механизм прототипов объектов, который является цепочкой поисков свойств, похожей на то, как обнаруживаются переменные в лексической области действия. Но обертка прототипов хранит другой большой промах с JS: идея эмуляции (замены) классов и так называемое наследование через прототипы.\n\nК сожалению, желание привнести мышление классами и наследованием в JavaScript — это просто наихудшая вещь, которую вы могли бы сделать; несмотря на то, что синтаксис может вводить вас в заблуждение, будто есть что-то подобное классам, в действительности механизм прототипов фундаментально противоположен по своему поведению.\n\nЧто является предметом спора, так это то, лучше ли проигнорировать несоответствие и притвориться, что вы реализуете \"наследование\", либо все-таки, что является более подходящим, изучить и принять то, как на самом деле работает система прототипов объектов. Последнее подходяще именуется \"делегированием поведения\".\n\nЭто больше, чем синтаксическое предпочтение. Делегирование — это совершенно другой и более мощный шаблон проектирования, который сам по себе заменяет необходимость проектировать классы и их наследование. Но эти утверждения полностью противоречат почти каждому второму посту в блогах, книгам и конференциям по этой теме на всем протяжении существования JavaScript.\n\nПретензии, которые я предъявляю касаемо делегирования в противовес наследованию, идут не от нелюбви к языку и его синтаксису, а от желания видеть правильное применение истинной возможности языка и свести на нет бесконечные путаницу и недовольство.\n\nНо объяснение необходимости рассматриваемых прототипов и делегирования гораздо более запутанно, чем то, которое я тут представил. Если вы готовы переосмыслить всё, что, как вы думаете, вы знаете о \"классах\" и \"наследовании\" в JavaScript, то я даю вам шанс \"принять красную таблетку\" (*Матрица*, 1999) и проверить главы 4-6 книги *this & прототипы объектов* этой серии.\n\n## Типы и синтаксис\n\nТретья книга в этой серии в первую очередь фокусируется на разборе еще одной в высшей степени спорной темы: приведение типов. Возможно, не существует темы, вызывающей большую досаду у разработчиков на JS, чем когда речь заходит о неразберихе, окружающей неявное приведение.\n\nПо большей части, общепринятый опыт — то, что неявное приведение — это \"плохая часть\" языка, и ее следует избегать любой ценой. Некоторые ушли так далеко, что называют ее \"дефектом\" в дизайне языка. Более того, есть утилиты, чья единственная работа не делать ничего кроме проверки вашего кода и сигнализирования о том, что вы делаете что-то, даже мало-мальски, похожее на неявное приведение.\n\nНо действительно ли приведение — такое сбивающее с толку, такое плохое, такое коварное, что ваш код обречен с самого начала, если вы будете использовать его?\n\nЯ отвечаю — нет. После постепенного построения понимания того, как на самом деле работают типы и значения, в главах 1-3, глава 4 берет на себя этот спор и полностью объясняет, как работает приведение типов со всеми его нюансами. Мы увидим, какие нюансы приведения действительно удивляют, а какие нюансы на самом деле имеют смысл, при должном их изучении.\n\nНо я не советую, лишь понять приведение типов, я утверждаю, что приведение — невероятно полезный и сильно недооцененный инструмент, который *вам следует использовать в вашем коде*. Приведение, при должном использовании, не только работает, но и делает ваш код лучше. Все скептики и спорщики несомненно поднимут на смех такую позицию, но я верю, что это одно из главных направлений, чтобы улучшить вашу игру в JS.\n\nХотите ли вы просто продолжать следовать тому, что говорит большинство, или не желаете принимать в расчет все допущения и хотите взглянуть на приведение свежим взглядом? Книга *Типы и синтаксис* этой серии заставит вас задуматься.\n\n## Асинхронность и производительность\n\nПервые три книги этой серии фокусируются на внутренней механике языка, а четвертая книга делает небольшое отступление, чтобы рассмотреть шаблоны для управления асинхронной разработкой, вдобавок к механике языка. Асинхронность не только критически важна для быстродействия наших приложений, она всё больше становится *тем самым* критическим фактором для легкости написания и обслуживания программы.\n\nСперва книга начинается с прояснения большей части путаницы с терминологией и подходом вокруг таких вещей как \"async\", \"parallel\" и \"concurrent\" и объясняет в деталях, как применять и как не применять такие вещи в JS.\n\nЗатем мы двинемся к изучению функций обратного вызова (callback) как к основному методу обеспечения асинхронности. Но тут мы быстро заметим, что сама по себе функция обратного вызова совершенно недостаточна для современных требований к асинхронной разработке. Мы определим два главных недостатка программирования только с помощью функций обратного вызова: потеря доверия к *инверсии управления* (IoC) и нехватка заурядной целесообразности.\n\nС целью решить эти два недостатка, ES6 предоставляет два новых механизма (и даже шаблоны): обещания и генераторы.\n\nОбещания — это независимые от времени обертки вокруг \"будущего значения (future value)\", которые позволяют вам рассуждать о них и составлять их независимо от того, готово ли уже это будущее значение или еще нет. Более того, они эффективно решают проблемы доверия к IoC, маршрутизируя функции обратного вызова посредством доверительного и компонуемого механизма обещаний.\n\nГенераторы предоставляют новый режим выполнения для функций в JS, в соответствии с которым генератор может быть приостановлен в точках с `yield` и продолжен асинхронно позже. Возможность \"приостановки-и-продолжения\" позволяет синхронному, последовательно выглядящему коду в генераторе быть обработанным асинхронно за кулисами. Делая так, мы устраняем путаницу с нелинейными, нелокальными переходами в функциях обратного вызова и, таким образом, делаем наш асинхронный код синхронно выглядящим, чтобы он был более осмысленным.\n\nИменно эта комбинация обещаний и генераторов и \"превращается\" в наш самый эффективный шаблон асинхронного кодирования в JavaScript в настоящий момент. Вообще-то, многие из будущих усовершенствований в асинхронности появятся в ES7 и позже будут обязательно построены на этой основе. Если серьезно относиться к тому, чтобы эффективно программировать в асинхронном мире, вам понадобится хорошенько освоиться с сочетанием обещаний и генераторов.\n\nХотя обещания и генераторы являются почти что явными шаблонами, которые позволяют вашим программам работать параллельно и, таким образом, обрабатывать больше за меньший период, в JS есть много других аспектов оптимизации производительности, стоящих изучения.\n\nГлава 5 затрагивает темы, такие как параллелизм программ с помощью Web Workers и параллелизм данных с помощью SIMD, а также техника низкоуровневой оптимизации, как например ASM.js. Глава 6 знакомит с оптимизацией производительности с точки зрения правильных техник оценки производительности, включая то, о каких видах производительности стоит беспокоиться, а какие проигнорировать.\n\nЭффективное программирование на JavaScript означает написание кода, который может разрушить барьеры ограничений будучи работающим динамически в широком диапазоне браузеров и других средах. Это потребует много сложного и детального планирования, а также усилий с вашей стороны, чтобы перевести программу с \"она работает\" на \"она работает хорошо\".\n\nКнига *Асинхронность и производительность* спроектирована так, чтобы дать вам все инструменты и навыки, необходимые чтобы писать адекватный и производительный JavaScript код.\n\n## ES6 и за его пределами\n\nНе важно насколько вы чувствуете себя владеющим JavaScript к этому моменту, правда в том, что JavaScript никогда не прекратит эволюционировать, и более того, скорость эволюции быстро растет. Этот факт — почти что образное представление духа этой серии, чтобы проникнуться тем, что мы никогда полностью *не узнаем* каждую часть JS, поскольку, как только вы овладеете всем, появятся новые вещи, опускающие границу того, что вам нужно будет изучить.\n\nЭта книга посвящена как краткосрочным, так и среднесрочным перспективам того, в каком направлении идет язык: не только *известные* вещи, как ES6, но и *предполагаемые* вещи за его пределами.\n\nКроме того, что все книги этой серии описывают состояние JavaScript на момент написания, которое на полпути к внедрению ES6, основной фокус в серии все-таки больше на ES5. Теперь мы хотим обратить наше внимание на ES6, ES7 и ...\n\nПоскольку ES6 почти готов на момент написания этих строк, *ES6 и за его пределами* начинается с того, что делится практическими вещами из пространства ES6 в нескольких ключевых категориях, включая новый синтаксис, новые структуры данных (коллекции) и новые возможности обработки и API. Мы рассмотрим каждую из этих новых возможностей ES6 на различных уровнях детализации, включая рассмотрение деталей, которые затрагиваются в других книгах серии.\n\nВот некоторые захватывающие вещи в ES6, ждущие вашего с ними ознакомления: деструктурирование (destructuring), значения параметров по умолчанию, символы, сокращенные методы (concise methods), вычисляемые свойства, стрелочные функции (arrow functions), блочная область действия, обещания (promises), генераторы, итераторы, модули, прокси, слабосвязанные коллекции ключ-значение (weakmaps) и многое, многое другое! Ну и ну, ES6 производит огромное впечатление!\n\nПервая часть книги — это дорожная карта по всем вещам, которые вам необходимо изучить, чтобы подготовиться к новому и улучшенному JavaScript, на котором вы будете писать и который будете исследовать в течение следующей пары лет.\n\nПоследняя часть книги фокусируется на быстром взгляде на вещи, ожидаемые в ближайшем будущем в JavaScript. Самая важная мысль здесь в том, что будет после ES6; JS, похоже, будет эволюционировать компонент за компонентом, а не версия за версией, это означает, что мы можем увидеть функции ближайшего будущего намного скорее, чем вы могли бы представить себе.\n\nУ JavaScript блестящее будущее. Разве сейчас не то самое время, чтобы начать изучать его!?\n\n## Обзор\n\nСерия *YDKJS* посвящена утверждению, что все разработчики на JS могут и должны изучить все составляющие этого могучего языка. Ни одно мнение, никакая надежда на фреймворк и ни один дедлайн проекта не должны быть извинением за то, почему вы так и не изучили и не пришли к глубокому пониманию JavaScript.\n\nМы возьмем каждое направление в языке и посвятим ему краткую, но очень насыщенную книгу, чтобы полностью исследовать все его части, которые как вам казалось вы знаете, но возможно не полностью.\n\n\"Вы не знаете JS\" — это не про критику и издевательство. Книга про то, что все мы, включая меня, должны найти общий язык. Изучение JavaScript — это не конечная цель, а процесс. Мы не знаем JavaScript, пока что. Но мы узнаем!\n"
  },
  {
    "path": "up & going/foreword.md",
    "content": "# Вы не знаете JS: Начните и Совершенствуйтесь\n# Введение\n\nЧто нового вы изучили в последнее время?\n\nВозможно, это был иностранный язык, например итальянский или немецкий. Или, может быть, это был графический редактор, например Photoshop. Это был кулинарный рецепт или новый способ обработки дерева, или спортивное упражнение. Я хочу чтобы Вы запомнили то чувство, когда Вы, наконец, получаете желаемое: тот момент, когда лампочка начинает гореть. Когда все, что было размыто, стало вдруг кристально ясным, когда Вы освоили настольную пилу, или поняли разницу между существительными мужского и женского рода во французском. Как ощущения? Довольно поразительно, правда?\n\nТеперь я хочу переместить Вас немного дальше в Вашу память, прямо к моменту перед изучением нового навыка. Как Вам *это* чувство? Вероятно, немного пугающее, и может быть, немного разочаровывающее, правда? В какой то момент все мы не знали тех вещей, которые знаем сейчас, и это совершенно нормально; мы все с чего-то начинали. Изучение нового материала, это захватывающее приключение, особенно если Вы собираетесь серьезно изучить новую тему.\n\nЯ веду много занятий для начинающих программистов. Студенты, посещающие мои занятия, часто пытались самостоятельно обучаться таким вещам, как HTML или JavaScript, просто читая записи в блогах, или копируя и вставляя код, но они не смогли по-настоящему хорошо освоить материал, чтобы получить код, соответствующий их ожиданиям. И, так как они не усвоили всех тонкостей определенных тем программирования на должном уровне, они не могут написать производительный код, или отладить его, так как в действительности, они не понимают что происходит.\n\nЯ всегда верю, что процесс обучения на моих занятиях построен правильно, подразумевая, что я обучаю веб-стандартам, семантической верстке, хорошо документированному коду, и другим лучшим практикам. Я освещаю предмет со всех сторон, чтобы объяснить что и как функционирует, вместо того чтобы просто скопировать и вставить код. Когда вы стремитесь понять Ваш код, Ваши результаты улучшаются, и Вы становитесь лучше в своем деле. Код - это теперь не просто Ваша *работа*, это Ваше *ремесло*. Поэтому я люблю *Начинать и Совершенствоваться*. Кайл берет нас с собой в глубокое погружение сквозь синтаксис и терминологию чтобы дать отличное введение в язык JavaScript, не срезая углов. Эта книга не скользит по поверхности, а наоборот позволяет нам по-настоящему понять описанные концепции языка.\n\nПотому что недостаточно уметь копировать фрагменты кода jQuery на Ваш сайт, точно также, как недостаточно научиться открывать, закрывать, и сохранять документ в Photoshop. Конечно, как только я узнала основы работы с программой, я могу создавать дизайн и делиться им. Но без настоящего знания инструментов и того, что скрывается за ними, как я могу нарисовать сетку, или разработать четкую систему типов, или оптимизировать графику для веба? То же самое относится и к JavaScript. Без понимания работы циклов, умения объявлять переменные, или понимания области видимости, мы не будем писать код лучше, чем пишем его сейчас. Мы не хотим соглашаться на что-то меньшее — это, все-таки, наше ремесло.\n\nЧем больше JavaScript влияет на Вас, тем яснее он для Вас становится. Такие слова как замыкания, объекты, и методы, сейчас могут казаться непонятными, но эта книга поможет этим терминам стать яснее. Я хочу чтобы перед чтением этой книги Вы сохранили эти два чувства в своей памяти: чувство до, и чувство после того, как что-нибудь изучите. Это может показаться сложным, но Вы ведь взяли эту книгу чтобы начать удивительное путешествие для оттачивания своих знаний. *Начните и Совершенствуйтесь* Ваша отправная точка в понимании программирования. Наслаждайтесь свечением лампы!\n\nДженн Лукас<br>\n[jennlukas.com](http://jennlukas.com/), [@jennlukas](https://twitter.com/jennlukas)<br>\nFront-end консультант\n"
  },
  {
    "path": "up & going/toc.md",
    "content": "# Вы не знаете JS: Начните и Совершенствуйтесь\n\n## Содержание\n\n* Предисловие\n* Введение\n* Глава 1: Введение в программирование\n\t* Код\n\t* Попробуйте сами\n\t* Операторы\n\t* Значения и типы\n\t* Комментарии в коде\n\t* Переменные\n\t* Блоки\n\t* Условные операторы\n\t* Циклы\n\t* Функции\n\t* Практика\n* Глава 2: Введение в JavaScript\n\t* Значения и типы\n\t* Переменные\n\t* Условные операторы\n\t* Строгий режим\n\t* Функции как значения\n\t* Ключевое слово `this`\n\t* Прототипы\n\t* Старый и новый\n\t* Не-JavaScript\n* Глава 3: Введение YDKJS\n\t* Область видимости и замыкания\n\t* this и прототипы объектов\n\t* Типы и синтаксис\n\t* Асинхронность и производительность\n\t* ES6 и за его пределами\n* Приложение А: Благодарности!\n"
  }
]