├── 10 ├── ht │ ├── TodoApp.png │ ├── TodoApp.bmpr │ └── README.md └── cls │ ├── React.xmind │ ├── notes │ ├── 01 - 02 - jsx │ │ └── index.html │ ├── 01 - 01 - pure react │ │ └── index.html │ ├── 01 - 04 - props │ │ └── index.html │ ├── 01 - 03 - jsx component │ │ └── index.html │ ├── 01 - 05 - state │ │ └── index.html │ ├── 01 - 06 - control state and pass props │ │ └── index.html │ └── 01 - 07 - hooks │ │ └── index.html │ └── index.html ├── 11 └── ht │ ├── TodoApp.png │ ├── TodoApp.bmpr │ └── README.md ├── 12 └── ht │ ├── mobileTodo.bmpr │ ├── mobileTodo.png │ └── README.md ├── 08 ├── cls │ ├── myFilter │ │ ├── myFilter.js │ │ ├── index.html │ │ └── tests.js │ ├── demo │ │ ├── index.htm │ │ └── script.js │ └── index.html └── ht │ ├── V-Game-of-Life.png │ ├── V-Game-of-Life.bmpr │ └── README.md ├── 02 └── ht │ ├── example │ ├── tests.js │ ├── index.html │ └── script.js │ └── README.md ├── favicon.ico ├── 01 ├── ht │ ├── example │ │ ├── tests.js │ │ ├── index.html │ │ └── script.js │ └── README.md └── cls │ └── index.html ├── 06 ├── ht │ ├── weather.bmpr │ ├── weatherPage.png │ ├── notes.md │ └── README.md └── cls │ └── index.html ├── 04 └── ht │ ├── calendar-spa.png │ ├── NOTES.md │ └── README.md ├── .eslintignore ├── .travis.yml ├── .gitignore ├── .eslintrc.js ├── .github └── PULL_REQUEST_TEMPLATE.md ├── gulpfile.js ├── .ht ├── diff │ ├── apply.test.js │ ├── promisify.test.js │ └── parallel.test.js ├── 05 │ ├── eventBus.test.js │ └── router.test.js ├── 01 │ └── script.tests.js └── 02 │ └── script.tests.js ├── 07 ├── ht │ └── README.md └── cls │ └── index.html ├── package.json ├── questions ├── index.html └── script.js ├── karma.conf.js ├── 03 └── ht │ └── README.md ├── final └── README.md ├── 09 └── ht │ └── README.md ├── 05 └── ht │ └── README.md ├── README.md └── 00 └── README.md /08/cls/myFilter/myFilter.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /02/ht/example/tests.js: -------------------------------------------------------------------------------- 1 | /* добавить тесты */ 2 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vvscode/js--base-course/HEAD/favicon.ico -------------------------------------------------------------------------------- /01/ht/example/tests.js: -------------------------------------------------------------------------------- 1 | /* Написать тесты на функции spiral и quadraticEquation */ 2 | -------------------------------------------------------------------------------- /10/ht/TodoApp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vvscode/js--base-course/HEAD/10/ht/TodoApp.png -------------------------------------------------------------------------------- /11/ht/TodoApp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vvscode/js--base-course/HEAD/11/ht/TodoApp.png -------------------------------------------------------------------------------- /06/ht/weather.bmpr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vvscode/js--base-course/HEAD/06/ht/weather.bmpr -------------------------------------------------------------------------------- /10/cls/React.xmind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vvscode/js--base-course/HEAD/10/cls/React.xmind -------------------------------------------------------------------------------- /10/ht/TodoApp.bmpr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vvscode/js--base-course/HEAD/10/ht/TodoApp.bmpr -------------------------------------------------------------------------------- /11/ht/TodoApp.bmpr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vvscode/js--base-course/HEAD/11/ht/TodoApp.bmpr -------------------------------------------------------------------------------- /04/ht/calendar-spa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vvscode/js--base-course/HEAD/04/ht/calendar-spa.png -------------------------------------------------------------------------------- /06/ht/weatherPage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vvscode/js--base-course/HEAD/06/ht/weatherPage.png -------------------------------------------------------------------------------- /12/ht/mobileTodo.bmpr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vvscode/js--base-course/HEAD/12/ht/mobileTodo.bmpr -------------------------------------------------------------------------------- /12/ht/mobileTodo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vvscode/js--base-course/HEAD/12/ht/mobileTodo.png -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 02/ht/example/script.js 3 | 08/cls/demo/script.js 4 | 08/cls/myFilter/tests.js -------------------------------------------------------------------------------- /08/ht/V-Game-of-Life.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vvscode/js--base-course/HEAD/08/ht/V-Game-of-Life.png -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '8' 4 | 5 | script: 6 | - npm run lint 7 | - npm test 8 | -------------------------------------------------------------------------------- /08/ht/V-Game-of-Life.bmpr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vvscode/js--base-course/HEAD/08/ht/V-Game-of-Life.bmpr -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea/ 3 | .vscode/ 4 | build/ 5 | dist/ 6 | node_modules/ 7 | npm-debug.log 8 | Thumbs.db -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: 'google', 3 | parserOptions: { 4 | ecmaVersion: 6, 5 | }, 6 | rules: { 7 | 'no-tabs': 'off', 8 | 'max-len': [ 9 | 'error', 10 | { 11 | ignoreStrings: true, 12 | code: 120, 13 | tabWidth: 4, 14 | }, 15 | ], 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Создавая пуллреквест, я: 2 | 3 | * [ ] убедился, что `diff` измненеий содержит только одно домашнее задание (_1 PR = 1 домашнее задание_) 4 | 5 | - [ ] убедился, что я изменял только файлы в своих директориях и не трогал общие файлы и файлы других студентов 6 | 7 | - [ ] проверил, что закоментированный код удален (это не касается именно закоментированного кода, а не заданий и настроек) 8 | 9 | - [ ] отформатировал мой код с помощью `prettier` - [prettier](http://prettier.io/) 10 | 11 | - [ ] проверил именование переменных, фунций и методов и их соответвие соглашениям 12 | -------------------------------------------------------------------------------- /12/ht/README.md: -------------------------------------------------------------------------------- 1 | ## Мобильный список дел 2 | 3 | Создать мобильное приложение на базе [react-native](http://reactnativedocs.ru/docs/getting-started.html). 4 | 5 | Приложение состоит из двух экранов: 6 | 7 | * About с описанием приложения и достоинств автора 8 | * TodoList со списком задач на сегодняшний день, отсортированным по степени важности 9 | 10 | Список задач доступен только после авторизации. 11 | 12 | Авторизацию и хранение реализовать на базе FireBase. Для решения задачи можно подключать сторонние пакеты. 13 | 14 | ![](mobileTodo.png) 15 | 16 | На странице со списков задач можно включать и отключать отображение выполненных задач. Добавление задач в список не обязательное условие. Главное - отображение списка и изменение статуса задачи 17 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const gulp = require('gulp'); 4 | const livereload = require('gulp-livereload'); 5 | const http = require('http'); 6 | const st = require('st'); 7 | 8 | const FILES_TO_WATCH_FOR = ['./**/*.*', '!node_modules/**/*.*']; 9 | 10 | gulp.task('watch', ['server'], () => 11 | gulp.watch(FILES_TO_WATCH_FOR, (e) => { 12 | console.log(e); 13 | gulp.src(e.path || FILES_TO_WATCH_FOR).pipe(livereload()); 14 | }) 15 | ); 16 | 17 | gulp.task('server', (done) => { 18 | http 19 | .createServer( 20 | st({ 21 | path: `${__dirname}/`, 22 | index: true, 23 | cache: false, 24 | }) 25 | ) 26 | .listen(8080, done); 27 | livereload.listen(); 28 | }); 29 | -------------------------------------------------------------------------------- /10/cls/notes/01 - 02 - jsx/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |

9 | Basic React element via JSX 10 |

11 |
12 |
13 | 25 | 26 | -------------------------------------------------------------------------------- /10/cls/notes/01 - 01 - pure react/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |

8 | Basic React element 9 |

10 |
11 |
12 | 38 | 39 | -------------------------------------------------------------------------------- /01/ht/example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | HT 01 12 | 13 | 14 | 15 |
16 |

17 |     
21 |     
22 |     
23 |     
24 |     
27 | 
28 | 
29 | 
30 | 


--------------------------------------------------------------------------------
/02/ht/example/index.html:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 | 
 4 | 
 5 |     
 6 |     
 7 |     
 8 |     
 9 |     
10 |     
11 |     HT 02
12 | 
13 | 
14 | 
15 |     
16 |

17 |     
21 |     
22 |     
23 |     
24 |     
27 | 
28 | 
29 | 
30 | 


--------------------------------------------------------------------------------
/.ht/diff/apply.test.js:
--------------------------------------------------------------------------------
 1 | mocha.setup({
 2 |   ui: 'bdd',
 3 |   bail: true,
 4 | });
 5 | const assert = chai.assert;
 6 | 
 7 | describe("Реализовать фукнцию `apply` тремя способами", () => {
 8 |   [
 9 |     { title: 'Определение функции', name: 'applyFD' },
10 |     { title: 'Выражение функции', name: 'applyFE' },
11 |     { title: 'Конструирование функции', name: 'applyFС' },
12 |   ].forEach((testItem) => {
13 |      describe(`${testItem.title} (${testItem.name})`, () => {
14 |          it(`функция ${testItem.name} определена`, () => {
15 |              assert.equal(typeof window[testItem.name], 'function');
16 |          });
17 |          
18 |          it(`вызывает функцию с аргументами`, () => {
19 |             let a;
20 |             let fun = (a, b) => a = [a, b];
21 |             window[testItem.name](fun, 1, 2);
22 |             assert.equal(Array.isArray(a), true);
23 |             assert.equal(a[0], 1);
24 |             assert.equal(a[1], 2);
25 |          });
26 |          
27 |         it(`возвращает результат работы функции`, () => {
28 |             let ret = Math.random();
29 |             let fun = (a, b) => ret;
30 |             assert.equal(window[testItem.name](fun, 1, 2), ret);
31 |          });
32 |      });
33 |   });
34 | });
35 | 


--------------------------------------------------------------------------------
/07/ht/README.md:
--------------------------------------------------------------------------------
 1 | ## Прочитать
 2 |  - [Введение в часто используемые особенности ES6. Часть 1](https://habrahabr.ru/post/340002/)
 3 |  - [Введение в часто используемые особенности ES6. Часть 2](https://habrahabr.ru/post/341500/)
 4 |  - [ES6 по-человечески](https://github.com/etnolover/ES6-for-humans-translation)
 5 |  - [Современные возможности ES-2015](http://learn.javascript.ru/es-modern)
 6 | 
 7 | С этого момента в коде используем `ES6`  по полной.
 8 | 
 9 | ## Сделать
10 | 
11 | Добавить в систему сборки проекта из прошлого задания транспиляцию с `babel` и поддержку ES6-модулей
12 | 
13 | ## Вопросы
14 | 
15 | - что такое `stage0` ... `stage1` ?
16 | - чем "стрелочная" функция отличается от обычной?
17 | - чем отличаются `let` / `const` / `var` ?
18 | - что такое `spread` оператор?
19 | - что такое `rest` параметр?
20 | - что такое _деструктуризация_ ?
21 | - что такое `super` ?
22 | - как сделать наследование классов?
23 | - что такое _генератор_ ?
24 | - что такое `Set` и `Map` ?
25 | - зачем нужен `Symbol` ?
26 | - чем классы отличаются от работы с прототипами?
27 | - что такое итератор?
28 | - какие дополнения в объявлении объектов?
29 | - как работать с ES6-imports ?
30 | - `this` в стрелочной функции?
31 | - как проверить поддерживается ли функция из ES6 каким-то браузером?


--------------------------------------------------------------------------------
/08/cls/demo/index.htm:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 | 
 4 | 
 5 | 
 6 |   
 7 |   
 8 |   
 9 |   
10 |   
11 |   
12 | 
13 | 
14 | 
15 |   
16 |   
17 | 
18 |   
19 |     
26 |     
27 |
28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /08/cls/myFilter/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 32 |
33 |
34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /10/cls/notes/01 - 04 - props/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |

9 | Basic React element via JSX 10 |

11 |
12 |
13 | 38 | 39 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js--base-course", 3 | "version": "0.0.0", 4 | "description": "Base javascript course", 5 | "main": "README.md", 6 | "scripts": { 7 | "test": "npm run lint", 8 | "lint": "eslint '**/*.js' '*.js'" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/vvscode/js--base-course.git" 13 | }, 14 | "author": "vvscode", 15 | "license": "ISC", 16 | "bugs": { 17 | "url": "https://github.com/vvscode/js--base-course/issues" 18 | }, 19 | "homepage": "https://github.com/vvscode/js--base-course#readme", 20 | "devDependencies": { 21 | "babe": "0.0.1", 22 | "babel-core": "^6.26.0", 23 | "babel-loader": "^8.0.4", 24 | "babel-preset-env": "1.7.0", 25 | "babel-preset-es2015-rollup": "3.0.0", 26 | "chai": "^4.1.2", 27 | "eslint": "^7.10.0", 28 | "eslint-config-google": "0.14.0", 29 | "gulp": "^4.0.0", 30 | "gulp-babel": "8.0.0", 31 | "gulp-concat": "2.6.1", 32 | "gulp-livereload": "4.0.2", 33 | "gulp-rollup": "2.17.0", 34 | "gulp-sourcemaps": "2.6.5", 35 | "karma": "^5.2.3", 36 | "karma-chai": "^0.1.0", 37 | "karma-chrome-launcher": "^3.1.0", 38 | "karma-mocha": "^2.0.1", 39 | "karma-phantomjs-launcher": "^1.0.4", 40 | "mocha": "^8.1.3", 41 | "rollup-plugin-babel": "4.4.0", 42 | "rollup-plugin-sourcemaps": "0.6.2", 43 | "st": "2.0.0" 44 | }, 45 | "eslintIgnore": [ 46 | "cls/**/*.js" 47 | ] 48 | } 49 | -------------------------------------------------------------------------------- /questions/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Questions 9 | 38 | 39 | 40 | 41 |
42 | Lessons 43 | 46 | 49 | 52 | 55 | 58 | 61 | 64 |
65 |

Go

66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /10/cls/notes/01 - 03 - jsx component/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |

9 | Basic React element via JSX 10 |

11 |
12 |
13 | 54 | 55 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Sun Sep 24 2017 11:47:21 GMT+0300 (+03) 3 | 4 | module.exports = (config) => { 5 | config.set({ 6 | // base path that will be used to resolve all patterns (eg. files, exclude) 7 | basePath: '', 8 | 9 | // frameworks to use 10 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 11 | frameworks: ['mocha', 'chai'], 12 | 13 | // list of files / patterns to load in the browser 14 | files: ['js/*.js', '**/*.js '], 15 | 16 | // list of files to exclude 17 | exclude: [], 18 | 19 | // preprocess matching files before serving them to the browser 20 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 21 | preprocessors: {}, 22 | 23 | // test results reporter to use 24 | // possible values: 'dots', 'progress' 25 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 26 | reporters: ['progress'], 27 | 28 | // web server port 29 | port: 9876, 30 | 31 | // enable / disable colors in the output (reporters and logs) 32 | colors: true, 33 | 34 | // level of logging 35 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 36 | logLevel: config.LOG_INFO, 37 | 38 | // enable / disable watching file and executing tests whenever any file changes 39 | autoWatch: true, 40 | 41 | // start these browsers 42 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 43 | browsers: ['ChromeHeadless'], 44 | 45 | // Continuous Integration mode 46 | // if true, Karma captures browsers, runs the tests and exits 47 | singleRun: false, 48 | 49 | // Concurrency level 50 | // how many browser should be started simultaneous 51 | concurrency: 2, 52 | }); 53 | }; 54 | -------------------------------------------------------------------------------- /10/cls/notes/01 - 05 - state/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |

9 | Basic React element via JSX 10 |

11 |
12 |
13 | 52 | 53 | -------------------------------------------------------------------------------- /04/ht/NOTES.md: -------------------------------------------------------------------------------- 1 | Информацию о REST API Firebase можно найти здесь https://firebase.google.com/docs/database/rest/start 2 | 3 | Для базы нужно отключить проверку прав доступа (`Project -> Database -> Rules`) 4 | 5 | ```javascript 6 | { 7 | "rules": { 8 | ".read": true, 9 | ".write": true 10 | } 11 | } 12 | ``` 13 | 14 | Добавление записи в Firebase 15 | 16 | ```javascript 17 | fetch(config.databaseURL + '/messages.json', { 18 | method: 'PUT', 19 | body: JSON.stringify([ 20 | { 21 | user: from, 22 | message: text, 23 | date: date, 24 | title: counter++ + 'message', 25 | }, 26 | ]), 27 | headers: { 28 | Accept: 'application/json', 29 | 'Content-Type': 'application/json', 30 | }, 31 | }) 32 | .then(function(response) { 33 | return response.json(); 34 | }) 35 | .then(console.log); 36 | ``` 37 | 38 | Добавление записи в список Firebase 39 | 40 | ```javascript 41 | fetch(config.databaseURL + '/messages.json', { 42 | method: 'POST', 43 | body: JSON.stringify([ 44 | { 45 | user: from, 46 | message: text, 47 | date: date, 48 | title: counter++ + 'message', 49 | }, 50 | ]), 51 | headers: { 52 | Accept: 'application/json', 53 | 'Content-Type': 'application/json', 54 | }, 55 | }) 56 | .then(function(response) { 57 | return response.json(); 58 | }) 59 | .then(console.log); 60 | ``` 61 | 62 | Чтение записи / списка 63 | 64 | ```javascript 65 | fetch(config.databaseURL + '/messages.json', { 66 | headers: { 67 | Accept: 'application/json', 68 | 'Content-Type': 'application/json', 69 | }, 70 | }) 71 | .then(function(response) { 72 | return response.json(); 73 | }) 74 | .then(console.log); 75 | ``` 76 | 77 | Чтение всей структуры базы 78 | 79 | ```javascript 80 | fetch(config.databaseURL + '/.json', { 81 | headers: { 82 | Accept: 'application/json', 83 | 'Content-Type': 'application/json', 84 | }, 85 | }) 86 | .then(function(response) { 87 | return response.json(); 88 | }) 89 | .then(console.log); 90 | ``` 91 | -------------------------------------------------------------------------------- /08/ht/README.md: -------------------------------------------------------------------------------- 1 | # Проект "Жизнь" 2 | 3 | Описание правил игры можно найти на странице в википедии [Жизнь (игра)](https://ru.wikipedia.org/wiki/%D0%96%D0%B8%D0%B7%D0%BD%D1%8C_(%D0%B8%D0%B3%D1%80%D0%B0)) 4 | 5 | 6 | Проект представляет из себя одностраничное приложение со страницами 7 | - текстовая игра (без разметки - тег `pre` и текстом отображние игры ) 8 | - игра на Canvas 9 | - игра на SVG 10 | - About - с информацией о проекте 11 | 12 | ![https://cdn.raw.githack.com/vvscode/js--base-course/f9e67820/08/ht/V-Game-of-Life.png](https://cdn.raw.githack.com/vvscode/js--base-course/f9e67820/08/ht/V-Game-of-Life.png) 13 | 14 | На страницах с игрой ( кроме страницы *About* ) в центре страницы находится поле, реализованное на соответствующей технологии. Внизу страницы находится блок с контролами состояния игры. 15 | 16 | ### Поле 17 | 18 | Отображает текущее поколение. И позволяет пользователю взаимодействовать с игрой. Клик по полю вызывает инверсию состояния клетки, по которой пользователь кликнул ( живая - умирает, мертвая - оживает ). 19 | 20 | ### Блок с контролами 21 | 22 | Позволяет 23 | - запускать и останавливать игру 24 | - изменять скорость игры с помощью регулятора 25 | - изменять размеры поля при помощи выпадающих списков с размерами поля по горизонтали и вертикали 26 | - при остановленной игре путешествовать назад и вперед по истории ( пока это возможно ). При этом состояние игры можно измененить на любой момент времени и запустить игру вновь 27 | 28 | ### Навигация 29 | 30 | Переход по страницам с разными реализациями поля не останавливает игру - она продолжается с заданными параметрами. Меняется только способ отображения игры. 31 | 32 | При уходе на страницу About - игра останавливается и ее состояние сохраняется. При возврате на страницу с полями подхватывается сохраненное состояние. 33 | 34 | Обновление страницы подхватывает технологию ( которая отображается на URL адресе ). Состояние игры сохранять в url или в хранилище по желанию. 35 | 36 | # Видео 37 | 38 | - [Паттерны проектирования JavaScript на 2017 год](https://www.youtube.com/watch?v=GjtfXIaQq7g) 39 | -------------------------------------------------------------------------------- /01/ht/example/script.js: -------------------------------------------------------------------------------- 1 | /* eslint no-var: "off" */ 2 | /* eslint no-unused-vars: "off" */ 3 | /* eslint max-len: "off" */ 4 | 5 | /** 6 | * Функция вывода строк для работы в fizzBuzz 7 | * @param {*} a 8 | */ 9 | function log(a) { 10 | console.log(a); 11 | } 12 | 13 | /* Раместите ваш код ниже */ 14 | 15 | /** 16 | * реализовать фукнцию `fizzBuzz` 17 | * которая выводит числа от 1 до 100. 18 | * Если число кратно 3 - вместо числа вывести `Fizz`. 19 | * Если кратно 5 - вывести вместо числа `Buzz`. 20 | * Если число кратно и 3 и 5 - вывести вместо числа `FizzBuzz`. 21 | * Для вывода использовать фукнцию `log` (аналогично заданию в классе). 22 | * В теле функции нельзя использовать `if`, `switch`, тернарный оператор `? :` 23 | */ 24 | function fizzBuzz() { 25 | /* Ваше решение */ 26 | } 27 | 28 | 29 | /** 30 | * реализовать фукнцию `isPolindrom`, 31 | * которая принимает на вход строку и возвращает результат проверки (`true`/ `false` ), 32 | * является строка полндромом (одинакого читается с лева на право и с права на лево ) или нет 33 | * @param {string} textString 34 | * @return {boolean} Является строка полндромом (одинакого читается с лева на право и с права на лево ) или нет 35 | */ 36 | function isPolindrom(textString) { 37 | /* Ваше решение */ 38 | return undefined; 39 | } 40 | 41 | 42 | /** 43 | * Реализовать фукнцию `drawCalendar` , 44 | * которая принимает три аргумента - год, месяц, htmlElement 45 | * и выводит в этот элемент календарь на месяц (дни недели начинаются с понедельника ). 46 | * @param {number} year 47 | * @param {number} month - номер месяца, начиная с 1 48 | * @param {external:HTMLElement} htmlEl 49 | */ 50 | function drawCalendar(year, month, htmlEl) { 51 | /* Ваше решение */ 52 | } 53 | 54 | 55 | /** 56 | * Написать функцию `isDeepEqual` 57 | * которая принимает на вход двe переменных 58 | * и проверяет идентичны ли они по содержимому. Например 59 | * @param {*} objA 60 | * @param {*} objB 61 | * @return {boolean} идентичны ли параметры по содержимому 62 | */ 63 | function isDeepEqual(objA, objB) { 64 | /* Ваше решение */ 65 | return undefined; 66 | } 67 | -------------------------------------------------------------------------------- /10/cls/notes/01 - 06 - control state and pass props/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |

9 | Basic React element via JSX 10 |

11 |
12 |
13 | 64 | 65 | -------------------------------------------------------------------------------- /.ht/diff/promisify.test.js: -------------------------------------------------------------------------------- 1 | /* global mocha, chai, describe, it */ 2 | /* global promisify, Hr, beforeEach */ 3 | mocha.setup({ 4 | ui: 'bdd', 5 | bail: true, 6 | }); 7 | const assert = chai.assert; 8 | 9 | describe('promisify', () => { 10 | it('is a function', () => assert.equal(typeof promisify, 'function')); 11 | it('returns function', () => { 12 | assert.equal(typeof promisify(() => null), 'function'); 13 | }); 14 | it('result calls original function', () => { 15 | var x = 0; 16 | var fn = (_) => x++; 17 | var pFn = promisify(fn); 18 | assert.equal(x, 0); 19 | pFn(); 20 | assert.equal(x, 1); 21 | }); 22 | it('passes params into original function', () => { 23 | var x = 0; 24 | var fn = (y) => (x += y); 25 | var pFn = promisify(fn); 26 | assert.equal(x, 0); 27 | pFn(2); 28 | assert.equal(x, 2); 29 | }); 30 | it('passes callback to original function', () => { 31 | var list = []; 32 | promisify((cb) => list.push(cb))(); 33 | promisify((x, cb) => list.push(cb))(1); 34 | promisify((x, y, cb) => list.push(cb))(1, 2); 35 | promisify((x, y, z, c, a, b, cb) => list.push(cb))(1, 2, 3, 4, 5, 6); 36 | assert.equal(list.length, 4); 37 | list.forEach((i) => assert.isFunction(i)); 38 | }); 39 | it('calls original function in correct context', () => { 40 | var o = { name: 'Bob' }; 41 | var x = null; 42 | var fn = function() { 43 | x = this; 44 | }; 45 | o.pfn = promisify(fn); 46 | o.pfn(); 47 | assert.equal(x, o); 48 | }); 49 | describe('promisified', () => { 50 | it('returns promise', () => { 51 | var fn = () => null; 52 | assert.isOk(promisify(fn)() instanceof Promise); 53 | }); 54 | it('rejects promise on error and pass error', (done) => { 55 | promisify((cb) => cb('xxx'))().catch((err) => { 56 | assert.equal(err, 'xxx'); 57 | done(); 58 | }); 59 | }); 60 | it('resolves promise on success and pass data', (done) => { 61 | promisify((cb) => cb(null, 'data'))().then((data) => { 62 | assert.equal(data, 'data'); 63 | done(); 64 | }); 65 | }); 66 | }); 67 | }); 68 | 69 | mocha.run(); 70 | -------------------------------------------------------------------------------- /10/ht/README.md: -------------------------------------------------------------------------------- 1 | # Практика 2 | 3 | ## Todo App 4 | 5 | Создать приложение **_Todo List_** 6 | 7 | ![Todo List](TodoApp.png) 8 | 9 | Реализовать приложение в отдельном репозитории. Заготовку создать с помощью 10 | `create-react-app`. 11 | 12 | Приложение состоих из трех частей 13 | 14 | ### Форма добавления задач 15 | 16 | Позволяет добавить в список задачи. Поля задачи, доступные для заполнения ( 17 | обязательным является только заголовок ): 18 | 19 | * Заголовок 20 | * Описание 21 | * Дата 22 | * Приоритет (выпадающий список с больше, чем одним значением ) 23 | 24 | При добавлении задачи в список поля формы сбрасываются в начальное значение 25 | (все, кроме даты). 26 | 27 | ### Фильтр для списка задач 28 | 29 | Фильт регулирует то, какие задачи будут доступны в списке ниже. Фильтр позволяет 30 | регулировать следующие настройки 31 | 32 | * показывать ли выполненные задачи 33 | * поиск по тексту ( регистронезависимый, поиск как в заголовке, так и в описании 34 | ) 35 | * фильтр по дате (минимальная и максимальная даты - заданы могут обе, 36 | одна-любая, ниодной) 37 | 38 | Изменения на списке отражаются сразу при изменении полей в фильтре - при вводе 39 | текста в фильтр, при изменении дат или состоянии чекбокса 40 | 41 | ### Список задач 42 | 43 | Отображает список задач в виде таблицы. Заголовок таблицы содержит элементы 44 | управления, позволяющие сортировать таблицу по колонке (в прямом и обратном 45 | порядке) 46 | 47 | ## Теория 48 | 49 | Пройти официальное руководство 50 | 51 | * https://reactjs.org/tutorial/tutorial.html 52 | * https://reactjs.org/docs/hello-world.html (Quck Start пройти, Advanced Guides 53 | просмотреть) 54 | 55 | Полезным может оказаться 56 | 57 | * https://www.gitbook.com/book/maxfarseer/react-course-ru/details 58 | * https://abraxabra.ru/react.js/bystryy-start 59 | * http://thewebland.net/react-js/ 60 | 61 | 62 | ### *** Дополнительно 63 | 64 | * Оформить приложение с использованием [React Semantic UI](https://react.semantic-ui.com/) 65 | * Двойной клик по строке с задачей ( если она не завершена ) открывает модальное окно для редактирования (с формой как при добавлении - те редактировать можно все поля). Для завершенных задач форма открывается в режиме для чтения, без возможности редактировать поля. 66 | -------------------------------------------------------------------------------- /03/ht/README.md: -------------------------------------------------------------------------------- 1 | ### Теория 2 | 3 | Прочитать (желательно с выполнением задач) разделы из учебника: 4 | 5 | * [Современные возможности ES-2015](http://learn.javascript.ru/es-modern) 6 | * [Основы работы с событиями](http://learn.javascript.ru/events-and-interfaces) 7 | * [Создание графических компонентов](http://learn.javascript.ru/widgets) 8 | * [Формы, элементы управления](http://learn.javascript.ru/js-misc) 9 | * [Современные возможности ES-2015](http://learn.javascript.ru/forms-controls) 10 | * [AJAX и COMET](http://learn.javascript.ru/ajax) 11 | * [Управление историей браузера](https://developer.mozilla.org/ru/docs/Web/API/History_API) 12 | 13 | --- 14 | 15 | * [Путеводитель по JavaScript Promise для новичков](https://habrahabr.ru/company/zerotech/blog/317256/) 16 | * [Промисы в ES6: паттерны и анти-паттерны](https://habrahabr.ru/company/ruvds/blog/339414/) 17 | 18 | ### Вопросы 19 | 20 | * Что такое "стрелочная" ("arrow function") функция? Чем она отличается от обычной? 21 | * Что такое Promise? Какой стандарт отписывает поведение Promise? Основные пункты стандарта? 22 | * Чем куки (cookie) отличаются от localStorage ? 23 | * Что такое CORS? 24 | * Что такое и какие есть коды ответов HTTP? 25 | * Что такое jsonp-запрос? 26 | * Как код, написанный на ES6 (ES2015-2017) превратить в код, который поддерживается IE10? 27 | * Как реализовать простейший модуль на js? 28 | * Что такое и зачем нужен паттерн модуль? Какие модули существуют в JS? 29 | * Как реализовать подписку на клик по кнопке, которая отработает только один раз? ( с примером кода ) 30 | * Какие события не "всплывают" ? 31 | * Что такое делегирование? 32 | * Преимущества и особенности работы с делегированием? 33 | * Какие вспомогательные методы есть для работы с промисами? 34 | * в чем разница между следующими кусками кода? 35 | 36 | ```javascript 37 | // promise - это экземпляр Promise 38 | // onSuccess - фукнция обработки успешного результата 39 | // onError - функция обработки ошибки 40 | // a: 41 | promise.then(onSuccess, onError); 42 | // b: 43 | promise.then(onSuccess).catch(onError); 44 | ``` 45 | 46 | * в чем разница между следующими кусками кода? 47 | 48 | ```javascript 49 | doSomething().then(function() { 50 | return doSomethingElse(); 51 | }); 52 | 53 | doSomething().then(function() { 54 | doSomethingElse(); 55 | }); 56 | 57 | doSomething().then(doSomethingElse()); 58 | 59 | doSomething().then(doSomethingElse); 60 | ``` 61 | -------------------------------------------------------------------------------- /08/cls/demo/script.js: -------------------------------------------------------------------------------- 1 | mocha.setup('bdd'); 2 | const assert = chai.assert; 3 | 4 | // CODE 5 | const dummyDebounc = (func, delay) => { 6 | let timer; 7 | return () => { 8 | clearTimeout(timer); 9 | timer = setTimeout(func, delay); 10 | }; 11 | }; 12 | 13 | // TESTS below 14 | describe('Simple tests', () => { 15 | it('0 is equal to 0', () => assert.equal(0, 0, 'should be equal')); // http://chaijs.com/api/assert/#method_equal 16 | it('Math.random is function', () => assert.isFunction(Math.random)); // http://chaijs.com/api/assert/#method_isfunction 17 | }); 18 | 19 | // https://mochajs.org/#asynchronous-code 20 | describe('dummyDebounce', () => { 21 | it('dummyDebounc is function', () => assert.isFunction(dummyDebounc)); 22 | it('dummyDebounc returns function', () => assert.isFunction(dummyDebounc(() => null, 0))); 23 | it('call function with delay', (done) => { 24 | let counter = 0; 25 | const debouncedFunc = dummyDebounc(() => counter++, 0); 26 | debouncedFunc(); 27 | assert.equal(counter, 0, 'should not incremenet counter'); 28 | setTimeout(() => { 29 | assert.equal(counter, 1, 'should incremenet counter'); 30 | done(); 31 | }, 100); 32 | }); 33 | it('call function twice cancel previous call', (done) => { 34 | // http://sinonjs.org/releases/v2.3.6/spies/ 35 | const spy = sinon.spy(); 36 | const debouncedFunc = dummyDebounc(spy, 0); 37 | debouncedFunc(); 38 | // http://chaijs.com/api/assert/#method_isnotok 39 | assert.notOk(spy.called, 'should not be called'); 40 | debouncedFunc(); 41 | // http://chaijs.com/api/assert/#method_isok 42 | assert.isOk(spy.notCalled, 'should not be called'); 43 | setTimeout(() => { 44 | // assert.isOk(spy.called, 'should be called'); 45 | assert.equal(spy.callCount, 1, 'should be called once'); 46 | done(); 47 | }, 100); 48 | }); 49 | }); 50 | 51 | describe('Simple mock usage', () => { 52 | let eventBus; 53 | let element; 54 | let clicker; 55 | 56 | // https://mochajs.org/#hooks 57 | beforeEach(() => { 58 | eventBus = new EventBus(); 59 | element = document.createElement('div'); 60 | }); 61 | 62 | it('should trigger event on click', () => { 63 | // http://sinonjs.org/releases/v2.0.0/spies/ 64 | const spy = sinon.spy(eventBus, 'trigger'); 65 | 66 | clicker = new Clicker(element, 0, eventBus); 67 | element.querySelector('button').click(); 68 | assert.isOk(spy.called); 69 | }); 70 | }); 71 | 72 | mocha.run(); 73 | -------------------------------------------------------------------------------- /final/README.md: -------------------------------------------------------------------------------- 1 | ## Требования к финальному проекту (критерии оценки) 2 | 3 | * [ ] Полезно / красиво 4 | * [ ] SPA (роутинг, переходы без перезагрузки страницы) 5 | * [ ] Работа с удаленным API 6 | * [ ] ООП (разбитие на классы) 7 | * [ ] ES6 (синтаксис, сборка) 8 | * [ ] Хранение данных пользователя 9 | * [ ] настроенная система сборки, минимизация 10 | * [ ] Приложение задеплоено и есть скрипт деплоя 11 | * [ ] Используются сторонние модули/библиотеки 12 | * [ ] Есть обработка данных от пользователя ( обработка форм ) 13 | 14 | ### Подготовка к защите 15 | 16 | * [ ] Код работает 17 | * [ ] Код почищен от ненужных коментариев, блоков кода и отформатирован в едином стиле 18 | * [ ] Все обновления залиты в гит. 19 | * [ ] К проекту добавлен README.md c описанием проекта ( назначение / структура / технологии и тп) и картинками ( структура/ скрины интерфейса и тп) 20 | * [ ] Собранный проект задеплоен на хостинг и проверен. В `README.md` добавлена ссылка на живое превью проекта на хостинге 21 | * [ ] Подготовлена презентация ( желательно на https://slides.com/ ) и ссылка на нее добавлена в файл `README.md` ( через короткую ссылку, например goo.gl ) 22 | * [ ] На бумаге написан текст выступления-презентации в соответствии с планом презентации 23 | 24 | ### Презентация должна включать 25 | 26 | * [ ] Ваши имя / фамилию 27 | * [ ] Название проекта 28 | * [ ] Назначение проекта / для кого / зачем / почему выбрали эту тему 29 | * [ ] Описание проекта с скринами основных экранов и описанием их функционала 30 | * [ ] Демонстрацию работы проекта ( лучше снять видео или подготовить точный порядок - куда когда щелкать и что вводить - идеально оба пункта ) 31 | * [ ] Обзор структуры проекта ( какие файлы / функциональные части где находятся ) 32 | * [ ] Описание задач, решенных в ходе работы над проектом ( какие были проблемы, как решали, что применили ). Дополнительно осветить пункты из требований к финальному проекту 33 | * [ ] Описание сложностей и проблем, которые встретились в процессе работы 34 | * [ ] Какая часть проекта оказалась самой сложной ( и почему? ) 35 | * [ ] Описание результата и процесса сборки - как выглядит собранный проект (число и размер файлов), как собрать и задеплоить проект (команды и что происходит при их выполнение) 36 | * [ ] Ваше мнение и выводы из проделанной работы 37 | 38 | #### Итого: 39 | 40 | В репозитории проекта создать Issue с короткими ссылками на проект на хостинге + на презентацию. Это нужно чтобы вы не искали флешки и прочее - с любого компьютера можно было открыть все, что нужно для знакомства с проектом и его кодом 41 | -------------------------------------------------------------------------------- /09/ht/README.md: -------------------------------------------------------------------------------- 1 | # Создание аркадной игры 2 | 3 | Создать аркадную игру, с отрисовкой на canvas со следующим функционалом ( набор 4 | идет с возрастанием по сложности, последующие шаги полезно держать в голове, но 5 | делать после реализации предыдущих ). Вся игра сделана на базе роутера из 6 | прошлого задания. Минимум три роута - описание правил, сама игра, таблица 7 | рекородов. Примерный план: 8 | 9 | * Создать одностраничное приложение - на главной описание игры и правил, на 10 | отдельной странице сама игра, на отдельной история побед и таблица рекордов. 11 | * Игра ведется на прямоугольном поле 12 | * Управление персонажем производится при помощи клавиатуры (стрелки) 13 | * Для мобильных устройств поверх игры рисуются полупрозрачные контроля для 14 | стрелок 15 | * При старте персонаж неподвижен, но после первой же команды начинает постоянно 16 | двигаться. Нажатие управляющих кнопок меняет направление движения. При выходе 17 | за границы поля персонаж появляется с противоположной стороны. 18 | * Со старта игры начинается отсчет времени, каждые n-секунд / n - ходов 19 | происходит переход на новый уровень. При завершении игры - запрашивается имя 20 | пользователя и сохраняется время игры для таблицы рекордов. 21 | * Новый уровень - появление на поле новый врагов того или иного типа. Враги 22 | разного типа выглядят по-разному 23 | * Враги первого типа - постоянно двигаются не меняя направления. Скорость 24 | постоянная, но у разных врагов может быть разной. 25 | * Враги второго типа - ведут себя так же, но при появлении персонажа в радиусе m 26 | меняют свое направление и начинают его преследовать. 27 | * При столкновении персонажа с врагом - игра заканчивается. 28 | * Реализовать отображение персонажа и врагов на основе спрайтов с анимацией. 29 | * Реализовать режим записи / сохранения / воспроизведения игры (использовать 30 | отдельный роут) 31 | * Добавить в игру ( с некого уровня ) появление предметов-модификаторов, которые 32 | позволяют уничтожать врагов, в течении некоторого времени. 33 | 34 | ## Прочитать: 35 | 36 | * https://learn.javascript.ru/drag-and-drop 37 | * https://learn.javascript.ru/drag-and-drop-objects 38 | 39 | * https://habrahabr.ru/company/mailru/blog/207048/ 40 | * https://habrahabr.ru/post/187582/ 41 | 42 | * https://codelabs.developers.google.com/codelabs/firebase-web-ru/index.html?index=..%2F..%2Flang-ru#0 43 | * http://progcoder.blogspot.com.by/2016/03/firebase-firebase.html 44 | * Пройти курс (после создания игры) http://www.w3ii.com/ru/firebase/default.html 45 | 46 | ## Может пригодиться 47 | 48 | * http://gaurav.munjal.us/Universal-LPC-Spritesheet-Character-Generator/ 49 | -------------------------------------------------------------------------------- /06/ht/notes.md: -------------------------------------------------------------------------------- 1 | ****# Загрузка данных с удаленного сервера 2 | 3 | Актуальные варианты работы c `ajax`: 4 | 5 | - [XHR](https://developer.mozilla.org/ru/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest) 6 | - [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) 7 | 8 | Для загрузки прогноза погоды можно использовать, например одно из двух: 9 | - [DarkSky](https://darksky.net/) + [MapsGoogle](https://developers.google.com/maps/documentation/geocoding/intro) 10 | - [OpenWeather](http://openweathermap.org/api#) 11 | 12 | Данные для работы с сервисами (а еще лучше создать свой аккант и использовать свои ключи): 13 | ```javascript 14 | // Google API Key : AIzaSyDa7DCL2NO9KMPd9DYVk_u3u0wCbm0XXFY 15 | // DarkSky API Key: d113af5f82393ef553f48314ae9f42e8 16 | ``` 17 | 18 | Пример получения координат по адресу с помощью GoogleMapsAPI: 19 | ```javascript 20 | // https://maps.googleapis.com/maps/api/geocode/json?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&key=AIzaSyDa7DCL2NO9KMPd9DYVk_u3u0wCbm0XXFY 21 | let GOOGLE_API_KEY = `AIzaSyDa7DCL2NO9KMPd9DYVk_u3u0wCbm0XXFY 22 | let getLatLng = (addr) => fetch(`https://maps.googleapis.com/maps/api/geocode/json?address=${addr}&key=${GOOGLE_API_KEY}`) 23 | .then((req) => req.json()) 24 | .then((data) => data.results[0].geometry.location); 25 | /* { lat: 53.890838, lng: 27.5372046 } */ 26 | ``` 27 | 28 | Пример получения прогноза по координатам: 29 | ```javascript 30 | // https://api.darksky.net/forecast/[key]/[latitude],[longitude] 31 | // https://api.darksky.net/forecast/SOME_KEY/53.890838,27.5372046 32 | // Для получения данных на русском + в метрической системе измерения нужно модицифровать запрос 33 | // https://api.darksky.net/forecast/SOME_KEY/53.890838,27.5372046?lang=ru&units=si 34 | // Для обхода CORS и запросов из браузера поднят прокси (именно поэтому в примере ниже адрес отличается от примеров для DarkSky ) 35 | // https://shrouded-spire-35703.herokuapp.com/forecast/53.890838,27.5372046 36 | let getForecastByLatLng = (lat, lng) => fetch(`https://shrouded-spire-35703.herokuapp.com/forecast/${lat},${lng}?lang=ru&units=si`) 37 | .then((req) => req.json()); 38 | ``` 39 | 40 | Пример объединения двух функция для получения прогноза по адресу: 41 | ```javascript 42 | let getForecastByAddress = (str) => getLatLng(str) 43 | .then(({lat, lng}) => getForecastByLatLng(lat, lng)) 44 | .catch((e) => { 45 | // здесь можно обработать ошибки, например 46 | }); 47 | ``` 48 | 49 | Пример использования CORS proxy: 50 | ``` 51 | http://cors-proxy.htmldriven.com/?url=https://api.darksky.net/forecast/d113af5f82393ef553f48314ae9f42e8/53.890838,27.5372046?lang=ru&units=si 52 | ``` -------------------------------------------------------------------------------- /05/ht/README.md: -------------------------------------------------------------------------------- 1 | ## Теория 2 | 3 | ### Прочитать 4 | Прочитать книгу ["Паттерны для масштабируемых JavaScript-приложений" Автор: Эдди Османи.](http://largescalejs.ru/) 5 | 6 | ### Быть способным рассказать о: 7 | 8 | - Как работать с XHR 9 | - Что такое AJAX 10 | - Как работать с fetch 11 | - CDN 12 | - GitHub Pages 13 | - TDD 14 | 15 | ## Практика 16 | 17 | Через [TDD](https://ru.wikipedia.org/wiki/%D0%A0%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0_%D1%87%D0%B5%D1%80%D0%B5%D0%B7_%D1%82%D0%B5%D1%81%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5) реализовать следующее: 18 | 19 | #### 1 Шаблонизатор 20 | Должен иметь следующую сигнатуру: 21 | ``` 22 | // compileTemplate = (tpl) => (el, data) 23 | // Компиляция шаблона возвращает функцию 24 | // при передаче этой функции элемента и объекта с данными 25 | // элемент получает разметку в соответсвии с tpl из data 26 | var tpl = "{{name}} is {{age}} years old"; 27 | var el = document.createElement('div'); 28 | var template = compileTemplate(tpl); 29 | template(el, { name: 'Bob', age: 33 }); 30 | el.innerHTML; // 'Bob is 33 years old 31 | ``` 32 | 33 | #### 2 EventBus c реализацией интерфейса 34 | ``` 35 | on(eventName, cb) 36 | off(eventName[, cb]) 37 | trigger(eventName[, data1 [, data2 [...data]]]) 38 | 39 | once(eventName, cb) 40 | ``` 41 | #### 3 Router 42 | 43 | Поддерживающий описание роутов в формате 44 | 45 | ``` 46 | IRoute { 47 | [name]: String optional 48 | [match]: String | RegExp | function 49 | onEnter([data]) | optional async function 50 | onLeave([data]) | optional async function 51 | onBeforeEnter([data]) | optional async function 52 | } 53 | ``` 54 | 55 | При этом он должен работать [как обсуждалось](https://raw.githack.com/vvscode/js--base-course/master/05/cls/index.html#/10/1) с роутами структуры 56 | 57 | ``` 58 | routes: [ 59 | { 60 | name: 'index', 61 | match: '', 62 | onBeforeEnter: () => console.log('onBeforeEnter index'), 63 | onEnter: () => console.log('onEnter index'), 64 | onLeave: () => console.log('onLeave index') 65 | }, 66 | { 67 | name: 'city', 68 | match: /city=(.+)/, 69 | onBeforeEnter: (city) => console.log(`onBeforeEnter city:${city}`), 70 | onEnter: (city) => console.log(`onEnter city:${city}`), 71 | onLeave: (city) => console.log(`onLeave city:${city}`) 72 | }, 73 | { 74 | name: 'about', 75 | match: (text) => text === 'about', 76 | onBeforeEnter: () => console.log(`onBeforeEnter about`), 77 | onEnter: () => console.log(`onEnter about`), 78 | onLeave: () => console.log(`onLeave about`) 79 | } 80 | ] 81 | ``` 82 | -------------------------------------------------------------------------------- /10/cls/notes/01 - 07 - hooks/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |

9 | Basic React element via JSX 10 |

11 |
12 |
13 |

14 |     
97 |   
98 | 


--------------------------------------------------------------------------------
/08/cls/myFilter/tests.js:
--------------------------------------------------------------------------------
  1 | 'use strict';
  2 | mocha.setup('bdd');
  3 | const assert = chai.assert;
  4 | describe('.myFilter', function() {
  5 |   it('is function', function() {
  6 |     return assert.isFunction([].myFilter);
  7 |   });
  8 | 
  9 |   it('needs cb as first param', function() {
 10 |     let ok = true;
 11 |     try {
 12 |       [].myFilter();
 13 |     } catch (e) {
 14 |       ok = false;
 15 |     }
 16 |     assert.equal(ok, false);
 17 |   });
 18 | 
 19 |   it('return list', function() {
 20 |     return assert.ok(
 21 |         [].myFilter(function() {
 22 |           return true;
 23 |         }) instanceof Array
 24 |     );
 25 |   });
 26 | 
 27 |   it('returns empty list for falsy cb', function() {
 28 |     return assert.ok(
 29 |         [1, 2, 3].myFilter(function() {
 30 |           return false;
 31 |         }).length === 0
 32 |     );
 33 |   });
 34 |   it('returns copy list for truthly cb', function() {
 35 |     return assert.deepEqual(
 36 |         [1, 2, 3].myFilter(function() {
 37 |           return true;
 38 |         }),
 39 |         [1, 2, 3]
 40 |     );
 41 |   });
 42 |   it('returns copy list for truthly cb', function() {
 43 |     return assert.deepEqual(
 44 |         [1, 2, 3].myFilter(function() {
 45 |           return 'some truthly param';
 46 |         }),
 47 |         [1, 2, 3]
 48 |     );
 49 |   });
 50 |   it('returns filtered list', function() {
 51 |     return assert.deepEqual(
 52 |         [1, 2, 3].myFilter(function(i) {
 53 |           return i % 2;
 54 |         }),
 55 |         [1, 3]
 56 |     );
 57 |   });
 58 | 
 59 |   it('calls passed cb', function() {
 60 |     const list = [1, 2, 3];
 61 |     const spy = sinon.spy();
 62 |     list.myFilter(spy);
 63 |     assert.equal(spy.callCount, list.length);
 64 |   });
 65 | 
 66 |   it('calls passed cb only for existing values', function() {
 67 |     const list = [1, , , 3];
 68 |     const spy = sinon.spy();
 69 |     list.myFilter(spy);
 70 |     assert.equal(spy.callCount, 2);
 71 |   });
 72 | 
 73 |   it('calls cb with params', function() {
 74 |     const list = [1, 2, 3];
 75 |     const spy = sinon.spy();
 76 |     list.myFilter(spy);
 77 | 
 78 |     assert.equal(spy.args.length, list.length);
 79 |     list.forEach(function(item, index) {
 80 |       return assert.deepEqual(spy.args[index], [item, index, list]);
 81 |     });
 82 |   });
 83 | 
 84 |   it('use passed thisArgs', function() {
 85 |     let that = undefined;
 86 | 
 87 |     const context = {name: 'fake object '};
 88 |     [1].myFilter(function() {
 89 |       that = this;
 90 |     }, context);
 91 |     assert.equal(that, context);
 92 |   });
 93 | 
 94 |   it('use `undefined` as thisArgs by default', function() {
 95 |     let that = 1;
 96 |     [1].myFilter(function() {
 97 |       that = this;
 98 |     });
 99 |     assert.isUndefined(that);
100 |   });
101 | 
102 |   it('call cb only on initial state of list', function() {
103 |     const list = [1, 2, 3];
104 |     const initialLength = list.length;
105 |     let counter = 0;
106 | 
107 |     list.myFilter(function() {
108 |       if (list.length < 4) {
109 |         list.push(1);
110 |       }
111 |       counter++;
112 |     });
113 |     assert.equal(counter, initialLength);
114 |   });
115 | });
116 | 
117 | mocha.run();
118 | 


--------------------------------------------------------------------------------
/11/ht/README.md:
--------------------------------------------------------------------------------
 1 | # Доработка TodoApp c использование Redux
 2 | 
 3 | Доработать приложение добавив в него
 4 | 
 5 | * redux (c поддержкой асинхронных операций)
 6 | * firebase (в качестве базы данных и провайдера авторизации)
 7 | * роутинг
 8 | * библиотеку UI компонентов (bootstrap/ semantic UI)
 9 | 
10 | ## Базовые блоки
11 | 
12 | Структурно приложение должно состоять из компонентов (см рисунок)
13 | ![TodoApp.png](TodoApp.png)
14 | 
15 | ### Форма фильтра (Filter Form)
16 | 
17 | Позволяет задать параметры фильтрации отображаемых записей. Позволяет фильтровать по
18 | 
19 | * дате (конкретные даты, или только текущий день с помощью отдельного чекбокса)
20 | * по флагу выполнения
21 | * по тексту (поиск делается в поле заголовка и в поле описания)
22 | 
23 | ### Форма добавления/редактирования (Add/Edit form)
24 | 
25 | Позволяет задавать значения полей при создании/редактировании записей
26 | 
27 | ### Список задач (List of tasks)
28 | 
29 | Позволяет отображать список задач, подходящих под фильтр. Сортировать по возрастанию/убывания через кнопки в заголовке таблицы.
30 | 
31 | ### Режим календаря (Calendar View)
32 | 
33 | Отображает задачи на календаре, позволяет фильтровать задачи по флагу выполнения (показывать или скрывать выполненные задачи)
34 | 
35 | ** С помощью DranNDrop позволяет изменять даты для задач
36 | 
37 | ## Работа с задачами
38 | 
39 | Страницы для работы с задачами имеют в шапке форму добавления задач.
40 | 
41 | На всех списках выполненные и невыполненные задачи отличаются либо иконкой, либо цветом блока.
42 | 
43 | Невыполненные задачи можно редактировать (двойное нажатие по элементу открывает модальное окно редактирования) и удалять (с запросом подтверждения от пользователя). Выполненные задачи измененять нельзя (либо сначала нужно снять флаг выполнения).
44 | 
45 | ## Страницы
46 | 
47 | Приложение имеет основное меню в шапке страницы, ведущее на три основных страницы
48 | 
49 | * Календарный вид
50 | * Список задач
51 | * О проекте
52 | 
53 | Изменения фильтров на страницах с задачами должно отображаться на URL адрес, чтобы при обновлении или передаче ссылки состояние фильтров было восстановлено.
54 | 
55 | ## Firebase
56 | 
57 | Для авторизации и хранения данных использовать сервис Firebase. Работа со страницами кроме `About` доступна только после авторизации. Данные разных пользователей должны храниться раздельно (данные пользователя А недоступны пользователю B).
58 | 
59 | ## Ссылки:
60 | 
61 | Redux:
62 | 
63 |  * https://www.gitbook.com/book/rajdee/redux-in-russian
64 |  * https://github.com/vvscode/js--redux-info
65 |  * https://www.gitbook.com/@maxfarseer/
66 | 
67 | Firebase:
68 | 
69 | * https://firebase.googleblog.com/2016/01/keeping-our-promises-and-callbacks_76.html
70 | * https://firebase.google.com/docs/web/setup
71 | * https://www.youtube.com/watch?v=GnORwtq1_1A
72 | * https://codelabs.developers.google.com/codelabs/firebase-web-ru/index.html?index=..%2F..%2Flang-ru#0
73 | * https://firebase-info.com/category/firebase/
74 | * Репозиторий с примерами https://github.com/firebase/quickstart-js
75 | 
76 | ## Процесс разработки
77 | 
78 | Процесс разработки разбит на три этапа
79 | 
80 | * изучение Firebase и разработка API для работы с его хранилищем
81 | * разработка приложения с хранением данных в localStorage
82 | * объединение firebase и разработанного приложения
83 | 
84 | Каждый студент выполняет все три части. Часть 3 он выполняет используя код двух других студентов (часть 1 + часть 2)
85 | 


--------------------------------------------------------------------------------
/.ht/05/eventBus.test.js:
--------------------------------------------------------------------------------
  1 | 'use strict';
  2 | // partialy
  3 | /* global EventBus, describe, it, assert, beforeEach  */
  4 | 
  5 | describe('EventBus', function() {
  6 |   it('is a function', function() {
  7 |     assert.isOk(typeof EventBus === 'function');
  8 |   });
  9 |   it('is a constructor', function() {
 10 |     assert.isOk(new EventBus() instanceof EventBus);
 11 |   });
 12 |   describe('methods', () => {
 13 |     var eb;
 14 |     beforeEach(() => (eb = new EventBus()));
 15 | 
 16 |     describe('.on', function() {
 17 |       it('a method', () => assert.equal(typeof eb.on, 'function'));
 18 |     });
 19 |     describe('.off', function() {
 20 |       it('a method', () => assert.equal(typeof eb.off, 'function'));
 21 |     });
 22 |     describe('.trigger', function() {
 23 |       it('a method', () => assert.equal(typeof eb.trigger, 'function'));
 24 |     });
 25 |     describe('.once', function() {
 26 |       it('a method', () => assert.equal(typeof eb.once, 'function'));
 27 |     });
 28 | 
 29 |     describe('logic', () => {
 30 |       it('calls .on handler by .trigger', () => {
 31 |         var a = 0;
 32 |         eb.on('some:event', () => (a = 1));
 33 |         assert.equal(a, 0);
 34 |         eb.trigger('some:event');
 35 |         assert.equal(a, 1);
 36 |       });
 37 |       it('works fine for no-handled events', () => {
 38 |         eb.trigger('some:event');
 39 |       });
 40 |       it('hanldes multiple events', () => {
 41 |         var x = 0;
 42 |         var y = 0;
 43 |         eb.on('x', () => (x = 1));
 44 |         eb.on('y', () => (y = 2));
 45 |         eb.trigger('x');
 46 |         eb.trigger('y');
 47 |         assert.equal(x, 1);
 48 |         assert.equal(y, 2);
 49 |       });
 50 |       it('manages multiple hanlder per one event', () => {
 51 |         var x = 0;
 52 |         var y = 0;
 53 |         eb.on('x', () => (x = 1));
 54 |         eb.on('x', () => (y = 2));
 55 |         eb.trigger('x');
 56 |         assert.equal(x, 1);
 57 |         assert.equal(y, 2);
 58 |       });
 59 |       it('passes params from .trigger into hanlders', () => {
 60 |         var x = [0];
 61 |         eb.on('x', (a) => x.push(a));
 62 |         eb.trigger('x', 2);
 63 |         assert.deepEqual(x, [0, 2]);
 64 |       });
 65 |       it('unsubscribes by .off call', () => {
 66 |         var x = 0;
 67 |         var _ = () => (x = 1);
 68 |         eb.on('x', _);
 69 |         eb.off('x', _);
 70 |         eb.trigger('x');
 71 |         assert.equal(x, 0);
 72 |       });
 73 |       it('unsubscribe multiple subscriptions', () => {
 74 |         var x = 0;
 75 |         var _ = () => (x = 1);
 76 |         eb.on('x', _);
 77 |         eb.on('x', _);
 78 |         eb.off('x', _);
 79 |         eb.trigger('x');
 80 |         assert.equal(x, 0);
 81 |       });
 82 |       it('once handles call only once', () => {
 83 |         var x = 0;
 84 |         var _ = () => x++;
 85 |         eb.once('x', _);
 86 |         eb.trigger('x');
 87 |         assert.equal(x, 1);
 88 |         eb.trigger('x');
 89 |         assert.equal(x, 1);
 90 |       });
 91 |       it('passes params into .once hanlder', () => {
 92 |         var x = [0];
 93 |         var _ = (y) => x.push(y);
 94 |         eb.once('x', _);
 95 |         eb.trigger('x', 4);
 96 |         assert.deepEqual(x, [0, 4]);
 97 |       });
 98 |       it('.off handles correctly', () => {
 99 |         var x = 0;
100 |         var y = 0;
101 |         var _ = () => x++;
102 |         eb.on('x', _);
103 |         eb.on('x', () => y++);
104 |         eb.off('x', _);
105 |         eb.trigger('x');
106 |         assert.equal(y, 1);
107 |       });
108 |     });
109 |   });
110 | });
111 | 


--------------------------------------------------------------------------------
/06/ht/README.md:
--------------------------------------------------------------------------------
 1 | # Сайт "Прогноз погоды"
 2 | 
 3 | ## Общая задача
 4 | 
 5 | Сайт состоит из трех блоков.
 6 | 
 7 | 1. в шапке сайта находится форма с полем ввода и кнопкой "Искать" и переключатель механизма запроса (два радиобаттона `fetch`/`XHR`) и меню, ведущее на другие страницы
 8 | 2. центральная часть содержит информационное описание для главной страницы. И прогноз погоды для страницы конкретного города. В случае ошибки при запросе она отображает сообщение об ошибке
 9 | 3. в подвале сайта отображаются 5 последних городов, погоду в которых искал пользователь. При ошибке запрос не добавляется в списко
10 | 
11 | ![](weatherPage.png)
12 | 
13 | ## Детали
14 | 
15 | * В любой момент времени взаимодействия с картой - ее состояние должно отображаться на URL-адрес, чтобы при обновлении страницы / отпавке ссылки другому человеку - страница открывалась на той же точке
16 | * При вводе текста в поле ввода и нажатие кнопки "Ввод" ( или по клику на кнопке "Искать" ) пользователь попадает на страницу с прогнозом погоды в заданном городе. При этом страницу можно добавить в закладки или отправить сообщением - при открытии ссылки должен показаться тот же город.
17 | * При изменении центра карты ( перетаскивание / зум ) должны отображаться данные по погоде для центра карты
18 | * При поиске города он появляется верхним пунктов в списке последних запросов ( нижний блок ), остальные пункты опускаются на 1 вниз. Пункты с номером больше 5 исчезают.
19 | * В любой точке на карте можно нажать 'Add to Favorites' - это добавить точку с описанием в список "Избранное". Из списка сущность можно удалить с помощью `x` возле записи. При клике на запись в списке "Избранное" происходит переход на сохраненные координаты
20 | * Функция загрузки прогноза должна быть реализована в двух вариантах - с использованием fetch и с использованием XHR. Блок с options для выбора (два пункта из которых всегда выбран только один) какую из реализаций использовать для получения следующего прогноза. Этот же переключатель влияет на реализацию всех запросов на сторонние ресурсы (определение координат пользователя, конвертация города в координаты и тп )
21 | * Для загрузки прогноза погоды использовать сайт https://darksky.net/
22 | * Для получения координат по введенным данным использовать API Google Maps
23 | * В шапку страницы добавить меню с двумя пунктами `Главная` / `О сайте`
24 |   Каждый пункт меню должен открывать соответствующую страницу.
25 |   "O сайте" - Отображает статическую информацию - ваше имя, фото, ссылки на соцсети и свободный текст
26 |   "Главная" - при входе на страницу сайт определяет местоположение пользователя ( запросом на `https://api.userinfo.io/userinfos` или на аналогичный ресурс) и перенаправляет на страницу с соответсвующими координатами
27 | * Должны поддерживаться ссылки с указанием города ( например `/city/Minsk` )
28 | 
29 | ## Настроить систему сборки, для работы с модулями / ES6 (используя gulp!!)
30 | 
31 | Полезными могут оказаться следующие статьи:
32 | 
33 | 1. [Setting up ES6+Babel+Gulp](http://ramkulkarni.com/blog/setting-up-es6-babel-gulp/)
34 | 2. [Getting import/export working ES6 style using Browserify + Babelify + Gulp = -5hrs of life](https://medium.com/@hey.aaron/getting-import-export-working-es6-style-using-browserify-babelify-gulp-5hrs-of-life-eca7786e44cc)
35 | 3. [Using ES6 with gulp](https://markgoodyear.com/2015/06/using-es6-with-gulp/)
36 | 
37 | Уделите этому пункту внимание и время! Настроенная система сборки экономит вам время и создает удобное окружение для хорошего кода.
38 | 
39 | ## Прочитать
40 | 
41 | 1. [Мультивставка: insertAdjacentHTML и DocumentFragment](https://learn.javascript.ru/multi-insert)
42 | 1. [Интерфейсы. Прочь от MVC](http://javascript.ru/optimize/antimvc)
43 | 
44 | ## Посмотреть
45 | 
46 | 1. [Компонентный подход от Вовы](https://www.youtube.com/watch?v=sH04-Ypak_s)
47 | 


--------------------------------------------------------------------------------
/.ht/diff/parallel.test.js:
--------------------------------------------------------------------------------
  1 | const assert = require('chai').assert;
  2 | const sinon = require('sinon');
  3 | 
  4 | const Parallel = require('./parallel');
  5 | 
  6 | describe('Parallel', () => {
  7 |   it('is a function', () => assert.isFunction(Parallel));
  8 |   it('is a constructor', () => assert.instanceOf(new Parallel(), Parallel));
  9 |   it('has public interface', () => {
 10 |     let p = new Parallel();
 11 |     assert.isFunction(p.job);
 12 |     assert.isFunction(p.done);
 13 |   });
 14 |   it('.job is chainable', () => {
 15 |     const p = new Parallel();
 16 |     assert.equal(p, p.job());
 17 |   });
 18 |   it('calls done if no jobs asynchroniosly', (done) => {
 19 |     const cb = sinon.spy();
 20 |     const p = new Parallel();
 21 |     p.done(cb);
 22 |     assert.isNotOk(cb.called);
 23 |     setTimeout(() => {
 24 |       assert.isOk(cb.called);
 25 |       done();
 26 |     });
 27 |   });
 28 |   it("doesn't call jobs with no .done call", (done) => {
 29 |     const p = new Parallel();
 30 |     const cb = sinon.spy();
 31 |     p.job(cb);
 32 |     assert.isNotOk(cb.called);
 33 |     setTimeout(() => {
 34 |       assert.isNotOk(cb.called);
 35 |       done();
 36 |     }, 100);
 37 |   });
 38 |   it('calls jobs with .done call', (done) => {
 39 |     const p = new Parallel();
 40 |     const cb = sinon.spy();
 41 |     p.job(cb).done(() => null);
 42 |     setTimeout(() => {
 43 |       assert.isOk(cb.called);
 44 |       done();
 45 |     }, 100);
 46 |   });
 47 |   it('calls .done cb with results of jobs', function(done) {
 48 |     this.timeout(10000 + 500);
 49 |     const runner = new Parallel(2);
 50 |     let result = 'before/';
 51 | 
 52 |     runner
 53 |       .job(step0)
 54 |       .job(step1)
 55 |       .job(step2)
 56 |       .job(step3)
 57 |       .job(step4)
 58 |       .done(onDone);
 59 | 
 60 |     result += 'after/';
 61 | 
 62 |     function step0(done) {
 63 |       result += 'step0/';
 64 | 
 65 |       done('step0');
 66 |     }
 67 | 
 68 |     function step1(done) {
 69 |       result += 'step1/';
 70 | 
 71 |       setTimeout(done, 3000, 'step1');
 72 |     }
 73 | 
 74 |     function step2(done) {
 75 |       result += 'step2/';
 76 | 
 77 |       setTimeout(done, 1500, 'step2');
 78 |     }
 79 | 
 80 |     function step3(done) {
 81 |       result += 'step3/';
 82 | 
 83 |       setTimeout(done, 2000, 'step3');
 84 |     }
 85 | 
 86 |     function step4(done) {
 87 |       result += 'step4/';
 88 | 
 89 |       setTimeout(done, 500, 'step4');
 90 |     }
 91 | 
 92 |     let isPassed = false;
 93 |     function onDone(results) {
 94 |       assert.isArray(results);
 95 |       assert.deepEqual(results, ['step0', 'step1', 'step2', 'step3', 'step4']);
 96 |       // assert.equal(result, "before/after/step0/step1/step2/step3/step4/");
 97 |       isPassed = true;
 98 |     }
 99 | 
100 |     setTimeout(() => done(isPassed ? null : 'not passed'), 8000);
101 |   });
102 | 
103 |   for (let i = 1; i <= 6; i++) {
104 |     let PARALLEL_LIMIT = i;
105 |     it(`calls jobs in ${PARALLEL_LIMIT} parallel`, function(done) {
106 |       this.timeout(PARALLEL_LIMIT * 500);
107 |       const runner = new Parallel(PARALLEL_LIMIT);
108 |       let currentTasks = 0;
109 |       let maxNumOfParallelTasks = 0;
110 |       const getTask = (delay) => (done) => {
111 |         currentTasks += 1;
112 |         maxNumOfParallelTasks = Math.max(maxNumOfParallelTasks, currentTasks);
113 |         setTimeout(() => {
114 |           maxNumOfParallelTasks = Math.max(maxNumOfParallelTasks, currentTasks);
115 |           currentTasks -= 1;
116 |           done(`task`);
117 |         }, delay);
118 |       };
119 | 
120 |       for (let j = 0; j <= PARALLEL_LIMIT * 5; j++) {
121 |         runner.job(getTask(20));
122 |       }
123 |       runner.done(() => {
124 |         assert.equal(maxNumOfParallelTasks, PARALLEL_LIMIT);
125 |         done();
126 |       });
127 |     });
128 |   }
129 | });
130 | 


--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
 1 | # Базовый курс JS
 2 | 
 3 | Хорошо подумайте перед тем, как платить деньги за курс. Я об этом говорю на вводном занятии, мне не верят. Вот вам отзывы студентов: [видео](https://www.youtube.com/watch?v=5r9kr_He3q0&list=PLX3Jlot18dp7R9Tg0ccN02Pc3NTYzjcat)
 4 | 
 5 | ## И еще отзывы студентов тут http://bit.ly/vvscode-js-truth
 6 | 
 7 | Там же можно найти профили живых студентов
 8 | 
 9 | 
10 | Доступ к чату курса можно получить здесь http://bit.ly/codehardjs
11 | 
12 | 
13 | |                                                                                   	|                                                                            	|                                                       	|
14 | |-----------------------------------------------------------------------------------	|----------------------------------------------------------------------------	|-------------------------------------------------------	|
15 | | [Введение](https://github.com/vvscode/js--base-course/tree/master/00)             	|                                                                            	| Что нужно сделать ДО начала курса                     	|
16 | | [Занятие #1](https://raw.githack.com/vvscode/js--base-course/master/01/cls/index.html) 	| [Задание #1](https://github.com/vvscode/js--base-course/tree/master/01/ht) 	| Вводное занятие и проверка подготовки к курсу         	|
17 | | [Занятие #2](https://raw.githack.com/vvscode/js--base-course/master/02/cls/index.html) 	| [Задание #2](https://github.com/vvscode/js--base-course/tree/master/02/ht) 	| Объекты, протипы, функции, конструкторы, наследование 	|
18 | | [Занятие #3](https://raw.githack.com/vvscode/js--base-course/master/03/cls/index.html) 	| [Задание #3](https://github.com/vvscode/js--base-course/tree/master/03/ht) 	| Очередь задач, асинхронность 	|
19 | | [Занятие #4](https://raw.githack.com/vvscode/js--base-course/master/04/cls/index.html) 	| [Задание #4](https://github.com/vvscode/js--base-course/tree/master/04/ht) 	| Интерфейсы, работа с URL	|
20 | | [Занятие #5](https://raw.githack.com/vvscode/js--base-course/master/05/cls/index.html) 	| [Задание #5](https://github.com/vvscode/js--base-course/tree/master/05/ht) 	| Модульность и роутинг	|
21 | | [Занятие #6](https://raw.githack.com/vvscode/js--base-course/master/06/cls/index.html) 	| [Задание #6](https://github.com/vvscode/js--base-course/tree/master/06/ht) 	| Части приложения и внешние библиотеки	|
22 | | [Занятие #7](https://raw.githack.com/vvscode/js--base-course/master/07/cls/index.html) 	| [Задание #7](https://github.com/vvscode/js--base-course/tree/master/07/ht) 	| Работа с графикой	|
23 | | [Занятие #8](https://raw.githack.com/vvscode/js--base-course/master/08/cls/index.html) 	| [Задание #8](https://github.com/vvscode/js--base-course/tree/master/08/ht) 	| Тестирование	|
24 | ---
25 | 
26 | [Список вопросов](https://raw.githack.com/vvscode/js--base-course/master/questions/index.html)
27 | 
28 | --- 
29 | 
30 | [![](https://sourcerer.io/fame/vvscode/vvscode/js--base-course/images/0)](https://sourcerer.io/fame/vvscode/vvscode/js--base-course/links/0)[![](https://sourcerer.io/fame/vvscode/vvscode/js--base-course/images/1)](https://sourcerer.io/fame/vvscode/vvscode/js--base-course/links/1)[![](https://sourcerer.io/fame/vvscode/vvscode/js--base-course/images/2)](https://sourcerer.io/fame/vvscode/vvscode/js--base-course/links/2)[![](https://sourcerer.io/fame/vvscode/vvscode/js--base-course/images/3)](https://sourcerer.io/fame/vvscode/vvscode/js--base-course/links/3)[![](https://sourcerer.io/fame/vvscode/vvscode/js--base-course/images/4)](https://sourcerer.io/fame/vvscode/vvscode/js--base-course/links/4)[![](https://sourcerer.io/fame/vvscode/vvscode/js--base-course/images/5)](https://sourcerer.io/fame/vvscode/vvscode/js--base-course/links/5)[![](https://sourcerer.io/fame/vvscode/vvscode/js--base-course/images/6)](https://sourcerer.io/fame/vvscode/vvscode/js--base-course/links/6)[![](https://sourcerer.io/fame/vvscode/vvscode/js--base-course/images/7)](https://sourcerer.io/fame/vvscode/vvscode/js--base-course/links/7)
31 | 


--------------------------------------------------------------------------------
/04/ht/README.md:
--------------------------------------------------------------------------------
 1 | # Теория
 2 | 
 3 | Прочитать материалы по следующим темам ( как минимум знать что это такое, а хотя бы пару слов зачем и как использовать ). По каждому пункту должна быть минимум 1 карточка в Anki
 4 | 
 5 | * SOLID
 6 | * KISS
 7 | * DRY
 8 | * YAGNI
 9 | * MVC
10 | * Паттерны проектирования ( Что это? Какие есть группы? )
11 | * Антипаттерны проектирования
12 | * Модульные системы (CommonJS/ ES6 modules/ AMD)
13 | * requirejs
14 | 
15 | ## Календарь задач
16 | 
17 | Реализовать одностраничное приложение "Календарь задач".
18 | 
19 | ![enter image description here](https://github.com/vvscode/js--base-course/blob/e39522cad41dfc6022bee5526fcb26f754c91260/04/ht/calendar-spa.png)
20 | 
21 | ### Функционал календаря
22 | 
23 | Опциональные параметры передаются в конструтор календаря
24 | 
25 | * Отображение календаря
26 | * Опциональное отображение текущего месяца/года
27 | * Опциональная возможность изменения месяца кнопками "вправо/влево"
28 | * При двойном клике на ячейку календаря с датой - запросить у пользователя данные о задаче, после чего вывести запись о задаче в соответствующей ячейке. Возможность добавления записей опциональная
29 | * На каждой записи должен отображаться значок удаления записи ( удаление записей опциональное ). При клике по нему нужно запросить у пользователя подтверждение. После подтверждения удалить запись из календаря.
30 | * Календарь должен иметь возможность работать в нескольких экземплярах на странице. Независимо друг от друга.
31 | * При обновлении страницы информация о созданных заданиях должна сохраняться
32 | 
33 | Календарь должен предоставлять API для программной смены месяца ( если это соответствует настройкам календаря )
34 | 
35 | ## Страницы SPA ( SinglePageApplication)
36 | 
37 | ### Демонстрация работы календаря
38 | 
39 | Представляет полнофункциональный календарь. Со всеми возможностями
40 | 
41 | ### Создание своего календаря
42 | 
43 | Отображение трех блоков
44 | 
45 | #### 1 - Форма настройки календаря
46 | 
47 | Форма для настройки всех опциональных возможностей календаря, ввода фиксированной даты ( или отсутствие фиксации даты ), настройка класса для виджета и тп
48 | 
49 | #### 2 - Блок с кодом
50 | 
51 | Блок с кодом, который позволит запустить на странице календарь с выбранными настройками ( см выше ). Например
52 | 
53 | ```
54 |     
55 | 		
68 | ```
69 | 
70 | #### 3 - Предпросмотр календаря
71 | 
72 | Отображение календаря с текущими настройками.
73 | 
74 | Любые изменения в форме 1 сразу отображаются на данных в блоках 2 и 3.
75 | 
76 | Навигация между страницами происходит через меню, вверху страницы. Данные в текущей итерации хранятся в `localStorage` (важно учесть, что при нескольких календарях на странице данные для них хранятся раздельно ).
77 | 
78 | Код разнести по нескольким файлам ( в соответсвии с назначением ) и интерфейсные методы/функции описать `jsdoc` комментариями.
79 | 
80 | ## Тесты
81 | 
82 | Приложение должно быть покрыто тестами ( unit тестами c `mocha` и интеграционными тестами c `testcafe` https://devexpress.github.io/testcafe/ ). Так же приложение должно быть задеплоено на githubpages.
83 | 
84 | Задание лучше делать в отдельном репозитории. Создать отдельную ветку от ветки master, и сделать PR для оценки кода (со ссылкой на развернутую на githubpages версию )
85 | 
86 | ---
87 | 
88 | Добавить к конфигуратору две опции (и обновить код календаря для соответствующего функционала)
89 | 
90 | * хранить данные в localStorage/firbase (изпользуя REST/fetch интерфейс к БД)
91 | * запрашивать данные через `prompt`/через модальное окно с html формой
92 | 
93 | Разные пользователи должны иметь возможность хранить данные независимо. К PR прикрепить ссылку, где можно посмотреть демо работы календаря и демо конфигуратора.
94 | 


--------------------------------------------------------------------------------
/02/ht/example/script.js:
--------------------------------------------------------------------------------
  1 | /* eslint no-var: "off" */
  2 | /* eslint no-unused-vars: "off" */
  3 | /* eslint max-len: "off" */
  4 | 
  5 | /**
  6 |  * Написать функцию `isDeepEqual`
  7 |  * которая принимает на вход двe переменных
  8 |  * и проверяет идентичны ли они по содержимому. Например
  9 |  * @param {*} objA
 10 |  * @param {*} objB
 11 |  * @return {boolean} идентичны ли параметры по содержимому
 12 |  */
 13 | function isDeepEqual(objA, objB) {
 14 |   /* Ваше решение */
 15 |   return undefined;
 16 | }
 17 | 
 18 | /**
 19 |  * Функция фиксации контекста
 20 |  * @param {*} func Функция для которой нужно зафиксировать контекст
 21 |  * @param {*} context значение для this
 22 |  * @return {function} функция с зафиксированным контекстом
 23 |  */
 24 | function bind(func, context) {
 25 |   return undefined;
 26 | }
 27 | 
 28 | /**
 29 |  * Реализовать метод .myBind для всех функций,
 30 |  * который работает так же как оригинальный .bind но не использует его внутри
 31 |  * (можно использовать фукнцию выше)
 32 |  */
 33 | 
 34 | /**
 35 | * создать объект с волшебным свойством,
 36 | * чтобы при присвоении ему значения, в консоль выводилась текущая дата и значение, которое присваиваем.
 37 | * А при чтении всегда выводилось число на 1 больше предыдущего
 38 | * o.magicProperty = 5; // 'Sat Mar 24 2018 13:48:47 GMT+0300 (+03) -- 5'
 39 | * console.log(o.magicProperty); // 6
 40 | * console.log(o.magicProperty); // 7
 41 | * console.log(o.magicProperty); // 8
 42 | */
 43 | 
 44 | /**
 45 | * Создать конструктор с методами, так,
 46 | * чтобы следующий код работал и делал соответствующие вещи
 47 | * те запуск кода ниже должен делать то, что говорят методы
 48 | * u.askName().askAge().showAgeInConsole().showNameInAlert();
 49 | */
 50 | 
 51 | /**
 52 |  * Написать фукнцию-калькулятор, которая работает следующим образом
 53 |  * calculate('+')(1)(2); // 3
 54 |  * calculate('*')(2)(3); // 6
 55 |  * Допустимые операции : + - * /
 56 |  */
 57 | function calculate() {
 58 |   /* put your code here */
 59 | }
 60 | 
 61 | /**
 62 |  * Создайте конструктор-синглтон? Что такое синглтон?
 63 |  * new Singleton() === new Singleton
 64 |  */
 65 | function Singleton() {
 66 |   throw 'undefined';
 67 | }
 68 | 
 69 | /**
 70 |   * Создайте функцию ForceConstructor
 71 |   * которая работает как конструктор независимо от того,
 72 |   * вызвана она с new или без
 73 |   * и сохраняет параметры в создаваемый объект с именами параметров
 74 |   */
 75 | function ForceContructor(a, b, c) {
 76 |   throw 'undefined';
 77 | }
 78 | 
 79 | /**
 80 |  * Написать фукнцию сумматор, которая будет работать
 81 |  * var s = sum();
 82 |  * log(s); // 0
 83 |  * log(s(1)); // 1
 84 |  * log(s(1)(2)); //3
 85 |  * log(s(3)(4)(5)); // 12
 86 |  * Число вызовов может быть неограниченым
 87 |  */
 88 | function sum() {
 89 |   throw 'undefined';
 90 | }
 91 | 
 92 | function log(x) {
 93 |   console.log(+x);
 94 | }
 95 | 
 96 | /**
 97 |  * Написать каррирующую функцию и покрыть ее тестами
 98 |  * Функция должна поддерживать каррирование функций с 2,3,4,5 параметрами
 99 |  * пример работы  функции
100 |  *
101 |  * function target1(a,b,c,d) { return a + b + c + d }
102 |  * function target2(a,b) { return a + b }
103 |  * curry(target1)(1)(2)(3)(4) // 10
104 |  * curry(target2)(5)(8) // 13
105 |  *
106 |  * Примеры тестов смотреть в файле тестов
107 |  *
108 |  * Читать
109 |  * http://prgssr.ru/development/vvedenie-v-karrirovanie-v-javascript.html
110 |  * https://github.com/MostlyAdequate/mostly-adequate-guide-ru/blob/master/ch4-ru.md
111 |  * @param {*} func
112 |  */
113 | function curry(func) {}
114 | 
115 | /*
116 | Написать код, который для объекта созданного с помощью конструктора будет показывать,
117 | что объект является экземпляром двух классов
118 | */
119 | /* Тут ваш код */
120 | // User === PreUser; // false
121 | // u instanceof User; // true
122 | // u instanceof Array; // true
123 | // u instanceof PreUser; // true
124 | 
125 | /*
126 | Создать веб страницу. Добавить на нее форму с полями
127 | - имя (строкое поле),
128 | - родной город (Выпадающий список),
129 | - Комментарий (многострочное поле), пол (radiobutton).
130 | При нажатии на кнопку - нужно собрать данные введенные в поля и вывести их в блоке под формой,
131 | после чего поля очистить.
132 | */
133 | 
134 | /*
135 | Используя функцию drawCalendar из прошлого урока
136 | создать функцию drawInteractiveCalendar(el)
137 | Которая выводит календарь, в шапке которого отображается
138 | [<] месяц / год [>]
139 | При клике по кнопкам [<] / [>] нужно реализовать листание календаря
140 | Добавть на страницу index.html вызов календаря
141 | */
142 | function drawInteractiveCalendar(el) {}
143 | 


--------------------------------------------------------------------------------
/00/README.md:
--------------------------------------------------------------------------------
 1 | # Это вводный материал, для подготовки к первому занятию на курсе FD2 по javascript
 2 | 
 3 | Очень советую ознакомиться со всеми материалами и выполнить все задания. До конца курса в моих группах доходят не все.
 4 | 
 5 | ## На случай, если ты подумал(а), что это шутки - нифига https://www.youtube.com/playlist?list=PLX3Jlot18dp7R9Tg0ccN02Pc3NTYzjcat
 6 | 
 7 | ## На занятиях понадобится
 8 | 
 9 |  - Тетрадь ( желательно формата А4)
10 |  - Ручка / Карандаш
11 |  - В идеале посещать занятия со своим компьютером. В классе есть рабочие машины, но гораздо удобнее работать в привычной среде, с знакомой клавиатурой/системой/редактором. Так что это не обязательно, но в ваших интересах.
12 | 
13 | 
14 | ## Перед первым занятием нужно прочитать
15 | 
16 |  - [Как правильно задавать вопросы в технических форумах](https://www.opennet.ru/docs/RUS/smart_question/) - прочитать и составить письменно чеклист по задаванию вопросов
17 |  - [Как эффективно сообщать об ошибках](https://www.chiark.greenend.org.uk/~sgtatham/bugs-ru.html) - как задавать вопросы о неработающем коде или примерах, прочитать, запомнить, усвоить
18 |  - [Блок-схемы алгоритмов. ГОСТ. Примеры](https://pro-prof.com/archives/1462)
19 | 
20 | ---
21 |  - [Введение в JavaScript](https://developer.mozilla.org/ru/docs/Web/JavaScript/Guide/%D0%92%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B2_JavaScript#Scratchpad)
22 |  - [Основы JavaScript](https://developer.mozilla.org/ru/docs/Learn/Getting_started_with_the_web/JavaScript_basics) - После прочтения найти соответствия из конструкций языка к элементам блок-схем
23 | 
24 | ---
25 |  - [Преимущества метода интервального запоминания](http://web.archive.org/web/20170315102949/https://habrahabr.ru/company/everydaytools/blog/322286/)
26 |  - [Дерек Сиверс: «Метод интервального повторения — лучший способ изучения языков программирования»](https://habrahabr.ru/post/196448/) 
27 |  
28 |  ---
29 |  - [Git. Просто Git](http://zzet.org/git/learning/undev/coursify/2014/02/09/lection-1-git-course-undev.html)
30 |  - [Скринкаст по Git](https://www.youtube.com/playlist?list=PLDyvV36pndZHkDRik6kKF6gSb0N0W995h)
31 | 
32 | 
33 | ## Перед первым занятием нужно сделать
34 | 
35 |  - Сформулировать развернутый ответ на вопросы *"Зачем мне этот курс? Зачем я сюда пришел?"*
36 |  - Сформулировать развернутый ответ на вопрос *"Как я пойму, что курс был для меня полезен? По каким критерия я буду оценивать свои результаты? Какой идеальный конечный результат, на который я нацелен?"*
37 |  - Зарегистрировать аккаунт на [GitHub.com](http://github.com) и максимально заполнить профиль (в идеале - имя аккаунта - это ваше имя+фамилия) + пройти до конца курс [TryGit](https://try.github.io/levels/1/challenges/1)
38 |  
39 | ## Практическое задание
40 | 
41 | Создать страницу:
42 | - При открытии у пользователя сначала нужно спросить его имя, а потом возраст (можно использовать функцию `prompt`). 
43 | - Если пользователь не ввел имя/возраст - запросить данные повторно ( пока данные не будут заполнены ). 
44 | - После ввода пользователя вывести на странице сообщение. 
45 | - Если возвраст пользователя меньше 18 - `Здарова, {{ИМЯ_ПОЛЬЗОВАТЕЛЯ}}. Как твои {{ВОЗРАCТ ПОЛЬЗОВАТЕЛЯ}}?`. 
46 | - Если возраст пользователя больше либо равен 18 - `Привествую, {{ИМЯ_ПОЛЬЗОВАТЕЛЯ}}. Уж {{ВОЗРАCТ ПОЛЬЗОВАТЕЛЯ}} лет прошло`
47 | 
48 | Для сдачи задания на проверку нужно сделать [fork](https://help.github.com/articles/fork-a-repo/) этого репозитория. В своем форке создать отдельную ветку `00`. В этой ветке создать папку `00/ht/{{ВАШ_НИК_НА_GITHUB}}` и в этой папке разместить созданную страницу. После чего сделать [commit и push](https://readwrite.com/2013/10/02/github-for-beginners-part-2/) и создать [pull request](https://help.github.com/articles/about-pull-requests/) в этот репозиторий. 
49 | 
50 | ### Теория (знание ответов на вопросы проверяется на занятии!)
51 |  - Что такое git?
52 |  - Какие есть системы контроля версий?
53 |  - как создать ветку в git?
54 |  - что такое HTML?
55 |  - что такое CSS?
56 |  - как зовут создателя JavaScript?
57 |  - в каком году был создан JavasScript?
58 |  - Какая текущая версия Javacript?
59 |  - Какая прошлая версия Javascript?
60 |  - Какого номера версии Javascript не было?
61 |  - Как называется комитет, занимающийся развитием JavaScript?
62 |  - Для чего нужен файл .gitignore?
63 |  - Как добавить в git пустую папку?
64 |  - Что такое "линтер"?
65 |  - Для чего нужен "prettier"?
66 |  - Как открыть DevTools в браузере?
67 |  - Как можно добавить javascript на страницу?
68 |  - Сколько будет `0.2 + 0.1`?
69 |  - Что такое breakpoint?
70 |  - Какие методы есть у объекта `console`?
71 |  - На странице два элемента с `id="awesomeId"`. Как из javascript найти второй?
72 |  - Что такое falsy (ложное) значение? Сколько их?
73 |  - Назовите 4 javascript фреймворка
74 |  - Назовите 3 javascript библиотеки
75 |  - Что такое cookies?
76 |  - Что происходит между вводом в адресной строке адреса страницы и появлением страницы на экране?
77 |  - Зачем нужен DNS сервер?
78 |  - Что такое HTTP?
79 |  - Назовите 3 программы-веб сервера
80 |  - Назовите 5 программ-браузеров
81 |  - Полное название Javascript?
82 |  - Что такое "транспиляция" в контексте разработки на Javascript?
83 |  - Как в Slack оформить многострочный код?
84 |  - Как в Slack оформить однострочный код?
85 |  - Что такое "императивное программирование"?
86 |  - Что такое ООП?
87 |  
88 | 


--------------------------------------------------------------------------------
/.ht/01/script.tests.js:
--------------------------------------------------------------------------------
  1 | "use strict";
  2 | 
  3 | /* eslint no-var: "off" */
  4 | /* eslint no-unused-vars: "off" */
  5 | /* eslint max-len: "off" */
  6 | 
  7 | describe("fizzBuzz", function() {
  8 |   it("функция", function() {
  9 |     return assert.isOk(typeof fizzBuzz === "function");
 10 |   });
 11 | 
 12 |   var result =
 13 |     "\n1\n2\nFizz\n4\nBuzz\nFizz\n7\n8\nFizz\nBuzz\n11\nFizz\n13\n14\nFizzBuzz\n16\n17\nFizz\n19\nBuzz\nFizz\n22\n23\nFizz\nBuzz\n26\nFizz\n28\n29\nFizzBuzz\n31\n32\nFizz\n34\nBuzz\nFizz\n37\n38\nFizz\nBuzz\n41\nFizz\n43\n44\nFizzBuzz\n46\n47\nFizz\n49\nBuzz\nFizz\n52\n53\nFizz\nBuzz\n56\nFizz\n58\n59\nFizzBuzz\n61\n62\nFizz\n64\nBuzz\nFizz\n67\n68\nFizz\nBuzz\n71\nFizz\n73\n74\nFizzBuzz\n76\n77\nFizz\n79\nBuzz\nFizz\n82\n83\nFizz\nBuzz\n86\nFizz\n88\n89\nFizzBuzz\n91\n92\nFizz\n94\nBuzz\nFizz\n97\n98\nFizz\nBuzz";
 14 | 
 15 |   var _log = window.log;
 16 |   var str = "";
 17 |   window.log = function(a) {
 18 |     return (str = str + a + "\n");
 19 |   };
 20 |   fizzBuzz();
 21 | 
 22 |   it("выводит правильные данные", function() {
 23 |     return assert.isOk(str.trim() === result.trim());
 24 |   });
 25 |   it("не использует `if`", function() {
 26 |     return assert.isOk(("" + fizzBuzz).indexOf("if") < 0);
 27 |   });
 28 |   it("не использует `else`", function() {
 29 |     return assert.isOk(("" + fizzBuzz).indexOf("else") < 0);
 30 |   });
 31 |   it("не использует `switch`", function() {
 32 |     return assert.isOk(("" + fizzBuzz).indexOf("switch") < 0);
 33 |   });
 34 |   it("не использует `? :`", function() {
 35 |     return assert.isOk(("" + fizzBuzz).indexOf("?") < 0);
 36 |   });
 37 | });
 38 | 
 39 | describe("isPolindrom", function() {
 40 |   it("функция", function() {
 41 |     return assert.isOk(typeof isPolindrom === "function");
 42 |   });
 43 |   it("возвращает true/false", function() {
 44 |     return assert.isOk(typeof isPolindrom("") === "boolean");
 45 |   });
 46 |   it("asd - не полиндром", function() {
 47 |     return assert.isOk(isPolindrom("asd") === false);
 48 |   });
 49 |   it("asdsa - полиндром", function() {
 50 |     return assert.isOk(isPolindrom("asdsa") === true);
 51 |   });
 52 |   it('"" - полиндром', function() {
 53 |     return assert.isOk(isPolindrom("") === true);
 54 |   });
 55 |   it("asdsb - не полиндром", function() {
 56 |     return assert.isOk(isPolindrom("asdsb") === false);
 57 |   });
 58 |   it("'1231' - не полиндром", function() {
 59 |     return assert.isOk(isPolindrom("1231") === false);
 60 |   });
 61 | });
 62 | 
 63 | describe("drawCalendar", function() {
 64 |   var el;
 65 |   beforeEach(function() {
 66 |     return (el = document.createElement("div"));
 67 |   });
 68 | 
 69 |   it("функция", function() {
 70 |     return assert.isOk(typeof drawCalendar === "function");
 71 |   });
 72 |   it("заполняет innerHTML у элемента (третий аргумент)", function() {
 73 |     drawCalendar(2017, 9, el);
 74 |     assert.isOk(el.innerHTML.trim() !== "");
 75 |   });
 76 |   it("генерирует разный html для разных месяцев", function() {
 77 |     drawCalendar(2017, 9, el);
 78 |     var html1 = el.innerHTML;
 79 |     drawCalendar(2017, 10, el);
 80 |     var html2 = el.innerHTML;
 81 |     assert.isOk(html1 !== html2);
 82 |   });
 83 |   it("правильно определяет число дней в месяце", function() {
 84 |     drawCalendar(2017, 9, el);
 85 |     var html = el.innerHTML;
 86 |     assert.isOk(html.indexOf("30") > 0);
 87 |     assert.isOk(html.indexOf("31") < 0);
 88 | 
 89 |     drawCalendar(2017, 2, el);
 90 |     var html = el.innerHTML;
 91 |     assert.isOk(html.indexOf("28") > 0);
 92 |     assert.isOk(html.indexOf("29") < 0);
 93 |     assert.isOk(html.indexOf("30") < 0);
 94 |     assert.isOk(html.indexOf("31") < 0);
 95 |   });
 96 |   /** Остальные проверки сильно зависят от разметки календаря */
 97 | });
 98 | 
 99 | describe("isDeepEqual", function() {
100 |   it("фунция", function() {
101 |     return assert.isOk(typeof isDeepEqual === "function");
102 |   });
103 |   it("возвращает true/false", function() {
104 |     return assert.isOk(typeof isDeepEqual("", "") === "boolean");
105 |   });
106 |   it("распознает одинаковые строки", function() {
107 |     return assert.isOk(isDeepEqual("мама", "мама") === true);
108 |   });
109 |   it("распознает разные строки", function() {
110 |     return assert.isOk(isDeepEqual("мама", "папа") === false);
111 |   });
112 | 
113 |   it("распознаем разные массивы", function() {
114 |     return assert.isOk(isDeepEqual([1, 4, 2], [1, 2, 4]) === false);
115 |   });
116 |   it("распознает одинаковые массивы", function() {
117 |     return assert.isOk(isDeepEqual([1, 2, 4, 3], [1, 2, 4, 3]) === true);
118 |   });
119 |   it("распознает массивы разной длинны", function() {
120 |     return assert.isOk(isDeepEqual([1, 2, 5], [1, 2, 5, 7]) === false);
121 |   });
122 | 
123 |   var a = { prop1: 1, list: [1, 2, 3], o: { x: 2 } };
124 |   var b = { list: [1, 2, 3], o: { x: 2 } };
125 |   it("распознает разные объекты", function() {
126 |     return assert.isOk(isDeepEqual(a, b) === false);
127 |   });
128 | 
129 |   it("распознает одинаковые объекты", function() {
130 |     b.prop1 = 1;
131 |     return assert.isOk(isDeepEqual(a, b) === true);
132 |   });
133 | 
134 |   it("распознает разные объекты", function() {
135 |     var a = { a: 1, b: 3, c: 2 };
136 |     var b = { a: 1, b: 4, c: 2 };
137 |     return assert.isOk(isDeepEqual(a, b) === false);
138 |   });
139 | 
140 |   it("распознает вложенные объекты", function() {
141 |     var a = { a: 1, b: { x: 5 }, c: 2 };
142 |     var b = { a: 1, b: { x: 5 }, c: 2 };
143 |     return assert.isOk(isDeepEqual(a, b) === true);
144 |   });
145 | 
146 |   it("распознает числа", function() {
147 |     var a = 1;
148 |     var b = 1.0;
149 |     return assert.isOk(isDeepEqual(a, b) === true);
150 |   });
151 | 
152 |   it("распознает разные числа", function() {
153 |     let a = 1;
154 |     let b = 2;
155 |     return assert.isOk(isDeepEqual(a, b) === false);
156 |   });
157 | });
158 | 


--------------------------------------------------------------------------------
/02/ht/README.md:
--------------------------------------------------------------------------------
  1 | ## Домашнее задание
  2 | 
  3 | ### Прочитать\* (с выполнением задач) разделы из учебника [Learn.Javascript.Ru](http://learn.javascript.ru/):
  4 | 
  5 | * [Автоматические тесты при помощи chai и mocha](https://learn.javascript.ru/testing)
  6 | * [Отладка в браузере Chrome](https://learn.javascript.ru/debugging-chrome)
  7 | * [Методы объектов и контекст вызова](https://learn.javascript.ru/objects-more)
  8 | * [setTimeout и setInterval](https://learn.javascript.ru/settimeout-setinterval)
  9 | * [Документ, события, интерфейсы](https://learn.javascript.ru/ui)
 10 | 
 11 | ### Найти ответы на вопросы (это то, что будет спрашиваться на занятии):
 12 | 
 13 | * Что такое контекст вызова функции? Чем определяется?
 14 | * Как изменить `this` внутри функции? (5 способов)
 15 | * чем различаются `.call` / `.apply` / `.bind`
 16 | * Что такое сигнатура функции?
 17 | * Чем характеризуется функция?
 18 | * Что такое прототип?
 19 | * Как работает конструктор? Что происходит при вызове со словом `new` ?
 20 | * Как происходит чтение свойств из объекта?
 21 | * Как происходит запись свойств в объект?
 22 | * Как проверить на принадлежность классу?
 23 | * Как работает `instanceof` ?
 24 | * 4е принципа ООП
 25 | * Виды полиморфизма. И их объяснение
 26 | * Событийный цикл в javascript
 27 | * Что такое фаза захвата / capturing ?
 28 | * Что такое фаза всплытия / bubbling ?
 29 | * Как подписаться на событие документа / html элемента?
 30 | * Что такое `Функция высшего порядка`?
 31 | * Что такое синхронный / асинхронный код?
 32 | * Что такое `каррирование` ?
 33 | * Что такое паттерн `цепочка` ? Как реализовать?
 34 | * В чем разница объявления методов в конструкторе и на `.prototype` ?
 35 | * Что такое 'полифилл'?
 36 | 
 37 | ### Решить задачи (подробнее см [файл с тестами](https://github.com/vvscode/js--base-course/blob/master/.ht/02/script.tests.js))
 38 | 
 39 | * `isDeepEqual` (добавлены тесты)
 40 | * написать ФВП (функцию высшего порядка) `bind`
 41 | * написать методы `.myBind` (именно с таким названием)
 42 | * создать объект с волшебным свойством, чтобы при присвоении ему значения, в консоль выводилась текущая дата и значение, которое присваиваем. А при чтении всегда выводилось число на 1 больше предыдущего
 43 | 
 44 | ```javascript
 45 | o.magicProperty = 5; // 'Sat Mar 24 2018 13:48:47 GMT+0300 (+03) -- 5'
 46 | console.log(o.magicProperty); // 6
 47 | console.log(o.magicProperty); // 7
 48 | console.log(o.magicProperty); // 8
 49 | ```
 50 | 
 51 | * создать конструктор для работы с цепочками вызовов
 52 | * написать функцию калькулятор
 53 | * написать синглтон
 54 | * написать конструктор, который всегда конструктор
 55 | 
 56 | ```javascript
 57 | var u = User();
 58 | u instanceof User; // true
 59 | ```
 60 | 
 61 | * написать сумматор
 62 | * написать и покрыть тестами каррирующую функцию `curry` ( преобразующую функцию - из функции многих аргументов, получить множество функций одного аргумента)
 63 | 
 64 | ```javascript
 65 | function sum2(x, y) {
 66 |   return x + y;
 67 | }
 68 | function sum4(a, b, c, d) {
 69 |   return a + b + c + d;
 70 | }
 71 | 
 72 | curry(sum2)(1)(2); // 3
 73 | curry(sum4)(2)(3)(4)(5); // 14
 74 | ```
 75 | 
 76 | * создать цепочку наследования
 77 | 
 78 | ```javascript
 79 | var u = new User();
 80 | var u2 = new User();
 81 | assert.isOk(u instanceof User);
 82 | assert.isOk(u instanceof Array);
 83 | assert.isOk(u instanceof PreUser);
 84 | ```
 85 | 
 86 | * создать форму и ее обработчик. На форме поля ввода - Имя пользователя( строка ), возраст (выпадающий список), пол - radio-button, есть ли водительские права - чекбокс, о себе - многострочное поле. Все поля обязательные. При отправке формы, если все заполнено - под формой вывести информацию собранную от пользователя.
 87 | * создать генератор листаемого календаря и покрыть его тестами. В шапку календаря из прошлго ДЗ добавить кнопки для листания вправо/влево, которые позволяют изменыть отображаемый месяц. Тесты должны проверять весь функционал
 88 | * создать функцию, которая не может работать как конструктор (работать с `new`, и покрыть ее тестами
 89 | 
 90 | ---
 91 | 
 92 | * Написать реализацию метода `.myCall`, который будет работать аналогично системному `.call` и покрыть реализацию тестами
 93 | * Написать реализацию функций [debounce](http://underscorejs.ru/#debounce) и [throttle](http://underscorejs.ru/#throttle) и покрыть реализации тестами ( Если ваше имя начинается с гласной - `debounce`, иначе - `throttle`. А лучше - обе ). Функции должны с сигнатурой `debounce(fun, delay)` / `throttle(fun, delay)`
 94 | * К генератору листаемого календаря добавить функционал: под календарем добавить блок. При клике на ячейку даты ( но не на пустую ячейку календаря ) в блоке должна добавляться запись о том, по какой ячейке кликнули. Можно добавить запрос описания даты от пользователя ( с помощью функции `prompt` и выводить это описание там же). История дат и список, по которым пользоатель кликал, должны сохраняться между перезагрузками страницы. Для сохранения использовать [LocalStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage). Интерфейс работы с данными (чтение/запись) лучше сделать асинхронным
 95 | * Создать синхронную функцию `sleep(seconds)` так, чтобы работал код
 96 | 
 97 | ```javascript
 98 | console.log(new Date()); // Sun Oct 08 2017 10:44:34 GMT+0300 (+03)
 99 | sleep(9);
100 | console.log(new Date()); // Sun Oct 08 2017 10:44:43 GMT+0300 (+03)
101 | ```
102 | 
103 | * Написать функцию `getCounter` и покрыть ее тестами, так, чтобы работал следующий код
104 | 
105 | ```javascript
106 | var c = getCounter(5);
107 | c
108 |   .log() // 5
109 |   .add(4)
110 |   .log() // 9
111 |   .add(3)
112 |   .log() // 12
113 |   .reset()
114 |   .log() // 0
115 |   .add(8)
116 |   .log(); // 8
117 | ```
118 | 
119 | ## Видео
120 | 
121 | * [https://www.youtube.com/watch?v=8cV4ZvHXQL4](https://www.youtube.com/watch?v=8cV4ZvHXQL4)
122 | * [https://learn.javascript.ru/screencast/gulp](https://learn.javascript.ru/screencast/gulp)
123 | 


--------------------------------------------------------------------------------
/10/cls/index.html:
--------------------------------------------------------------------------------
  1 | 
  2 | 
  3 | 
  4 | 
  5 |   
  6 |   Js Base Course - Занятие 10
  7 |   
  8 |   
  9 |   
 10 |   
 11 | 
 12 | 
 13 | 
 14 |   
15 |
16 |
17 |

Вопросы?

18 |
19 |
20 |

21 | Вопросы! 23 |

24 |
25 |
26 |

Занятие 10

27 |
28 |
29 |
30 | 31 | 32 | 33 | 174 | 175 | 176 | 177 | -------------------------------------------------------------------------------- /questions/script.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len */ 2 | 3 | const questions0 = `Что такое git? 4 | Какие есть системы контроля версий? 5 | как создать ветку в git? 6 | что такое HTML? 7 | что такое CSS? 8 | как зовут создателя JavaScript? 9 | в каком году был создан JavasScript? 10 | Какая текущая версия Javacript? 11 | Какая прошлая версия Javascript? 12 | Какого номера версии Javascript не было? 13 | Как называется комитет, занимающийся развитием JavaScript? 14 | Для чего нужен файл .gitignore? 15 | Как добавить в git пустую папку? 16 | Что такое "линтер"? 17 | Для чего нужен "prettier"? 18 | Как открыть DevTools в браузере? 19 | Как можно добавить javascript на страницу? 20 | Сколько будет 0.2 + 0.1? 21 | Что такое breakpoint? 22 | Какие методы есть у объекта console? 23 | На странице два элемента с id="awesomeId". Как из javascript найти второй? 24 | Что такое falsy (ложное) значение? Сколько их? 25 | Назовите 4 javascript фреймворка 26 | Назовите 3 javascript библиотеки 27 | Что такое cookies? 28 | Что происходит между вводом в адресной строке адреса страницы и появлением страницы на экране? 29 | Зачем нужен DNS сервер? 30 | Что такое HTTP? 31 | Назовите 3 программы-веб сервера 32 | Назовите 5 программ-браузеров 33 | Полное название Javascript? 34 | Что такое "транспиляция" в контексте разработки на Javascript? 35 | Как в Slack оформить многострочный код? 36 | Как в Slack оформить однострочный код? 37 | Что такое "императивное программирование"? 38 | Что такое ООП?`; 39 | 40 | const questions1 = ` 41 | Что такое переменная? 42 | как объявить переменную? как инициализировать переменную? 43 | виды циклов ( 3 вида ) ? 44 | сколько и какие типы данных в javascript? 45 | Как узнать тип переменной? 46 | что такое область видимости? 47 | каким образом можно реализовать условное выполнение кода ? 48 | условные операторы в javascript - какие? 49 | что такое тернарный оператор? 50 | Как обойтись без условных операторов если нужно сделать условное выполнение кода? 51 | что такое функция? 52 | какими характеристиками можно описать функцию? 53 | Как можно создать функцию? 3 способа. 54 | Что такое объект? Как создать объект? ( 3 способа ) 55 | Что такое передача по ссылке / передача по значению? 56 | Что такое минификация и зачем она нужна? 57 | Как можно добавить javascript код в html страницу? 2 способа 58 | Что такое массив? 59 | Как создать массив? ( 3 способа ) 60 | Как запросить данные у пользователя? 61 | Что такое замыкание? 62 | Как узнать сколько параметров принимает функция? 63 | Как узнать есть ли у объекта свойство x ? 64 | Как сделать ревес строки? 65 | Как удалить предпоследний элемент в массиве? 66 | Как заменить в строке "papa roach" все буквы a на A ? 67 | Сколькими способами ( с примерами кода ) можно найти на странице div с id someId ? 68 | Как устроен событийный цикл в js? 69 | Что такое API? Примеры? 70 | Как в js реализовать многопоточность? 71 | Как в js реализовать наследование одного "класса" от другого? 72 | Сколькими способами можно проитерироваться по всем полям объекта? 73 | Что такое callback ? Зачем ? 74 | Почему 1 + '2' ? и 1 - '2' ? 75 | Как и когда работает преобразование типов? 76 | Что такое HTTP ? 77 | Какие есть методы HTTP запросов? Для чего каждый? 78 | Что такое REST ? RPC ? 79 | Что такое "линтер" (linter) ? Зачем они нужны? Какие линтеры есть для javascript? 80 | Что такое "jsdoc" ? Найдите его в своем домашнем задании. Зачем он нужен? Объясните использовнные теги. 81 | Что такое пакетный менеджер? 82 | Какие пакетные менеджеры есть для js? 83 | Что делают системы сборки? 84 | Какие системы сборки есть для js?`; 85 | 86 | const questions2 = `Как изменить "this" внутри функции? (5 способов) 87 | чем различаются ".call" / ".apply" / ".bind" 88 | Что такое контекст вызова функции? Чем определяется? 89 | Что такое сигнатура функции? 90 | Чем характеризуется функция? 91 | Что такое прототип? 92 | Как работает конструктор? Что происходит при вызове со словом "new" ? 93 | Как происходит чтение свойств из объекта? 94 | Как происходит запись свойств в объект? 95 | Как проверить на принадлежность классу? 96 | Как работает "instanceof" ? 97 | 4е принципа ООП 98 | виды полиморфизма. И их объяснение 99 | событийный цикл в javascript 100 | что такое фаза захвата / capturing ? 101 | что такое фаза всплытия / bubbling ? 102 | как подписаться на событие документа / html элемента? 103 | что такое "Функция высшего порядка"? 104 | что такое синхронный / асинхронный код? 105 | что такое "каррирование" ? 106 | в чем разница объявления методов в конструкторе и на .prototype" ? 107 | что такое 'полифилл'?`; 108 | 109 | const questions3 = `Что такое "стрелочная" ("arrow function") функция? Чем она отличается от обычной? 110 | Что такое Promise? Какой стандарт отписывает поведение Promise? Основные пункты стандарта? 111 | Чем куки (cookie) отличаются от localStorage ? 112 | Что такое CORS? 113 | Что такое и какие есть коды ответов HTTP? 114 | Что такое jsonp-запрос? 115 | Как код, написанный на ES6 (ES2015-2017) превратить в код, который поддерживается IE10? 116 | Как реализовать простейший модуль на js? 117 | Что такое и зачем нужен паттерн модуль? Какие модули существуют в JS? 118 | Как реализовать подписку на клик по кнопке, которая отработает только один раз? ( с примером кода ) 119 | Какие события не "всплывают" ? 120 | Что такое делегирование? 121 | Преимущества и особенности работы с делегированием? 122 | Какие вспомогательные методы есть для работы с промисами? 123 | в чем разница между следующими кусками кода?
promise.then(onSuccess, onError);

promise.then(onSuccess).catch(onError); 124 | в чем разница между следующими кусками кода?
doSomething().then(function () { return doSomethingElse(); });

doSomething().then(function () { doSomethingElse(); });

doSomething().then(doSomethingElse());

doSomething().then(doSomethingElse);
125 | `; 126 | 127 | const questions4 = ` 128 | SOLID 129 | KISS 130 | DRY 131 | YAGNI 132 | MVC 133 | Паттерны проектирования ( Что это? Какие есть группы? ) 134 | Антипаттерны проектирования 135 | Модульные системы (CommonJS/ ES6 modules/ AMD) 136 | requirejs 137 | `; 138 | 139 | const questions5 = ` 140 | что такое stage0 ... stage1 ? 141 | чем "стрелочная" функция отличается от обычной? 142 | чем отличаются let / const / var ? 143 | что такое spread оператор? 144 | что такое rest параметр? 145 | что такое деструктуризация ? 146 | что такое super ? 147 | как сделать наследование классов? 148 | что такое генератор ? 149 | что такое Set и Map ? 150 | зачем нужен Symbol ? 151 | чем классы отличаются от работы с прототипами? 152 | что такое итератор? 153 | какие дополнения в объявлении объектов? 154 | как работать с ES6-imports ? 155 | this в стрелочной функции? 156 | как проверить поддерживается ли функция из ES6 каким-то браузером? 157 | `; 158 | 159 | const shuffleList = (list) => { 160 | for (let i = 0; i < list.length; i++) { 161 | const rand = Math.floor(Math.random() * list.length); 162 | const tmp = list[rand]; 163 | list[rand] = list[list.length - 1]; 164 | list[list.length - 1] = tmp; 165 | } 166 | return list; 167 | }; 168 | 169 | const $$ = document.querySelector.bind(document); 170 | const questionsStrings = [questions0, questions1, questions2, questions3, questions4, questions5]; 171 | let roundQuestionsNumber = 0; 172 | let i = 0; 173 | 174 | const getQuestions = (() => { 175 | let questions = []; 176 | const generateQuestions = () => { 177 | [...document.querySelectorAll('fieldset input[type=checkbox]')].forEach((el, index) => { 178 | if (el.checked) { 179 | questions = [...questions, ...(questionsStrings[index] || '').trim().split('\n')]; 180 | } 181 | }); 182 | 183 | questions = questions.map((i) => i.trim()).filter(Boolean); 184 | 185 | shuffleList(questions); 186 | shuffleList(questions); 187 | roundQuestionsNumber = questions.length; 188 | i = 0; 189 | }; 190 | 191 | return () => { 192 | if (!questions.length) { 193 | generateQuestions(); 194 | } 195 | return questions; 196 | }; 197 | })(); 198 | 199 | const drawNextQuestion = () => { 200 | const questions = getQuestions(); 201 | i++; 202 | const question = questions.pop(); 203 | $$('.question').innerHTML = `${i}/${roundQuestionsNumber} > ${question}`; 204 | }; 205 | 206 | $$('.question').addEventListener('click', drawNextQuestion); 207 | document.body.addEventListener('keyup', (ev) => { 208 | const SPACE_KEY_CODE = 32; 209 | if (ev.key === ' ' || ev.keyCode === SPACE_KEY_CODE) { 210 | drawNextQuestion(); 211 | } 212 | }); 213 | -------------------------------------------------------------------------------- /01/ht/README.md: -------------------------------------------------------------------------------- 1 | # Вводная 2 | 3 | ## Что вам понадобится 4 | 5 | 1. Редактор: 6 | * [VSCode](https://code.visualstudio.com/) 7 | * [Atom](https://atom.io/) 8 | * [WebStorm](https://confluence.jetbrains.com/display/WI/WebStorm+EAP) 9 | 2. Браузер: Chrome / Firefox / Opera 10 | 3. Утилиты: 11 | 1. [Git](https://git-scm.com/downloads) 12 | 2. [Node.js](https://nodejs.org/en/) 13 | 4. Опционально: 14 | * Гит-клиент: [SourceTree](https://www.sourcetreeapp.com/) / [GitHub Client](https://desktop.github.com/) / etc 15 | 16 | ### Что нужно сделать сразу 17 | 18 | 1. Завести и заполнить [github](https://github.com) аккаунт 19 | 2. Пройти [Git HowTo до 49-го шага](https://githowto.com/ru/) ( используя репозиторий на гитхабе ) 20 | 3. Зарегистрировать аккаунт на хостинге ( например, на бесплатном beget.ru ) и разобраться как заливать файлы по ftp чтобы получать к ним доступ из браузера (как предпочтительный вариант - разобраться с тем как работают [github-pages](https://info.nic.ua/blog/github-pages-website/) или как пользоваться [surge.sh](http://surge.sh/) ). 21 | 22 | ## Домашнее задание 23 | 24 | ### Прочитать\* (с выполнением задач) разделы из учебника [Learn.Javascript.Ru](http://learn.javascript.ru/): 25 | 26 | * [Введение](http://learn.javascript.ru/getting-started) 27 | * [Основы JavaScript](http://learn.javascript.ru/first-steps) 28 | * [Качество кода](http://learn.javascript.ru/writing-js) 29 | * [Структуры данных](http://learn.javascript.ru/data-structures) 30 | * [Замыкания, область видимости](http://learn.javascript.ru/functions-closures) 31 | * [Методы объектов и контекст вызова](http://learn.javascript.ru/objects-more) 32 | * [ООП в прототипном стиле](http://learn.javascript.ru/prototypes) 33 | * [Некоторые другие возможности](http://learn.javascript.ru/js-misc) 34 | * [Документ и объекты страницы](http://learn.javascript.ru/document) 35 | 36 | ### Найти ответы на вопросы (это то, что будет спрашиваться на занятии): 37 | 38 | * Что такое переменная? 39 | * Как объявить переменную? Как инициализировать переменную? Примеры кода 40 | * Виды циклов ( 3 вида )? Примеры использования 41 | * Сколько и какие типы данных в javascript? Примеры создания переменных каждого типа 42 | * Как узнать тип переменной? Пример кода 43 | * Что такое область видимости? 44 | * Как из javascript в брaузере вывести на экран строчку? ( 4-ре способа ) Примеры кода 45 | * Каким образом можно реализовать условное выполнение кода? 46 | * Условные операторы в javascript - какие? Примеры использования 47 | * Что такое тернарный оператор? 48 | * Как обойтись без условных операторов если нужно сделать условное выполнение кода? С примером 49 | * Что такое функция? Какими характеристиками можно описать функцию? 50 | * Как можно создать функцию? 3 способа. C примерами кода 51 | * Что такое объект? Как создать объект? ( 3 способа ) С примерами кода 52 | * Что такое передача по ссылке / передача по значению? 53 | * Что такое минификация и зачем она нужна? 54 | * Как можно добавить javascript код в html страницу? 2 способа. C примерами кода 55 | * Что такое массив? 56 | * Как создать массив? ( 3 способа ) С примером кода 57 | * Как запросить данные у пользователя? с примером кода 58 | * Что такое замыкание? 59 | * Как узнать сколько параметров принимает функция? 60 | * Как узнать есть ли у объекта свойство `x` ? 61 | * Как сделать ревес строки? 62 | * Как удалить предпоследний элемент в массиве? 63 | * Как заменить в строке `"papa roach"` все буквы `a` на `A` ? 64 | * Сколькими способами ( с примерами кода ) можно найти на странице `div` с id `someId` ? 65 | * Как устроен событийный цикл в js? 66 | * Что такое API? Примеры? 67 | * Как в js реализовать многопоточность? 68 | * Как в js реализовать наследование одного "класса" от другого? Пример кода 69 | * Сколькими способами можно проитерироваться по всем полям объекта? С примерами кода 70 | * Что такое _callback_ ? Зачем? Пример кода 71 | * Почему `1 + '2'` ? и `1 - '2'` ? 72 | * Как и когда работает преобразование типов? 73 | * Что такое HTTP ? Из чего состоит HTTP протокол? 74 | * Какие есть методы HTTP запросов? Для чего каждый? 75 | * Что такое `REST` ? `RPC` ? 76 | * Что такое "линтер" (linter)? Зачем они нужны? Какие линтеры есть для javascript? 77 | * Включить в своем редакторе поддержку eslint (установить плагин), чтобы код проверялся по правилам репозитория 78 | * Настроить автоматическое форматирование, чтобы код форматировался под правила репозитория 79 | * Что такое "jsdoc" ? Найдите его в своем домашнем задании. Зачем он нужен? Объясните использовнные теги. 80 | * Что такое пакетный менеджер? Какие пакетные менеджеры есть для js? 81 | * Что делают системы сборки? Какие системы сборки есть для js? 82 | * Как с помощью `gulp` минифицировать js файл? 83 | 84 | ### Решить задачи из коанов 85 | 86 | * https://github.com/mrdavidlaing/javascript-koans 87 | * https://github.com/liammclennan/JavaScript-Koans 88 | 89 | Если с какой-то темой будут затруднения - пишите в общий чат, с упоминанием `@vvscode`. 90 | Схема работы: 91 | 92 | 1. Сделать fork репозитория в свой аккаунт 93 | 2. Сделать скачать репозиторий из форка к себе на компьютер ( с помощью `git clone` ) 94 | 3. Сделать новую ветку `solution` 95 | 4. В это ветке решать коаны, делая коммиты на каждое значимое решение. 96 | 5. В конце отправить ветку `solution` на github и сделать pull request в своем репозитории - ссылку на PR (pull request) сбросить в личные соощения `@vvscode` на ревью 97 | 98 | ### Написать функции\* 99 | 100 | * Сделать fork этого репозитория 101 | * Скачать к себе на компьютер 102 | * Создать новую ветку `01` 103 | * Скорпировать папку `01/ht/example` в `01/ht/your_nick` ( например `01/ht/vvscode` ) 104 | * Поместить решения в файл `script.js` ( там уже будут заглушки для функций, которые нужно реализовать ). 105 | 106 | Название функций - важно. Для проверки - откройте свой файл `index.html` 107 | 108 | 1. Реализовать функцию `fizzBuzz` которая выводит числа от 1 до 100. Если число кратно 3 - вместо числа вывести `Fizz`. Если кратно 5 - вывести вместо числа `Buzz`. Если число кратно и 3 и 5 - вывести вместо числа `FizzBuzz`. Для вывода использовать функцию `log` (аналогично заданию в классе). В теле функции нельзя использовать `if`, `switch`, тернарный оператор `? :` 109 | 2. Реализовать фукнцию `isPalindrom`, которая принимает на вход строку и возвращает результат проверки (`true`/ `false` ), является строка палиндромом (одинаково читается слева направо и справа налево ) или нет 110 | 3. Реализовать функцию `drawCalendar` , которая принимает три аргумента - год, месяц, htmlElement и выводит в этот элемент календарь на месяц (дни недели начинаются с понедельника ). 111 | 4. Написать функцию `isDeepEqual` которая принимает на вход двe переменных и проверяет идентичны ли они по содержимому. Например 112 | 113 | ```javascript 114 | var a = { prop1: 1, list: [1, 2, 3], o: { x: 2 } }; 115 | var b = { list: [1, 2, 3], o: { x: 2 } }; 116 | isDeepEqual(a, b); // false 117 | b.prop1 = 1; 118 | isDeepEqual(a, b); // true 119 | ``` 120 | 121 | 5. Написать тесты и саму функцию `spiral`, которая принимает на вход двумерный массив и возвращает одномерный массив с элементами расположенными по спирали. Матрица не обязательно имеет одинаковые размеры по обеим сторонам. Примеры: 122 | 123 | ```javascript 124 | spiral([[4, 5], [6, 7]]); // [4,5,7,6] 125 | 126 | spiral([[1, 2, 3], [4, 5, 6], [7, 8, 9]]); // [1,2,3,6,7,8,7,4,5] 127 | 128 | spiral([ 129 | [1, 2, 3, 4, 5], 130 | [6, 7, 8, 9, 10], 131 | [11, 12, 13, 14, 15], 132 | [16, 17, 18, 19, 20] 133 | ]); // [1,2,3,4,5,10,15,20,19,18,17,16,11,6,7,8,9,14,13,12] 134 | ``` 135 | 136 | 6. Написать тесты и саму функцию `quadraticEquation`, которая на вход принимает коэффициенты квадратного уравнения, а возвращает массив с вещественными корнями этого уравнения (если они есть). 137 | 138 | Пример 139 | 140 | ```javascript 141 | quadraticEquation(1, -8, 72); // x^2 - 8*x + 72 -> [] 142 | quadraticEquation(1, 12, 36); // x^2 + 12*x + 36 -> [-6] 143 | quadraticEquation(1, 6, 1); // 1*x^2 + 6*x + 1 -> [-0.1715728752538097, -5.82842712474619] 144 | ``` 145 | 146 | ## Дополнительно 147 | 148 | ### Основные ресурсы 149 | 150 | * [MDN](https://developer.mozilla.org/ru/docs/Web/JavaScript) 151 | * [Learn.javascript.ru](http://learn.javascript.ru/?map) 152 | * [Google] 153 | 154 | ### Литература ( читать параллельно курсу ) 155 | 156 | * [Javascript для детей](http://www.mann-ivanov-ferber.ru/books/javascript-dlya-detej/) 157 | * [JavaScript для профессиональных веб-разработчиков](http://www.ozon.ru/context/detail/id/31257038/) 158 | * [Секреты JavaScript ниндзя](http://www.ozon.ru/context/detail/id/22421421/) 159 | 160 | ### Что полезно посмотреть 161 | 162 | #### Отдельные видео каналы, которыми полезно заменить обычное видео на youtube (и подписаться тоже) 163 | 164 | * [.getInstance](https://www.youtube.com/channel/UCEBHlT_L1ME6e9ixaRPp0wg) - Ru 165 | * [Fun Fun Function](https://www.youtube.com/channel/UCO1cgjhGzsSYb1rsB4bFe4Q) - En 166 | 167 | #### Курсы 168 | 169 | * [Основы JavaScript от Zorax](https://www.youtube.com/playlist?list=PL363QX7S8MfSxcHzvkNEqMYbOyhLeWwem) 170 | * [Курс «Введение в Javascript» от Hexlet](https://www.youtube.com/playlist?list=PLo6puixMwuSNxJCgadaaavKqq4-ocKPrR) 171 | 172 | ``` 173 | 174 | ``` 175 | -------------------------------------------------------------------------------- /.ht/05/router.test.js: -------------------------------------------------------------------------------- 1 | /* global mocha, chai, describe, it */ 2 | /* global HashRouter, Hr, beforeEach, findRoute */ 3 | mocha.setup({ 4 | ui: "bdd", 5 | bail: true 6 | }); 7 | const assert = chai.assert; 8 | const $$ = document.querySelector.bind(document); 9 | const sleep = x => new Promise(resolve => setTimeout(resolve, x)); 10 | 11 | describe("HashRouter", () => { 12 | it("is function and constructor", () => { 13 | assert.equal(typeof HashRouter, "function"); 14 | assert.isOk(new HashRouter() instanceof HashRouter); 15 | }); 16 | 17 | it('set .routes from options', () => { 18 | var routes = []; 19 | var router = new HashRouter({ routes: routes }); 20 | assert.equal(router.routes, routes); 21 | }); 22 | 23 | describe(".handleUrl", () => { 24 | it("is method (on prototype)", () => { 25 | assert.equal(typeof new HashRouter().handleUrl, "function"); 26 | assert.equal(new HashRouter().handleUrl, HashRouter.prototype.handleUrl); 27 | }); 28 | 29 | it("called on start with current hash", () => { 30 | window.location.hash = "some string"; 31 | var handleUrl = HashRouter.prototype.handleUrl; 32 | let param = null; 33 | HashRouter.prototype.handleUrl = url => (param = url); 34 | new HashRouter(); 35 | HashRouter.prototype.handleUrl = handleUrl; 36 | assert.equal(param, "some string"); 37 | }); 38 | 39 | it("called on hashchange with current hash", done => { 40 | window.location.hash = "some string"; 41 | var handleUrl = HashRouter.prototype.handleUrl; 42 | let param = null; 43 | HashRouter.prototype.handleUrl = url => (param = url); 44 | new HashRouter(); 45 | window.location.hash = "some new string"; 46 | setTimeout(() => { 47 | HashRouter.prototype.handleUrl = handleUrl; 48 | done(assert.equal(param, "some new string")); 49 | }, 150); 50 | }); 51 | 52 | it("calls .onBeforeEnter on matched route from `this.routes` with param", done => { 53 | var x = 0; 54 | var param = null; 55 | var o = { 56 | routes: [ 57 | { 58 | match: "string", 59 | onBeforeEnter: url => { 60 | x++; 61 | param = url; 62 | } 63 | } 64 | ] 65 | }; 66 | window.location.hash = "string"; 67 | HashRouter.prototype.handleUrl.call(o, "string"); 68 | setTimeout(() => { 69 | assert.equal(x, 1); 70 | assert.equal(param, "string"); 71 | done(); 72 | }, 100); 73 | }); 74 | it("calls .onEnter on matched route from `this.routes` with param", done => { 75 | var x = 0; 76 | var param = null; 77 | var o = { 78 | routes: [ 79 | { 80 | match: "string", 81 | onEnter: url => { 82 | x++; 83 | param = url; 84 | } 85 | } 86 | ] 87 | }; 88 | window.location.hash = "string"; 89 | HashRouter.prototype.handleUrl.call(o, "string"); 90 | setTimeout(() => { 91 | assert.equal(x, 1); 92 | assert.equal(param, "string"); 93 | done(); 94 | }, 100); 95 | }); 96 | it("calls .onEnter on matched route from `this.routes` with param", done => { 97 | var x = []; 98 | var o = { 99 | routes: [ 100 | { 101 | match: "string", 102 | onBeforeEnter: () => { 103 | x.push("onBeforeEnterStart"); 104 | return new Promise(resolve => { 105 | setTimeout(() => { 106 | x.push("onBeforeEnterEnd"); 107 | resolve(); 108 | }, 100); 109 | }); 110 | }, 111 | onEnter: () => { 112 | x.push("onEnterStart"); 113 | return new Promise(resolve => { 114 | setTimeout(() => { 115 | x.push("onEnterEnd"); 116 | resolve(); 117 | }, 100); 118 | }); 119 | } 120 | } 121 | ] 122 | }; 123 | HashRouter.prototype.handleUrl.call(o, "string"); 124 | setTimeout(() => { 125 | assert.deepEqual(x, [ 126 | "onBeforeEnterStart", 127 | "onBeforeEnterEnd", 128 | "onEnterStart", 129 | "onEnterEnd" 130 | ]); 131 | done(); 132 | }, 400); 133 | }); 134 | 135 | it("saves route as .prevRoute", async () => { 136 | var firstRoute = { match: "string" }; 137 | var secondRoute = { match: "another string" }; 138 | var o = { 139 | routes: [firstRoute, secondRoute] 140 | }; 141 | try { 142 | HashRouter.prototype.handleUrl.call(o, firstRoute.match); 143 | await sleep(100); 144 | assert.equal(o.prevRoute, firstRoute); 145 | 146 | HashRouter.prototype.handleUrl.call(o, secondRoute.match); 147 | await sleep(100); 148 | assert.equal(o.prevRoute, secondRoute); 149 | // done(); 150 | } catch (e) { 151 | return Promise.reject(e); 152 | } 153 | }); 154 | 155 | it("calls .onLeave (with params) if .prevRoute presented", async () => { 156 | var x = []; 157 | var firstRoute = { match: "string", onLeave: url => x.push(url) }; 158 | var secondRoute = { match: "another string" }; 159 | var o = { 160 | routes: [firstRoute, secondRoute] 161 | }; 162 | try { 163 | HashRouter.prototype.handleUrl.call(o, firstRoute.match); 164 | await sleep(100); 165 | HashRouter.prototype.handleUrl.call(o, secondRoute.match); 166 | await sleep(100); 167 | assert.deepEqual(x, [firstRoute.match]); 168 | } catch (e) { 169 | return Promise.reject(e); 170 | } 171 | }); 172 | 173 | it("calls .onLeave -> .onBeforeEnter -> .onEnter", async () => { 174 | var x = []; 175 | var o = { 176 | routes: [ 177 | { 178 | match: "string", 179 | onLeave: () => { 180 | x.push("onLeaveStart"); 181 | return new Promise(resolve => { 182 | setTimeout(() => { 183 | x.push("onLeaveEnd"); 184 | resolve(); 185 | }, 20); 186 | }); 187 | } 188 | }, 189 | { 190 | match: "another string", 191 | onBeforeEnter: () => { 192 | x.push("onBeforeEnterStart"); 193 | return new Promise(resolve => { 194 | setTimeout(() => { 195 | x.push("onBeforeEnterEnd"); 196 | resolve(); 197 | }, 20); 198 | }); 199 | }, 200 | onEnter: () => { 201 | x.push("onEnterStart"); 202 | return new Promise(resolve => { 203 | setTimeout(() => { 204 | x.push("onEnterEnd"); 205 | resolve(); 206 | }, 20); 207 | }); 208 | } 209 | } 210 | ] 211 | }; 212 | HashRouter.prototype.handleUrl.call(o, "string"); 213 | await sleep(50); 214 | HashRouter.prototype.handleUrl.call(o, "another string"); 215 | try { 216 | await sleep(100); 217 | assert.deepEqual(JSON.stringify(x), JSON.stringify([ 218 | "onLeaveStart", 219 | "onLeaveEnd", 220 | "onBeforeEnterStart", 221 | "onBeforeEnterEnd", 222 | "onEnterStart", 223 | "onEnterEnd" 224 | ])); 225 | } catch (e) { 226 | return Promise.reject(e); 227 | } 228 | }); 229 | }); 230 | 231 | // ------------------------ 232 | 233 | describe("findRoute", () => { 234 | var flag = false; 235 | var funcParam; 236 | var str = { match: "string" }; 237 | var regExp = { match: /param=(.+)/ }; 238 | var func = { 239 | match: url => { 240 | funcParam = url; 241 | return flag ? [1, flag, url] : null; 242 | } 243 | }; 244 | it("is function", () => { 245 | assert.equal(typeof findRoute, "function"); 246 | }); 247 | it("takes 2 params", () => assert.equal(findRoute.length, 2)); 248 | it("returns list of nulls by default", () => { 249 | assert.deepEqual(findRoute([], "some_url"), [null, null]); 250 | }); 251 | it("able to find route from list by string match", () => { 252 | assert.deepEqual(findRoute([regExp, str, func], "string"), [ 253 | str, 254 | "string" 255 | ]); 256 | }); 257 | it("able to find route from list by regExp", () => { 258 | assert.deepEqual(findRoute([regExp, str, func], "param=123"), [ 259 | regExp, 260 | ["param=123", "123"] 261 | ]); 262 | }); 263 | it("able to find route from list by functional match", () => { 264 | flag = false; 265 | assert.deepEqual(findRoute([regExp, str, func], "xxxx"), [null, null]); 266 | flag = true; // now func returns list / truethly value 267 | assert.deepEqual(findRoute([regExp, str, func], "xxxxyy"), [ 268 | func, 269 | [1, flag, "xxxxyy"] 270 | ]); 271 | assert.equal(funcParam, "xxxxyy", "passes url into function"); 272 | }); 273 | it("returns first match", () => { 274 | flag = true; 275 | assert.deepEqual(findRoute([regExp, str, func], "string"), [ 276 | str, 277 | "string" 278 | ]); 279 | }); 280 | it('detects strings matching correctly', () => { 281 | var one = { match: 'string' }; 282 | var two = { match: 'another string' }; 283 | assert.deepEqual( 284 | JSON.stringify(findRoute([one, two], 'string')), 285 | JSON.stringify([one, one.match]) 286 | ); 287 | assert.deepEqual( 288 | JSON.stringify(findRoute([one, two], 'another string')), 289 | JSON.stringify([two, two.match]) 290 | ); 291 | }); 292 | }); 293 | }); 294 | 295 | mocha.run(); 296 | -------------------------------------------------------------------------------- /.ht/02/script.tests.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /* eslint no-var: "off" */ 4 | /* eslint no-unused-vars: "off" */ 5 | /* eslint max-len: "off" */ 6 | describe("isDeepEqual", function() { 7 | it("фунция", function() { 8 | return assert.isOk(typeof isDeepEqual === "function"); 9 | }); 10 | it("возвращает true/false", function() { 11 | return assert.isOk(typeof isDeepEqual("", "") === "boolean"); 12 | }); 13 | it("распознает одинаковые строки", function() { 14 | return assert.isOk(isDeepEqual("мама", "мама") === true); 15 | }); 16 | it("распознает разные строки", function() { 17 | return assert.isOk(isDeepEqual("мама", "папа") === false); 18 | }); 19 | 20 | it("распознаем разные массивы", function() { 21 | return assert.isOk(isDeepEqual([1, 4, 2], [1, 2, 4]) === false); 22 | }); 23 | it("распознает одинаковые массивы", function() { 24 | return assert.isOk(isDeepEqual([1, 2, 4, 3], [1, 2, 4, 3]) === true); 25 | }); 26 | it("распознает массивы разной длинны", function() { 27 | return assert.isOk(isDeepEqual([1, 2, 5], [1, 2, 5, 7]) === false); 28 | }); 29 | 30 | var a = { prop1: 1, list: [1, 2, 3], o: { x: 2 } }; 31 | var b = { list: [1, 2, 3], o: { x: 2 } }; 32 | it("распознает разные объекты", function() { 33 | return assert.isOk(isDeepEqual(a, b) === false); 34 | }); 35 | 36 | it("распознает одинаковые объекты", function() { 37 | b.prop1 = 1; 38 | return assert.isOk(isDeepEqual(a, b) === true); 39 | }); 40 | 41 | it("распознает разные объекты", function() { 42 | var a = { a: 1, b: 3, c: 2 }; 43 | var b = { a: 1, b: 4, c: 2 }; 44 | return assert.isOk(isDeepEqual(a, b) === false); 45 | }); 46 | 47 | it("распознает вложенные объекты", function() { 48 | var a = { a: 1, b: { x: 5 }, c: 2 }; 49 | var b = { a: 1, b: { x: 5 }, c: 2 }; 50 | return assert.isOk(isDeepEqual(a, b) === true); 51 | }); 52 | 53 | it("распознает числа", function() { 54 | var a = 1; 55 | var b = 1.0; 56 | return assert.isOk(isDeepEqual(a, b) === true); 57 | }); 58 | 59 | it("распознает разные числа", function() { 60 | let a = 1; 61 | let b = 2; 62 | return assert.isOk(isDeepEqual(a, b) === false); 63 | }); 64 | 65 | it("Может работать с NaN", function() { 66 | let a = { NaN: NaN }; 67 | let b = { NaN: NaN }; 68 | 69 | assert.isOk(isDeepEqual(NaN, NaN) === true); 70 | assert.isOk(isDeepEqual(a, b) === true); 71 | }); 72 | 73 | it("Moжет работать с рекурсивными ссылками", function() { 74 | var a = { 75 | prop: 1 76 | }; 77 | a.a = a; 78 | var b = { 79 | prop: 1 80 | }; 81 | b.a = b; 82 | assert.isOk(isDeepEqual(a, b) === true); 83 | }); 84 | }); 85 | 86 | describe("bind", function() { 87 | var func; 88 | var obj; 89 | var counter; 90 | var originalBind; 91 | beforeEach(function() { 92 | counter = 0; 93 | func = function(val) { 94 | counter++; 95 | return [val, this.name]; 96 | }; 97 | obj = { 98 | name: "Some dummy context" 99 | }; 100 | var originalBind = Function.prototype.bind; 101 | }); 102 | afterEach(function() { 103 | Function.prototype.bind = originalBind; 104 | }); 105 | it("функция", function() { 106 | assert.isOk(typeof bind === "function"); 107 | }); 108 | it("Возвращает фукнцию", function() { 109 | assert.isOk(typeof bind(function() {}, {}) === "function"); 110 | assert.isOk(typeof bind(function() {}, null) === "function"); 111 | }); 112 | it("Результат вызывает оригинальную фукнцию", function() { 113 | assert.isOk(counter === 0); 114 | let binded = bind(func, {}); 115 | binded(); 116 | assert.isOk(counter === 1); 117 | binded(); 118 | assert.isOk(counter === 2); 119 | }); 120 | it("Вызывает с правильным контекстом", function() { 121 | var context = { dummy: "context" }; 122 | const binded = bind(function() { 123 | assert.isOk(this === context); 124 | }, context); 125 | binded(); 126 | }); 127 | it("Пробрасывает параметры контекстом", function() { 128 | bind(function() { 129 | assert.isOk(arguments.length === 0); 130 | }, {})(); 131 | bind(function() { 132 | assert.isOk(arguments.length === 1); 133 | assert.isOk(arguments[0] === 1); 134 | }, {})(1); 135 | bind(function() { 136 | assert.isOk(arguments.length === 3); 137 | assert.isOk(arguments[0] === 1); 138 | assert.isOk(arguments[1] === 2); 139 | assert.isOk(arguments[2] === "три"); 140 | }, {})(1, 2, "три"); 141 | }); 142 | }); 143 | 144 | describe(".myBind", function() { 145 | var func; 146 | var obj; 147 | var counter; 148 | var originalBind = Function.prototype.bind; 149 | beforeEach(function() { 150 | counter = 0; 151 | Function.prototype.bind = null; 152 | func = function(val) { 153 | counter++; 154 | return [val, this.name]; 155 | }; 156 | obj = { 157 | name: "Some dummy context" 158 | }; 159 | }); 160 | afterEach(function() { 161 | Function.prototype.bind = originalBind; 162 | }); 163 | it("функция", function() { 164 | assert.isOk(typeof func.myBind === "function"); 165 | }); 166 | it("Возвращает фукнцию", function() { 167 | assert.isOk(typeof function() {}.myBind({}) === "function"); 168 | assert.isOk(typeof function() {}.myBind(null) === "function"); 169 | }); 170 | it("не использует встроенный .bind", function() { 171 | assert.isOk(func.myBind.toString().indexOf(".bind") < 0); 172 | }); 173 | it("Результат вызывает оригинальную фукнцию", function() { 174 | assert.isOk(counter === 0); 175 | let binded = func.myBind({}); 176 | binded(); 177 | assert.isOk(counter === 1); 178 | binded(); 179 | assert.isOk(counter === 2); 180 | }); 181 | it("Вызывает с правильным контекстом", function() { 182 | var context = { dummy: "context" }; 183 | const binded = function() { 184 | assert.isOk(this === context); 185 | }.myBind(context); 186 | binded(); 187 | }); 188 | it("Пробрасывает параметры контекстом", function() { 189 | (function() { 190 | assert.isOk(arguments.length === 0); 191 | }.myBind({})()); 192 | (function() { 193 | assert.isOk(arguments.length === 1); 194 | assert.isOk(arguments[0] === 1); 195 | }.myBind({})(1)); 196 | (function() { 197 | assert.isOk(arguments.length === 3); 198 | assert.isOk(arguments[0] === 1); 199 | assert.isOk(arguments[1] === 2); 200 | assert.isOk(arguments[2] === "три"); 201 | }.myBind({})(1, 2, "три")); 202 | }); 203 | }); 204 | 205 | describe("calculate", function() { 206 | it("считает примеры", function() { 207 | assert.isOk(calculate("+")(1)(2) === 3); 208 | assert.isOk(calculate("*")(4)(2) === 8); 209 | assert.isOk(calculate("/")(9)(3) === 3); 210 | assert.isOk(calculate("-")(8)(7) === 1); 211 | }); 212 | }); 213 | 214 | describe("Singleton", function() { 215 | it("конструктор", function() { 216 | assert.isOk(typeof new Singleton() === "object"); 217 | assert.isOk(new Singleton() instanceof Singleton === true); 218 | }); 219 | it("синглтон", function() { 220 | assert.isOk(new Singleton() === new Singleton()); 221 | }); 222 | }); 223 | 224 | describe("ForceContructor", function() { 225 | it("работает как конструктор и сохраняет параметры в объекте", function() { 226 | var a = Math.random(); 227 | var c = Math.random(); 228 | var o = new ForceContructor(a, undefined, c); 229 | assert.isOk(typeof o === "object"); 230 | assert.isOk(o instanceof ForceContructor); 231 | assert.isOk(o.a === a); 232 | assert.isOk("b" in o); 233 | assert.isOk(o.b === undefined); 234 | assert.isOk(o.c === c); 235 | }); 236 | it("работает как конструктор без new", function() { 237 | var a = Math.random(); 238 | var c = Math.random(); 239 | var o = ForceContructor(a, undefined, c); 240 | var o2 = new ForceContructor(a, undefined, c); 241 | var o3 = ForceContructor(a, undefined, c); 242 | assert.isOk(typeof o === "object"); 243 | assert.isOk(o instanceof ForceContructor === true); 244 | assert.isOk(o.a === a); 245 | assert.isOk("b" in o); 246 | assert.isOk(o.b === undefined); 247 | assert.isOk(o.c === c); 248 | assert.isOk(o !== o2); 249 | assert.isOk(o !== o3); 250 | assert.isOk(o2 !== o3); 251 | }); 252 | }); 253 | 254 | describe("sum", function() { 255 | it("функция", function() { 256 | assert.isOk(typeof sum === "function"); 257 | }); 258 | it("по-умолчанию инициализируется нулем", function() { 259 | assert.isOk(+sum() === 0); 260 | }); 261 | it("инициализируется числом", function() { 262 | assert.isOk(+sum(5) === 5); 263 | }); 264 | it("складывает числа", function() { 265 | var s = sum(1); 266 | assert.isOk(+s(2) === 3); 267 | assert.isOk(+s(3) === 4); 268 | assert.isOk(+s(95) === 96); 269 | }); 270 | it("складывает числа последовательно", function() { 271 | assert.isOk(+sum(1)(2) === 3); 272 | assert.isOk(+sum(5)(7)(9) === 21); 273 | 274 | var s = sum(); 275 | for (var i = 0; i < 15; i++) { 276 | s = s(1); 277 | } 278 | assert.isOk(+s(1) === 16); 279 | }); 280 | it("добавляет 0 по-умолчанию", function() { 281 | assert.isOk(+sum(4)() === 4); 282 | assert.isOk(+sum(7)()(2) === 9); 283 | }); 284 | it("сумматоры независимые", function() { 285 | var s1 = sum(1); 286 | var s12 = s1(2); 287 | var s15 = s1(5); 288 | var s152 = s15(2); 289 | var s159 = s15(9); 290 | var s10 = s1(); 291 | assert.isOk(+s1 === 1); 292 | assert.isOk(+s12 === 3); 293 | assert.isOk(+s15 === 6); 294 | assert.isOk(+s152 === 8); 295 | assert.isOk(+s159 === 15); 296 | assert.isOk(+s10 === 1); 297 | }); 298 | it("может отработать много раз", function() { 299 | var s = sum(); 300 | for (var i = 0; i < 999; i++) { 301 | s = s(1); 302 | } 303 | assert.isOk(+s() === 999); 304 | }); 305 | }); 306 | 307 | describe("User / PreUser", function() { 308 | it("конструкторы", function() { 309 | var u = new User(); 310 | var u2 = new User(); 311 | assert.isOk(typeof User === "function"); 312 | assert.isOk(typeof PreUser === "function"); 313 | assert.isOk(new User() instanceof User); 314 | assert.isOk(new PreUser() instanceof PreUser); 315 | assert.isOk(u !== u2); 316 | }); 317 | it("разные конструкторы", function() { 318 | assert.isOk(User !== PreUser); 319 | }); 320 | it("создают правильное дерево наследования", function() { 321 | var u = new User(); 322 | var u2 = new User(); 323 | assert.isOk(u instanceof User); 324 | assert.isOk(u instanceof Array); 325 | assert.isOk(u instanceof PreUser); 326 | }); 327 | }); 328 | 329 | describe("curry", function() { 330 | it("добавить тесты", function() { 331 | assert.isOk(false === true); 332 | }); 333 | }); 334 | -------------------------------------------------------------------------------- /01/cls/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Js Base Course - Занятие 1 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |
17 |

Занятие 1

18 |
19 |
20 |
21 |
22 |

@vvscode

23 |
24 |
25 |

disclamer

26 |
    27 |
  • это нужно ВАМ
  • 28 |
  • умеете читать
  • 29 |
  • можете объяснить, как пройти в библиотеку
  • 30 |
  • закон сохранения и превращения энергии
  • 31 |
  • HTML/CSS
  • 32 |
  • Про вопросы
  • 33 |
34 |
35 |
36 |
    37 |
  • Зачем мне этот курс? Зачем я сюда пришел?
  • 38 |
  • Как я пойму, что курс был для меня полезен?
  • 39 |
  • Кто я? Работа? Опыт?
  • 40 |
  • ОС?
  • 41 |
  • Что такое переменная?
  • 42 |
  • Виды циклов?
  • 43 |
  • Что такое рекурсия?
  • 44 |
45 |
46 |
47 |

Как проходит курс

48 |
49 |
50 |

Орг вопросы

51 |
52 |
53 |

Вопросы?

54 |
55 |
56 |
57 |
58 |

На кой нужен JS?

59 |
    60 |
  • Интерактивные страницы
  • 61 |
  • Мобильные приложения
  • 62 |
  • Десктопные приложения
  • 63 |
  • Серверные приложения
  • 64 |
  • Автоматизировация
  • 65 |
  • Утилиты и скрипты командной строки
  • 66 |
67 |
68 |
69 |

С чем работает разрабочик:

70 |
    71 |
  • Язык (js)
  • 72 |
  • API (application program interface)
  • 73 |
74 |
75 |
76 |

Про версии языка и API

77 |
78 |
79 | Вопросы? 80 |
81 |
82 |
83 |

Как взаимодействовать с пользователем?

84 |
85 |
Спросить пользователя:
86 |

 87 | // Спросить подтверждение
 88 | var result1 = confirm('Are you sure?');
 89 | 
 90 | // Запросить строчку от пользователя
 91 | var result2 = prompt('What is your name?', 'John Doe');
 92 | 
 93 | // Прочитать данные из поля ввода
 94 | var result3 = document.querySelector('input.someClass').value;
 95 |                           
96 |
97 |
98 |
Сообщить пользователю:
99 |

100 | // Модальное окно
101 | alert('Hi');
102 | 
103 | // Сообщение в консоль
104 | console.log('Hello');
105 |   
106 | // Вывести прямо в документ
107 | document.write('Good morning');
108 | 
109 | // Вывести в блок на странице
110 | document.querySelector('.someCSS-selector').innerHTML = '

Hola

'; 111 |
112 |
113 |
114 |
115 |
116 |

117 |               // Цикл?
118 |               
119 |               // Условное выполнение?
120 | 
121 |               // Вызов функции?
122 |         
123 |
124 |
125 |

126 |                 // Цикл?
127 |                 for(var i = 0; i < 10; i++) { console.log(i); }
128 |                 
129 |                 // Условное выполнение?
130 |                 var a = 1;
131 |                 if(a === 2) { console.log('a !== 1'); } 
132 |   
133 |                 // Вызов функции?
134 |                 log(a);
135 |           
136 |
137 |
138 |

139 | function log(a) { console.log(a); }
140 | /*
141 | Напишите программу, которая выводит на экран числа от 1 до 100. 
142 | При этом вместо чисел, кратных трем, программа должна выводить слово «Fizz», 
143 | а вместо чисел, кратных пяти — слово «Buzz». 
144 | Если число кратно и 3, и 5, то программа должна выводить слово «FizzBuzz»
145 | */
146 | log(1);
147 | log(2);
148 | log('Fizz');
149 | log(4);
150 | log('Buzz');
151 |         
152 |
153 |
154 | http://bit.ly/jsFizzBuzz 155 |
156 |
157 |

158 | Это задача с собеседований! 159 |

160 |
161 |
162 |

Представление о тестировании

163 |

164 | function sum(a, b) { return a + b; }
165 | 
166 |

167 | function sum(a, b) { return a + b; }
168 | 
169 | // проверки
170 | console.log('1+2', sum(1, 2) === 3);
171 | console.log('-1+2', sum(-1, 2) === 1);
172 | console.log('0+0', sum(0, ) === 0);
173 | 
174 |
175 |
176 | Вопросы? 177 |
178 |
179 |
180 |

Что нужно для учебы

181 |
182 |
    183 |
  • Chrome
  • 184 |
  • Node.js
  • 185 |
  • Git
  • 186 |
  • Slack
  • 187 |
  • TeamViewer
  • 188 |
  • Вопросы и ответы
  • 189 |
190 |
191 |
192 |
Редактор / IDE
193 |
    194 |
  • Подсветка синтаксиса
  • 195 |
  • Автодополнение
  • 196 |
  • Форматирование
  • 197 |
  • Подсветка ошибок
  • 198 |
199 | Atom / VSCode / Sublime / WebStorm 200 |
201 |
202 |
Anki ( телефон + компьютер )
203 |
    204 |
  • Новые слова
  • 205 |
  • API
  • 206 |
  • Определения
  • 207 |
  • Вопросы и ответы
  • 208 |
209 |
210 |
211 |
212 |

Как проходит курс

213 |
214 |
    215 |
  • Домашнее задание
  • 216 |
  • Ответы на вопросы
  • 217 |
  • Вопросы
  • 218 |
  • Разбор теории / обсуждение задачи
  • 219 |
220 |
221 |
222 | Вопросы? 223 |
224 |
225 |
226 |
227 | 228 | 229 | 230 | 366 | 367 | 368 | 369 | -------------------------------------------------------------------------------- /07/cls/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Js Base Course - Занятие 7 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |
17 |

Занятие 7

18 |
19 |
20 |
21 |

Вопросы?

22 |
23 |
24 |

25 | Вопросы! 27 |

28 |
29 |
30 |
31 |

Работа с графикой

32 |
    33 |
  • HTML + CSS
  • 34 |
  • SVG
  • 35 |
  • Canvas
  • 36 |
  • WebGL
  • 37 |
38 |
39 |
40 |

HTML + CSS...

41 |
42 | 65 |
66 |
67 |

Вопросы?

68 |
69 |
70 |
71 |

72 | SVG ( Scalable Vector Graphics ) 73 |

74 |
75 |
    76 |
  • XML
  • 77 |
  • Векторная графика
  • 78 |
  • Совместимость с CSS
  • 79 |
  • Размер / сложность
  • 80 |
81 |
82 |
83 | 98 |
99 |
100 | 101 | 103 | 104 | 105 |
106 |
107 |

Вопросы?

108 |
109 |
110 |
111 |

112 | WebGL 113 |
( Web-based Graphics Library )
114 |

115 |
116 |
    117 |
  • 3D
  • 118 |
  • OpenGL / апаратная обработка графики
  • 119 |
  • Большое число "объектов"
  • 120 |
  • Сложность при работе "на примитивном" уровне
  • 121 |
122 |
123 |
124 | Примеры на http://webglsamples.org/ 125 |
Инструменты для работы: 126 |
127 | 138 |
139 |
140 |

Вопросы?

141 |
142 |
143 |
144 |

145 | Canvas 146 |

147 |
148 |
    149 |
  • 2D контекст
  • 150 |
  • Работа с примитивами (линии, полифигуры, точки)
  • 151 |
  • Перемещение по матрице координат и преобразования
  • 152 |
  • "Растровость"
  • 153 |
154 |
155 |
156 | Порядок работы: 157 | 164 |
165 |
166 | Руководство по Canvas 167 | 197 |
198 |
199 |

200 |   var ctx = document.getElementById('canvas').getContext('2d');
201 |   // draw background
202 |   ctx.fillStyle = '#FD0';
203 |   ctx.fillRect(0, 0, 75, 75);
204 | 
205 |   ctx.fillStyle = '#6C0';
206 |   ctx.fillRect(75, 0, 75, 75);
207 | 
208 |   // set transparency value
209 |   ctx.globalAlpha = 0.2;
210 | 
211 |   // Draw semi transparent circles
212 |   for (i = 0; i < 7; i++) {
213 |     ctx.beginPath();
214 |     ctx.arc(75, 75, 10 + 10 * i, 0, Math.PI * 2, true);
215 |     ctx.fill();
216 |   }
217 | 
218 |
219 |
220 |

Вопросы?

221 |
222 |
223 |
224 |

Домашнее задание

225 |
226 | Game Of Life Screen 227 |
228 |
229 | 230 |
231 |
232 | 233 |
234 |
235 |

Вопросы?

236 |
237 |
238 |
239 | Demo - Arena 240 |
241 | Demo - Sprite Animation 242 |
243 | Demo - Sprite Animation * 244 |
245 |
246 |
247 |
248 | 249 | 250 | 251 | 393 | 394 | 395 | 396 | -------------------------------------------------------------------------------- /06/cls/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Js Base Course - Занятие 5 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |
17 |

Вопросы?

18 |
19 |
20 |

21 | Вопросы! 23 |

24 |
25 |
26 |

Занятие 6

27 |
28 |
29 |

Использование ООП

30 |
    31 |
  • Абстракция
  • 32 |
  • Наследование
  • 33 |
  • 34 | Состояние 35 |
  • 36 |
37 |
38 |
39 |

Вопросы?

40 |
41 |
42 | Составные части приложения 43 |
44 |
45 |
Компонент
46 |
    47 |
  • Функциональная единица приложения
  • 48 |
  • Инкапсулирует логику работы
  • 49 |
  • Может быть переиспользован
  • 50 |
  • Может включать в себя другие компоненты
  • 51 |
  • Работает с "узлом" DOM дерева 52 | * 53 |
  • 54 |
55 |
56 |
57 | Примеры компонентов: 58 |
59 |
    60 |
  • Календарь
  • 61 |
  • Форма
  • 62 |
  • Меню
  • 63 |
  • Контрол формы
  • 64 |
  • Кнопка
  • 65 |
66 |
67 |
68 | Обычный компонент включает: 69 |
70 |
    71 |
  • 72 | .render 73 |
  • 74 |
  • Конструктор принимающий зависимости и опции
  • 75 |
  • Служебные методы
  • 76 |
77 |
78 |
79 | Пример компонента: 80 |
81 |

 82 | var BtnComponent = function(el, num, allowIncrement) {
 83 |   this.el = el;
 84 |   this.num = num;
 85 |   this.render();
 86 |   if (allowIncrement) {
 87 |     this.subscribeToClicks();
 88 |   }
 89 | }
 90 | BtnComponent.prototype.render = function() {
 91 |   this.el.innerHTML = '';
 92 | }
 93 | 
 94 | BtnComponent.prototype.subscribeToClicks = function() {
 95 |   this.el.addEventListener('click', function() {
 96 |     this.num = this.num + 1;
 97 |     this.render();
 98 |   }.bind(this));
 99 | }
100 | 
101 |                         
102 |
103 |
104 | Router 105 |
106 |
107 | Service 108 |
109 |
    110 |
  • Вспомогательные фукнции и методы
  • 111 |
  • Обертка и абстракция
  • 112 |
  • StateFull / StateLess
  • 113 |
114 |
115 |
116 | Пример сервиса 117 |
118 |

119 | var LsStore = function(prefix) {
120 |   this.prefix = prefix;
121 | } 
122 | LsStore.prototype = {
123 |   getItem: function(key) {
124 |     return Promise.resolve(localStorage.getItem(this.prefix + '_' + key));
125 |   },
126 |   setItem: function(key, val) {
127 |     return Promise.resolve(localStorage.setItem(this.prefix + '_' + key, JSON.stringify(val)));
128 |   }
129 | };
130 |   
131 |
132 |
133 | Application 134 |
Собрать все вместе и запустить 135 |

136 | /* Page1Component , Page2Component , eventBus, Router, service1, service2 */
137 | var router = new Router([
138 | { url: '/page1', onEnter: () => new Page1Component('.content', eventBus, service1) },
139 | { url: '/page2', onEnter: () => new Page2Component('.content', service2) }
140 | ], {
141 |   eventBus: eventBus
142 | });
143 |                 
144 |
145 |
146 |
147 |

Вопросы?

148 |
149 |
150 |

Использование сторонних библиотек

151 |
    152 |
  • Имеют namespace или доступны как модуль
  • 153 |
  • Подключаются в сборку или через 154 | CDN 155 |
  • 156 |
  • Иногда имеют модульную струтуру и поддержку нестандартных сборок
  • 157 |
158 |
159 |
160 |

Основные библиотеки

161 |
162 |
163 |

164 | JQuery / 165 | Zepto 166 |

167 |
168 | Основные разделы библиотеки: 169 |
    170 |
  • Выборка элементов ( расширенные селекторы ) / манипуляция DOM
  • 171 |
  • Работа с атрибутами / значениями / CSS / размерами элементов
  • 172 |
  • AJAX
  • 173 |
  • Работа с событиями / Promises
  • 174 |
  • Работа с событиями ( подписа / отписка / тригеринг )
  • 175 |
  • Анимации 176 | * 177 |
  • 178 |
179 |
180 |
181 | Выделяется: 182 |
    183 |
  • Расширяемость ( много плагинов )
  • 184 |
  • Решение проблем кроссбраузерности
  • 185 |
  • Большое число примеров кода / решения
  • 186 |
  • Не изменяет стандартные объекты
  • 187 |
  • Null-object паттерн
  • 188 |
189 |
190 |
191 |
192 |

193 | Underscore / 194 | Lodash 195 |

196 |
197 | Основные разделы библиотеки: 198 |
    199 |
  • Работа с коллекциями/массивами
  • 200 |
  • Работа с функциями (изменение контекста/работа с аргументами ...)
  • 201 |
  • Работа с объектами ( выборка свойств, расширение и тп)
  • 202 |
  • Дополнения для строк и чисел
  • 203 |
  • Шаблонизатор и утилиты
  • 204 |
205 |
206 |
207 |
208 |

209 | D3 / 210 | Chart.js 211 |

212 |
213 | Основные разделы библиотеки: 214 |
    215 |
  • Визуализация данных (построение графиков/чартов)
  • 216 |
  • Анимация
  • 217 |
218 | Примеры 219 |
220 |
221 |
222 |

223 | Backbone.js 224 |

225 |
226 | Основные разделы библиотеки: 227 |
    228 |
  • Роутинг
  • 229 |
  • MVC составляющие
  • 230 |
  • Обертка для синхронизации данных
  • 231 |
  • Событийная модель
  • 232 |
  • Работа с коллекциями
  • 233 |
234 |
235 |
236 |
237 |

238 | JQuery UI 239 |

240 |
241 | Основные разделы библиотеки: 242 |
    243 |
  • Виджеты (календарь/ табы/ меню/ диалоговые окна / слайдеры )
  • 244 |
  • Эффекты (расширение эффектов jquery)
  • 245 |
  • Реализация drag-n-drop, resize, сортировки
  • 246 |
247 |
248 |
249 |
250 |

UI Toolkits

251 |
252 | 266 |
267 |
268 | Особенности: 269 |
    270 |
  • Внешний вид "под десктоп"
  • 271 |
  • Своя объектная/компонентная модель
  • 272 |
  • Не рады работе с DOM
  • 273 |
  • Задают структуру приложения
  • 274 |
275 |
276 |
277 |
278 |

Фреймворки 279 | * 280 |

281 | 301 |
302 |
303 |

Вопросы?

304 |
305 |
306 |
307 | 308 | 309 | 310 | 451 | 452 | 453 | -------------------------------------------------------------------------------- /08/cls/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Js Base Course - Занятие 8 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |
17 |

Вопросы?

18 |
19 |
20 |

Вопросы

21 |
22 |
23 |

Занятие 8

24 |
25 |
26 |

Тестирование

27 |
28 |

Цели (c точки зрения разработчика):

29 |
    30 |
  • Проверка соответствия ожиданиям
  • 31 |
  • Проверка состояния системы (регрессия)
  • 32 |
  • Документирование кода
  • 33 |
  • Примеры использования
  • 34 |
  • Поиск / проверка на ошибки
  • 35 |
36 |
37 |
38 |

Вопросы?

39 |
40 |
41 |

Уровни тестирования

42 |
    43 |
  • Модульное ( функция / класс )
  • 44 |
  • Интеграционное (межмодульное)
  • 45 |
  • UI ( системное )
  • 46 |
47 |
48 |
49 |

Пирамида тестирования

50 | 52 |
53 |
54 |

Пирамида тестирования

55 | 56 |
57 |
58 |

Вопросы?

59 |
60 |
61 |

По объекту тестирования

62 |
    63 |
  • Функционал
  • 64 |
  • Кроссбраузерность
  • 65 |
  • Нагрузочное тестирование
  • 66 |
  • Стресс тестирование
  • 67 |
  • Юзабилити
  • 68 |
  • Безопасность 69 | * 70 |
  • 71 |
72 |
73 |
74 |

Вопросы?

75 |
76 |
77 |

Относительно выполнения кода:

78 |
    79 |
  • Без выполнения кода
  • 80 |
  • С частичным выполнением кода
  • 81 |
  • С выполнением кода
  • 82 |
83 |
84 |
85 |
86 |

Тестирование без выполнения - статический анализ

87 | 102 |
103 |
104 |

Ручное тестирование

105 |

106 | Важно! Иметь сценарии использования, чтобы тестировать методически.

107 |

Хаотичное тестирование - метод свободного поиска.

108 |
109 | 110 |
111 |

Автоматизированное тестирование

112 |
113 |

По уровню:

114 |
    115 |
  • Модуль
  • 116 |
  • Взаимодествие компонентов
  • 117 |
  • Интеграционное тестирование
  • 118 |
  • Системное
  • 119 |
120 |
121 |
122 |

123 | Общий подход: Выполнить код и проверить результат его работы

124 |
125 |
126 |
127 |

Вопросы?

128 |
129 |
130 |

Модульное тестирование

131 |
132 | Особенности: 133 |
    134 |
  • Тестирует реализацию
  • 135 |
  • Скорость работы и точность выявления ошибок
  • 136 |
  • "Белый" ящик
  • 137 |
  • Влияют на устройство кода "внутри"
  • 138 |
139 |
140 |
141 | 155 |
156 |
157 |

158 | describe('Array', function() {
159 |   describe('#indexOf()', function() {
160 |     it('should return -1 when the value is not present', function() {
161 |       [1,2,3].indexOf(5).should.equal(-1);
162 |       [1,2,3].indexOf(0).should.equal(-1);
163 |     });
164 |   });
165 | });
166 |             
167 |
168 |
169 | Success tests 170 |
171 |
172 | Failed tests 173 |
174 |
175 |

176 | describe('Connection', function() {
177 |   var db = new Connection,
178 |     tobi = new User('tobi');
179 | 
180 |   beforeEach(function(done) {
181 |     db.clear((err) => {
182 |       return (err) ? done(err): db.save([tobi, loki, jane], done);
183 |     });
184 |   });
185 | 
186 |   describe('#find()', () => {
187 |     it('respond with matching records', (done) => {
188 |       db.find({type: 'User'}, (err, res) => {
189 |         if (err) return done(err);
190 |         res.should.have.length(3);
191 |         done();
192 |       });
193 |     });
194 |   });
195 | });
196 |             
197 |
198 |
199 |

Вопросы?

200 |
201 |
202 |

Почему его не достаточно?

203 |
204 |
205 | No integration tests 206 |
207 |
208 | No integration tests 209 |
210 |
211 | No integration tests 212 |
213 |
214 | No integration tests 215 |
216 |
217 |

218 | Вспомогательные объекты/методы 219 |

220 |

221 | test stub (заглушка), используется для получения данных из внешней зависимости, подменяя её.

222 |

223 | test spy (тестовый шпион), используется для тестов взаимодействия, основной функцией является запись 224 | данных и вызовов, поступающих из тестируемого объекта для последующей проверки

225 |

226 | mock object (мок-объект), очень похож на тестовый шпион, однако не записывает последовательность вызовов 227 | с переданными параметрами для последующей проверки

228 |
229 |
230 |
231 |

Вопросы?

232 |
233 |
234 |

UI тестирование

235 |
236 | Особенности: 237 |
    238 |
  • Тестирует функционал, а не код
  • 239 |
  • Сценарии со стороны пользователя
  • 240 |
  • Кроссбраузерность
  • 241 |
  • Нет привязки к средствам реализации
  • 242 |
  • "Черный" ящик
  • 243 |
  • "Простое" создание тестов
  • 244 |
  • Медленные 245 | * 246 |
  • 247 |
248 |
249 |
250 | Selenium tests 252 |
253 |
254 | 269 |
270 |
271 |

272 | var webdriverio = require('webdriverio');
273 | var options = { desiredCapabilities: { browserName: 'chrome' } };
274 | var client = webdriverio.remote(options);
275 | client
276 |     .init()
277 |     .url('https://duckduckgo.com/')
278 |     .setValue('#search_form_input_homepage', 'WebdriverIO')
279 |     .click('#search_button_homepage')
280 |     .getTitle().then(function(title) {
281 |         console.log('Title is: ' + title);
282 |         // outputs:
283 |         // "Title is: WebdriverIO (Software) at DuckDuckGo"
284 |     })
285 |     .end();
286 |             
287 |
288 |
289 |
290 | Разбор примера тестов 291 |
292 |
293 |

Вопросы?

294 |
295 |
296 |
297 | 298 | 299 | 300 | 441 | 442 | 443 | 444 | --------------------------------------------------------------------------------