├── README.md └── slides ├── 14 └── arrow_functions.js ├── 15 └── arrow_functions.js ├── 16 └── default_parameters.js ├── 30 └── iterators.js ├── 35 └── strings.js ├── 38 └── map_set_weakmap_weakset.js ├── 39 └── proxy.js ├── 12-13 └── block_scope.js ├── 17-18 └── rest_spread.js ├── 19-20 └── destructuring.js ├── 21-22 └── class.js ├── 23-24 └── promises.js ├── 25-27 └── generators.js ├── 28-29 └── promises_generators.js ├── 31-34 └── symbols.js └── 36-37 ├── main.js └── src └── process.js /README.md: -------------------------------------------------------------------------------- 1 | # ECMAScript 6 2 | 3 | ### Самые полезные материалы: 4 | 5 | * https://goo.gl/o8EP24 - Слайды из доклада :) 6 | * http://frontend-science.com/ Front-end Science 7 | * https://kangax.github.io/compat-table/es6/ - табличка совместимости 8 | * http://es6-features.org/ - краткие примеры по каждой фиче и сравнение их с аналогами на старом стандарте 9 | * http://es6katas.org/ - решаем свалившиеся тесты, закрепляем полученные знания :) 10 | * https://github.com/lukehoban/es6features - краткое описание фич и примеры к ним 11 | * https://github.com/paulkogel/simple-babel-webpack-template - готовый шаблон для новичков с минимальным функционалом Babel + Webpack + React 12 | * https://github.com/este/este - очень функциональный шаблон (не для новичков) 13 | * https://github.com/ericdouglas/ES6-Learning - огромная база полезных ресурсов! 14 | * http://css-live.ru/articles/obzor-es6-v-350-punktax.html - краткий обзор фич стандарта 15 | * https://egghead.io/courses/learn-es6-ecmascript-2015 - хорошие уроки, содержательный сайт 16 | * https://learn.javascript.ru/es-modern - удобный и всеми любимый учебник 17 | * http://exploringjs.com/es6/ - детальный учебник 18 | * https://www.youtube.com/watch?v=sBzRwzY7G-k видео-обзор необходимых для изучения технологий начинающему JavaScript разработчику в 2016/2017 году 19 | * https://www.youtube.com/user/learncodeacademy/playlists - хорошие видео-уроки 20 | * http://nodetuts.com/ Node туториалы 21 | * http://survivejs.com/webpack/introduction/ - книга по Webpack 22 | * https://scotch.io/tutorials - много подробных туториалов 23 | * https://www.youtube.com/channel/UCO1cgjhGzsSYb1rsB4bFe4Q - полезные небольшие видео-уроки 24 | * http://largescalejs.ru/ - книга, немного о паттернах 25 | * https://addyosmani.com/resources/essentialjsdesignpatterns/book/ - книга, чуть больше о паттернах :) 26 | * https://devmastery.com/ - рассылка только полезных материалов и тем 27 | 28 | ### Полезные материалы по теме: 29 | * http://getinstance.info/articles/javascript/5-javascript-bad-parts-that-are-fixed-in-es6/ - 5 недостатков JavaScript, исправленных в ES6 30 | * http://codeutopia.net/blog/2015/01/06/es6-what-are-the-benefits-of-the-new-features-in-practice/ - профиты от использования нового стандарта 31 | * http://jamesknelson.com/using-es6-in-the-browser-with-babel-6-and-webpack/ - использование ЕС6 в браузере с Babel & Webpack 32 | * http://developer.telerik.com/featured/hail-babel-the-transpiling-overlord/ - o Babel 33 | * https://www.twilio.com/blog/2015/08/setting-up-react-for-es6-with-webpack-and-babel-2.html - настраиваем Babel, Webpack для ES6 34 | * http://sysoev.org/es6-arrow-functions/ - о стрелочных функциях 35 | * http://exploringjs.com/es6/ch_arrow-functions.html - стрелочные функции 36 | * https://leanpub.com/understandinges6/read/#leanpub-auto-arrow-functions - стрелочные функции 37 | * http://www.2ality.com/2015/02/es6-scoping.html - блочная область видимости 38 | * https://www.sitepoint.com/joys-block-scoping-es6/ - блочная область видимости 39 | * https://blog.makushev.com/2015/12/21/es6-destructuring/ - деструктуризация 40 | * https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment - деструктуризация 41 | * https://habrahabr.ru/post/267639/ - модули 42 | * https://habrahabr.ru/company/nixsolutions/blog/261141/ - модули 43 | * http://frontender.info/es6-modules/ - модули 44 | * http://webtackles.ru/javascript/js-module-bundling/ - модули 45 | * http://frontender.info/es6-in-depth-template-strings/ - шаблонные строки 46 | * http://stackoverflow.com/questions/33898512/spread-operator-vs-rest-parameter-in-es2015-es6 - spread operator vs rest parameter 47 | * http://getinstance.info/articles/javascript/grokking-es6-promises-the-four-functions-you-need-to-avoid-callback-hel/ - Введение в ES6 Promises, или четыре функции, которые вам нужно знать 48 | * https://github.com/promises-aplus/promises-spec - стандарт Промисов/А+ 49 | * http://frontender.info/promises/ - промисы 50 | * https://ponyfoo.com/articles/es6-promises-in-depth - промисы 51 | * https://github.com/petkaantonov/bluebird - промисы на стероидах 52 | * https://github.com/kriskowal/q - промисы на стероидах 2 53 | * http://frontender.info/es6-in-depth-symbols/ - символы 54 | * http://www.2ality.com/2015/01/es6-maps-sets.html - maps, sets 55 | * https://ponyfoo.com/articles/es6-maps-in-depth - maps 56 | * http://www.2ality.com/2014/12/es6-proxies.html - proxy 57 | * https://h3manth.com/new/blog/2015/es6-reflect-api/ - reflect 58 | * https://ponyfoo.com/articles/es6-reflection-in-depth - reflect 59 | -------------------------------------------------------------------------------- /slides/12-13/block_scope.js: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | ПРОФИТЫ блочной видимости: 4 | 1. Делает использование функций в циклах тривиальным. 5 | 2. Предотвращает подъем переменных за пределы области видимости. 6 | 3. Предотвращает двойное объявление переменной в той же зоне видимости. 7 | 4. Устраняет необходимость IIFE. 8 | */ 9 | 10 | 11 | /* 12 | До введения стандарта ES6 основой всех областей видимости являлись функции. 13 | У любой функции существует своя область видимости 14 | */ 15 | 16 | var num = 10; 17 | var func = function() { 18 | var num = 20; 19 | console.log(num); // 20 20 | }; 21 | console.log(num); // 10 22 | 23 | /* 24 | До ЕS6 если нужно было реализовать блок со своей областью видимости, 25 | то использовали IIFE (иффи - выражение немедленно вызывающейся функции) 26 | */ 27 | 28 | (function() { 29 | // Переменные a и b находятся в области видимости 30 | // самовызывающейся анонимной функции и не доступны 31 | // на более высоких уровнях 32 | var a = 10; 33 | var b = 20; 34 | // Для вывода переменной в глобальную область видимости 35 | // используется подобная конструкция 36 | window.b = b; 37 | })(); 38 | console.log(a); // undefined 39 | console.log(b); // 20 40 | 41 | /* 42 | Иффи работали исключительно с функциями, а на другие блочные конструкции 43 | не действовали. 44 | Теперь появилась блочная область видимости (block scoping). 45 | Все, что нам необходимо для создания новой области видимости - фигурные скобки { }. 46 | Вместо использования оператора var, который мы использовали 47 | для объявления переменных внутренней (или глобальной) области видимости, 48 | мы можем использовать let и const для объявления блочной: 49 | */ 50 | 51 | var a = 2; 52 | { 53 | let a = 3; 54 | console.log( a ); // 3 55 | } 56 | console.log( a ); // 2 57 | 58 | /* 59 | Эти операторы тоже hoist`ятся, но не инициализируют переменные при входе 60 | в функцию, поэтому можно столкнуться с Temporary Dead Zone. 61 | Мы получим ReferenceError, который будет вызван ранним обращением к переменной, 62 | до того как она была объявлена или инициализирована. 63 | 64 | Поэтому лучше все переменные объявлять в начале блока. 65 | */ 66 | 67 | { 68 | console.log( a ); // undefined 69 | console.log( b ); // ReferenceError! 70 | 71 | var a; // резервируется имя, инициализируется как undefined; 72 | let b; // только резервируется имя. 73 | } 74 | 75 | /* 76 | Подробней о хоистинге - при использовании ключевого слова let происходит 77 | поднятие переменных (hoisting), хотя на первый взгляд может показаться 78 | что это не так. Но сам процесс поднятия реализуется совершенно другим образом: 79 | */ 80 | 81 | let b = 20; 82 | if (true) { 83 | console.log(b); // ReferenceError: b is not defined 84 | let b = 10; 85 | } 86 | 87 | /* 88 | Несмотря на то, что переменная b была объявлена вне блока и поэтому 89 | должна быть доступна, мы все равно получим ReferenceError. 90 | Здесь столкнулись с “временной мёртвой зоной”: в этом блоке 91 | переменная b своя, и она ещё не инициализированна, но имя переменной уже 92 | зарезервированно. Поэтому лучше объявлять все переменные в начале блока. 93 | */ 94 | /* 95 | Весь смысл ВМЗ — легче вылавливать ошибки там, 96 | где обращение к переменной до её объявления приводит к неожиданностям. 97 | Это зачастую происходило в ES5 из-за поднятия и непродуманных соглашений 98 | о стиле кода. Теперь переменные работают так, как в многих других языках. 99 | */ 100 | 101 | if (false) { 102 | var a = 10; 103 | } 104 | console.log(a); // Reference Error? WRONG! Undefined! 105 | 106 | /* 107 | Код внутри конструкции if не запускался, 108 | а значит и перменная a не была инициализирована. Логично предположить, 109 | что единственным возможным результатом является ошибка 110 | (попытка обратиться к несуществующей переменной обычно выдает ReferenceError). 111 | На самом деле результат будет undefined изза hoisting`a переменных. 112 | */ 113 | 114 | /* 115 | Теперь всё гораздо проще! 116 | Рассмотрим решение частой проблемы при использовании var в цикле for: 117 | для каждой итерации создаётся новая i, которая не hoist`ится за пределы цикла. 118 | */ 119 | 120 | var funcs = []; 121 | for (let i = 0; i < 5; i++) { 122 | funcs.push(function(){ 123 | console.log( i ); 124 | }); 125 | } 126 | funcs[3](); // 3 127 | console.log(i); // ReferenceError! 128 | 129 | /* 130 | Временная мёртвая зона не распространяется на функции до первого их вызова: 131 | */ 132 | 133 | var f = function() { 134 | return num; 135 | }; 136 | let num = 10; 137 | console.log(f()); // 10 138 | 139 | /* 140 | Но если вы попытаетесь вызвать функцию f до того, 141 | как будет объявлена переменная num, то всё равно получите ошибку: 142 | */ 143 | 144 | var f = function() { 145 | return num; 146 | }; 147 | console.log(f()); // ReferenceError: num is not defined 148 | let num = 10; 149 | 150 | /* 151 | Так как переменная а не была объявлена, то единственный безопасным способом 152 | проверить ее на существование будет использование оператора typeof. 153 | Но даже typeof бросает ошибку если переманная была объявлена позже! 154 | */ 155 | 156 | { 157 | if (typeof b === "undefined") { // ReferenceError! 158 | console.log('b is undefined'); 159 | } 160 | let b; 161 | } 162 | 163 | 164 | /* 165 | const 166 | Надо обязательно присваивать значение при объявлении. 167 | По-умолчанию константа не получает значение undefined, поэтому 168 | если нужен undefined, надо явно это указать. 169 | */ 170 | 171 | const a; // SyntaxError: Missing initializer in const declaration 172 | const a = undefined; //undefined 173 | 174 | /* 175 | После объявления const нельзя менять только примитивные типы данных 176 | или ссылку на составные. То-есть это не неизменное значение, 177 | а неизменная ссылка на значение. 178 | */ 179 | 180 | const lit = 4; 181 | lit = 5; // TypeError: Литерал изменить нельзя 182 | 183 | const obj = { a: 1 }; 184 | obj.a = 2; // Значения внутри объекта изменить можно 185 | obj = { a: 3 }; // TypeError: Ссылку менять нельзя 186 | 187 | const arr = [1, 2, 3]; 188 | arr.push(4); // Значения внутри массива изменить можно 189 | arr = [4, 3, 2, 1]; // TypeError: Ссылку менять нельзя 190 | 191 | 192 | /* 193 | Блочная область видимости функций 194 | Начиная с ES6, подразумевается, что функции которые были объявлены в блоке, 195 | буду иметь его область видимости (блочную). До ES6, спецификация умалчивала 196 | по этому поводу, в отличии от различных конкретных реализации. 197 | Тем не менее, сейчас спецификация соответствует реальности. 198 | */ 199 | 200 | { 201 | foo(); // работает! 202 | 203 | function foo() { 204 | console.log('it works!'); 205 | } 206 | } 207 | 208 | foo(); // ReferenceError 209 | 210 | /* 211 | Тут функция объявлена в блочной области видимости и не доступна из вне. 212 | Но в отличии от объявления let, с которым мы не можем работать до того, 213 | как такая переменная будет проиницилизированна, 214 | в данном случае ошибки TDZ не возникает. 215 | */ 216 | -------------------------------------------------------------------------------- /slides/14/arrow_functions.js: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Стрелочные функции, в первую очередь, созданы для обхода некоторых особенностей 4 | традиционных функций, которые не всегда нужны. 5 | Например нам не всегда(а точнее - в большинстве случаев) нужна 6 | гибкость JavaScript`ового this 7 | */ 8 | 9 | var pageHandler = { 10 | id: "123456", 11 | init: function() { 12 | document.addEventListener("click", function(event) { 13 | this.doSomething(event.type); // ошибка потому что this===document, а не pageHandler 14 | }); 15 | }, 16 | doSomething: function(type) { console.log("Handling " + type + " for " + this.id) } 17 | }; 18 | 19 | /* 20 | Чтобы добиться того, что мы хочем, мы можем использовать несколько вариантов: 21 | */ 22 | 23 | var pageHandler = { 24 | id: "123456", 25 | init: function() { 26 | document.addEventListener("click", function(event) { 27 | this.doSomething(event.type); 28 | }).bind(this); 29 | }, 30 | doSomething: function(type) { console.log("Handling " + type + " for " + this.id) } 31 | }; 32 | 33 | /* 34 | или 35 | */ 36 | 37 | var pageHandler = { 38 | id: "123456", 39 | init: function() { 40 | var self = this; 41 | document.addEventListener("click", function(event) { 42 | self.doSomething(event.type); 43 | }); 44 | }, 45 | doSomething: function(type) { console.log("Handling " + type + " for " + this.id) } 46 | }; 47 | 48 | /* 49 | Теперь код работает так, как и задумывалось, но выглядит более громоздко, 50 | и всегда остаётся возможность что-то упустить при рефакторинге, 51 | надо постоянно следить за контекстом - что куда надо забиндить и т.д. 52 | И это ещё самый простой пример, а представьте что будет если у нас будет 53 | несколько вложенных функций, редюсы, мапы и колбэки... 54 | 55 | Стрелочные функции решают проблему более элегантным способом, 56 | поскольку используют лексическое связывание значения this, super и arguments 57 | и его значение определяется значением this в том месте, 58 | где стрелочная функция была создана. 59 | */ 60 | 61 | var pageHandler = { 62 | id: "123456", 63 | init: function() { 64 | document.addEventListener("click", event => this.doSomething(event.type)); 65 | }, 66 | doSomething: function(type) { console.log("Handling " + type + " for " + this.id) } 67 | }; 68 | 69 | /* 70 | Прокидывание» контекста между несколькими вызовами становится тривиальной задачей 71 | */ 72 | 73 | var obj = { 74 | arr1: [1, 2, 3], 75 | arr2: ['a', 'b', 'c'], 76 | concatenate: function(a, b){ return a + "|" + b }, 77 | intersection: function() { 78 | return this.arr1.reduce( (sum, v1) => // arrow function 1 79 | this.arr2.reduce( (sum, v2) => { // arrow function 2 80 | sum.push( this.concatenate( v1, v2 ) ) 81 | return sum; 82 | }, sum ), 83 | [] ); 84 | } 85 | }; 86 | var arrSum = obj.intersection(); //['1|a', '1|b', '1|c', '2|a', '2|b', '2|c', '3|a', '3|b', '3|c'] 87 | -------------------------------------------------------------------------------- /slides/15/arrow_functions.js: -------------------------------------------------------------------------------- 1 | /* 2 | Лёгким движением руки... 3 | */ 4 | 5 | function () { return 1; } 6 | () => { return 1; } 7 | () => 1 8 | 9 | function (a) { return a * 2; } 10 | (a) => { return a * 2; } 11 | (a) => a * 2 12 | a => a * 2 13 | 14 | function (a, b) { return a * b; } 15 | (a, b) => { return a * b; } 16 | (a, b) => a * b 17 | 18 | function () { return arguments[0]; } 19 | (...args) => args[0] 20 | 21 | () => {} // undefined 22 | () => ({}) // {} 23 | 24 | x => { throw x } 25 | 26 | /* 27 | Cтрелочные функции позволяют писать код быстрее, проще и читабельней: 28 | */ 29 | 30 | var user = { 31 | multiplier: 20, 32 | defaultValues: [1, 2, 5], 33 | doThis: function () { 34 | var self = this; 35 | sendRequest() // send request 36 | .then(function(results){ // async process each result 37 | return Promise.all(results.map(function(result){ 38 | return processResults(result); 39 | })); 40 | }) 41 | .then(function(results){ 42 | return results.reduce( // calculate results depending on status 43 | function(num, result){ 44 | return result.valid ? 45 | num + result.value * self.multiplier : num; 46 | }, 47 | 0 48 | ); 49 | }) 50 | .then(function(result){ // concat them with defaults 51 | return self.defaultValues.concat(result).sort(function(a, b){ 52 | return a - b; 53 | }); 54 | }) 55 | } 56 | }; 57 | 58 | /* 59 | А теперь получится в два раза меньше строк: 60 | */ 61 | 62 | var user = { 63 | multiplier: 20, 64 | defaultValues: [1, 2, 5], 65 | doThis () { 66 | sendRequest() // send request 67 | .then(results => Promise.all( // async process each result 68 | results.map(result => processResults(result)) 69 | )) 70 | .then(results => results.reduce((num, result) => result.valid ? // calculate results depending on status 71 | num + result.value * self.multiplier : num, 72 | 0 73 | )) 74 | .then(result => self.defaultValues.concat(result).sort((a, b) => a - b)) // concat them with defaults 75 | } 76 | }; 77 | 78 | /* 79 | Но нужно быть внимательными: не переносить стрелку на следующую строку: 80 | */ 81 | 82 | const func1 = (x, y) // SyntaxError 83 | => { 84 | return x + y; 85 | }; 86 | 87 | const func2 = (x, y) => // OK 88 | { 89 | return x + y; 90 | }; 91 | 92 | /* 93 | И не использовать стрелочные функции в декларации методов 94 | с использованием литерала объекта или Function.prototype 95 | */ 96 | 97 | var component = { 98 | _privateMethod: function (params) { 99 | console.log(params); 100 | }, 101 | // this в handleAction будет указывать на глобальный объект, 102 | // что приведет к ошибке 103 | handleAction: (params) => this._privateMethod(params), 104 | // Если, все же, хочется писать покороче, 105 | // лучше использовать новый способ декларации методов, 106 | // поведение которого осталось неизменным 107 | handleAction2 (params) { 108 | return this._privateMethod(params); 109 | } 110 | }; 111 | 112 | /* 113 | ДРУГИЕ ОСОБЕННОСТИ: 114 | 115 | Связывают контекст — значение this определяется не тем, 116 | как и где функция вызвана, а где она была создана. 117 | 118 | Наследуют super и arguments от родительского контекста. 119 | 120 | Так как this биндится при создании функции, 121 | он не может быть изменен в дальнейшем даже с помощью .call(), .apply() и .bind(). 122 | 123 | Не могут быть использованы как конструктор, кидают TypeError при использовании с new. 124 | 125 | Не могут быть генераторами и использовать yield внутри себя. 126 | 127 | Отсутствует .prototype. 128 | 129 | Стрелочные функции всегда анонимны. 130 | */ 131 | -------------------------------------------------------------------------------- /slides/16/default_parameters.js: -------------------------------------------------------------------------------- 1 | /* 2 | В ES6 стало возможным указание значений по умолчанию для аргументов функции. 3 | Ранее для проверки и задания стандартных значений использовалось тело функции, 4 | где параметры сравнивались с undefined. 5 | */ 6 | 7 | function doSomething(x, y) { 8 | y = y === undefined ? 2 : y; 9 | return x * y; 10 | } 11 | 12 | /* 13 | Аналогичный функционал на ES6: 14 | */ 15 | 16 | function doSomething(x, y = 2) { 17 | return x * y; 18 | } 19 | 20 | doSomething(5); // 10 21 | doSomething(5, undefined); // 10 22 | doSomething(5, 3); // 15 23 | 24 | /* 25 | Они вычисляются во время выполнения (а не объявления), но перед выполнением 26 | самих операций в теле функции. Поэтому нельзя использовать что-то из тела функции 27 | для определения параметров: 28 | */ 29 | 30 | function f(a = go()) { // ReferenceError. 31 | function go(){ return ":P" } 32 | } 33 | 34 | /* 35 | Параметры, которые уже объявлены, 36 | могут использоваться для объявления следующих, но не наоборот: 37 | */ 38 | 39 | function doSomething(arg1, arg2 = arg1 * 2) { 40 | console.log(arg1 + arg2); 41 | } 42 | doSomething(3); // 9 43 | 44 | /* 45 | Для указания значений по-умолчанию можно использовать 46 | деструктуризацию, ...rest и даже выражения включающие в себя вызовы функций: 47 | */ 48 | 49 | function f([x, y] = [1, 2], {z: z} = {z: 3}) { 50 | return x + y + z; 51 | } 52 | f(); // 6 53 | 54 | // или 55 | 56 | function doSomething(x, ...remaining) { 57 | return x * remaining.length; 58 | } 59 | doSomething(5, 0, 0, 0); // 15 60 | 61 | // или 62 | 63 | function getTwo() { 64 | return 2; 65 | } 66 | function doSomething(arg1, arg2 = getTwo()) { 67 | console.log(arg1 + arg2); 68 | } 69 | doSomething(3); // 5 70 | doSomething(3, 1); // 4 71 | -------------------------------------------------------------------------------- /slides/17-18/rest_spread.js: -------------------------------------------------------------------------------- 1 | /* 2 | Разберёмся - какая разница между rest и spread если они обозначаются одинаково. 3 | */ 4 | 5 | 6 | // Вы используете spread, когда разбираете одну переменную на элементы: 7 | 8 | var abc = ['a', 'b', 'c']; 9 | var def = ['d', 'e', 'f']; 10 | var alpha = [ ...abc, ...def ]; // ['a', 'b', 'c', 'd', 'e', 'f']; 11 | 12 | // Вы используете rest при объединении оставшихся аргументов функции в один массив: 13 | 14 | function sum( first, ...others ) { 15 | for ( let i = 0; i < others.length; i++ ) { 16 | first += others[i]; 17 | } 18 | return first; 19 | } 20 | sum(1, 2, 3, 4); // 10; 21 | 22 | // В ES5 это делали так: 23 | 24 | function sum() { 25 | var first = arguments[0]; 26 | var others = [].slice.call(arguments, 1); 27 | ··· 28 | } 29 | -------------------------------------------------------------------------------- /slides/19-20/destructuring.js: -------------------------------------------------------------------------------- 1 | /* 2 | Деструктуризация – это синтаксис, при котором можно присвоить массив или объект 3 | сразу нескольким переменным, разбив его на части. 4 | */ 5 | 6 | let [ first, second ] = [ 'alpha', 'beta', 'gamma' ]; 7 | console.log(second); // alpha 8 | 9 | // Ненужные элементы массива также можно отбросить, поставив лишнюю запятую: 10 | 11 | let [ first, , third ] = [ 'alpha', 'beta', 'gamma' ]; 12 | console.log(third); // gamma 13 | 14 | // Используем rest оператор: 15 | 16 | let [ first, ...other ] = [ 'alpha', 'beta', 'gamma' ]; 17 | console.log(other); // [ 'beta', 'gamma' ] 18 | 19 | // Если значений в массиве не хватает, то будет присвоено undefined: 20 | 21 | let [ first, second ] = [ 'alpha' ]; 22 | console.log(second); // undefined 23 | 24 | // Можно использовать значения по умолчанию! 25 | 26 | function getThird (){ 27 | return 'gamma'; 28 | } 29 | let [ first, second = 'beta', third = getThird()] = [ 'alpha' ]; 30 | console.log(first, second, third); 31 | 32 | /* 33 | При деструктуризации объектов мы указываем 34 | какие свойства в какие переменные должны «идти», 35 | при этом можно присвоить свойство объекта в переменную 36 | с другим именем через двоеточие 37 | можно даже сочетать это с значениями по-умолчанию или вычисляемыми значениями: 38 | */ 39 | 40 | let employee = { 41 | name: "Mykola", 42 | age: 50, 43 | salary: 200000, 44 | married: true, 45 | kids: 3 46 | }; 47 | let importantKey = 'age'; 48 | 49 | let { name, [importantKey]: years, job="truck driver", salary:money=0 } = employee; 50 | console.log(name, years, job, money); 51 | 52 | /* 53 | Eсли в объекте больше значений, чем переменных, то мы их пока-что не можем получить. 54 | Возможно в будущих стандартах сможем с помощью ...rest, тогда мы сможем делать так: 55 | */ 56 | 57 | let { name, years, job="truck driver", salary:money=0, ...family } = employee; 58 | // family = { married: true, kids: 3 } 59 | 60 | /* 61 | Можно использовать уже существующие переменные, но в таком случае надо обернуть 62 | конструкцию в ( ) скобки чтобы это не было воспринято как блок из { }: 63 | */ 64 | 65 | let a, b; 66 | { a, b } = { a:5, b:6 }; // будет ошибка, потому что { a, b } - блок, 67 | 68 | // поэтому: 69 | 70 | let a, b; 71 | ({a, b} = {a:5, b:6}); // внутри выражения это уже не блок 72 | -------------------------------------------------------------------------------- /slides/21-22/class.js: -------------------------------------------------------------------------------- 1 | /* 2 | Новая конструкция class – удобный «синтаксический сахар» 3 | для задания конструктора вместе с прототипом. 4 | */ 5 | 6 | class User { 7 | constructor(name) { 8 | this.name = name; 9 | } 10 | sayHi() { 11 | alert(this.name); 12 | } 13 | } 14 | 15 | // Это объявление примерно аналогично такому: 16 | 17 | function User(name) { 18 | this.name = name; 19 | } 20 | User.prototype.sayHi = function() { 21 | alert(this.name); 22 | }; 23 | 24 | /* 25 | ОСОБЕННОСТИ: 26 | Классы имеют блочную область видимости. 27 | Статические свойства можно задать через static. 28 | В классах, как и в обычных объектах, можно объявлять геттеры и сеттеры, 29 | а также использовать [ ] для свойств с вычисляемыми именами. 30 | Добавлен синтаксис super для доступа к родителю (до его вызова this не будет доступен). 31 | Наследование делается через extends 32 | */ 33 | 34 | class Human { 35 | constructor(firstName, lastName){ 36 | this.firstName = firstName; 37 | this.lastName = lastName; 38 | } 39 | run(){ 40 | console.log('OK, I am running!'); 41 | } 42 | } 43 | 44 | /* 45 | через extends формируется стандартная цепочка прототипов: 46 | методы Hero находятся в Hero.prototype, методы Human – в Human.prototype, 47 | и они связаны через __proto__ (Hero.prototype.__proto__ == Human.prototype) 48 | constructor родителя наследуется автоматически. 49 | То есть, если в потомке не указан свой constructor, то используется родительский. 50 | Если же у потомка свой constructor, то, чтобы в нём вызвать конструктор родителя, 51 | используется синтаксис super() с аргументами для родителя. 52 | */ 53 | 54 | class Hero extends Human { 55 | constructor(firstName, lastName) { 56 | // this здесь пока-что не доступен 57 | super(firstName, lastName); 58 | this.privileges = 5; // теперь доступен 59 | } 60 | get fullName() { // геттер 61 | return `${this.firstName} ${this.lastName}`; 62 | } 63 | set fullName(newValue) { // сеттер 64 | [this.firstName, this.lastName] = newValue.split(' '); 65 | } 66 | run() { 67 | super.run(); 68 | console.log('And Im not tired!'); 69 | } 70 | ["test".toUpperCase()]() { // вычисляемое название метода 71 | console.log('TEST passed!'); 72 | } 73 | static createAdmin() { 74 | return new Hero("Thomas", "Anderson"); 75 | } 76 | }; 77 | 78 | let neo = Hero.createAdmin(); 79 | neo.TEST(); // TEST passed! 80 | neo.fullName = 'Chosen One'; 81 | console.log(neo.fullName); // 'Chosen One' 82 | neo.run(); // OK, I am running! And Im not tired! 83 | 84 | 85 | /* 86 | Миксины. 87 | Класс может иметь только один суперкласс, поэтому множественное наследование 88 | не представляется возможным. Функциональность должна быть предоставлена суперклассом. 89 | Функция которая принимает суперкласс, а возвращает субкласс 90 | который расширяет этот суперкласс может быть использована для реализации миксинов. 91 | */ 92 | 93 | var calculatorMixin = Base => class extends Base { 94 | calc() { console.log('Im calculating!'); } 95 | }; 96 | 97 | var randomizerMixin = Base => class extends Base { 98 | randomize() { console.log('Im randomizing!'); } 99 | }; 100 | 101 | // Класс, который использует эти миксины может быть создан вот так: 102 | 103 | class Foo { } 104 | class Bar extends calculatorMixin(randomizerMixin(Foo)) { 105 | 106 | } 107 | -------------------------------------------------------------------------------- /slides/23-24/promises.js: -------------------------------------------------------------------------------- 1 | /* 2 | Промис – объект-обёртка для удобной организации асинхронного кода 3 | через построение цепочек обработчиков. 4 | Промисификация применяется для всего, что только возможно. 5 | 6 | Имеет состояние (state) – вначале pending, затем fulfilled/rejected, 7 | после чего остаётся неизменным. На settled state`ы навешиваются колбэки. 8 | 9 | Функции resolve/reject принимают один аргумент – результат/ошибку, 10 | который передаётся обработчикам. 11 | Синхронный throw триггерит reject. 12 | */ 13 | 14 | // Где-то здесь ошибка: 15 | 16 | function getMultipleResults(requestIDs) { 17 | return Promise.all(requestIDs.map(requestID => requestAsync(reqUrl + requestIDs) 18 | .then(res => processData(res)) 19 | .then(processedData => processedData.fields) 20 | .catch(err => logToDB(err, requestID)) 21 | .catch(err => log(err, requestID)) 22 | )); 23 | } 24 | 25 | /* 26 | Код, которому надо сделать что-то асинхронно, создаёт объект promise и возвращает его. 27 | Внешний код, получив promise, навешивает на него обработчики. 28 | 29 | По завершении процесса асинхронный код переводит promise в состояние 30 | fulfilled (с результатом) или rejected (с ошибкой). При этом 31 | автоматически вызываются соответствующие обработчики во внешнем коде. 32 | */ 33 | 34 | function requestAsync(options){ 35 | return new Promise((resolve, reject) => { 36 | request(options, (err, res) => { 37 | if(err){ 38 | return reject(err); 39 | } 40 | return resolve(res); 41 | }); 42 | }); 43 | } 44 | 45 | requestAsync(options) 46 | .then(result => processData(result)) 47 | .catch(err => logToDB(err)); 48 | 49 | /* 50 | Промисификация – это когда берут асинхронный функционал 51 | и делают для него обёртку, возвращающую промис. 52 | После промисификации использование функционала зачастую становится 53 | гораздо удобнее, ведь можно строить цепочки промисов. 54 | */ 55 | 56 | /* 57 | Обработчик .catch получает ошибку и должен обработать её: 58 | либо возвратить значение через return и продолжить, 59 | либо сделать throw или ещё один reject, и тогда ошибка переходит в следующий .catch 60 | */ 61 | 62 | //Можно добавлять и много обработчиков на один и тот же промис: 63 | var promise = new Promise((resolve, reject) => resolve(1)); 64 | 65 | promise.then( function(result) { 66 | console.log(result + 1); 67 | }); 68 | 69 | promise.then( function(result) { 70 | console.log(result + 2); 71 | }); 72 | 73 | /* 74 | Параллельное выполнение 75 | Что, если мы хотим осуществить несколько асинхронных процессов одновременно 76 | и обработать их результаты? 77 | Вызов Promise.all(iterable) получает массив (или другой итерируемый объект) 78 | промисов и возвращает промис, который ждёт, пока все переданные промисы завершатся, 79 | и возвращает массив их результатов. 80 | Если хоть один промис reject - получаем только его. 81 | */ 82 | 83 | Promise.all([ 84 | Promise.resolve('alpha'), //так тоже можно 85 | Promise.resolve('beta') 86 | ]).then(results => { 87 | console.log(results[0], results[1]); // alpha, beta 88 | }).catch(err => { 89 | console.log('something went wrong', err); 90 | }); 91 | 92 | /* 93 | В Promise.race результатом будет только первый 94 | успешно выполнившийся промис из списка. Остальные игнорируются. 95 | */ 96 | 97 | function slowPromise(str) { 98 | return new Promise((resolve, reject) => { 99 | setTimeout(function() { 100 | resolve(str); 101 | }, 1000); 102 | }); 103 | } 104 | 105 | Promise.race([ 106 | slowPromise('alpha'), 107 | Promise.resolve('beta') 108 | ]).then(result => { 109 | console.log(result); // beta 110 | }).catch(err => { 111 | console.log('something went wrong', err); 112 | }); 113 | 114 | 115 | /* 116 | Есть некоторые либы, которые улучшают или расширяют функционал промисов. 117 | Они отвечают стандарту + добавляют новые возможности. 118 | 119 | Например Bluebird намного лучше в плане производительности 120 | и может промифицировать сразу все методы обьекта с помощью Bluebird.promisifyAll, 121 | при этом в обьект добавлятся промисифицированные методы с суффиксом Async: 122 | */ 123 | var fs = Promise.promisifyAll(require("fs")); 124 | 125 | fs.readFileAsync("myfile.js", "utf8").then(function(contents) { 126 | console.log(contents); 127 | }).catch(function(e) { 128 | console.error(e.stack); 129 | }); 130 | 131 | /* 132 | В другой известной библиотеке Q есть метод Q.allSettled, 133 | который может быть полезен если нам надо дождаться сэтла всех промисов, 134 | а потом в зависимости от того, успешна она или нет, 135 | с каждым результатом сделать что-то 136 | ({ state: "fulfilled", value: v } or { state: "rejected", reason: r }): 137 | */ 138 | 139 | Q.allSettled([saveToDisk(), saveToCloud()]).then(function (settledArr) { 140 | let successResults = settledArr 141 | .filter(settled => settled.state === 'fulfilled') 142 | .map(promise => promise.value); 143 | return processResults(successResults); 144 | }); 145 | -------------------------------------------------------------------------------- /slides/25-27/generators.js: -------------------------------------------------------------------------------- 1 | /* 2 | Генераторы – новый вид функций, которые могут приостанавливать свое выполнение, 3 | возвращать промежуточный результат и далее возобновлять его позже. 4 | При первом запуске код такой функции не выполняется, 5 | а возвращает специальный объект «генератор». 6 | */ 7 | 8 | function* generateSequence() { 9 | yield 1; 10 | yield 2; 11 | return 3; 12 | } 13 | let generator = generateSequence(); 14 | 15 | /* 16 | У генераторов есть метод next(), который возобновляет выполнение кода 17 | до ближайшего ключевого слова yield и принимает/возвращает его значение 18 | и текущий статус (done) во внешний код. 19 | */ 20 | 21 | let one = generator.next(); 22 | console.log(JSON.stringify(one)); // {value: 1, done: false} 23 | 24 | let two = generator.next(); 25 | console.log(JSON.stringify(two)); // {value: 2, done: false} 26 | 27 | let three = generator.next(); 28 | console.log(JSON.stringify(three)); // {value: 3, done: true} 29 | 30 | let four = generator.next(); 31 | console.log(JSON.stringify(three)); // {done: true} 32 | 33 | /* 34 | Функция завершена. 35 | Внешний код должен увидеть это из свойства done:true 36 | и обработать value:3, как окончательный результат. 37 | */ 38 | 39 | function* gen() { 40 | // Передать вопрос во внешний код и подождать ответа 41 | let result = yield "2 + 2?"; 42 | console.log('Result is ' + result); 43 | } 44 | let generator = gen(); 45 | let question = generator.next().value; // "2 + 2?" 46 | 47 | generator.next(4); //result is 4 48 | 49 | /* 50 | При композиции генераторов используется yield* 51 | чтоб интерпретатор перешел внутрь генератора-аргумента, 52 | выполнил его, и все yield, которые он делает, вышли из внешнего генератора. 53 | 54 | Это хорошо сочетается с тем, что генератор является итерируемым обьектом. 55 | Его можно перебирать и через for..of или ...spread 56 | но надо использовать yield вместо return 57 | */ 58 | 59 | function* getAllVehicles() { 60 | yield* getBlueCars(); 61 | yield* getGreenTrucks(); 62 | } 63 | let vehicles = [...getAllVehicles()]; 64 | 65 | /* 66 | Можно так же бросить в генератор ошибкой: 67 | */ 68 | 69 | function* gen() { 70 | try { 71 | let result = yield "Сколько будет 2 + 2?"; 72 | //сюда мы уже не дойдём, выше будет исключение 73 | } catch(e) { 74 | console.log('I GOT ERROR: ' + e); // выведет ошибку 75 | } 76 | } 77 | 78 | let generator = gen(); 79 | let question = generator.next().value; 80 | generator.throw(new Error("ответ не найден в моей базе данных")); 81 | // I GOT ERROR: ответ не найден в моей базе данных 82 | -------------------------------------------------------------------------------- /slides/28-29/promises_generators.js: -------------------------------------------------------------------------------- 1 | /* 2 | Одно из основных применений генераторов – написание плоского асинхронного кода: 3 | - генератор yield`ит не просто значения, а промисы; 4 | - есть специальная функция (например известная библиотека со) 5 | которая запускает генератор, последовательными вызовами next получает из него 6 | промисы – один за другим, и возвращает их результаты в генератор 7 | в следующие next, пока не дойдёт до последнего; 8 | - return значения генератора (done:true) уже обрабатывается 9 | как окончательный результат 10 | */ 11 | 12 | function slowDoublePromise(num) { 13 | return new Promise((resolve, reject) => { 14 | setTimeout(function() { 15 | resolve(num * 2); 16 | }, 1000); 17 | }); 18 | } 19 | 20 | function* processNumber(num) { 21 | let result1 = yield slowDoublePromise(num); 22 | let result2 = yield slowDoublePromise(result1); 23 | 24 | let result3; 25 | if(result2 > 7){ 26 | result3 = yield slowDoublePromise(result2 + result1); 27 | } else { 28 | throw new Error('too small, can not process further'); 29 | } 30 | return result3; 31 | } 32 | 33 | co(processNumber(2)) 34 | .then(res => console.log(res))// 20 35 | .catch(err => console.log('ERROR: ', err)); 36 | // co возвращает промис, поэтому нужно не забывать о catch. 37 | 38 | co(processNumber(1)) 39 | .then(res => console.log(res)) 40 | .catch(err => console.log('ERROR: ', err)); //ERROR: too small, can not process further 41 | 42 | /* 43 | Библиотека co умеет yield`ить промисы, генераторы, 44 | функции-thunk`и с единственным аргументом вида function(callback(err, result)), 45 | массив или объект из вышеперечисленного. При этом все задачи 46 | будут выполнены параллельно, а результат в той же структуре, будет выдан наружу. 47 | */ 48 | 49 | co(function*() { 50 | let result; 51 | 52 | result = yield* function*() { // генератор, yield* чтоб сохранить стек трейс 53 | return 1; 54 | }(); 55 | 56 | result = yield* function*() { // функция-генератор 57 | return 2; 58 | }; 59 | 60 | result = yield Promise.resolve(3); // промис 61 | 62 | result = yield function(callback) { // function(callback) 63 | setTimeout(() => callback(null, 4), 1000); 64 | }; 65 | 66 | result = yield { // две задачи выполнит параллельно, как Promise.all 67 | one: Promise.resolve(1), 68 | two: function*() { return 2; } 69 | }; 70 | 71 | result = yield [ // две задачи выполнит параллельно, как Promise.all 72 | Promise.resolve(1), 73 | function*() { return 2 } 74 | ]; 75 | return result; 76 | }).then(res => console.log(res)); // [1, 2]; 77 | -------------------------------------------------------------------------------- /slides/30/iterators.js: -------------------------------------------------------------------------------- 1 | /* 2 | В ECMAScript 6 добавлена концепция итерируемых (iterable) объектов, 3 | содержимое которых можно перебрать в цикле. Например, перебираемым объектом 4 | является массив или строка, но итераторы позволяют сделать перебираемыми другие объекты. 5 | 6 | С итерируемыми объектами работает …spread и добавлен новый синтаксис цикла for…of 7 | */ 8 | 9 | let arr = [1, 2, 3]; // массив — пример итерируемого объекта 10 | 11 | for (let value of arr) { 12 | console.log(value); // 1, затем 2, затем 3 13 | } 14 | 15 | /* 16 | В отличие от массивов, «перебираемые» объекты могут не иметь length. 17 | Как мы увидим далее, итераторы дают возможность сделать «перебираемыми» любые объекты. 18 | */ 19 | 20 | /* 21 | Для возможности использовать объект в for..of и ...spread 22 | нужно создать в нём свойство с названием Symbol.iterator (системный символ). 23 | 24 | При вызове метода Symbol.iterator перебираемый объект должен возвращать 25 | объект («итератор»), который умеет осуществлять перебор. 26 | 27 | По стандарту у такого объекта должен быть метод next(), 28 | который при каждом вызове возвращает очередное значение и окончен ли перебор. 29 | Здесь мы можем видеть сходство с генераторами в плане получения значений. 30 | */ 31 | 32 | let range = { 33 | from: 1, 34 | to: 5 35 | } 36 | 37 | // сделаем объект range итерируемым 38 | range[Symbol.iterator] = function() { 39 | let current = this.from; 40 | let last = this.to; 41 | // метод должен вернуть объект с методом next() 42 | return { 43 | next() { 44 | if (current <= last) { 45 | return { 46 | done: false, 47 | value: current++ 48 | }; 49 | } else { 50 | return { 51 | done: true 52 | }; 53 | } 54 | } 55 | } 56 | }; 57 | 58 | for (let num of range) { 59 | console.log(num); // 1, затем 2, 3, 4, 5 60 | } 61 | 62 | // Так же возможно вернуть this в качестве итератора, если объект содержит его 63 | ... 64 | [Symbol.iterator]() { 65 | return this; 66 | }, 67 | next(){ 68 | return { 69 | ... 70 | } 71 | }, 72 | ... 73 | 74 | /* 75 | Как мы видим, возможны и бесконечные итераторы. 76 | Например, пример выше при range.to = Infinity будет таковым. 77 | Или можно сделать итератор, генерирующий бесконечную 78 | последовательность псевдослучайных чисел. Тоже полезно. 79 | 80 | Разумеется, цикл for..of по такому итератору тоже будет бесконечным, 81 | нужно его прерывать, например, через break. 82 | */ 83 | -------------------------------------------------------------------------------- /slides/31-34/symbols.js: -------------------------------------------------------------------------------- 1 | /* 2 | Вот делаете Вы игру на канвас-движке, и хотите следить за движущимися объектами. 3 | Можно просто добавить свойство. 4 | */ 5 | 6 | if (element.isMoving) { 7 | smoothAnimations(element); 8 | } 9 | element.isMoving = true; 10 | 11 | /* 12 | При таком подходе существует несколько потенциальных проблем. 13 | Все они связаны с тем, что c обьектами может работать не только ваш текущий код. 14 | Конечно, можно сделать название свойства таким длинным и дурацким, 15 | что никто в жизни его не станет к ним лезть: 16 | */ 17 | element.__$animation_library$PLEASE_DO_NOT_USE_THIS_PROPERTY$isMoving__ = true; 18 | 19 | /* 20 | Но не стоит на этом останавливаться. Можно генерировать практически уникальное 21 | имя свойства, используя криптографию: 22 | */ 23 | 24 | let isMoving = SecureRandom.generateName(); 25 | 26 | if (element[isMoving]) { 27 | smoothAnimations(element); 28 | } 29 | element[isMoving] = true; 30 | 31 | /* 32 | Но такой синтаксис приводит к проблемам при отладке кода. 33 | Каждый раз, когда вы делаете console.log() для элемента с таким свойством, 34 | вы будете получать длинную бессмысленную строку. 35 | А если таких свойств должно быть много? 36 | 37 | Разве это так сложно? Нам нужен просто один маленький boolean! 38 | */ 39 | 40 | /* 41 | РЕШЕНИЕ: 42 | Символы — это значения, которые используются в качестве названия свойств 43 | без риска пересечения пространств имен. 44 | Важно отметить - символы не приватные ключи, а уникальные, 45 | хотя появилась тенденция использовать их для создания приватных ключей. 46 | */ 47 | 48 | let isMoving = Symbol("object is moving"); 49 | 50 | if (element[isMoving]) { 51 | smoothAnimations(element); 52 | } 53 | element[isMoving] = true; 54 | 55 | /* 56 | ЧУДЕСНО! 57 | Теперь не возможно обратиться к свойству, не имея ссылку на символ. 58 | И наиболее распространённые способы просмотра свойств объектов 59 | просто игнорирут ключи-символы - например, 60 | в цикле for…in или Object.keys(obj) и Object.getOwnPropertyNames(obj). 61 | 62 | К символам объекта можно обращаться только через [ ] скобки. 63 | При создании можно указать optional параметр, который служит только для 64 | помощи при отладке и не изменяет поведение символа. 65 | Обратиться к символу через него нельзя. 66 | 67 | После создания символы невозможно изменить, а только пересоздать. 68 | Сами свойства, конечно же можно. 69 | */ 70 | 71 | typeof Symbol() === "symbol" 72 | 73 | // Символы не могут быть автоматически конвертированны в строку. 74 | 75 | let sym = Symbol("<3"); 76 | "your symbol is " + sym // TypeError 77 | 78 | //Избежать ошибки поможет явная конвертация символа в строку 79 | 80 | String(sym) === "Symbol(<3)" 81 | 82 | //Все символы уникальны: 83 | 84 | let firstScore = Symbol('score'); 85 | let secondScore = Symbol('score'); 86 | 87 | firstScore === secondScore; // false 88 | 89 | /* 90 | С появлением символов объект Object был расширен методом, который позволяет 91 | получить все символы объекта. Наличие этого метода лишает нас возможности 92 | создавать по-настоящему приватные свойства: 93 | */ 94 | 95 | let userSymbols = Object.getOwnPropertySymbols(user); 96 | let roleSymbol = userSymbols[0]; 97 | user[ roleSymbol ]; // 'admin' 98 | 99 | /* 100 | Три способа получения символов: 101 | */ 102 | 103 | let sym1 = Symbol('qwe'); // каждый раз будет возвращаться новый уникальный символ; 104 | let sym2 = Symbol.for("www"); // который позволяет хранить символы глобально для среды текущего выполнения 105 | let key = Symbol.keyFor(sym2); // www, позволяет получить ключ, по которому символ добавлен в реестр. 106 | let iterator = Symbol.iterator; //использование описанных в стандарте символов вроде Symbol.iterator. 107 | -------------------------------------------------------------------------------- /slides/35/strings.js: -------------------------------------------------------------------------------- 1 | /* 2 | Интерполяция с помощью ${} и перенос строк с учётом отступов и переносов: 3 | */ 4 | 5 | function generateElement(h1, text, comment) { 6 | let clean = filter` 7 |

