├── FEEDBACK.md ├── README.md └── docs ├── README.md ├── new-features ├── README.md ├── array-methods │ └── README.md ├── generators │ └── README.md ├── internationalization │ └── README.md ├── iterators │ └── README.md ├── module │ └── README.md └── promise │ └── README.md ├── syntax-sugar ├── README.md ├── arrow-functions │ └── README.md ├── classes │ └── README.md ├── decorators │ └── README.md ├── exponentation │ └── README.md ├── fn-parameters │ └── README.md ├── object-destructering │ └── README.md ├── object-literals │ └── README.md ├── pipeline │ └── README.md ├── spread │ └── README.md ├── template-strings │ └── README.md └── variables │ ├── README.md │ ├── const │ └── README.md │ └── let │ └── README.md └── transpiling └── README.md /FEEDBACK.md: -------------------------------------------------------------------------------- 1 | # Обратная связь 2 | 3 | Вы можете как открыть `issue` или `pull request` для обсуждения какой-либо проблемы или недопонимания, 4 | так и лично связаться со мной по следующим каналам связи: 5 | 6 | — [E-mail](mailto:ya@Tamik.ru) 7 | — [Telegram](https://t.me/Tamik) 8 | — [Facebook](https://fb.com/tamik.lokyaev) 9 | — [VK](https://vk.com/yatamik) 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Новые возможности JavaScript 2 | 3 | Всё имеет тенденцию устаревать, и стандарты JavaScript не исключение. 4 | Каждый год международный комитет TC-391 рассматривает и принимает 5 | стандарты ECMAScript, которые могут расширить функциональность языка или 6 | добавить новый синтаксический сахар. 7 | Данный материал поможет вам ознакомиться с новыми возможностями, появившихся 8 | в JavaScript за последние годы. 9 | 10 | ### [Оглавление](./docs/README.md) 11 | 12 | ### [Транспиляция](./docs/transpiling/README.md) 13 | 14 | ### [Синтаксический сахар](./docs/syntax-sugar/README.md) 15 | 16 | - [Новые типы переменных](./docs/syntax-sugar/variables/README.md) 17 | - [`let`](./docs/syntax-sugar/variables/let/README.md) 18 | - [`const`](./docs/syntax-sugar/variables/const/README.md) 19 | - [Классы](./docs/syntax-sugar/classes/README.md) 20 | - [Стрелочные функции и их особенности](./docs/syntax-sugar/arrow-functions/README.md) 21 | - [Параметры функции](./docs/syntax-sugar/fn-parameters/README.md) 22 | - [Деструктурирующее присваивание](./docs/syntax-sugar/object-destructering/README.md) 23 | - [Расширение объектных литералов](./docs/syntax-sugar/object-literals/README.md) 24 | - [Оператор разворота](./docs/syntax-sugar/spread/README.md) 25 | - [Оператор возведения в степень](./docs/syntax-sugar/exponentation/README.md) 26 | - [Шаблонные строки](./docs/syntax-sugar/template-strings/README.md) 27 | - [Декораторы](./docs/syntax-sugar/decorators/README.md) 28 | 29 | ### [Новая функциональность](./docs/new-features/README.md) 30 | 31 | - Цикл `for..of` 32 | - [«ES6: Цикл for .. of»](http://jsraccoon.ru/es6-for-of-loop) 33 | - [«for..of loop»](http://putaindecode.io/en/articles/js/es2015/for-of/) 34 | - Обещания 35 | - [LearnJS](https://learn.javascript.ru/promise) 36 | - [Getinstance](https://getinstance.info/articles/javascript/grokking-es6-promises-the-four-functions-you-need-to-avoid-callback-hel/) 37 | - `async`/`await` 38 | - [«Async/await: 6 причин забыть о промисах»](https://habrahabr.ru/company/ruvds/blog/326074/) 39 | - [«Async/Await explained through a clear example»](https://codeburst.io/javascript-es-2017-learn-async-await-by-example-48acc58bad65) 40 | - [Метапрограммирование](https://developer.mozilla.org/ru/docs/Web/JavaScript/Guide/Meta_programming) 41 | - [ещё о метапрограммировании](https://habrahabr.ru/post/227753/) 42 | - [Генераторы](./docs/new-features/generators/README.md) 43 | - Итераторы 44 | - [Краткое описание](./docs/new-features/iterators/README.md) 45 | - [Полное описание](https://developer.mozilla.org/ru/docs/Web/JavaScript/Guide/Iterators_and_generators) (MDN) 46 | - [Модули](./docs/new-features/module/README.md) 47 | - [Новые методы `Array`](./docs/new-features/array-methods/README.md) 48 | - Типы структур данных 49 | - [`Map`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Map) 50 | - [`WeakMap`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/WeakMap) 51 | - [`Set`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Set) 52 | - [`WeakSet`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/WeakSet) 53 | - [`Symbol`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Symbol) 54 | - [Интернационализация](./docs/new-features/internationalization/README.md) 55 | 56 | ### Дополнительные материалы и ресурсы 57 | - [Mozilla Developer Network](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference) 58 | - [«You Don't Know JS»](https://github.com/azat-io/you-dont-know-js-ru) (серия книг) 59 | - [«Exploring ES2018 and ES2019»](http://exploringjs.com/es2018-es2019/index.html) 60 | - [«JavaScript. Шаблоны»](https://www.ozon.ru/context/detail/id/6287517/) 61 | 62 | --- 63 | 64 | Материал создан для самостоятельного изучения студентам 65 | [Школы разработки интерфейсов](https://academy.yandex.ru/events/frontend) Яндекса в 2018 году. 66 | [Тамерлан Локьяев](http://Tamik.ru), [Яндекс](https://yandex.ru) © 2018. 67 | 68 | --- 69 | 70 | TC-391 — Technical Committee 39 – ECMAScript. 71 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Новые возможности JavaScript — Оглавление 2 | 3 | ## [Транспиляция](./transpiling/README.md) 4 | 5 | ## [Синтаксический сахар](./syntax-sugar/README.md) 6 | 7 | - [Новые типы переменных](./syntax-sugar/variables/README.md) 8 | - [`let`](./syntax-sugar/variables/let/README.md) 9 | - [`const`](./syntax-sugar/variables/const/README.md) 10 | - [Классы](./syntax-sugar/classes/README.md) 11 | - [Стрелочные функции и их особенности](./syntax-sugar/arrow-functions/README.md) 12 | - [Параметры функции](./syntax-sugar/fn-parameters/README.md) 13 | - [Деструктурирующее присваивание](./syntax-sugar/object-destructering/README.md) 14 | - [Расширение объектных литералов](./syntax-sugar/object-literals/README.md) 15 | - [Оператор разворота](./syntax-sugar/spread/README.md) 16 | - [Оператор возведения в степень](./syntax-sugar/exponentation/README.md) 17 | - [Шаблонные строки](./syntax-sugar/template-strings/README.md) 18 | - [Декораторы](./syntax-sugar/decorators/README.md) 19 | 20 | ## [Новая функциональность](./new-features/README.md) 21 | 22 | - Цикл `for..of` 23 | - [«Цикл for..of»](http://jsraccoon.ru/es6-for-of-loop) 24 | - [«for..of loop»](http://putaindecode.io/en/articles/js/es2015/for-of/) 25 | - [Обещания](./new-features/promise/README.md) 26 | - `async`/`await` 27 | - [«async/await: 6 причин забыть о промисах»](https://habrahabr.ru/company/ruvds/blog/326074/) 28 | - [«async/await explained through a clear example»](https://codeburst.io/javascript-es-2017-learn-async-await-by-example-48acc58bad65) 29 | - [Метапрограммирование](https://developer.mozilla.org/ru/docs/Web/JavaScript/Guide/Meta_programming) ([ещё](https://habrahabr.ru/post/227753/)) 30 | - [Генераторы](./new-features/generators/README.md) 31 | - Итераторы 32 | - [Краткое описание](./new-features/iterators/README.md) 33 | - [Полное описание](https://developer.mozilla.org/ru/docs/Web/JavaScript/Guide/Iterators_and_generators) (MDN) 34 | - [Модули](./new-features/module/README.md) 35 | - [Новые методы `Array`](./new-features/array-methods/README.md) 36 | - Типы структур данных 37 | - [`Map`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Map) 38 | - [`WeakMap`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/WeakMap) 39 | - [`Set`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Set) 40 | - [`WeakSet`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/WeakSet) 41 | - [`Symbol`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Symbol) 42 | - [Интернационализация](./new-features/internationalization/README.md) 43 | -------------------------------------------------------------------------------- /docs/new-features/README.md: -------------------------------------------------------------------------------- 1 | # Новые возможности JavaScript — Новая функциональность 2 | 3 | #### [Оглавление](../README.md) 4 | 5 | - Цикл `for..of` 6 | - [«Цикл for..of»](http://jsraccoon.ru/es6-for-of-loop) 7 | - [«for..of loop»](http://putaindecode.io/en/articles/js/es2015/for-of/) 8 | - Обещания 9 | - [LearnJS](https://learn.javascript.ru/promise) 10 | - [Getinstance](https://getinstance.info/articles/javascript/grokking-es6-promises-the-four-functions-you-need-to-avoid-callback-hel/) 11 | - `async`/`await` 12 | - [«async/await: 6 причин забыть о промисах»](https://habrahabr.ru/company/ruvds/blog/326074/) 13 | - [«async/await explained through a clear example»](https://codeburst.io/javascript-es-2017-learn-async-await-by-example-48acc58bad65) 14 | - [Метапрограммирование](https://developer.mozilla.org/ru/docs/Web/JavaScript/Guide/Meta_programming) ([ещё](https://habrahabr.ru/post/227753/)) 15 | - [Генераторы](./generators/README.md) 16 | - Итераторы 17 | - [Краткое описание](./iterators/README.md) 18 | - [Подробное описание](https://developer.mozilla.org/ru/docs/Web/JavaScript/Guide/Iterators_and_generators) (MDN) 19 | - [Модули](./module/README.md) 20 | - [Новые методы `Array`](./array-methods/README.md) 21 | - Типы структур данных 22 | - [`Map`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Map) 23 | - [`WeakMap`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/WeakMap) 24 | - [`Set`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Set) 25 | - [`WeakSet`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/WeakSet) 26 | - [`Symbol`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Symbol) 27 | - [Интернационализация](./internationalization/README.md) 28 | -------------------------------------------------------------------------------- /docs/new-features/array-methods/README.md: -------------------------------------------------------------------------------- 1 | # Новые возможности JavaScript — Новые методы `Array` 2 | 3 | #### [Оглавление](../../README.md) 4 | 5 | ### `Array.includes` 6 | 7 | В ECMAScript 5 для поиска требуемого элемента в массиве приходилось использовать 8 | метод `Array.indexOf` или `Array.some` (при этом мало кто знает о методах `Array.some`/`Array.every`). 9 | 10 | Вот как это выглядело: 11 | 12 | ```javascript 13 | // ECMAScript 5 14 | var array = [1, 2, 3, 4, 5]; 15 | var searchElement = 5; 16 | 17 | console.log(array.indexOf(searchElement) !== -1); 18 | // Ожидаемый результат: true 19 | ``` 20 | 21 | ```javascript 22 | // ECMAScript 5 23 | var array = [1, 2, 3, 4, 5]; 24 | var searchElement = 5; 25 | 26 | console.log(array.some(item => item === searchElement)); 27 | // Ожидаемый результат: true 28 | ``` 29 | 30 | Однако в ECMAScript 7 появился метод `Array.includes`. В него достаточно передать искомый 31 | элемент, и метод вернёт `boolean` значение. В отличие от предыдущих двух методов теперь 32 | сравнивать текущий элемент массива с искомым не надо. 33 | При этом стоит отметить, что алгоритмическая сложность осталась прежней `O(n)`. 34 | 35 | ```javascript 36 | // ECMAScript 7 37 | const array = [1, 2, 3, 4, 5]; 38 | const searchElement = 5; 39 | 40 | console.log(array.includes(searchElement)); 41 | // Ожидаемый результат: true 42 | ``` 43 | 44 | ### `Array.find` 45 | 46 | Метод `Array.find` производит поиск искомого элемента по массиву, и возвращает первое значение, 47 | которое соответствует заданному условию в функции обратного вызова. 48 | 49 | ```javascript 50 | // ECMAScript 6 51 | const array = [0, 5, 10]; 52 | 53 | console.log(array.find(item => item > 1)); 54 | // Ожидаемый результат: 5 55 | ``` 56 | 57 | ### `Array.findIndex` 58 | 59 | Метод `Array.findIndex` работает таким же образом, как и `find`, но вместо значения искомого 60 | элемента, соответствующему условию в функции обратного вызова, возвращает индекс 61 | данного элемента. 62 | 63 | ```javascript 64 | // ECMAScript 6 65 | const array = [0, 5, 10]; 66 | 67 | console.log(array.findIndex(item => item > 1)); 68 | // Ожидаемый результат: 1 69 | ``` 70 | 71 | ### `Array.fill` 72 | 73 | Метод `Array.fill` позволяет заполнить массив заданным значением. 74 | 75 | ```javascript 76 | // ECMAScript 6 77 | const array = [1, 2, 3]; 78 | 79 | console.log(array.fill(5)); 80 | // Ожидаемый результат: [5, 5, 5] 81 | ``` 82 | 83 | ```javascript 84 | // ECMAScript 6 85 | console.log(new Array(3).fill(5)); 86 | // Ожидаемый результат: [5, 5, 5] 87 | ``` 88 | 89 | При этом `fill` принимает 2 дополнительных аргумента: индекс позиций начала и конца 90 | заполнения массива. 91 | 92 | ```javascript 93 | // ECMAScript 6 94 | const array = [0, 2, 4, 6, 8]; 95 | 96 | console.log(array.fill(10, 1, 3)); 97 | // Ожидаемый результат: [0, 10, 10, 10, 8] 98 | ``` 99 | 100 | ### `Array.from` 101 | 102 | Метод `Array.from` создаёт новый экземпляр массива `Array` из: 103 | 104 | - «Псевдомассива», имеющего свойство `length` и индексированные элементы. 105 | Например, результат поиска по DOM методом `document.getElementsByClassName()`; 106 | - Интерируемых объектов, содержимое которых можно получить по одному элементу за раз. 107 | Массивы являются итерируемыми, так же как и новые структуры данных `Map` и `Set`. 108 | 109 | ```javascript 110 | // ECMAScript 6 111 | const list = document.querySelectorAll('.className'); 112 | 113 | Array.from(list).forEach(item => console.log(item)); 114 | ``` 115 | 116 | ```javascript 117 | function Fn() { 118 | return Array.from(arguments); 119 | } 120 | 121 | console.log(Fn('one', 'two', 3, 4, 5)); 122 | // Ожидаемый результат: ["one", "two", 3, 4, 5] 123 | ``` 124 | 125 | Вот так, например, можно создать массив со значениями элементов, соответствующих 126 | индексу: 127 | 128 | ```javascript 129 | // ECMAScript 6 130 | const array = Array.from(new Array(5), (value, index) => index); 131 | 132 | console.log(array); 133 | // Ожидаемый результат: [0, 1, 2, 3, 4] 134 | ``` 135 | 136 | ### `Array.of` 137 | 138 | Метод `Array.of` создаёт новый экземпляр массива `Array` из произвольного числа аргументов, 139 | вне зависимости от числа или типа аргумента. 140 | 141 | ```javascript 142 | // ECMAScript 6 143 | const array = [1, 2, 3, 4, 5]; 144 | 145 | console.log(Array.of(1)); 146 | // Ожидаемый результат: [1] 147 | console.log(Array.of(1, 2, 3)); 148 | // Ожидаемый результат: [1, 2, 3] 149 | console.log(Array.of(array)); 150 | // Ожидаемый результат: [[1, 2, 3, 4, 5]] 151 | console.log(Array.of(...array)); 152 | // Ожидаемый результат: [1, 2, 3, 4, 5] 153 | ``` 154 | 155 | --- 156 | 157 | Следующие методы помогают в повторении массивов: 158 | 159 | - `Array.entries` 160 | - `Array.keys` 161 | - `Array.values` 162 | 163 | Результатом каждого из вышеупомянутых методов является последовательность значений, 164 | но они не возвращаются как массив; они раскрываются один за другим через [итератор](../iterators/README.md). 165 | 166 | ```javascript 167 | // ECMAScript 6 168 | const array = ['a', 'b', 'c']; 169 | 170 | console.log(array.entries()); 171 | // Ожидаемый результат: [[0, "a"], [1, "b"], [2, "c"]] 172 | console.log(array.keys()); 173 | // Ожидаемый результат: [0, 1, 2] 174 | console.log(array.values()); 175 | // Ожидаемый результат: ["a", "b", "c"] 176 | ``` 177 | -------------------------------------------------------------------------------- /docs/new-features/generators/README.md: -------------------------------------------------------------------------------- 1 | # Новые возможности JavaScript — Генераторы 2 | 3 | #### [Оглавление](../../README.md) 4 | 5 | Генераторы — новый вид функций в современном JavaScript, который был добавлен 6 | в ECMAScript 6. Отличаются они от обычных функций тем, что могу приостанавливать 7 | своё выполнение, возвращать промежуточный результат и далее возобновлять его 8 | позже, в произвольный момент времени. 9 | 10 | Для объявления генератора используется новая синтаксическая конструкция: 11 | `function* ()`, — её называют «функция-генератор». 12 | 13 | ```javascript 14 | // ECMAScript 6 15 | function* createRequest(url) { 16 | try { 17 | let request = yield fetch(url); 18 | let response = yield request.text(); 19 | 20 | return JSON.parse(response); 21 | } catch(error) { 22 | throw new Error(`Error: ${error.stack}`); 23 | } 24 | } 25 | ``` 26 | 27 | Основным методом генератора является `next()`. При вызове он возобновляет выполнение 28 | кода до ближайшего ключевого слова `yield`. По достижении `yield` выполнение 29 | приостанавливается, а значение — возвращается во внешний код: 30 | 31 | ```javascript 32 | // ECMAScript 6 33 | function* sequence() { 34 | yield 'one'; 35 | yield 'two'; 36 | return 'three'; 37 | } 38 | 39 | let generator = sequence(); 40 | 41 | let step = generator.next(); 42 | 43 | console.log(step); 44 | // Ожидаемый результат: {value: "one", done: false} 45 | 46 | let secondStep = generator.next(); 47 | 48 | console.log(secondStep); 49 | // Ожидаемый результат: {value: "two", done: false} 50 | 51 | let thirdStep = generator.next(); 52 | 53 | console.log(thirdStep); 54 | // Ожидаемый результат: {value: "three", done: true} 55 | ``` 56 | 57 | Функции-генераторы имеют 2 отличия от обычных функций: 58 | - Обычные функции начинаются с `function`, функции-генераторы начинаются с `function*`; 59 | - Внутри функции-генератора есть ключевое слово `yield` с синтаксисом, похожим на `return`. 60 | Отличие в том, что функция (в том числе функция-генератор) может вернуть значение только 61 | один раз, но отдать значение функция-генератор может любое количество раз. Выражение `yield` 62 | приостанавливает выполнение генератора, так что его можно позже обновить. 63 | 64 | В этом и есть самая большая разница между обычными функциями и функциями-генераторами. 65 | Обычные функции не могут поставить себя на паузу, а функции-генераторы могут. 66 | 67 | Вызов генератора выглядит так же как и обычной функции. Но после того, как вы вызовете 68 | генератор, он ещё не начнёт выполняться. Вместо этого он вернёт приостановленный объект 69 | `Generator`. Вы можете считать, что объект `Generator` — это вызов функции, замороженный 70 | во времени. Если точнее, он заморожен прямо в самом начале, функции-генератора, перед первой 71 | строчкой кода. 72 | 73 | Каждый раз, когда вызывается метод `next()` у объекта `Generator`, вызов функции 74 | «оттаивает» и выполняется, пока не достигнет следующего выражения `yield`. 75 | 76 | Вот почему в примере выше после вызовов метода `next()` мы всякий раз получали новое 77 | строковое значение. Эти значения производятся выражениями `yield` в теле функции. 78 | 79 | При последнем вызове `next()` мы, наконец, достигли конца функции-генератора, 80 | так что поле `done` результата стало равно `true`. 81 | 82 | Стоит отметить, что генераторы не являются потоками выполнения. В языках с потоками 83 | различные куски кода могут выполняться одновременно, обычно приводя к состояниям 84 | гонки, недетерменированности и страстно желанному приросту производительности. 85 | Генераторы вообще на это не похожи. Когда генератор выполняется, он работает в том 86 | же потоке, что и код его вызвавший. Порядок выполнения последователен и строго 87 | определён, и нет никакой параллельности. В отличие от системных потоков, генератор 88 | останавливается только на тех местах, где в коде есть `yield`. 89 | -------------------------------------------------------------------------------- /docs/new-features/internationalization/README.md: -------------------------------------------------------------------------------- 1 | # Новые возможности JavaScript — Интернационализация 2 | 3 | #### [Оглавление](../../README.md) 4 | 5 | Интернационализация — это задача, которую, в большинстве случаев, решить непросто, 6 | но радует то, что в JavaScript имеется API интернационализации, хорошо 7 | поддерживаемое большинством браузеров. 8 | 9 | Примеры: 10 | 11 | ## Числовой формат 12 | 13 | ```javascript 14 | // ECMAScript 6 15 | const i18nEN = new Intl.NumberFormat("en-US"); 16 | const i18nDE = new Intl.NumberFormat("de-DE"); 17 | const i18nRU = new Intl.NumberFormat("ru-RU"); 18 | 19 | console.log(i18nEN.format(1234567.89)); 20 | // Ожидаемый результат: "1,234,567.89" 21 | console.log(i18nDE.format(1234567.89)); 22 | // Ожидаемый результат: "1.234.567,89" 23 | console.log(i18nRU.format(1234567.89)); 24 | // Ожидаемый результат: "1 234 567,89" 25 | ``` 26 | 27 | ## Денежный формат 28 | 29 | ```javascript 30 | // ECMAScript 6 31 | const i18nUSD = new Intl.NumberFormat("en-US", { 32 | style: "currency", 33 | currency: "USD", 34 | }); 35 | const i18nEUR = new Intl.NumberFormat("de-DE", { 36 | style: "currency", 37 | currency: "EUR", 38 | }); 39 | const i18nRUR = new Intl.NumberFormat("ru-RU", { 40 | style: "currency", 41 | currency: "RUR", 42 | }); 43 | 44 | console.log(i18nUSD.format(100200300.40)); 45 | // Ожидаемый результат: "$100,200,300.40" 46 | console.log(i18nEUR.format(100200300.40)); 47 | // Ожидаемый результат: "100.200.300,40 €" 48 | console.log(i18nRUR.format(100200300.40)); 49 | // Ожидаемый результат: "100 200 300,40 р." 50 | ``` 51 | 52 | ## Формат даты 53 | 54 | ```javascript 55 | // ECMAScript 6 56 | const i18nEN = new Intl.DateTimeFormat("en-US"); 57 | const i18nDE = new Intl.DateTimeFormat("de-DE"); 58 | const i18nRU = new Intl.DateTimeFormat("ru-RU"); 59 | 60 | console.log(i18nEN.format(new Date("2018-04-05"))); 61 | // Ожидаемый результат: "4/5/2018" 62 | console.log(i18nDE.format(new Date("2018-04-05"))); 63 | // Ожидаемый результат: "5.4.2018" 64 | console.log(i18nRU.format(new Date("2018-04-05"))); 65 | // Ожидаемый результат: "05.04.2018" 66 | ``` 67 | 68 | Подробнее на [learn.javascript.ru](https://learn.javascript.ru/intl). 69 | -------------------------------------------------------------------------------- /docs/new-features/iterators/README.md: -------------------------------------------------------------------------------- 1 | # Новые возможности JavaScript — Итераторы 2 | 3 | #### [Оглавление](../../README.md) 4 | 5 | В ECMAScript 6 была добавлена новая концепция «итерируемых» объектов, 6 | т.н. итераторов. 7 | Итерируемые или, иными словами, «перебираемые» объекты – это те, 8 | содержимое которых можно перебрать в цикле. 9 | 10 | Для перебора таких объектов добавлен новый синтаксис цикла: [`for..of`](../for-of/README.md). 11 | 12 | ```javascript 13 | // ECMAScript 6 14 | const arr = [1, 2, 3]; 15 | 16 | for (let value of arr) { 17 | console.log(value); 18 | } 19 | // Ожидаемый результат: 1 -> 2 -> 3 20 | ``` 21 | 22 | Итераторы – расширяющая понятие «массив» концепция, которая пронизывает 23 | современный стандарт JavaScript сверху донизу. 24 | 25 | Вот как выглядит простой итератор изнутри: 26 | 27 | ```javascript 28 | // ECMAScript 6 29 | const iterator = { 30 | [Symbol.iterator]: function() { 31 | return this; 32 | }, 33 | 34 | next: function() { 35 | return {value: 0, done: false}; 36 | }, 37 | }; 38 | ``` 39 | 40 | Цикл `for..of` начинается с вызова метода `[Symbol.iterator]()` на коллекции. 41 | Он возвращает объект-итератор. Итератором может быть любой объект с методом 42 | `next()`, и цикл `for..of` будет вызывать этот метод раз за разом, по-одному 43 | за один проход цикла. 44 | 45 | Всякий раз, как метод `next()` вызывается, он возвращает один и тот же результат, 46 | сообщая циклу `for..of`, что: итерирование ещё не закончено, следующее значение — 0. 47 | Это означает, что `for (value of iterator) {}` будет бесконечным циклом. 48 | Разумеется, типичный итератор не будет таким тривиальным. 49 | 50 | Практически везде, где нужен перебор, он осуществляется через итераторы. Это включает 51 | в себя не только строки, массивы, но и вызов функции с оператором `Spread` `f(...args)`, 52 | и многое другое. 53 | 54 | В отличие от массивов, перебираемые объекты могут не иметь «длины» `length`. 55 | 56 | Более подробно узнать про итераторы можно на [MDN](https://developer.mozilla.org/ru/docs/Web/JavaScript/Guide/Iterators_and_generators). 57 | -------------------------------------------------------------------------------- /docs/new-features/module/README.md: -------------------------------------------------------------------------------- 1 | # Новые возможности JavaScript — Модули 2 | 3 | #### [Оглавление](../../README.md) 4 | 5 | Целью модулей ECMAScript 6 было создание формата, удобного как для пользователей 6 | CommonJS, так и для пользователей AMD. В связи с этим они имеют такой же компактный 7 | синтаксис, как и модули CommonJS. Но с другой стороны, они не такие динамичные. 8 | 9 | Это даёт два основных преимущества: 10 | - На этапе компиляции можно обнаружить ошибки, если импортировано что-то, что не 11 | было предварительно экспортировано; 12 | - Можно легко осуществить асинхронную загрузку модулей ECMAScript 6. 13 | 14 | ### Импорт 15 | 16 | Ключевое слово `import`. Путь до файла указывается относительно директории, в которой 17 | лежит файл, импортирующий другой модуль. Расширение опускается. 18 | 19 | ```javascript 20 | // ECMAScript 6 21 | import {APP_VERSION} from './path/to/module'; 22 | 23 | console.log(APP_VERSION); 24 | // Ожидаемый результат: 1.0 25 | ``` 26 | 27 | Также при импорте можно заменить название переменной на иное: 28 | 29 | ```javascript 30 | // ECMAScript 6 31 | import {APP_VERSION as version} from './path/to/module'; 32 | 33 | console.log(version); 34 | // Ожидаемый результат: 1.0 35 | ``` 36 | 37 | При надобности импортировать все сущности из одного модуля, можно воспользоваться 38 | следующей конструкцией: 39 | 40 | ```javascript 41 | // ECMAScript 6 42 | import * as module from './path/to/module'; 43 | 44 | console.log(module.APP_VERSION); 45 | // Ожидаемый результат: 1.0 46 | 47 | console.log(module.generateSequence(5)); 48 | // Ожидаемый результат: [0, 1, 2, 3, 4] 49 | ``` 50 | 51 | ### Экспорт 52 | 53 | Ключевое слово `export`, стоящее перед объявлением переменной (непосредственно 54 | перед `var`, `let`, `const`), функции или класса экспортирует их в остальные 55 | части приложения. 56 | 57 | ```javascript 58 | // ECMAScript 6 59 | const toExport = false; 60 | 61 | export const APP_VERSION = 1.0; 62 | 63 | export function generateSequence(length) { 64 | const array = []; 65 | 66 | for (let i = 0; i < length; i++) { 67 | array.push(i); 68 | } 69 | 70 | return array; 71 | } 72 | ``` 73 | 74 | Модуль выше экспортирует константу `APP_VERSION` и [функцию-генератор](../generators/README.md) `generateSequence`. 75 | 76 | ### Экспорт по умолчанию 77 | 78 | Иногда модуль экспортирует только одно значение (большой класс, например). 79 | В таком случае удобно определить это значение как экспортируемое по умолчанию: 80 | 81 | ```javascript 82 | // ECMAScript 6 83 | export default class { // анонимный класс 84 | // ... 85 | } 86 | ``` 87 | 88 | Синтаксис импорта таких значений аналогичный обычному импорту без фигурных скобок. 89 | 90 | ### Альтернатива встроенному экспорту 91 | 92 | Если не хотите вставлять `export`-ы в код, то можно всё экспортировать позже, 93 | например, в конце: 94 | 95 | ```javascript 96 | // ECMAScript 6 97 | const toExport = false; 98 | 99 | const APP_VERSION = 1.0; 100 | 101 | function generateSequence(length) { 102 | const array = []; 103 | 104 | for (let i = 0; i < length; i++) { 105 | array.push(i); 106 | } 107 | 108 | return array; 109 | } 110 | 111 | export { 112 | APP_VERSION, 113 | generateSequence, 114 | } 115 | ``` 116 | 117 | ### Изменение названия сущности при экспорте 118 | 119 | ```javascript 120 | // ECMAScript 6 121 | // ./app/moduleOne.js 122 | export const APP_CONFIG = { 123 | version: 0.1, 124 | }; 125 | 126 | export function getVersion(config) { 127 | return config.version; 128 | } 129 | 130 | // ./app/moduleTwo.js 131 | export default function connectDb() { 132 | // ... 133 | } 134 | 135 | // ./app/index.js 136 | export { 137 | APP_CONFIG as appConfig, 138 | getVersion, 139 | } from './moduleOne'; 140 | 141 | export {default as initDb} from './moduleTwo'; 142 | 143 | // ./index.js 144 | import {appConfig, getVersion, init} from './app'; 145 | ``` 146 | 147 | ### Встроенные модули 148 | 149 | Другим вариантом использования может быть предотвращение того, чтобы переменные 150 | становились глобальными. На данный момент, например, для этой цели лучше всего 151 | использовать самовызывающуюся функцию. 152 | 153 | В ECMAScript 6 вы можете использовать анонимный внутренний модуль: 154 | 155 | ```javascript 156 | // ECMAScript 6 157 | module { 158 | // ... 159 | } 160 | ``` 161 | 162 | Кроме того, что такая конструкция проще с точки зрения синтаксиса, её содержание 163 | автоматические отображается в `strict mode`. 164 | 165 | Обратите внимание, что не обязательно осуществлять импорт внутри модуля. 166 | Инструкция `import` может использоваться в контексте обычного скрипта. 167 | -------------------------------------------------------------------------------- /docs/new-features/promise/README.md: -------------------------------------------------------------------------------- 1 | # Новые возможности JavaScript — Обещания 2 | 3 | #### [Оглавление](../../README.md) 4 | 5 | Обещание (`Promise`) представляет собой конечный результат асинхронной операции. Это 6 | наполнитель, в котором находится значение успешного результата или нематерилизуемой 7 | причины отказа. 8 | 9 | Зачем использовать обещания? 10 | 11 | Обещания предоставляют простую альтернативу для выполнения, составления и управления 12 | асинхронными операциями по сравнению с традиционными подходами на основании функций 13 | обратного вызова. Они также позволяют обрабатывать асинхронно ошибки, используя 14 | подходы, которые похожи на синхронный `try/catch`. 15 | 16 | Обещание может быть в одном из трёх состояний: 17 | - `Pending` — результат обещания пока не определён, потому что асинхронная операция 18 | ещё не завершила свою работу; 19 | - `Fulfilled` — асинхронная операция завершилась, обещание имеет значение; 20 | - `Rejected` — асинхронная операция завершилась с ошибкой и обещание никогда не 21 | сбудется. В этом состоянии обещание имеет глагол _reason_, который указывает, из-за 22 | чего произошла ошибка. 23 | 24 | ```javascript 25 | // ECMAScript 5 26 | function get(url, successFn, errorFn) { 27 | var request = new XMLHttpRequest(); 28 | 29 | request.open('GET', url); 30 | 31 | request.onload = function () { 32 | if (request.status === 200) { 33 | successFn(request.data); 34 | } else { 35 | errorFn(request.statusText); 36 | } 37 | 38 | request.onerror = function () { 39 | errorFn(Error('Network error')); 40 | } 41 | } 42 | 43 | request.send(); 44 | } 45 | ``` 46 | 47 | ```javascript 48 | // ECMAScript 6 49 | function getAsync(url) { 50 | return new Promise((resolve, reject) => { 51 | const request = new XMLHttpRequest(); 52 | 53 | request.open('GET', url); 54 | 55 | request.onload = () => { 56 | if (request.status === 200) { 57 | resolve(request.data); 58 | } else { 59 | reject(Error(request.statusText)); 60 | } 61 | }; 62 | 63 | request.onerror = () => reject(Error('Network error')); 64 | 65 | request.send(); 66 | }); 67 | } 68 | ``` 69 | -------------------------------------------------------------------------------- /docs/syntax-sugar/README.md: -------------------------------------------------------------------------------- 1 | # Новые возможности JavaScript — Синтаксический сахар 2 | 3 | #### [Оглавление](../README.md) 4 | 5 | - [Новые типы переменных](./variables/README.md) 6 | - [`let`](./variables/let/README.md) 7 | - [`const`](./variables/const/README.md) 8 | - [Классы](./classes/README.md) 9 | - [Стрелочные функции и их особенности](./arrow-functions/README.md) 10 | - [Параметры функции](./fn-parameters/README.md) 11 | - [Деструктурирующее присваивание](./object-destructering/README.md) 12 | - [Расширение объектных литералов](./object-literals/README.md) 13 | - [Оператор разворота](./spread/README.md) 14 | - [Оператор возведения в степень](./exponentation/README.md) 15 | - [Шаблонные строки](./template-strings/README.md) 16 | - [Декораторы](./decorators/README.md) 17 | -------------------------------------------------------------------------------- /docs/syntax-sugar/arrow-functions/README.md: -------------------------------------------------------------------------------- 1 | # Новые возможности JavaScript — Стрелочные функции 2 | 3 | #### [Оглавление](../../README.md) 4 | 5 | В ECMAScript 6 появился новый синтаксис функций. 6 | 7 | ```javascript 8 | // ECMAScript 5 9 | var numbers = [-2, -1, 0, 1, 2]; 10 | 11 | var positiveIntegers = numbers.filter(function(number) { 12 | return number > 0; 13 | }); 14 | 15 | console.log(positiveIntegers); 16 | // Ожидаемый результат: [1, 2] 17 | ``` 18 | 19 | ```javascript 20 | // ECMAScript 6 21 | const numbers = [-2, -1, 0, 1, 2]; 22 | 23 | const positiveIntegers = numbers.filter(number => number > 0); 24 | 25 | console.log(positiveIntegers); 26 | // Ожидаемый результат: [1, 2] 27 | ``` 28 | 29 | Если вам нужна простая функция с одним аргументом, то синтаксис новых, стрелочных 30 | функций, — это просто `идентификатор => выражение`. Не нужно печатать ни `function`, 31 | ни `return`, ни круглых с фигурными скобками и точек с запятой. 32 | 33 | ```javascript 34 | // ECMAScript 5 35 | function add(a, b) { 36 | return a + b; 37 | } 38 | 39 | console.log(add(1, 2)); 40 | // Ожидаемый результат: 3 41 | ``` 42 | 43 | ```javascript 44 | // ECMAScript 6 45 | const add = (a, b) => a + b; 46 | 47 | console.log(add(1, 2)); 48 | // Ожидаемый результат: 3 49 | ``` 50 | 51 | Чтобы создать функцию с несколькими аргументами (или без аргументов, или с остаточными 52 | параметрами, или с значениями по умолчанию, или с деструктурирующим присваиваиванием), 53 | нужно просто добавить скобки вокруг списка аргументов. 54 | 55 | ```javascript 56 | // ECMAScript 5 57 | var array = [1, 2, 3, 4, 5]; 58 | 59 | var total = array.reduce(function(acc, item) { 60 | return acc + item; 61 | }, 0); 62 | 63 | console.log(total); 64 | // Ожидаемый результат: 15 65 | ``` 66 | 67 | ```javascript 68 | // ECMAScript 6 69 | const array = [1, 2, 3, 4, 5]; 70 | 71 | const total = array.reduce((acc, item) => acc + item, 0); 72 | 73 | console.log(total); 74 | // Ожидаемый результат: 15 75 | ``` 76 | 77 | Эффект при использовании [обещаний](../../new-features/promise/README.md) может быть 78 | более заметным из-за нагромождения лишних блоков с фигурными скобами. 79 | 80 | Без использования стрелочных функций: 81 | 82 | ```javascript 83 | fetch(url) 84 | .then(function(result) { 85 | return JSON.parse(result); 86 | }) 87 | .then(function(result) { 88 | console.log(result); 89 | 90 | return result; 91 | }) 92 | .then(function(result) { 93 | return processResultData(result); 94 | }); 95 | ``` 96 | 97 | С использованием стрелочных функций: 98 | 99 | ```javascript 100 | fetch(url) 101 | .then(result => JSON.parse(result)) 102 | .then(result => { 103 | console.log(result); 104 | 105 | return result; 106 | }) 107 | .then(result => processResultData(result)); 108 | ``` 109 | 110 | Также существует ещё одно отличие в поведении обычных и стрелочных функций. 111 | У стрелочных функций нет собственного значения `this`. Внутри стрелочной функции 112 | `this` наследуется из окружающего лексического окружения (т. н. «лексический 113 | контекст»). 114 | 115 | ```javascript 116 | // ECMAScript 5 117 | var person = { 118 | name: 'Tamik', 119 | showName: function() { 120 | return this.name; 121 | } 122 | }; 123 | 124 | console.log(person.showName()); 125 | // Ожидаемый результат: "Tamik" 126 | ``` 127 | 128 | ```javascript 129 | // ECMAScript 6 130 | const person = { 131 | name: 'Tamik', 132 | showName: () => this.name, 133 | }; 134 | 135 | console.log(person.showName()); 136 | // Ожидаемый результат: undefined 137 | ``` 138 | 139 | ```javascript 140 | // ECMAScript 5 141 | var person = { 142 | name: 'Tamik', 143 | showName: function() { 144 | setTimeout(function() { 145 | console.log(this.name) 146 | }, 1000); 147 | } 148 | }; 149 | 150 | person.showName(); 151 | // Ожидаемый результат: undefined 152 | ``` 153 | 154 | ```javascript 155 | // ECMAScript 6 156 | const person = { 157 | name: 'Tamik', 158 | showName: function() { 159 | setTimeout(() => console.log(this.name), 1000); 160 | }, 161 | }; 162 | 163 | person.showName(); 164 | // Ожидаемый результат: "Tamik" 165 | ``` 166 | 167 | Стрелочные функции позволяет избавиться от большинства проблем с замыканиям 168 | (в которых не всегда «прозрачен» контекст). 169 | Но запомните: обычные функции получают значение 170 | `this` автоматически, неважно, нужно оно им, или нет. Стрелочные функции 171 | получают `this` из лексического окружения, которого у функции может не оказаться. 172 | 173 | В ECMAScript 6 танцы с бубном вокруг `this` в большинстве случаев не нужны, 174 | если придерживаться этих правил: 175 | - Использовать обычные функции для методов, которые будут вызываться с 176 | использованием синтаксиса `object.method()`, таким способом эти функции получает 177 | вменяемый `this` от вызывающего кода; 178 | - Использовать стрелочные функции для всего остального. Это позволит вам избавиться 179 | от лишних проблем с замыканием, с которым часто сталкиваются в функциях обратного 180 | вызова (т.н. «callback»). 181 | 182 | Также ECMAScript 6 предоставляет более краткий способ записи методов в литералах 183 | объектов, так что код можно писать ещё проще. Подробнее об этом можно прочитать 184 | в разделе [«Расширение объектных литералов»](../object-literals/README.md). 185 | 186 | Ещё небольшие отличия стрелочных функций от обычных. 187 | 188 | Работа с массивами и объектами несколько отличается: 189 | 190 | ```javascript 191 | // ECMAScript 5 192 | function getPerson() { 193 | return { 194 | name: 'Tamik', 195 | age: 19 196 | }; 197 | } 198 | 199 | function getServices() { 200 | return ['Market', 'Maps', 'Music']; 201 | } 202 | 203 | console.log(getPerson()); 204 | // Ожидаемый результат: {name: "Tamik", age: 19} 205 | console.log(getServices()); 206 | // Ожидаемый результат: ["Market", "Maps", "Music"] 207 | ``` 208 | 209 | ```javascript 210 | // ECMAScript 6 211 | const getPerson = () => ({ 212 | name: 'Tamik', 213 | age: 19, 214 | }); 215 | 216 | const getServices = () => (['Market', 'Maps', 'Music']); 217 | 218 | console.log(getPerson()); 219 | // Ожидаемый результат: {name: "Tamik", age: 19} 220 | console.log(getServices()); 221 | // Ожидаемый результат: ["Market", "Maps", "Music"] 222 | ``` 223 | 224 | Стрелочная функция может быть IIFE1. 225 | 226 | ```javascript 227 | // ECMAScript 5 228 | (function() { 229 | // ... 230 | })(); 231 | ``` 232 | 233 | ```javascript 234 | // ECMAScript 6 235 | (() => { 236 | // ... 237 | })(); 238 | ``` 239 | 240 | Стрелочные функции не могут быть конструкторами, с ними нельзя использовать 241 | оператор `new`. 242 | 243 | ```javascript 244 | // ECMAScript 6 245 | const Person = () => console.log('Construct!'); 246 | 247 | const person = new Person(); // Ошибка! Person не является конструктором 248 | ``` 249 | 250 | Не рекомендуется использовать методы `bind`, `call` и `apply`, так как в стрелочных 251 | функциях не имеет смысла изменять контекст. Присваивание контекста при помощи `bind` 252 | создаёт новую функцию, которой присваивается заданный контекст. В итоге увеличивается 253 | потребление памяти вашего приложения. 254 | 255 | --- 256 | 257 | IIFE1 (Immediately Invoked Function Expression) — функция, которая выполняется 258 | сразу же после того как была определена. 259 | -------------------------------------------------------------------------------- /docs/syntax-sugar/classes/README.md: -------------------------------------------------------------------------------- 1 | # Новые возможности JavaScript — Классы 2 | 3 | #### [Оглавление](../../README.md) 4 | 5 | Классы в ECMAScript 6 — это синтаксический сахар, а не "честная" реализация, 6 | как в других языках. По сути, это те же конструкторы функций 7 | с использованием прототипов, только «приправленные» типичным 8 | синтаксисом в виде классов из ООП. 9 | У классов, по сравнению с обычными функциями и переменными, есть особенности. 10 | Во-первых, классы не поднимаются (т.н. «hoisting») — поэтому 11 | обращаться к классу можно только после его декларации. Во-вторых, тело класса 12 | должно содержать только методы, но не свойства. Прототип, имеющий свойства, 13 | обычно считается анти-паттерном. 14 | Также классы поддерживают геттеры и сеттеры в соответствии с 15 | [объектными литералами](../object-literals/README.md). 16 | 17 | ```javascript 18 | // ECMAScript 5 19 | function A(prop) { 20 | this.prop = prop; 21 | } 22 | 23 | A.prototype.setProp = function(prop) { 24 | this.prop = prop; 25 | } 26 | 27 | A.prototype.getProp = function() { 28 | return this.prop; 29 | } 30 | 31 | var a = new A('Example'); 32 | 33 | console.log(a.getProp()); 34 | // Ожидаемый результат: "Example" 35 | 36 | a.setProp('Another example'); 37 | 38 | console.log(a.getProp()); 39 | // Ожидаемый результат: "Another example" 40 | ``` 41 | 42 | ```javascript 43 | // ECMAScript 6 44 | class A { 45 | constructor(prop) { 46 | this.prop = prop; 47 | } 48 | 49 | setProp(prop) { 50 | this.prop = prop; 51 | } 52 | 53 | getProp() { 54 | return this.prop; 55 | } 56 | } 57 | 58 | const a = new A('Example'); 59 | 60 | console.log(a.getProp()); 61 | // Ожидаемый результат: "Example" 62 | 63 | a.setProp('Another Example'); 64 | 65 | console.log(a.getProp()); 66 | // Ожидаемый результат: "Another example" 67 | ``` 68 | 69 | --- 70 | 71 | ```javascript 72 | // ECMAScript 5 73 | function A() { 74 | // ... 75 | } 76 | 77 | function B() { 78 | // ... 79 | } 80 | 81 | A.prototype.prop = function() { 82 | return 1; 83 | }; 84 | 85 | B.prototype.anotherProp = function() { 86 | return 2; 87 | }; 88 | 89 | // Задаём наследование 90 | B.prototype.__proto__ = A.prototype; 91 | 92 | var b = new B(); 93 | 94 | console.log(b.prop()); 95 | // Ожидаемый результат: 1 96 | 97 | console.log(b.anotherProp()); 98 | // Ожидаемый результат: 2 99 | ``` 100 | 101 | Однако стоит отметить, что доступ к ссылке `__proto__` не доступен в Internet Explorer до 10 версии, 102 | и также является deprecated-способом для наследования. Для наследования в стандарте ES5 можно 103 | использовать метод `Object.create`. 104 | 105 | ```javascript 106 | // ECMAScript 5 107 | function A() { 108 | // ... 109 | } 110 | 111 | function B() { 112 | // ... 113 | } 114 | 115 | A.prototype.prop = function () { 116 | return 1; 117 | }; 118 | 119 | // Задаём наследование 120 | B.prototype = Object.create(A.prototype); 121 | 122 | B.prototype.anotherProp = function () { 123 | return 2; 124 | }; 125 | 126 | var b = new B(); 127 | 128 | console.log(b.prop()); 129 | // Ожидаемый результат: 1 130 | 131 | console.log(b.anotherProp()); 132 | // Ожидаемый результат: 2 133 | ``` 134 | 135 | ```javascript 136 | // ECMAScript 6 137 | class A { 138 | // ... 139 | 140 | prop() { 141 | return 1; 142 | } 143 | } 144 | 145 | class B extends A { 146 | // ... 147 | 148 | anotherProp() { 149 | return 2; 150 | } 151 | } 152 | 153 | const b = new B(); 154 | 155 | console.log(b.prop()); 156 | // Ожидаемый результат: 1 157 | 158 | console.log(b.anotherProp()); 159 | // Ожидаемый результат: 2 160 | ``` 161 | 162 | В классе-наследнике нужно вызвать `super()` до того, как обращаться к свойствам 163 | через `this`, иначе произойдёт ошибка. 164 | 165 | ```javascript 166 | // ECMAScript 6 167 | class A { 168 | // ... 169 | } 170 | 171 | class B extends A { 172 | constructor() { 173 | } 174 | 175 | // ... 176 | } 177 | 178 | const b = new B(); // Ошибка! 179 | ``` 180 | 181 | Также рекомендую прочитать статью [«Новые #приватные поля классов в JavaScript»](https://medium.com/devschacht/javascripts-new-private-class-fields-c60daffe361b) на Medium. 182 | -------------------------------------------------------------------------------- /docs/syntax-sugar/decorators/README.md: -------------------------------------------------------------------------------- 1 | # Новые возможности JavaScript — Декораторы 2 | 3 | #### [Оглавление](../../README.md) 4 | 5 | Декораторы в JavaScript — это синтаксический сахар, который позволяет упрощённо вызывать 6 | функции высшего порядка1. 7 | Декораторы в ECMAScript 7 могут работать с классами и дескрипторами свойств. Им автоматически 8 | передаются дескриптор свойства и целевой объект. Имея доступ к дескриптору свойства, декоратор 9 | может делать такие вещи как: добавление геттера к свойству, расширение поведения, которое могло 10 | бы выглядеть громоздко без вынесения его в декоратор, автоматическая смена контекста вызова 11 | функции на текущую сущность при первой попытке доступа к свойству. 12 | 13 | На сегодняшний день декораторы могут быть определены как для определения классов, так и для 14 | определения свойства. 15 | 16 | ```javascript 17 | // ECMAScript 7 18 | @readonly 19 | class Person { 20 | // ... 21 | 22 | getAge() { 23 | return this.age; 24 | } 25 | } 26 | ``` 27 | 28 | ```javascript 29 | // ECMAScript 7 30 | class Person { 31 | // ... 32 | 33 | @readonly // Декоратор 34 | getAge() { 35 | return this.age; 36 | } 37 | } 38 | ``` 39 | 40 | При добавлении метода к прототипу `Person` получится такое определение свойства: 41 | 42 | ```javascript 43 | // ECMAScript 5 44 | Object.defineProperty(Person.prototype, 'getAge', { 45 | value: specifiedFunction, 46 | enumerable: false, 47 | configurable: true, 48 | writable: true, 49 | }); 50 | ``` 51 | 52 | Видно, что на прототип вешается метод `getAge`. Этот метод не участвует в переборе свойств 53 | объекта, его можно изменять и он доступен для записи. Но, допустим, что потребовалось явно 54 | запретить возможность изменения реализации данного метода. 55 | Это возможно сделать при помощи декоратора `@readonly`, который, как понятно из названия, 56 | давал бы доступ к такому методу «только для чтения» и запрещал бы любые 57 | переопределения: 58 | 59 | ```javascript 60 | function readonly(target, key, descriptor) { 61 | descriptor.writable = false; 62 | 63 | return descriptor; 64 | } 65 | ``` 66 | 67 | Затем сам декоратор добавляется к методу следующим образом: 68 | 69 | ```javascript 70 | class Person { 71 | // ... 72 | 73 | @readonly 74 | getAge() { 75 | return this.age; 76 | } 77 | } 78 | ``` 79 | 80 | Теперь переопределить метод `getAge` у прототипа `Person` невозможно. 81 | 82 | ```javascript 83 | class Person { 84 | // ... 85 | 86 | @readonly 87 | getAge() { 88 | return this.age; 89 | } 90 | } 91 | 92 | const person = new Person(19); 93 | 94 | person.getAge = () => console.log(this.age); // Ошибка! Данный метод доступен только для чтения 95 | ``` 96 | 97 | Декоратор также может принимать параметры. В конечном итоге декоратор — это выражение, 98 | поэтому как `@readonly`, так и `@something(param)` должны работать. 99 | 100 | Далее, давайте посмотрим на декорирование классов. Согласно предлагаемой спецификации, 101 | декоратор принимает целевой конструктор. Например, мы могли бы создать декоратор 102 | `@internalNetworkOnly` для класса `Permissions`: 103 | 104 | Декорирование классов реализовано таким же способом. Согласно предлагаемой спецификации, 105 | декоратор принимает целевой конструктор. 106 | Рассмотрим следующий пример: 107 | 108 | ```javascript 109 | // ECMAScript 7 110 | function internalNetworkOnly(target) { 111 | target.internalNetworkOnly = true; 112 | } 113 | 114 | @internalNetworkOnly 115 | class Permissions { 116 | // ... 117 | } 118 | 119 | console.log(Permissions.internalNetworkOnly); 120 | // Ожидаемый результат: true 121 | ``` 122 | 123 | Также можно дать возможность принимать декоратору параметры, тем самым превратив его 124 | в фабричный метод: 125 | 126 | ```javascript 127 | // ECMAScript 7 128 | const params = { 129 | internalNetworkOnly: false, 130 | accessLevel: 0, 131 | }; 132 | 133 | function setNetworkParams({internalNetworkOnly, accessLevel}) { 134 | return function(target) { 135 | target.internalNetworkOnly = internalNetworkOnly; 136 | target.accessLevel = accessLevel; 137 | } 138 | } 139 | 140 | @setNetworkParams(params) 141 | class Permissions { 142 | // ... 143 | } 144 | 145 | console.log(Permissions.internalNetworkOnly); 146 | // Ожидаемый результат: true 147 | ``` 148 | 149 | --- 150 | 151 | Функция высшего порядка1 — это функция, которая может принимать другую функцию в качестве 152 | аргумента или возвращать другую функцию в качестве результата. 153 | -------------------------------------------------------------------------------- /docs/syntax-sugar/exponentation/README.md: -------------------------------------------------------------------------------- 1 | # Новые возможности JavaScript — Оператор возведения в степень 2 | 3 | #### [Оглавление](../../README.md) 4 | 5 | В ECMAScript 7 появился оператор возведения в степень. 6 | 7 | `**` — это инфиксный оператор для возведения в степень. 8 | 9 | ```javascript 10 | // ECMAScript 5 11 | Math.pow(x, y); 12 | ``` 13 | 14 | вернёт тот же результат, что и выражение `x ** y` 15 | 16 | Примеры использования: 17 | 18 | ```javascript 19 | // ECMAScript 7 20 | const squared = 3 ** 2; 21 | 22 | console.log(squared); 23 | // Ожидаемый результат: 9 24 | ``` 25 | 26 | ```javascript 27 | // ECMAScript 7 28 | let squared = 3; 29 | 30 | squared **= 2; 31 | 32 | console.log(squared); 33 | // Ожидаемый результат: 9 34 | ``` 35 | -------------------------------------------------------------------------------- /docs/syntax-sugar/fn-parameters/README.md: -------------------------------------------------------------------------------- 1 | # Новые возможности JavaScript — Параметры функции 2 | 3 | #### [Оглавление](../../README.md) 4 | 5 | Начиная с ECMAScript 6 появилась возможность использовать параметры по умолчанию 6 | и остаточные параметры у функций. 7 | 8 | ## Параметры по умолчанию 9 | 10 | Зачастую функции не нужно, чтобы все её параметры передавались ей явным образом, и 11 | есть какие-то значения по умолчанию, которые используются вместо тех параметров, 12 | которые не были переданы. В JavaScript всегда существовала не очень гибкая разновидность 13 | параметров по умолчанию — параметры, для которых значение не передано, равны `undefined`. 14 | В ECMAScript 6 появилась возможность задавать для параметров функции произвольные значения 15 | по умолчанию. 16 | 17 | ```javascript 18 | // ECMAScript 5 19 | function greet(name) { 20 | if (!name) { 21 | return `Hello, guest.`; 22 | } 23 | 24 | return `Hello, ${name}.`; 25 | } 26 | 27 | console.log(greet()); 28 | // Ожидаемый результат: "Hello, guest." 29 | 30 | console.log(greet('John')); 31 | // Ожидаемый результат: "Hello, John." 32 | 33 | console.log(greet(undefined)); 34 | // Ожидаемый результат: "Hello, guest." 35 | ``` 36 | 37 | Если в качестве одного из аргументов не было передано значение, то можно задать значение 38 | по умолчанию у данного аргумента. Это позволяет избавиться от проверок внутри функции. 39 | 40 | ```javascript 41 | // ECMAScript 6 42 | function greet(name = 'guest') { 43 | return `Hello, ${name}.`; 44 | } 45 | 46 | console.log(greet()); 47 | // Ожидаемый результат: "Hello, guest." 48 | 49 | console.log(greet('John')); 50 | // Ожидаемый результат: "Hello, John." 51 | 52 | console.log(greet(undefined)); 53 | // Ожидаемый результат: "Hello, guest." 54 | ``` 55 | 56 | Существует несколько особенностей, связанных с параметрами по умолчанию: 57 | - В отличие от других языков программирования, например, Python, выражения для определения 58 | значений по умолчанию вычисляются в момент вызовы функции, слева направо. Это означает, 59 | что такие выражения могут использовать значения из параметров, заполненных перед ними; 60 | - Если функции передано `undefined`, то это считается эквивалентным тому, что вообще 61 | ничего не передано; 62 | - У параметра, для которого не указано значение по умолчанию, оно неявно равно `undefined`. 63 | 64 | ## Остаточные параметры 65 | 66 | При создании API часто приходится писать вариадические1 функции. К примеру, метод 67 | `String#concat` может принимать любое количество строковых аргументов. 68 | ECMAScript 6 предоставляет новый способ писать вариадические функции: при помощи 69 | остаточных параметров. 70 | 71 | ```javascript 72 | // ECMAScript 5 73 | var array = []; 74 | 75 | function containsAll(arr) { 76 | for (var i = 0; i < arguments.length; i++) { 77 | var value = arguments[i]; 78 | 79 | if (arr.indexOf(value) === -1) { 80 | return false; 81 | } 82 | } 83 | 84 | return true; 85 | } 86 | ``` 87 | 88 | В такой реализации используется объект `arguments` — массивоподобный объект (т.н. «псевдомассив»), 89 | содержащий все параметры, переданные функции. Этот код определённо делает то, что 90 | нужно, но его читаемость оставляет желать лучшего. 91 | В сигнатуре функции указан только один параметр, `arr`, поэтому с первого 92 | взгляда непонятно, что эта функция на самом деле может принимать сколько угодно аргументов. 93 | Вдобавок следует быть осторожными и не забывать, что начинать перебирать `arguments` 94 | следует со смещения 1, а не 0, потому что `arguments[0]` соответствует объявленному 95 | параметру `arr`. Если когда-нибудь потребуется добавить ещё один параметр перед или после 96 | `arr`, нужно будет обновить цикл `for`. 97 | Остаточные параметры призваны обходить оба этих затруднения. Вот как выглядит 98 | реализация этой же функции на ECMAScript 6, с использованием остаточного параметра: 99 | 100 | ```javascript 101 | // ECMAScript 6 102 | const array = []; 103 | 104 | function containsAll(arr, ...values) { 105 | for (let value of values) { 106 | if (!arr.includes(value)) return false; 107 | } 108 | 109 | return true; 110 | } 111 | ``` 112 | 113 | Многоточие перед `values` означает, что это остаточный параметр. Все остальные 114 | переданные параметры собираются в массив, и кладутся в аргумент `values`. Далее 115 | выполнение функции продолжается как обычно. 116 | 117 | Только последний параметр функции может быть помечен как остаточный. При вызове 118 | параметры функции перед остаточным параметром заполняются как обычно. Все 119 | «дополнительные» аргументы помещаются в массив и присваиваются 120 | остаточному параметру. Если дополнительных аргументов нет, остаточный параметр будет 121 | просто пустым массивом, он никогда не может быть равным `undefined`. 122 | 123 | ```javascript 124 | // ECMAScript 6 125 | function sum(...values) { 126 | return values.reduce((acc, item) => acc + item, 0); 127 | } 128 | 129 | console.log(sum(1, 2, 3, 4, 5)); 130 | // Ожидаемый результат: 15 131 | ``` 132 | 133 | --- 134 | 135 | Вариадическая функция1 — функция, принимающая любое количество аргументов. 136 | -------------------------------------------------------------------------------- /docs/syntax-sugar/object-destructering/README.md: -------------------------------------------------------------------------------- 1 | # Новые возможности JavaScript — Деструктурирующее присваивание 2 | 3 | #### [Оглавление](../../README.md) 4 | 5 | Деструктурирующее присваивание позволяет присваивать переменным свойства 6 | массивов и объектов при помощи синтаксиса, который внешне напоминает литералы 7 | массивов и объектов. Этот синтаксис может быть очень сжатым, но при этом более 8 | выразительным, чем традиционный доступ к переменным. 9 | 10 | Без деструктурирующего присваивания можно обратиться к первым двум элементам 11 | массива так: 12 | 13 | ```javascript 14 | // ECMAScript 5 15 | var array = [{}, {}]; 16 | 17 | var firstElement = array[0]; 18 | var secondElement = array[1]; 19 | ``` 20 | 21 | С деструктурирующим присваиванием эквивалентный код становится более лаконичным и 22 | читаемым: 23 | 24 | ```javascript 25 | // ECMAScript 6 26 | const array = [{}, {}]; 27 | 28 | const [firstElement, secondElement] = array; 29 | ``` 30 | 31 | Также можно собрать все последние элементы массива используя [«остаточный» параметр](../fn-parameters/README.md): 32 | 33 | ```javascript 34 | // ECMAScript 6 35 | const [first, ...rest] = [1, 2, 3]; 36 | 37 | console.log(rest); 38 | // Ожидаемый результат: [2, 3] 39 | ``` 40 | 41 | Присваивание несуществующего элемента обрабатывается корректно - как `undefined`. Например, 42 | такое произойдет, если мы попытаемся обратиться к “лишнему” элементу массива: 43 | 44 | ```javascript 45 | // ECMAScript 6 46 | const array = []; 47 | 48 | const [first, ...rest] = array; 49 | 50 | console.log(first); 51 | // Ожидаемый результат: undefined 52 | 53 | console.log(rest); 54 | // Ожидаемый результат: undefined 55 | ``` 56 | 57 | Деструктурирование позволяет сопоставлять переменным различные поля объектов. 58 | Указав имя поля, а через двоеточие переменную, с которой оно сопоставляется, 59 | мы получим переменную, которой присвоено значение поля. 60 | 61 | ```javascript 62 | // ECMAScript 6 63 | const person = { 64 | name: 'Tamik', 65 | age: 19, 66 | }; 67 | 68 | const {name: firstName, age: age} = person; 69 | 70 | console.log(firstName); 71 | // Ожидаемый результат: "Tamik" 72 | 73 | console.log(age); 74 | // Ожидаемый результат: 19 75 | ``` 76 | 77 | Это очень удобно, например, если надо развести совпадающие значения внутренних полей: 78 | 79 | ```javascript 80 | // ECMAScript 6 81 | const person = { 82 | firstName: { 83 | isFirst: true, 84 | text: 'Tamik', 85 | }, 86 | secondName: { 87 | isFirst: false, 88 | text: 'Lokyaev', 89 | }, 90 | age: 19, 91 | }; 92 | 93 | const {firstName: {text: firstName}, secondName: {text: secondName}, age} = person; 94 | 95 | console.log(firstName); 96 | // Ожидаемый результат: "Tamik" 97 | 98 | console.log(secondName); 99 | // Ожидаемый результат: "Lokyaev" 100 | 101 | console.log(age); 102 | // Ожидаемый результат: 19 103 | ``` 104 | 105 | При совпадении имени свойства и переменной можно воспользоваться следующей синтаксической 106 | конструкцией: 107 | 108 | ```javascript 109 | // ECMAScript 6 110 | const person = { 111 | name: 'Tamik', 112 | age: 19, 113 | }; 114 | 115 | const = {name, age} = person; 116 | 117 | console.log(name); 118 | // Ожидаемый результат: "Tamik" 119 | 120 | console.log(age); 121 | // Ожидаемый результат: 19 122 | ``` 123 | 124 | Деструктурирование можно вкладывать и совмещать: 125 | 126 | ```javascript 127 | // ECMAScript 6 128 | const deepObj = { 129 | props: [ 130 | 'prop_id', 131 | { 132 | id: 1, 133 | } 134 | ], 135 | }; 136 | 137 | const {props: [propId, {id}]} = deepObj; 138 | 139 | console.log(propId); 140 | // Ожидаемый результат: "prop_id" 141 | 142 | console.log(id); 143 | // Ожидаемый результат: 1 144 | ``` 145 | 146 | Если при деструктурировании обратиться к свойствам, которые не определены, будет 147 | возвращено значение `undefined`. 148 | 149 | ```javascript 150 | // ECMAScript 6 151 | const obj = {}; 152 | 153 | const {prop} = obj; 154 | 155 | console.log(prop); 156 | // Ожидаемый результат: undefined 157 | ``` 158 | 159 | Также возможно указать значения по умолчанию на случай, если свойство, которое 160 | нужно деструктурировать, может быть неопределено: 161 | 162 | ```javascript 163 | // ECMAScript 6 164 | const array = []; 165 | 166 | const [missing = 'Empty cell'] = array; 167 | 168 | console.log(missing); 169 | // Ожидаемый результат: "Empty cell" 170 | ``` 171 | 172 | ### Применение 173 | 174 | Передача множества параметров в функцию всегда опасна: легко запутаться, какие 175 | параметры передавать и в каком порядке. Объект-хэш решает проблему порядка, но 176 | набор полей в этом хэше приходилось писать в комментариях функции - иначе сигнатура 177 | метода становилась совсем непрозрачной. Деструктурирование помогает решать эту 178 | проблему: структура объекта попадает в сигнатуру функции, при этом порядок 179 | аргументов по-прежнему не важен: 180 | 181 | ```javascript 182 | // ECMAScript 6 183 | function makeRequest({url, params}) { 184 | // ... 185 | } 186 | ``` 187 | 188 | При этом есть возможность задать любому свойству значение по умолчанию: 189 | 190 | ```javascript 191 | // ECMAScript 6 192 | function makeRequest({url, params = {}}) { 193 | // ... 194 | } 195 | ``` 196 | 197 | #### Использование с протоколом итераторов 198 | 199 | ECMAScript 6 также определяет протокол для работы с итераторами. При итерации `Map` 200 | происходит получение пары `[key, value]`, которое можно деструктурировать, чтобы было 201 | удобнее работать как с ключом, так и со значением: 202 | 203 | ```javascript 204 | // ECMAScript 6 205 | const map = new Map(); 206 | 207 | map.set(1, true); 208 | map.set(2, false); 209 | 210 | for (let [key, value] of map) { 211 | console.log(key, value); 212 | } 213 | // Ожидаемый результат: 1, true -> 2, false 214 | ``` 215 | 216 | Перебор только ключей: 217 | 218 | ```javascript 219 | // ECMAScript 6 220 | const map = new Map(); 221 | 222 | for (let [key] of map) { 223 | // ... 224 | } 225 | ``` 226 | 227 | Перебор только значений: 228 | 229 | ```javascript 230 | // ECMAScript 6 231 | const map = new Map(); 232 | 233 | for (let [, value] of map) { 234 | // ... 235 | } 236 | ``` 237 | -------------------------------------------------------------------------------- /docs/syntax-sugar/object-literals/README.md: -------------------------------------------------------------------------------- 1 | # Новые возможности JavaScript — Расширение объектных литералов 2 | 3 | #### [Оглавление](../../README.md) 4 | 5 | Стандарт ECMAScript 6 добавил ряд улучшений для удобства работы с объектными 6 | литералами. В первую очередь выделяются краткие свойства и возможность определения 7 | методов без привязки анонимной функции. 8 | 9 | Ранее при присваивании свойству значения одноимённой переменной приходилось писать 10 | примерно такую запись: 11 | 12 | ```javascript 13 | // ECMAScript 5 14 | var a = 5; 15 | var b = 5; 16 | 17 | var obj = { 18 | a: a, 19 | b: b 20 | }; 21 | 22 | console.log(obj); 23 | // Ожидаемый результат: {a: 5, b: 5} 24 | ``` 25 | 26 | Благодаря добавлению кратких свойств, теперь присваивание свойствам значения 27 | одноимённых переменных происходит проще: 28 | 29 | ```javascript 30 | // ECMAScript 6 31 | const a = 5; 32 | const b = 5; 33 | 34 | const obj = { 35 | a, 36 | b, 37 | }; 38 | 39 | console.log(obj); 40 | // Ожидаемый результат: {a: 5, b: 5} 41 | ``` 42 | 43 | Также при определении метода у объекта теперь не придётся присваивать значение со 44 | ссылкой на функцию: 45 | 46 | ```javascript 47 | // ECMAScript 5 48 | var obj = { 49 | prop: true, 50 | fn: function(value) { 51 | console.log(value); 52 | } 53 | } 54 | 55 | obj.fn(false); 56 | // Ожидаемый результат: false 57 | ``` 58 | 59 | Теперь можно определять методы прямо в объекте: 60 | 61 | ```javascript 62 | // ECMAScript 6 63 | const obj = { 64 | prop: true, 65 | fn(value) { 66 | console.log(value); 67 | }, 68 | }; 69 | 70 | obj.fn(false); 71 | // Ожидаемый результат: false 72 | ``` 73 | 74 | Также появилась возможность использовать вычисляемые свойства: 75 | 76 | ```javascript 77 | // ECMAScript 6 78 | const appConst = 'string'; 79 | 80 | const obj = { 81 | [appConst]: v => ({v}), 82 | }; 83 | 84 | obj[`prefix_${appConst}`] = false; 85 | 86 | console.log(obj.string('value')); 87 | // Ожидаемый результат: {v: "value"} 88 | 89 | console.log(obj.prefix_string); 90 | // Ожидаемый результат: false 91 | ``` 92 | 93 | Помимо прочего, ещё со стандарта ECMAScript 5 существуют геттеры и сеттеры, 94 | однако о их существовании знает не каждый: 95 | 96 | ```javascript 97 | // ECMAScript 5 98 | const obj = { 99 | __id: 1, 100 | get id() { 101 | return this.__id; 102 | }, 103 | set id(value) { 104 | this.__id = value; 105 | }, 106 | }; 107 | 108 | console.log(obj.id); 109 | // Ожидаемый результат: 1 110 | 111 | obj.id = 5; 112 | 113 | console.log(obj.id); 114 | // Ожидаемый результат: 5 115 | 116 | console.log(obj.__id); 117 | // Ожидаемый результат: 5 118 | ``` 119 | -------------------------------------------------------------------------------- /docs/syntax-sugar/pipeline/README.md: -------------------------------------------------------------------------------- 1 | # Новые возможности JavaScript — Оператор конвейера 2 | 3 | Оператор конвейера, на момент написания этого материала, поддерживается лишь 4 | в Firefox 58+, да и то, его нужно включать. Однако в Babel уже имеется 5 | предложение по этому поводу. 6 | Код с таким оператором выглядит как команды `bash`. 7 | 8 | ```javascript 9 | // ECMAScript 6 10 | const square = n => n * n; 11 | const increment = n => n + 1; 12 | 13 | console.log(square(increment(square(2)))); 14 | // Ожидаемый результат: 25 15 | ``` 16 | 17 | ```javascript 18 | // ECMAScript Next 19 | const square = n => n * n; 20 | const increment = n => n + 1; 21 | 22 | console.log(2 |> square |> increment |> square); 23 | // Ожидаемый результат: 25 24 | ``` 25 | 26 | ```javascript 27 | // ECMAScript 6 28 | const upperFirst = string => string[0].toUpperCase() + string.substring(1); 29 | const dotEnd = string => `${string}.`; 30 | 31 | const phrase = 'hello, world'; 32 | 33 | const result = dotEnd(upperFirst(phrase)); 34 | 35 | console.log(result); 36 | // Ожидаемый результат: "Hello, world." 37 | ``` 38 | 39 | ```javascript 40 | // ECMAScript Next 41 | const upperFirst = string => string[0].toUpperCase() + string.substring(1); 42 | const dotEnd = string => `${string}.`; 43 | 44 | const phrase = 'hello, world'; 45 | 46 | const result = phrase 47 | |> upperFirst 48 | |> dotEnd; 49 | 50 | console.log(result); 51 | // Ожидаемый результат: "Hello, world." 52 | ``` 53 | 54 | Использование с различными аргументами: 55 | 56 | Оператор пайплайна не требует каких-либо специальных правил для использования функций с 57 | множеством аргументов. 58 | 59 | ```javascript 60 | // ECMAScript 6 61 | const square = x => x * x; 62 | const pow = (x, y) => Math.pow(x ** y); 63 | 64 | const result = pow(square(2), 5); 65 | 66 | console.log(result); 67 | // Ожидаемый результат: 1024 68 | ``` 69 | 70 | ```javascript 71 | // ECMAScript Next 72 | const square = x => x * x; 73 | const pow => (x, y) => x ** y; // Оператор возведения в степень 74 | 75 | const result = 2 76 | |> square 77 | |> (basis => pow(basis, 5)); 78 | 79 | console.log(result); 80 | // Ожидаемый результат: 1024 81 | ``` 82 | 83 | Использование с `async`/`await`: 84 | 85 | ```javascript 86 | // ECMAScript 6 87 | async function f(x) { 88 | // ... 89 | } 90 | 91 | await f(x); 92 | ``` 93 | 94 | ```javascript 95 | // ECMAScript Next 96 | async function f(x) { 97 | // ... 98 | } 99 | 100 | x |> await f; 101 | ``` 102 | -------------------------------------------------------------------------------- /docs/syntax-sugar/spread/README.md: -------------------------------------------------------------------------------- 1 | # Новые возможности JavaScript — Оператор разворота 2 | 3 | #### [Оглавление](../../README.md) 4 | 5 | Оператор `Spread` (также известный как «оператор разворота») позволяет разворачивать 6 | элементы массива для передачи элементов в аргументы функции или в другой массив. 7 | 8 | Например, нужно собрать один массив из двух разных. В современном JavaScript это возможно 9 | благодаря оператору `Spread`, минуя использование метода `concat`. 10 | 11 | ```javascript 12 | // ECMAScript 5 13 | var array = [1, 2, 3]; 14 | var anotherArray = [4, 5, 6]; 15 | 16 | console.log([array, anotherArray]); 17 | // Ожидаемый результат: [[1, 2, 3], [4, 5, 6]] 18 | ``` 19 | 20 | ```javascript 21 | // ECMAScript 6 22 | const array = [1, 2, 3]; 23 | const array = [4, 5, 6]; 24 | 25 | console.log([...array, ...anotherArray]); 26 | // Ожидаемый результат: [1, 2, 3, 4, 5, 6] 27 | ``` 28 | 29 | Это так же работает и с объектами: 30 | 31 | ```javascript 32 | // ECMAScript 5 33 | var obj = { 34 | one: true, 35 | two: true, 36 | }; 37 | 38 | var anotherObj = { 39 | three: false, 40 | four: false, 41 | }; 42 | 43 | console.log({obj: obj, anotherObj: anotherObj}); 44 | // Ожидаемый результат: {obj: {one: true, two: true}, anotherObj: {three: false, four: false}} 45 | ``` 46 | 47 | ```javascript 48 | // ECMAScript 6 49 | const obj = { 50 | one: true, 51 | two: true, 52 | }; 53 | 54 | const anotherObj = { 55 | three: false, 56 | four: false, 57 | }; 58 | 59 | console.log({...obj, ...anotherObj}); 60 | // Ожидаемый результат: {one: true, two: true, three: false, four: false} 61 | ``` 62 | 63 | `Spread`-оператор также удобен для передачи массивов в качестве аргументов функции. 64 | 65 | ```javascript 66 | // ECMAScript 5 67 | var numbers = [1, 2, 3]; 68 | 69 | function add(a, b, c) { 70 | return a + b + c; 71 | } 72 | 73 | console.log(add(numbers)); 74 | // Ожидаемый результат: 1,2,3undefinedundefined 75 | ``` 76 | 77 | ```javascript 78 | // ECMAScript 6 79 | const numbers = [1, 2, 3]; 80 | 81 | const add = (a, b, c) => (a + b + c); 82 | 83 | console.log(add(...numbers)); 84 | // Ожидаемый результат: 6 85 | ``` 86 | -------------------------------------------------------------------------------- /docs/syntax-sugar/template-strings/README.md: -------------------------------------------------------------------------------- 1 | # Новые возможности JavaScript — Шаблонные строки 2 | 3 | #### [Оглавление](../../README.md) 4 | 5 | Шаблонные строки (шаблоны) являются строковыми литералами, допускающими использование выражений. 6 | 7 | В ECMAScript 5 подобную функциональность приходилось писать вот так: 8 | 9 | ```javascript 10 | // ECMAScript 5 11 | function greet(name) { 12 | return 'Hello, ' + name + '!'; 13 | } 14 | 15 | console.log(greet('John')); 16 | // Ожидаемый результат: "Hello, John!" 17 | ``` 18 | 19 | ```javascript 20 | // ECMAScript 5 21 | var protocol = 'https'; 22 | var company = 'yandex'; 23 | var domain = 'ru'; 24 | 25 | console.log('Link: ' + protocol + '://' + company + '.' + domain); 26 | // Ожидаемый результат: "Link: https://yandex.ru" 27 | ``` 28 | 29 | ```javascript 30 | // ECMAScript 5 31 | var tag = 'div'; 32 | var className = 'bem'; 33 | var children = 'Hello, world!'; 34 | 35 | function createElement(tagName, className, children) { 36 | return '<' + tagName + ' class="' + className + '">' + children + ''; 37 | } 38 | 39 | console.log(createElement(tag, className, children)); 40 | // Ожидаемый результат: "
Hello, world!
" 41 | ``` 42 | 43 | В ECMAScript 6, благодаря шаблонным строкам, всё проще: 44 | 45 | ```javascript 46 | // ECMAScript 6 47 | function greet(name) { 48 | return `Hello, ${name}!`; 49 | } 50 | 51 | console.log(greet('John')); 52 | // Ожидаемый результат: "Hello, John!" 53 | ``` 54 | 55 | ```javascript 56 | // ECMAScript 6 57 | const protocol = 'https'; 58 | const company = 'yandex'; 59 | const domain = 'ru'; 60 | 61 | console.log(`Link: ${protocol}://${company}.${domain}`); 62 | // Ожидаемый результат: "Link: https://yandex.ru" 63 | ``` 64 | 65 | Также стоит отметить, что шаблонные строки поддерживают многострочность. 66 | 67 | ```javascript 68 | // ECMAScript 6 69 | const tag = 'div'; 70 | const className = 'i-bem'; 71 | const children = 'Hello, world!'; 72 | 73 | function createElement(tagName, className, children) { 74 | return ` 75 | <${tagName} class="${className}"> 76 | ${children} 77 | 78 | `; 79 | } 80 | 81 | console.log(createElement(tag, className, children)); 82 | // Ожидаемый результат: "
Hello, world!
" 83 | ``` 84 | 85 | В выражениях можно использовать различные операции (сложение, вычитание, и т.д.) и вызовы функций. 86 | Для того, чтобы убедиться, что мы действительно складываем числа, можно использовать `parseInt`. 87 | 88 | ```javascript 89 | // ECMAScript 6 90 | function add(a, b) { 91 | return `${a} + ${b} = ${parseInt(a) + parseInt(b)}`; 92 | } 93 | 94 | console.log(add(1, '2')); 95 | // Ожидаемый результат: "1 + 2 = 3" 96 | ``` 97 | 98 | Шаблонные строки можно тегировать. Это позволяет изменять вывод шаблонов при помощи функции. 99 | Её первый аргумент будет содержать массив строковых литералов, второй и последующие содержат 100 | значения вычисленных выражений. В конце функция должна вернуть итоговую строку. 101 | 102 | ```javascript 103 | // ECMAScript 6 104 | const name = 'Tamik'; 105 | 106 | console.log(`Hello, ${name}!`); 107 | // Ожидаемый результат: "Hello, Tamik!" 108 | 109 | function upperName(literals, ...values) { 110 | return literals[0] + values[0].toUpperCase(); 111 | } 112 | 113 | console.log(upperName`Hello, ${name}!`); 114 | // Ожидаемый результат: "Hello, TAMIK!" 115 | ``` 116 | -------------------------------------------------------------------------------- /docs/syntax-sugar/variables/README.md: -------------------------------------------------------------------------------- 1 | # Новые возможности JavaScript — Типы переменных 2 | 3 | #### [Оглавление](../../README.md) 4 | 5 | ## `let` ([подробнее](./let/README.md)) 6 | Переменные типа `let` — это локальные переменные, область видимости которых равна 7 | блоку с фигурными скобками (`{...}`), в котором они объявлены. 8 | Данный тип переменной имеет 3 основных отличия от переменной типа `var`. 9 | 10 | ## `const` ([подробнее](./const/README.md)) 11 | Переменные типа `const` — это постоянные переменные. Их нельзя переопределить или 12 | объявить без присваивания значения. 13 | Данные тип переменной имеет 2 основных отличия от переменной типа `var`. 14 | -------------------------------------------------------------------------------- /docs/syntax-sugar/variables/const/README.md: -------------------------------------------------------------------------------- 1 | # Новые возможности JavaScript — `const` 2 | 3 | Переменные, объявленные с ключевым словом `const`, являются постоянными и их 4 | значение нельзя изменить в исходном коде. При определении переменной типа 5 | `const` ей нужно сразу же задавать значение, иначе произойдёт ошибка. 6 | 7 | Во многих языках, в том числе и в JavaScript, по традиции константы пишут большими 8 | буквами, чтобы отделить их от переменных и не путать. 9 | 10 | То, как мы делали это ранее: 11 | 12 | ```javascript 13 | // ECMAScript 5 14 | var COMPANY = 'Yandex'; 15 | 16 | console.log(COMPANY); 17 | // Ожидаемый результат: "Yandex" 18 | ``` 19 | 20 | И в сообществе, до появления `const`, была договорённость, что переменные, объявленные 21 | большими буквами, переопределять нельзя. 22 | Теперь всё иначе: 23 | 24 | ```javascript 25 | // ECMAScript 6 26 | const COMPANY; // Ошибка! Нельзя объявлять const без присваивания значения 27 | ``` 28 | 29 | ```javascript 30 | // ECMAScript 6 31 | const COMPANY = 'Yandex'; 32 | 33 | COMPANY = 'Яндекс'; // Ошибка! Нельзя переопределять постоянную переменную 34 | 35 | console.log(COMPANY); 36 | ``` 37 | 38 | Стоит отметить, что переменные типа `const` не поднимаются движком V8, как и `let`. 39 | Подробнее об этом можно почитать в описании переменной типа `let`. 40 | 41 | ```javascript 42 | // ECMAScript 6 43 | console.log(COMPANY); // Ошибка! Такой переменной не существует 44 | 45 | const COMPANY = 'Yandex'; 46 | ``` 47 | 48 | Однако можно изменять объект, который присвоен постоянной переменной. Дело в том, 49 | что переменная хранит не сам объект, а ссылку на него. 50 | 51 | ```javascript 52 | // ECMAScript 6 53 | const OBJ = { 54 | prop: true, 55 | }; 56 | 57 | console.log(OBJ.prop); 58 | // Ожидаемый результат: true 59 | 60 | OBJ.prop = false; 61 | 62 | console.log(OBJ.prop); 63 | // Ожидаемый результат: false 64 | ``` 65 | 66 | Это происходит из-за того, что изменяется свойство самого объекта, а не значение постоянной 67 | переменной (которая хранит ссылку на объект, а она не меняется). 68 | Тоже самое работает и с массивами. 69 | 70 | Итого: ключевое слово const объявляет константу, причём доступ к ней осуществляется по ссылке 71 | (как, впрочем, и ко всем переменным в JS). Таким образом, внутреннее состояние не примитивных 72 | объектов можно менять, даже если они константы, но не присваивать в переменную другое значение. 73 | -------------------------------------------------------------------------------- /docs/syntax-sugar/variables/let/README.md: -------------------------------------------------------------------------------- 1 | # Новые возможности JavaScript — `let` 2 | 3 | Переменные, объявленные с ключевым словом `let`, являются локальными. 4 | Они имеют 3 основных отличия от переменных типа `var`. 5 | 6 | ### 1. Переменная `let` видна только после объявления. 7 | 8 | При вызове данной переменной до её объявления произойдёт ошибка. 9 | Происходит это потому, что перед тем как выполнить код, движок JavaScript 10 | поднимает переменные типа `var` «наверх» (т.н. «hoisting»)1 11 | и присваивает им значение `undefined`. В случае с `let` такого не происходит, поэтому 12 | появляется ошибка. 13 | 14 | ```javascript 15 | // ECMAScript 5 16 | console.log(a); // undefined 17 | 18 | var a = true; 19 | ``` 20 | 21 | ```javascript 22 | // ECMAScript 6 23 | console.log(a); // Ошибка! Такой переменной не существует 24 | 25 | let a = true; 26 | ``` 27 | 28 | ### 2. Область видимости переменной `let` — блок c фигурными скобками (`{...}`) 29 | 30 | Объявленная переменная типа `let` видна только в рамках блока с фигурными скобками, в 31 | котором объявлена. 32 | 33 | В примере ниже переменная `a` объявляется на весь код, и модифицируется в `if`. 34 | 35 | ```javascript 36 | // ECMAScript 5 37 | var a = true; 38 | 39 | if (true) { 40 | var a = false; 41 | 42 | console.log(a); 43 | // Ожидаемый результат: false 44 | } 45 | 46 | console.log(a); 47 | // Ожидаемый результат: false 48 | ``` 49 | 50 | С `let` будет иначе, так как областью видимости переменной типа `let` является блок с 51 | фигурными скобками. Поэтому в примере ниже существует 2 независимые переменные `a`: 52 | одна — глобальная, вторая — в блоке `if`. 53 | 54 | ```javascript 55 | // ECMAScript 6 56 | let a = true; 57 | 58 | if (true) { 59 | let a = false; 60 | 61 | console.log(a); 62 | // Ожидаемый результат: false 63 | } 64 | 65 | console.log(a); 66 | // Ожидаемый результат: true 67 | ``` 68 | 69 | ### 3. Использование в циклах 70 | 71 | Переменная типа `var` всегда является одной на все итерации цикла и существует даже после 72 | цикла. 73 | 74 | ```javascript 75 | // ECMAScript 5 76 | for (var i = 0; i < 10; i++) { 77 | // ... 78 | } 79 | 80 | console.log(i); 81 | // Ожидаемый результат: 10 82 | ``` 83 | 84 | Иначе говоря, этот фрагмент кода можно записать вот так: 85 | 86 | ```javascript 87 | // ECMAScript 5 88 | var i; // undefined 89 | 90 | for (i = 0; i < 10; i++) { 91 | // ... 92 | } 93 | 94 | console.log(i); 95 | // Ожидаемый результат: 10 96 | ``` 97 | 98 | Переменная типа `let` работает иначе. 99 | В каждом повторении цикла существует своя независимая переменная `let`. 100 | Это, например, позволяет легко справиться с проблемами замыкания, так как при каждой 101 | итерации в замыкании будет то значение переменной, которая была на соответствующей 102 | итерации. 103 | 104 | ```javascript 105 | // ECMAScript 5 106 | function makeArray() { 107 | var arr = []; 108 | 109 | for (var i = 0; i < 10; i++) { 110 | arr.push(function () { 111 | console.log(i); // выведется номер итерации 112 | }) 113 | } 114 | 115 | return arr; 116 | } 117 | 118 | var array = makeArray(); 119 | 120 | array[0](); 121 | // Ожидаемый результат: 10 122 | array[1](); 123 | // Ожидаемый результат: 10 124 | ``` 125 | 126 | ```javascript 127 | // ECMAScript 6 128 | function makeArray() { 129 | const arr = []; 130 | 131 | for (let i = 0; i < 10; i++) { 132 | arr.push(() => console.log(i)); // выведется номер итерации 133 | } 134 | 135 | return arr; 136 | } 137 | 138 | const array = makeArray(); 139 | 140 | array[0](); 141 | // Ожидаемый результат: 0 142 | array[1](); 143 | // Ожидаемый результат: 1 144 | ``` 145 | 146 | Переменные типа `let` могут сделать работу с переменными более понятной и интуитивной, 147 | особенно для людей с опытом в других языках программирования. 148 | Переменные данного типа позволяют лучше работать с инкапсуляцией в вашем приложении. 149 | Это действительно может помочь вам предотвратить ошибки на архитектурном уровне. 150 | 151 | --- 152 | 153 | А вы реально думали, что JavaScript1 — интерпретируемый язык? :) 154 | -------------------------------------------------------------------------------- /docs/transpiling/README.md: -------------------------------------------------------------------------------- 1 | # Новые возможности JavaScript — Транспиляция 2 | 3 | #### [Оглавление](../README.md) 4 | 5 | ECMAScript 6 привнёс множество новой функциональности и синтаксического сахара в JavaScript. 6 | Всё это помогает в разработке современных веб-приложений, однако даже сейчас не каждый браузер 7 | поддерживает полностью всю функциональность, принятую в стандарте ECMAScript 6. 8 | 9 | Именно поэтому в разработке современных веб-приложений используется транспиляция1. 10 | Для транспиляции исходного кода из современного стандарта ECMAScript в стандарт ECMAScript 5, 11 | который поддерживают более-менее все современные браузеры, используют [Babel](https://babeljs.io). 12 | 13 | **Babel** состоит из двух частей: 14 | - Транспайлер, который переписывает код; 15 | - Полифиллы2, которые добавляют методы, неподдерживаемые более-менее современными браузерами. 16 | 17 | Обычно Babel работает как одна из составляющих системы сборки современных веб-приложений, 18 | и автоматически транспилирует весь код в ECMAScript 5. 19 | 20 | Установить и настроить Babel проще простого: достаточно следовать инструкции на 21 | [официальном сайте](https://babeljs.io). 22 | 23 | --- 24 | 25 | Транспиляция1 — это перевод исходного кода с одного языка на другой. 26 | 27 | Полифилл2 — это тип библиотеки, который добавляет в более-менее современные браузеры поддержку 28 | функциональности, которая в современных браузерах встроена. 29 | --------------------------------------------------------------------------------