${h1}

8 |

Текст статьи:

9 |

${text}

10 |

Текст комментария:

11 |

${comment}

12 | `; 13 | return clean; 14 | } 15 | 16 | /* 17 | Функция шаблонизации: 18 | участки строки идут в первый аргумент-массив strings, 19 | а список последующих аргументов функции шаблонизации – это значения 20 | интерполированных выражений в ${...}. 21 | */ 22 | function filter(strings, ...args){ 23 | return args.reduce((result, string, i) => 24 | result += strings[i] + String(string).replace(/BAD_WORD/g, ''), '') 25 | + strings[strings.length - 1]; 26 | } 27 | 28 | console.log( 29 | generateElement('qwe', 'BAD_WORD222', 'BAD_WORD333') 30 | ); 31 | -------------------------------------------------------------------------------- /slides/36-37/main.js: -------------------------------------------------------------------------------- 1 | /* 2 | Пока-что не поддерживается нодой, https://github.com/nodejs/help/issues/53 3 | */ 4 | 5 | import { process } from 'src/process'; 6 | console.log(process('data')); 7 | 8 | /* 9 | import 'src/process' as c; 10 | console.log(c.process('data')); 11 | */ 12 | 13 | /* 14 | import { process as proc } from 'src/process'; 15 | console.log(proc('data')); 16 | */ 17 | -------------------------------------------------------------------------------- /slides/36-37/src/process.js: -------------------------------------------------------------------------------- 1 | let localVar = 'cant C me'; 2 | export const prefix = 'Processed data: '; 3 | export function process(string) { 4 | return `${prefix}${string}`; 5 | } 6 | -------------------------------------------------------------------------------- /slides/38/map_set_weakmap_weakset.js: -------------------------------------------------------------------------------- 1 | //Map. Базовые операции 2 | 3 | let map11 = new Map(); 4 | 5 | map1.set('foo', 123); 6 | map1.set('bar', false); 7 | 8 | console.log(map1.size); //2 9 | console.log(map1.get('foo')); //123 10 | console.log(map1.get('qwe')); //undefined 11 | 12 | console.log(map1.has('foo')); //true 13 | map1.delete('foo'); 14 | console.log(map1.has('foo')); //false 15 | 16 | map1.clear(); 17 | console.log(map1.size); //0 18 | 19 | // Создание 20 | 21 | const key1 = {}; 22 | let map2 = new Map([ 23 | [ key1, 'one' ], 24 | [ false, 123 ], 25 | [ NaN, 'three' ], // лишняя запятая игнорируется + NaN всегда один (в отличие от NaN !== NaN) 26 | ]); 27 | console.log(map2.get(key1)) // one 28 | 29 | //Альтернативный способ создания с помощью чейнинга метода set: 30 | 31 | let map3 = new Map() 32 | .set(key1, 'one') 33 | .set(false, 123) 34 | .set(NaN, 'three'); 35 | 36 | // перебор ключей и элементов 37 | 38 | for (let key of map3.keys()) { 39 | console.log(key); 40 | } // Object {}, false, NaN 41 | 42 | for (let key of map3.values()) { 43 | console.log(key); 44 | } // one, 123, three 45 | 46 | map3.clear(); // удаляет все значения 47 | 48 | /* 49 | WeakMap. То же самое, только ключи должны быть объектами, 50 | нельзя итерировать ключи или значения, нельзя очищать. 51 | */ 52 | 53 | /* 54 | Использование WeakMap для приватных данных: 55 | */ 56 | 57 | let _counter = new WeakMap(); 58 | let _action = new WeakMap(); 59 | class Countdown { 60 | constructor(counter, action) { 61 | _counter.set(this, counter); 62 | _action.set(this, action); 63 | } 64 | dec() { 65 | let counter = _counter.get(this); 66 | if (counter < 1) return; 67 | counter--; 68 | _counter.set(this, counter); 69 | if (counter === 0) { 70 | _action.get(this)(); 71 | } 72 | } 73 | } 74 | 75 | // запустим наш обратный отсчет: 76 | let c = new Countdown(2, () => console.log('DONE')); 77 | c.dec(); 78 | c.dec(); //DONE 79 | /* 80 | Поскольку обратный отсчет сохраняет специфичные для экземпляра данные 81 | в другом месте, это экземпляр с не имеет собственных ключей свойств: 82 | */ 83 | Reflect.ownKeys(c) // [] 84 | 85 | // Set. Базовые операции: 86 | 87 | let set = new Set(); 88 | set.add('red'); 89 | set.add('green'); 90 | set.add('yellow'); 91 | console.log(set.size, set.has('red')); //3, true 92 | set.delete('red'); 93 | console.log(set.size, set.has('red')); //2, false 94 | set.clear(); 95 | console.log(set.size); // 0 96 | 97 | // Создание 98 | 99 | let set2 = new Set(['red', 'green', 'blue']); 100 | 101 | // или 102 | 103 | let set3 = new Set().add('red').add('green').add('blue'); 104 | 105 | /* 106 | WeakSet так же как и WeakMap удаляет элементы, 107 | которые присутствуют только в нём, не поддерживает итерацию и очистку. 108 | */ 109 | -------------------------------------------------------------------------------- /slides/39/proxy.js: -------------------------------------------------------------------------------- 1 | /* 2 | Список возможных прокси достаточно большой, поэтому на developer.mozilla.org 3 | был создан мега-пример который создает различные ловушки для объекта docCookies: 4 | https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie/Simple_document.cookie_framework 5 | Ссылка на оригинал: 6 | https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Proxy 7 | */ 8 | 9 | var docCookies = new Proxy(docCookies, { 10 | get: function (oTarget, sKey) { 11 | return oTarget[sKey] || oTarget.getItem(sKey) || undefined; 12 | }, 13 | set: function (oTarget, sKey, vValue) { 14 | if (sKey in oTarget) { return false; } 15 | return oTarget.setItem(sKey, vValue); 16 | }, 17 | deleteProperty: function (oTarget, sKey) { 18 | if (sKey in oTarget) { return false; } 19 | return oTarget.removeItem(sKey); 20 | }, 21 | enumerate: function (oTarget, sKey) { 22 | return oTarget.keys(); 23 | }, 24 | ownKeys: function (oTarget, sKey) { 25 | return oTarget.keys(); 26 | }, 27 | has: function (oTarget, sKey) { 28 | return sKey in oTarget || oTarget.hasItem(sKey); 29 | }, 30 | defineProperty: function (oTarget, sKey, oDesc) { 31 | if (oDesc && "value" in oDesc) { oTarget.setItem(sKey, oDesc.value); } 32 | return oTarget; 33 | }, 34 | getOwnPropertyDescriptor: function (oTarget, sKey) { 35 | var vValue = oTarget.getItem(sKey); 36 | return vValue ? { 37 | value: vValue, 38 | writable: true, 39 | enumerable: true, 40 | configurable: false 41 | } : undefined; 42 | }, 43 | }); 44 | 45 | /* Cookies test */ 46 | 47 | console.log(docCookies.my_cookie1 = "First value"); 48 | console.log(docCookies.getItem("my_cookie1")); 49 | 50 | docCookies.setItem("my_cookie1", "Changed value"); 51 | console.log(docCookies.my_cookie1); 52 | --------------------------------------------------------------------------------