diff --git a/6-async/01-callbacks/01-animate-circle-callback/solution.md b/1-js/09-async/01-callbacks/01-animate-circle-callback/solution.md similarity index 100% rename from 6-async/01-callbacks/01-animate-circle-callback/solution.md rename to 1-js/09-async/01-callbacks/01-animate-circle-callback/solution.md diff --git a/6-async/01-callbacks/01-animate-circle-callback/solution.view/index.html b/1-js/09-async/01-callbacks/01-animate-circle-callback/solution.view/index.html similarity index 100% rename from 6-async/01-callbacks/01-animate-circle-callback/solution.view/index.html rename to 1-js/09-async/01-callbacks/01-animate-circle-callback/solution.view/index.html diff --git a/6-async/01-callbacks/01-animate-circle-callback/task.md b/1-js/09-async/01-callbacks/01-animate-circle-callback/task.md similarity index 100% rename from 6-async/01-callbacks/01-animate-circle-callback/task.md rename to 1-js/09-async/01-callbacks/01-animate-circle-callback/task.md diff --git a/6-async/01-callbacks/article.md b/1-js/09-async/01-callbacks/article.md similarity index 100% rename from 6-async/01-callbacks/article.md rename to 1-js/09-async/01-callbacks/article.md diff --git a/6-async/01-callbacks/callback-hell.png b/1-js/09-async/01-callbacks/callback-hell.png similarity index 100% rename from 6-async/01-callbacks/callback-hell.png rename to 1-js/09-async/01-callbacks/callback-hell.png diff --git a/6-async/01-callbacks/callback-hell@2x.png b/1-js/09-async/01-callbacks/callback-hell@2x.png similarity index 100% rename from 6-async/01-callbacks/callback-hell@2x.png rename to 1-js/09-async/01-callbacks/callback-hell@2x.png diff --git a/6-async/01-callbacks/one.js b/1-js/09-async/01-callbacks/one.js similarity index 100% rename from 6-async/01-callbacks/one.js rename to 1-js/09-async/01-callbacks/one.js diff --git a/6-async/02-promise-basics/01-re-resolve/solution.md b/1-js/09-async/02-promise-basics/01-re-resolve/solution.md similarity index 100% rename from 6-async/02-promise-basics/01-re-resolve/solution.md rename to 1-js/09-async/02-promise-basics/01-re-resolve/solution.md diff --git a/6-async/02-promise-basics/01-re-resolve/task.md b/1-js/09-async/02-promise-basics/01-re-resolve/task.md similarity index 100% rename from 6-async/02-promise-basics/01-re-resolve/task.md rename to 1-js/09-async/02-promise-basics/01-re-resolve/task.md diff --git a/6-async/02-promise-basics/02-delay-promise/solution.md b/1-js/09-async/02-promise-basics/02-delay-promise/solution.md similarity index 100% rename from 6-async/02-promise-basics/02-delay-promise/solution.md rename to 1-js/09-async/02-promise-basics/02-delay-promise/solution.md diff --git a/6-async/02-promise-basics/02-delay-promise/task.md b/1-js/09-async/02-promise-basics/02-delay-promise/task.md similarity index 100% rename from 6-async/02-promise-basics/02-delay-promise/task.md rename to 1-js/09-async/02-promise-basics/02-delay-promise/task.md diff --git a/6-async/02-promise-basics/03-animate-circle-promise/solution.md b/1-js/09-async/02-promise-basics/03-animate-circle-promise/solution.md similarity index 100% rename from 6-async/02-promise-basics/03-animate-circle-promise/solution.md rename to 1-js/09-async/02-promise-basics/03-animate-circle-promise/solution.md diff --git a/6-async/02-promise-basics/03-animate-circle-promise/solution.view/index.html b/1-js/09-async/02-promise-basics/03-animate-circle-promise/solution.view/index.html similarity index 100% rename from 6-async/02-promise-basics/03-animate-circle-promise/solution.view/index.html rename to 1-js/09-async/02-promise-basics/03-animate-circle-promise/solution.view/index.html diff --git a/6-async/02-promise-basics/03-animate-circle-promise/task.md b/1-js/09-async/02-promise-basics/03-animate-circle-promise/task.md similarity index 100% rename from 6-async/02-promise-basics/03-animate-circle-promise/task.md rename to 1-js/09-async/02-promise-basics/03-animate-circle-promise/task.md diff --git a/6-async/02-promise-basics/article.md b/1-js/09-async/02-promise-basics/article.md similarity index 98% rename from 6-async/02-promise-basics/article.md rename to 1-js/09-async/02-promise-basics/article.md index 14c025c0..23d20268 100644 --- a/6-async/02-promise-basics/article.md +++ b/1-js/09-async/02-promise-basics/article.md @@ -80,7 +80,7 @@ To summarize, the executor should do a job (something that takes time usually) a The Promise that is either resolved or rejected is called "settled", as opposed to a "pending" Promise. ````smart header="There can be only a single result or an error" -The executor should call only one `resolve` or `reject`. The promise's state change is final. +The executor should call only one `resolve` or one `reject`. The promise's state change is final. All further calls of `resolve` and `reject` are ignored: @@ -95,7 +95,7 @@ let promise = new Promise(function(resolve, reject) { The idea is that a job done by the executor may have only one result or an error. -Further, `resolve`/`reject` expect only one argument and will ignore additional arguments. +Also, `resolve`/`reject` expect only one argument (or none) and will ignore additional arguments. ```` ```smart header="Reject with `Error` objects" diff --git a/6-async/02-promise-basics/head.html b/1-js/09-async/02-promise-basics/head.html similarity index 100% rename from 6-async/02-promise-basics/head.html rename to 1-js/09-async/02-promise-basics/head.html diff --git a/6-async/02-promise-basics/promise-init.png b/1-js/09-async/02-promise-basics/promise-init.png similarity index 100% rename from 6-async/02-promise-basics/promise-init.png rename to 1-js/09-async/02-promise-basics/promise-init.png diff --git a/6-async/02-promise-basics/promise-init@2x.png b/1-js/09-async/02-promise-basics/promise-init@2x.png similarity index 100% rename from 6-async/02-promise-basics/promise-init@2x.png rename to 1-js/09-async/02-promise-basics/promise-init@2x.png diff --git a/6-async/02-promise-basics/promise-reject-1.png b/1-js/09-async/02-promise-basics/promise-reject-1.png similarity index 100% rename from 6-async/02-promise-basics/promise-reject-1.png rename to 1-js/09-async/02-promise-basics/promise-reject-1.png diff --git a/6-async/02-promise-basics/promise-reject-1@2x.png b/1-js/09-async/02-promise-basics/promise-reject-1@2x.png similarity index 100% rename from 6-async/02-promise-basics/promise-reject-1@2x.png rename to 1-js/09-async/02-promise-basics/promise-reject-1@2x.png diff --git a/6-async/02-promise-basics/promise-resolve-1.png b/1-js/09-async/02-promise-basics/promise-resolve-1.png similarity index 100% rename from 6-async/02-promise-basics/promise-resolve-1.png rename to 1-js/09-async/02-promise-basics/promise-resolve-1.png diff --git a/6-async/02-promise-basics/promise-resolve-1@2x.png b/1-js/09-async/02-promise-basics/promise-resolve-1@2x.png similarity index 100% rename from 6-async/02-promise-basics/promise-resolve-1@2x.png rename to 1-js/09-async/02-promise-basics/promise-resolve-1@2x.png diff --git a/6-async/02-promise-basics/promise-resolve-reject.png b/1-js/09-async/02-promise-basics/promise-resolve-reject.png similarity index 100% rename from 6-async/02-promise-basics/promise-resolve-reject.png rename to 1-js/09-async/02-promise-basics/promise-resolve-reject.png diff --git a/6-async/02-promise-basics/promise-resolve-reject@2x.png b/1-js/09-async/02-promise-basics/promise-resolve-reject@2x.png similarity index 100% rename from 6-async/02-promise-basics/promise-resolve-reject@2x.png rename to 1-js/09-async/02-promise-basics/promise-resolve-reject@2x.png diff --git a/6-async/03-promise-chaining/01-then-vs-catch/solution.md b/1-js/09-async/03-promise-chaining/01-then-vs-catch/solution.md similarity index 100% rename from 6-async/03-promise-chaining/01-then-vs-catch/solution.md rename to 1-js/09-async/03-promise-chaining/01-then-vs-catch/solution.md diff --git a/6-async/03-promise-chaining/01-then-vs-catch/task.md b/1-js/09-async/03-promise-chaining/01-then-vs-catch/task.md similarity index 100% rename from 6-async/03-promise-chaining/01-then-vs-catch/task.md rename to 1-js/09-async/03-promise-chaining/01-then-vs-catch/task.md diff --git a/6-async/03-promise-chaining/02-error-async/solution.md b/1-js/09-async/03-promise-chaining/02-error-async/solution.md similarity index 100% rename from 6-async/03-promise-chaining/02-error-async/solution.md rename to 1-js/09-async/03-promise-chaining/02-error-async/solution.md diff --git a/6-async/03-promise-chaining/02-error-async/task.md b/1-js/09-async/03-promise-chaining/02-error-async/task.md similarity index 100% rename from 6-async/03-promise-chaining/02-error-async/task.md rename to 1-js/09-async/03-promise-chaining/02-error-async/task.md diff --git a/6-async/03-promise-chaining/article.md b/1-js/09-async/03-promise-chaining/article.md similarity index 100% rename from 6-async/03-promise-chaining/article.md rename to 1-js/09-async/03-promise-chaining/article.md diff --git a/6-async/03-promise-chaining/getMessage.js b/1-js/09-async/03-promise-chaining/getMessage.js similarity index 100% rename from 6-async/03-promise-chaining/getMessage.js rename to 1-js/09-async/03-promise-chaining/getMessage.js diff --git a/6-async/03-promise-chaining/head.html b/1-js/09-async/03-promise-chaining/head.html similarity index 100% rename from 6-async/03-promise-chaining/head.html rename to 1-js/09-async/03-promise-chaining/head.html diff --git a/6-async/03-promise-chaining/one.js b/1-js/09-async/03-promise-chaining/one.js similarity index 100% rename from 6-async/03-promise-chaining/one.js rename to 1-js/09-async/03-promise-chaining/one.js diff --git a/6-async/03-promise-chaining/promise-handler-variants-2.png b/1-js/09-async/03-promise-chaining/promise-handler-variants-2.png similarity index 100% rename from 6-async/03-promise-chaining/promise-handler-variants-2.png rename to 1-js/09-async/03-promise-chaining/promise-handler-variants-2.png diff --git a/6-async/03-promise-chaining/promise-handler-variants-2@2x.png b/1-js/09-async/03-promise-chaining/promise-handler-variants-2@2x.png similarity index 100% rename from 6-async/03-promise-chaining/promise-handler-variants-2@2x.png rename to 1-js/09-async/03-promise-chaining/promise-handler-variants-2@2x.png diff --git a/6-async/03-promise-chaining/promise-handler-variants.png b/1-js/09-async/03-promise-chaining/promise-handler-variants.png similarity index 100% rename from 6-async/03-promise-chaining/promise-handler-variants.png rename to 1-js/09-async/03-promise-chaining/promise-handler-variants.png diff --git a/6-async/03-promise-chaining/promise-handler-variants@2x.png b/1-js/09-async/03-promise-chaining/promise-handler-variants@2x.png similarity index 100% rename from 6-async/03-promise-chaining/promise-handler-variants@2x.png rename to 1-js/09-async/03-promise-chaining/promise-handler-variants@2x.png diff --git a/6-async/03-promise-chaining/promise-then-chain.png b/1-js/09-async/03-promise-chaining/promise-then-chain.png similarity index 100% rename from 6-async/03-promise-chaining/promise-then-chain.png rename to 1-js/09-async/03-promise-chaining/promise-then-chain.png diff --git a/6-async/03-promise-chaining/promise-then-chain@2x.png b/1-js/09-async/03-promise-chaining/promise-then-chain@2x.png similarity index 100% rename from 6-async/03-promise-chaining/promise-then-chain@2x.png rename to 1-js/09-async/03-promise-chaining/promise-then-chain@2x.png diff --git a/6-async/03-promise-chaining/promise-then-many.png b/1-js/09-async/03-promise-chaining/promise-then-many.png similarity index 100% rename from 6-async/03-promise-chaining/promise-then-many.png rename to 1-js/09-async/03-promise-chaining/promise-then-many.png diff --git a/6-async/03-promise-chaining/promise-then-many@2x.png b/1-js/09-async/03-promise-chaining/promise-then-many@2x.png similarity index 100% rename from 6-async/03-promise-chaining/promise-then-many@2x.png rename to 1-js/09-async/03-promise-chaining/promise-then-many@2x.png diff --git a/6-async/03-promise-chaining/three.js b/1-js/09-async/03-promise-chaining/three.js similarity index 100% rename from 6-async/03-promise-chaining/three.js rename to 1-js/09-async/03-promise-chaining/three.js diff --git a/6-async/03-promise-chaining/two.js b/1-js/09-async/03-promise-chaining/two.js similarity index 100% rename from 6-async/03-promise-chaining/two.js rename to 1-js/09-async/03-promise-chaining/two.js diff --git a/6-async/03-promise-chaining/user.json b/1-js/09-async/03-promise-chaining/user.json similarity index 100% rename from 6-async/03-promise-chaining/user.json rename to 1-js/09-async/03-promise-chaining/user.json diff --git a/6-async/04-promise-api/01-promise-errors-as-results/solution.md b/1-js/09-async/04-promise-api/01-promise-errors-as-results/solution.md similarity index 100% rename from 6-async/04-promise-api/01-promise-errors-as-results/solution.md rename to 1-js/09-async/04-promise-api/01-promise-errors-as-results/solution.md diff --git a/6-async/04-promise-api/01-promise-errors-as-results/solution.view/index.html b/1-js/09-async/04-promise-api/01-promise-errors-as-results/solution.view/index.html similarity index 100% rename from 6-async/04-promise-api/01-promise-errors-as-results/solution.view/index.html rename to 1-js/09-async/04-promise-api/01-promise-errors-as-results/solution.view/index.html diff --git a/6-async/04-promise-api/01-promise-errors-as-results/source.view/index.html b/1-js/09-async/04-promise-api/01-promise-errors-as-results/source.view/index.html similarity index 100% rename from 6-async/04-promise-api/01-promise-errors-as-results/source.view/index.html rename to 1-js/09-async/04-promise-api/01-promise-errors-as-results/source.view/index.html diff --git a/6-async/04-promise-api/01-promise-errors-as-results/task.md b/1-js/09-async/04-promise-api/01-promise-errors-as-results/task.md similarity index 100% rename from 6-async/04-promise-api/01-promise-errors-as-results/task.md rename to 1-js/09-async/04-promise-api/01-promise-errors-as-results/task.md diff --git a/6-async/04-promise-api/02-promise-errors-as-results-2/solution.md b/1-js/09-async/04-promise-api/02-promise-errors-as-results-2/solution.md similarity index 100% rename from 6-async/04-promise-api/02-promise-errors-as-results-2/solution.md rename to 1-js/09-async/04-promise-api/02-promise-errors-as-results-2/solution.md diff --git a/6-async/04-promise-api/02-promise-errors-as-results-2/solution.view/index.html b/1-js/09-async/04-promise-api/02-promise-errors-as-results-2/solution.view/index.html similarity index 100% rename from 6-async/04-promise-api/02-promise-errors-as-results-2/solution.view/index.html rename to 1-js/09-async/04-promise-api/02-promise-errors-as-results-2/solution.view/index.html diff --git a/6-async/04-promise-api/02-promise-errors-as-results-2/source.view/index.html b/1-js/09-async/04-promise-api/02-promise-errors-as-results-2/source.view/index.html similarity index 100% rename from 6-async/04-promise-api/02-promise-errors-as-results-2/source.view/index.html rename to 1-js/09-async/04-promise-api/02-promise-errors-as-results-2/source.view/index.html diff --git a/6-async/04-promise-api/02-promise-errors-as-results-2/task.md b/1-js/09-async/04-promise-api/02-promise-errors-as-results-2/task.md similarity index 100% rename from 6-async/04-promise-api/02-promise-errors-as-results-2/task.md rename to 1-js/09-async/04-promise-api/02-promise-errors-as-results-2/task.md diff --git a/6-async/04-promise-api/article.md b/1-js/09-async/04-promise-api/article.md similarity index 100% rename from 6-async/04-promise-api/article.md rename to 1-js/09-async/04-promise-api/article.md diff --git a/6-async/04-promise-api/head.html b/1-js/09-async/04-promise-api/head.html similarity index 100% rename from 6-async/04-promise-api/head.html rename to 1-js/09-async/04-promise-api/head.html diff --git a/6-async/04-promise-api/iliakan.json b/1-js/09-async/04-promise-api/iliakan.json similarity index 100% rename from 6-async/04-promise-api/iliakan.json rename to 1-js/09-async/04-promise-api/iliakan.json diff --git a/6-async/04-promise-api/one.js b/1-js/09-async/04-promise-api/one.js similarity index 100% rename from 6-async/04-promise-api/one.js rename to 1-js/09-async/04-promise-api/one.js diff --git a/6-async/04-promise-api/two.js b/1-js/09-async/04-promise-api/two.js similarity index 100% rename from 6-async/04-promise-api/two.js rename to 1-js/09-async/04-promise-api/two.js diff --git a/6-async/05-async-await/01-rewrite-async-2/solution.md b/1-js/09-async/05-async-await/01-rewrite-async-2/solution.md similarity index 100% rename from 6-async/05-async-await/01-rewrite-async-2/solution.md rename to 1-js/09-async/05-async-await/01-rewrite-async-2/solution.md diff --git a/6-async/05-async-await/01-rewrite-async-2/task.md b/1-js/09-async/05-async-await/01-rewrite-async-2/task.md similarity index 100% rename from 6-async/05-async-await/01-rewrite-async-2/task.md rename to 1-js/09-async/05-async-await/01-rewrite-async-2/task.md diff --git a/6-async/05-async-await/01-rewrite-async/solution.md b/1-js/09-async/05-async-await/01-rewrite-async/solution.md similarity index 100% rename from 6-async/05-async-await/01-rewrite-async/solution.md rename to 1-js/09-async/05-async-await/01-rewrite-async/solution.md diff --git a/6-async/05-async-await/01-rewrite-async/task.md b/1-js/09-async/05-async-await/01-rewrite-async/task.md similarity index 100% rename from 6-async/05-async-await/01-rewrite-async/task.md rename to 1-js/09-async/05-async-await/01-rewrite-async/task.md diff --git a/6-async/05-async-await/article.md b/1-js/09-async/05-async-await/article.md similarity index 100% rename from 6-async/05-async-await/article.md rename to 1-js/09-async/05-async-await/article.md diff --git a/6-async/05-async-await/head.html b/1-js/09-async/05-async-await/head.html similarity index 100% rename from 6-async/05-async-await/head.html rename to 1-js/09-async/05-async-await/head.html diff --git a/6-async/index.md b/1-js/09-async/index.md similarity index 100% rename from 6-async/index.md rename to 1-js/09-async/index.md diff --git a/1-js/10-modules/01-modules-intro/example/index.html b/1-js/10-modules/01-modules-intro/example/index.html deleted file mode 100644 index deff2a7d..00000000 --- a/1-js/10-modules/01-modules-intro/example/index.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - diff --git a/1-js/10-modules/01-modules-intro/example/weekdays.js b/1-js/10-modules/01-modules-intro/example/weekdays.js deleted file mode 100644 index d44ec6ba..00000000 --- a/1-js/10-modules/01-modules-intro/example/weekdays.js +++ /dev/null @@ -1 +0,0 @@ -export default ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]; diff --git a/1-js/10-modules/01-modules-intro/nums.view/bundle.js b/1-js/10-modules/01-modules-intro/nums.view/bundle.js deleted file mode 100644 index 843371e4..00000000 --- a/1-js/10-modules/01-modules-intro/nums.view/bundle.js +++ /dev/null @@ -1,70 +0,0 @@ -/******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; - -/******/ // The require function -/******/ function __webpack_require__(moduleId) { - -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; - -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ exports: {}, -/******/ id: moduleId, -/******/ loaded: false -/******/ }; - -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); - -/******/ // Flag the module as loaded -/******/ module.loaded = true; - -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } - - -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; - -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; - -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; - -/******/ // Load entry module and return exports -/******/ return __webpack_require__(0); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var _nums = __webpack_require__(1); - - document.write('Сумма импортов: ' + (_nums.one + _nums.two)); - -/***/ }, -/* 1 */ -/***/ function(module, exports) { - - "use strict"; - - Object.defineProperty(exports, "__esModule", { - value: true - }); - var one = 1; - - exports.one = one; - var two = 2; - - exports.two = two; - -/***/ } -/******/ ]); \ No newline at end of file diff --git a/1-js/10-modules/01-modules-intro/nums.view/index.html b/1-js/10-modules/01-modules-intro/nums.view/index.html deleted file mode 100644 index c2f2d57f..00000000 --- a/1-js/10-modules/01-modules-intro/nums.view/index.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/1-js/10-modules/01-modules-intro/nums.view/main.js b/1-js/10-modules/01-modules-intro/nums.view/main.js deleted file mode 100644 index d5ad677d..00000000 --- a/1-js/10-modules/01-modules-intro/nums.view/main.js +++ /dev/null @@ -1,3 +0,0 @@ -import {one, two} from './nums'; - -document.write(`Сумма импортов: ${one + two}`); \ No newline at end of file diff --git a/1-js/10-modules/01-modules-intro/nums.view/nums.js b/1-js/10-modules/01-modules-intro/nums.view/nums.js deleted file mode 100644 index 1cce84a7..00000000 --- a/1-js/10-modules/01-modules-intro/nums.view/nums.js +++ /dev/null @@ -1,5 +0,0 @@ -export let one = 1; - -let two = 2; - -export {two}; \ No newline at end of file diff --git a/1-js/10-modules/01-modules-intro/nums.view/webpack.config.js b/1-js/10-modules/01-modules-intro/nums.view/webpack.config.js deleted file mode 100644 index 0d1553f3..00000000 --- a/1-js/10-modules/01-modules-intro/nums.view/webpack.config.js +++ /dev/null @@ -1,22 +0,0 @@ -// Для использования нужен Node.JS -// Поставьте webpack: -// npm i -g webpack -// Поставьте babel-loader: -// npm i babel-loader -// Запустите его в директории с файлами: -// webpack - -module.exports = { - entry: './main', - - output: { - filename: 'bundle.js' - }, - - module: { - loaders: [ - { test: /\.js$/, loader: "babel" } - ] - } -}; - diff --git a/1-js/10-modules/02-import-export/article.md b/1-js/10-modules/02-import-export/article.md new file mode 100644 index 00000000..d8ee7ea9 --- /dev/null +++ b/1-js/10-modules/02-import-export/article.md @@ -0,0 +1,413 @@ + +# Export and Import + +Export and import directives are very versatile. + +In the previous chapter we saw a simple use, now let's explore more examples. + +## Export before declarations + +We can label any declaration as exported by placing `export` before it, be it a variable, function or a class. + +For instance, here all exports are valid: + +```js +// export an array +*!*export*/!* let months = ['Jan', 'Feb', 'Mar','Apr', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; + +// export a constant +*!*export*/!* const MODULES_BECAME_STANDARD_YEAR = 2015; + +// export a class +*!*export*/!* class User { + constructor(name) { + this.name = name; + } +} +``` + +````smart header="No semicolons after export class/function" +Please note that `export` before a class or a function does not make it a [function expression](info:function-expressions-arrows). It's still a function declaration, albeit exported. + +Most Javascript style guides recommend semicolons after statements, but not after function and class declarations. + +That's why there should bes no semicolons at the end of `export class` and `export function`. + +```js +export function sayHi(user) { + alert(`Hello, ${user}!`); +} *!* // no ; at the end */!* +``` + +```` + +## Export after declarations + +Also, we can put `export` separately. + +Here we first declare, and then export: + +```js +// 📁 say.js +function sayHi(user) { + alert(`Hello, ${user}!`); +} + +function sayBye(user) { + alert(`Bye, ${user}!`); +} + +*!* +export {sayHi, sayBye}; // a list of exported variables +*/!* +``` + +...Or, technically we could put `export` above functions as well. + +## Import * + +Usually, we put a list of what to import into `import {...}`, like this: + +```js +// 📁 main.js +*!* +import {sayHi, sayBye} from './say.js'; +*/!* + +sayHi('John'); // Hello, John! +sayBye('John'); // Bye, John! +``` + +But if the list is long, we can import everything as an object using `import * as `, for instance: + +```js +// 📁 main.js +*!* +import * as say from './say.js'; +*/!* + +say.sayHi('John'); +say.sayBye('John'); +``` + +At first sight, "import everything" seems such a cool thing, short to write, why should we ever explicitly list what we need to import? + +Well, there are few reasons. + +1. Modern build tools ([webpack](http://webpack.github.io) and others) bundle modules together and optimize them to speedup loading and remove unused stuff. + + Let's say, we added a 3rd-party library `lib.js` to our project with many functions: + ```js + // 📁 lib.js + export function sayHi() { ... } + export function sayBye() { ... } + export function becomeSilent() { ... } + ``` + + Now if we in fact need only one of them in our project: + ```js + // 📁 main.js + import {sayHi} from './lib.js'; + ``` + ...Then the optimizer will automatically detect it and totally remove the other functions from the bundled code, thus making the build smaller. That is called "tree-shaking". + +2. Explicitly listing what to import gives shorter names: `sayHi()` instead of `lib.sayHi()`. +3. Explicit imports give better overview of the code structure: what is used and where. It makes code support and refactoring easier. + +## Import "as" + +We can also use `as` to import under different names. + +For instance, let's import `sayHi` into the local variable `hi` for brevity, and same for `sayBye`: + +```js +// 📁 main.js +*!* +import {sayHi as hi, sayBye as bye} from './say.js'; +*/!* + +hi('John'); // Hello, John! +bye('John'); // Bye, John! +``` + +## Export "as" + +The similar syntax exists for `export`. + +Let's export functions as `hi` and `bye`: + +```js +// 📁 say.js +... +export {sayHi as hi, sayBye as bye}; +``` + +Now `hi` and `bye` are official names for outsiders: + +```js +// 📁 main.js +import * as say from './say.js'; + +say.hi('John'); // Hello, John! +say.bye('John'); // Bye, John! +``` + +## export default + +So far, we've seen how to import/export multiple things, optionally "as" other names. + +In practice, modules contain either: +- A library, pack of functions, like `lib.js`. +- Or an entity, like `class User` is descirbed in `user.js`, the whole module has only this class. + +Mostly, the second approach is preferred, so that every "thing" resides in its own module. + +Naturally, that requires a lot of files, as everything wants its own module, but that's not a problem at all. Actually, code navigation becomes easier, if files are well-named and structured into folders. + +Modules provide special `export default` syntax to make "one thing per module" way look better. + +It requires following `export` and `import` statements: + +1. Put `export default` before the "main export" of the module. +2. Call `import` without curly braces. + +For instance, here `user.js` exports `class User`: + +```js +// 📁 user.js +export *!*default*/!* class User { // just add "default" + constructor(name) { + this.name = name; + } +} +``` + +...And `main.js` imports it: + +```js +// 📁 main.js +import *!*User*/!* from './user.js'; // not {User}, just User + +new User('John'); +``` + +Imports without curly braces look nicer. A common mistake when starting to use modules is to forget curly braces at all. So, remember, `import` needs curly braces for named imports and doesn't need them for the default one. + +| Named export | Default export | +|--------------|----------------| +| `export class User {...}` | `export default class User {...}` | +| `import {User} from ...` | `import User from ...`| + +Naturally, there may be only one "default" export per file. + +We may have both default and named exports in a single module, but in practice people usually don't mix them. A module has either named exports or the default one. + +**Another thing to note is that named exports must (naturally) have a name, while `export default` may be anonymous.** + +For instance, these are all perfecly valid default exports: + +```js +export default class { // no class name + constructor() { ... } +} + +export default function(user) { // no function name + alert(`Hello, ${user}!`); +} + +// export a single value, without making a variable +export default ['Jan', 'Feb', 'Mar','Apr', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; +``` + +That's fine, because `export default` is only one per file, so `import` always knows what to import. + Contrary to that, omitting a name for named imports would be an error: + +```js +export class { // Error! (non-default export needs a name) + constructor() {} +} +``` + +When importing, to keep the code consistent, teams usually employ the rule that local variables should be named after files, e.g: + +```js +import User from './user.js'; +import LoginForm from './loginForm.js'; +import func from '/path/to/func.js'; +... +``` + +### "Default" alias + +The "default" word is a kind of "alias" for the default export, for scenarios when we need to reference it somehow. + +For example, if we already have a function declared, that's how to `export default` it: + +```js +function sayHi(user) { + alert(`Hello, ${user}!`); +} + +export {sayHi as default}; // same as if we added "export default" before the function +``` + +Or, let's say a module `user.js` exports one main "default" thing and a few named ones (rarely the case, but happens): + +```js +// 📁 user.js +export default class User { + constructor(name) { + this.name = name; + } +} + +export function sayHi(user) { + alert(`Hello, ${user}!`); +} +``` + +Here's how to import the default export along with a named one: + +```js +// 📁 main.js +import {*!*default as User*/!*, sayHi} from './user.js'; + +new User('John'); +``` + +Or, if we consider importing `*` as an object, then the `default` property is exactly the default export: + +```js +// 📁 main.js +import * as user from './user.js'; + +let User = user.default; +new User('John'); +``` + + + +## Re-export + +"Re-export" syntax `export ... from ...` allows to import things and immediately export them (possibly under another name), like this: + +```js +export {sayHi} from './say.js'; +export {default as User} from './user.js'; +``` + +What's the point, why that's needed? Let's see a practical use case. + +Imagine, we're writing a "package": a folder with a lot of modules, mostly needed internally, with some of the functionality exported outside (tools like NPM allow to publish and distribute packages, but here it doesn't matter). + +A directory structure could be like this: +``` +auth/ + index.js + user.js + helpers.js + tests/ + login.js + providers/ + github.js + facebook.js + ... +``` + +We'd like to expose the package functionality via a single entry point, the "main file" `auth/index.js`, to be used like this: + +```js +import {login, logout} from 'auth/index.js' +``` + +The idea is that outsiders, developers who use our package, should not meddle with its internal structure. They should not search for files inside our package folder. We export only what's necessary in `auth/index.js` and keep the rest hidden from prying eyes. + +Now, as the actual exported functionality is scattered among the package, we can gather and "re-export" it in `auth/index.js`: + +```js +// 📁 auth/index.js +import {login, logout} from './helpers.js'; +export {login, logout}; + +import User from './user.js'; +export {User}; + +import Githib from './providers/github.js'; +export {Github}; +... +``` + +"Re-exporting" is just a shorter notation for that: + +```js +// 📁 auth/index.js +export {login, logout} from './helpers.js'; +// or, to re-export all helpers, we could use: +// export * from './helpers.js'; + +export {default as User} from './user.js'; + +export {default as Githib} from './providers/github.js'; +... +``` + +````warn header="Re-exporting default is tricky" +Please note: `export User from './user.js'` won't work. It's actually a syntax error. To re-export the default export, we must mention it explicitly `{default as ...}`, like in the example above. + +Also, there's another oddity: `export * from './user.js'` re-exports only named exports, exluding the default one. Once again, we need to mention it explicitly. + +For instance, to re-export everything, two statements will be necessary: +```js +export * from './module.js'; // to re-export named exports +export {default} from './module.js'; // to re-export default +``` + +The default should be mentioned explicitly only when re-exporting: `import * as obj` works fine. It imports the default export as `obj.default`. So there's a slight asymmetry between import and export constructs here. +```` + +## Summary + +There are following types of `export`: + +- Before declaration: + - `export [default] class/function/variable ...` +- Standalone: + - `export {x [as y], ...}`. +- Re-export: + - `export {x [as y], ...} from "mod"` + - `export * from "mod"` (doesn't re-export default). + - `export {default [as y]} from "mod"` (re-export default). + +Import: + +- Named exports from module: + - `import {x [as y], ...} from "mod"` +- Default export: + - `import x from "mod"` + - `import {default as x} from "mod"` +- Everything: + - `import * as obj from "mod"` +- Only fetch/evalute the module, don't import: + - `import "mod"` + +We can put import/export statements below or after other code, that doesn't matter. + +So this is technically fine: +```js +sayHi(); + +import {sayHi} from './say.js'; // import at the end of the file +``` + +In practice imports are usually at the start of the file, but that's only for better convenience. + +**Please note that all import/export statements must be at the top level of the script.** + +This won't work: +```js +if (something) { + import {sayHi} from "./say.js"; // Error: import must be at top level +} +``` + +...But what if we really need to import something dynamically? Like, load a module upon request, when it's really needed? We'll see how to do it in the next chapter. diff --git a/1-js/10-modules/02-modules-browser/article.md b/1-js/10-modules/02-modules-browser/article.md deleted file mode 100644 index 46909fab..00000000 --- a/1-js/10-modules/02-modules-browser/article.md +++ /dev/null @@ -1,704 +0,0 @@ - -# Modules - -As our application grows bigger, we want to split it into multiple files, so called 'modules'. -A module usually contains a class or a library of useful functions. Then, for browsers we bundle them together with a special tool such as [webpack](https://webpack.js.org/) and deploy to the production server. - -For a long time, Javascript existed without a language-level module syntax. That wasn't a problem, because initially scripts were small and simple. So there was no need. - -But eventually scripts became more and more complex, so the community invented a variety of ways to organize code into modules. - -For instance: - -- [AMD](https://en.wikipedia.org/wiki/Asynchronous_module_definition) -- one of the most ancient module systems, initially implemented by the library [require.js](http://requirejs.org/). -- [CommonJS](http://wiki.commonjs.org/wiki/Modules/1.1) -- the module system created for Node.JS server. -- [UMD](https://github.com/umdjs/umd) -- one more module system, suggested as a universal one, compatible with AMD and CommonJS. - -Now all these slowly become a part of history, but we still can find them in old scripts. - -The language-level module system appeared in the standard in 2015, gradually evolved since then, and is now supported by all major browsers and in Node.js. - -## What is a module? - -A module is just a file. One single script, as simple as that. - -Directives `export` and `import` allow to interchange functionality between modules: - -- `export` keyword labels variables and functions that should be accessible from outside the file. -- `import` allows to import functionality from other modules. - -For instance, if we have a file `sayHi.js` exporting a function: - -```js -// 📁 sayHi.js -export function sayHi(user) { - alert(`Hello, ${user}!`); -} -``` - -...Then another file may import and use it: - -```js -// 📁 main.js -import {sayHi} from './sayHi.js'; - -alert(sayHi); // function... -sayHi('John'); // Hello, John! -``` - -So, one Javascript file ("module") may import functionality from other ones. Not any functionality, but only what's intended (exported). - - - - - - - - -**Each module has its own top-level scope.** - -In other words, global variables from one file are only seen in that file, they do not get into other files. If we want something to be available for other modules -- let's export it. - -For browser scripts, that's something new, so modules require a special tag ` -``` - -Scripts with `type='module'` have several important differences: - -1. They always have enabled `use strict`. So e.g. assigning to undeclared variables will give an error: - ```html - - ``` -2. Scripts are always deferred, same effect as `defer` attribute (described in the chapter [](info:onload-ondomcontentloaded)), for both external and inline scripts. Or, to put it short, they always run after the HTML is fully downloaded and rendered. - ```html run - - - - - - ``` -3. Async attribute ` - - ``` -4. External scripts that are fetched from another domain require [CORS](mdn:Web/HTTP/CORS) headers. In other words, if a module script is fetched from another domain, the remote server must supply a header `Access-Control-Allow-Origin: *` (may use fetching domain instead of `*`) to indicate that the fetch is allowed. - ```html - - - - ``` -5. And, probably, the most notable difference: modules have their own global scope. In other words, top-level variables and functions from modules are not seen in other scripts. - - ```html - - - - ``` - That's natural: modules are expected to `export` what they want to be accessible from outside. And interact via export/import. If we really need the shared `window` scope, then we can use `window.user`, but that should be an exception requiring a good reason. - -If you look at the list, all items are a 'good thing', leading to correct coding practices. - -## export default - -As we've just seen, a module can export individual variables. - -But it's quite common for a file to implement a single thing. For instance, a file `user.js` describes `class User`, a file `login.js` -- `function login()` for authorization, and so on. One file -- one entity. - -There's a special `export default` statement to better implement that approch. Only one may exist per module, and it labels the export as 'the default one', that may be imported directly without figure brackets. - -For instance, `user.js`: - -```js -*!*export default*/!* class User { - constructor(name) { - this.name = name; - } -}; -``` - -...And in `login.js`: - -```js -import User from './user'; - -new User('John'); -``` - -The default export is technically just a syntax sugar. We can live without it. - -If `user.js` had the regular `export` without `default`, then `login.js` would need to import with figure brackets: - -```js -// if user.js had -// export class User { ... } - -// …then to import it we'd need figuree brackets: -import {User} from './user'; - -new User('John'); -``` - -In practice, such 'sugar' is very convenient, it allows to easily see what exactly is exported and omit extra characters while importing. - -Please note that default exports may be unnamed: -```js -// that's allowed: -export default function() {} -``` - -We can also export a regular value, like an array with days of week: -```js -// weekdays.js -export default ['Monday', 'Tuesday', ..., 'Sunday']; -``` - -That's fine, as the default export is only one per module, so `import` knows what to get: - -```js -// assuming export default is used -import weekdays from './weekdays'; - -alert(weekdays[0]); // Monday -``` - -Usually, there's a rule that the default export is imported under the name of the module itself, or under the name of the corresponding entity. Like `import weekdays from './weekdays'` or `import User from './user'`. - - -## Использование - -Современный стандарт ECMAScript описывает, как импортировать и экспортировать значения из модулей, но он ничего не говорит о том, как эти модули искать, загружать и т.п. - -Такие механизмы предлагались в процессе создания стандарта, но были убраны по причине недостаточной проработанности. Возможно, они появятся в будущем. - -Сейчас используются системы сборки, как правило, в сочетании с Babel.JS. - -Система сборки обрабатывает скрипты, находит в них `import/export` и заменяет их на свои внутренние JavaScript-вызовы. При этом, как правило, много файлов-модулей объединяются в один или несколько скриптов, смотря как указано в конфигурации сборки. - -Ниже вы можете увидеть полный пример использования модулей с системой сборки [webpack](http://webpack.github.io). - -В нём есть: - -- `nums.js` -- модуль, экспортирующий `one` и `two`, как описано выше. -- `main.js` -- модуль, который импортирует `one`, `two` из `nums` и выводит их сумму. -- `webpack.config.js` -- конфигурация для системы сборки. -- `bundle.js` -- файл, который создала система сборки из `main.js` и `nums.js`. -- `index.html` -- простой HTML-файл для демонстрации. - -[codetabs src='nums'] - -## Итого - -Современный стандарт описывает, как организовать код в модули, экспортировать и импортировать значения. - -Экспорт: - -- `export` можно поставить прямо перед объявлением функции, класса, переменной. -- Если `export` стоит отдельно от объявления, то значения в нём указываются в фигурных скобках: `export {…}`. -- Также можно экспортировать 'значение по умолчанию' при помощи `export default`. - -Импорт: - -- В фигурных скобках указываются значения, а затем -- модуль, откуда их брать: `import {a, b, c as d} from 'module'`. -- Можно импортировать все значения в виде объекта при помощи `import * as obj from 'module'`. -- Без фигурных скобок будет импортировано 'значение по умолчанию': `import User from 'user'`. - -На текущий момент модули требуют системы сборки на сервере. Автор этого текста преимущественно использует webpack, но есть и другие варианты. diff --git a/1-js/10-modules/02-modules-browser/example/index.html b/1-js/10-modules/02-modules-browser/example/index.html deleted file mode 100644 index deff2a7d..00000000 --- a/1-js/10-modules/02-modules-browser/example/index.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - diff --git a/1-js/10-modules/02-modules-browser/example/weekdays.js b/1-js/10-modules/02-modules-browser/example/weekdays.js deleted file mode 100644 index d44ec6ba..00000000 --- a/1-js/10-modules/02-modules-browser/example/weekdays.js +++ /dev/null @@ -1 +0,0 @@ -export default ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]; diff --git a/1-js/10-modules/02-modules-browser/nums.view/bundle.js b/1-js/10-modules/02-modules-browser/nums.view/bundle.js deleted file mode 100644 index 843371e4..00000000 --- a/1-js/10-modules/02-modules-browser/nums.view/bundle.js +++ /dev/null @@ -1,70 +0,0 @@ -/******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; - -/******/ // The require function -/******/ function __webpack_require__(moduleId) { - -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; - -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ exports: {}, -/******/ id: moduleId, -/******/ loaded: false -/******/ }; - -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); - -/******/ // Flag the module as loaded -/******/ module.loaded = true; - -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } - - -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; - -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; - -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; - -/******/ // Load entry module and return exports -/******/ return __webpack_require__(0); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var _nums = __webpack_require__(1); - - document.write('Сумма импортов: ' + (_nums.one + _nums.two)); - -/***/ }, -/* 1 */ -/***/ function(module, exports) { - - "use strict"; - - Object.defineProperty(exports, "__esModule", { - value: true - }); - var one = 1; - - exports.one = one; - var two = 2; - - exports.two = two; - -/***/ } -/******/ ]); \ No newline at end of file diff --git a/1-js/10-modules/02-modules-browser/nums.view/index.html b/1-js/10-modules/02-modules-browser/nums.view/index.html deleted file mode 100644 index c2f2d57f..00000000 --- a/1-js/10-modules/02-modules-browser/nums.view/index.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/1-js/10-modules/02-modules-browser/nums.view/main.js b/1-js/10-modules/02-modules-browser/nums.view/main.js deleted file mode 100644 index d5ad677d..00000000 --- a/1-js/10-modules/02-modules-browser/nums.view/main.js +++ /dev/null @@ -1,3 +0,0 @@ -import {one, two} from './nums'; - -document.write(`Сумма импортов: ${one + two}`); \ No newline at end of file diff --git a/1-js/10-modules/02-modules-browser/nums.view/nums.js b/1-js/10-modules/02-modules-browser/nums.view/nums.js deleted file mode 100644 index 1cce84a7..00000000 --- a/1-js/10-modules/02-modules-browser/nums.view/nums.js +++ /dev/null @@ -1,5 +0,0 @@ -export let one = 1; - -let two = 2; - -export {two}; \ No newline at end of file diff --git a/1-js/10-modules/02-modules-browser/nums.view/webpack.config.js b/1-js/10-modules/02-modules-browser/nums.view/webpack.config.js deleted file mode 100644 index 0d1553f3..00000000 --- a/1-js/10-modules/02-modules-browser/nums.view/webpack.config.js +++ /dev/null @@ -1,22 +0,0 @@ -// Для использования нужен Node.JS -// Поставьте webpack: -// npm i -g webpack -// Поставьте babel-loader: -// npm i babel-loader -// Запустите его в директории с файлами: -// webpack - -module.exports = { - entry: './main', - - output: { - filename: 'bundle.js' - }, - - module: { - loaders: [ - { test: /\.js$/, loader: "babel" } - ] - } -}; - diff --git a/1-js/10-modules/02-modules-browser/say.view/index.html b/1-js/10-modules/02-modules-browser/say.view/index.html deleted file mode 100644 index 44b948f2..00000000 --- a/1-js/10-modules/02-modules-browser/say.view/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - diff --git a/1-js/10-modules/02-modules-browser/say.view/say.js b/1-js/10-modules/02-modules-browser/say.view/say.js deleted file mode 100644 index ed409cb3..00000000 --- a/1-js/10-modules/02-modules-browser/say.view/say.js +++ /dev/null @@ -1,7 +0,0 @@ -export function sayHi(user) { - alert(`Hello, ${user}!`); -} - -export function sayBye(user) { - alert(`Bye, ${user}!`); -} diff --git a/1-js/10-modules/03-modules-dynamic-imports/article.md b/1-js/10-modules/03-modules-dynamic-imports/article.md new file mode 100644 index 00000000..c7ea6290 --- /dev/null +++ b/1-js/10-modules/03-modules-dynamic-imports/article.md @@ -0,0 +1,48 @@ + +# Dynamic imports + +Export and import statements that we covered in previous chaters are called "static". + +What's because they are indeed static. + +First, we can't generate module name. It must be a string. This won't work: + +```js +import {func} from getModuleName(); // Error, only from "string" is allowed +``` + +Second, we can't import conditionally or at run-time: + +```js +if(...) { + import ...; // Error, not allowed! +} + +{ + import ...; // Error, we can't put import in a block, must be at the top level +} +``` + +So, import/export provide a rigid code structure. That's a good thing, as code structure can be analyzed, modules can be gathered and bundled together, unused exports can be removed (tree-shaken), just because everything is fixed. + +But how do we import a module on-demand? + +## The import() function + +The `import(module)` function can be called from anywhere. It returns a promise that resolved into a module object. + +The usage pattern looks like this: + +```js run +let modulePath = prompt("Module path?"); + +import(modulePath) + .then(obj => ) + .catch(err => ) +``` + +Or, we could use `async/away` here, like this: + +[codetabs src="say" current="index.html"] + +Please note: dynamic imports work in regular scripts, they don't require `script type="module"`, like static imports. diff --git a/1-js/10-modules/03-modules-dynamic-imports/say.view/index.html b/1-js/10-modules/03-modules-dynamic-imports/say.view/index.html new file mode 100644 index 00000000..6cd9734f --- /dev/null +++ b/1-js/10-modules/03-modules-dynamic-imports/say.view/index.html @@ -0,0 +1,10 @@ + + + diff --git a/1-js/10-modules/03-modules-dynamic-imports/say.view/say.js b/1-js/10-modules/03-modules-dynamic-imports/say.view/say.js new file mode 100644 index 00000000..cff234b7 --- /dev/null +++ b/1-js/10-modules/03-modules-dynamic-imports/say.view/say.js @@ -0,0 +1,11 @@ +export function hi() { + alert(`Hello`); +} + +export function bye() { + alert(`Bye`); +} + +export default function() { + alert("Module loaded (export default)!"); +} diff --git a/1-js/10-modules/03-modules-export-import/article.md b/1-js/10-modules/03-modules-export-import/article.md deleted file mode 100644 index 4e1844f9..00000000 --- a/1-js/10-modules/03-modules-export-import/article.md +++ /dev/null @@ -1,693 +0,0 @@ - -# Modules - -As our application grows bigger, we want to split it into multiple files, so called 'modules'. -A module usually contains a class or a library of useful functions. Then, for browsers we bundle them together with a special tool such as [webpack](https://webpack.js.org/) and deploy to the production server. - -For a long time, Javascript existed without a language-level module syntax. That wasn't a problem, because initially scripts were small and simple. So there was no need. - -But eventually scripts became more and more complex, so the community invented a variety of ways to organize code into modules. - -For instance: - -- [AMD](https://en.wikipedia.org/wiki/Asynchronous_module_definition) -- one of the most ancient module systems, initially implemented by the library [require.js](http://requirejs.org/). -- [CommonJS](http://wiki.commonjs.org/wiki/Modules/1.1) -- the module system created for Node.JS server. -- [UMD](https://github.com/umdjs/umd) -- one more module system, suggested as a universal one, compatible with AMD and CommonJS. - -Now all these slowly become a part of history, but we still can find them in old scripts. - -The language-level module system appeared in the standard in 2015, gradually evolved since then, and is now supported by all major browsers and in Node.js. - -## What is a module? - -A module is just a file. One single script, as simple as that. - -Directives `export` and `import` allow to interchange functionality between modules: - -- `export` keyword labels variables and functions that should be accessible from outside the file. -- `import` allows to import functionality from other modules. - -For instance, if we have a file `sayHi.js` exporting a function: - -```js -// 📁 sayHi.js -export function sayHi(user) { - alert(`Hello, ${user}!`); -} -``` - -...Then another file may import and use it: - -```js -// 📁 main.js -import {sayHi} from './sayHi.js'; - -alert(sayHi); // function... -sayHi('John'); // Hello, John! -``` - -So, one Javascript file ("module") may import functionality from other ones. Not any functionality, but only what's intended (exported). - -**Each module has its own top-level scope.** - -In other words, global variables from one file are only seen in that file, they do not get into other files. If we want something to be available for other modules -- let's export it. - -For browser scripts, that's something new, so modules require a special tag ` -``` - -Scripts with `type='module'` have several important differences: - -1. They always have enabled `use strict`. So e.g. assigning to undeclared variables will give an error: - ```html - - ``` -2. Scripts are always deferred, same effect as `defer` attribute (described in the chapter [](info:onload-ondomcontentloaded)), for both external and inline scripts. Or, to put it short, they always run after the HTML is fully downloaded and rendered. - ```html run - - - - - - ``` -3. Async attribute ` - - ``` -4. External scripts that are fetched from another domain require [CORS](mdn:Web/HTTP/CORS) headers. In other words, if a module script is fetched from another domain, the remote server must supply a header `Access-Control-Allow-Origin: *` (may use fetching domain instead of `*`) to indicate that the fetch is allowed. - ```html - - - - ``` -5. And, probably, the most notable difference: modules have their own global scope. In other words, top-level variables and functions from modules are not seen in other scripts. - - ```html - - - - ``` - That's natural: modules are expected to `export` what they want to be accessible from outside. And interact via export/import. If we really need the shared `window` scope, then we can use `window.user`, but that should be an exception requiring a good reason. - -If you look at the list, all items are a 'good thing', leading to correct coding practices. - -## export default - -As we've just seen, a module can export individual variables. - -But it's quite common for a file to implement a single thing. For instance, a file `user.js` describes `class User`, a file `login.js` -- `function login()` for authorization, and so on. One file -- one entity. - -There's a special `export default` statement to better implement that approch. Only one may exist per module, and it labels the export as 'the default one', that may be imported directly without figure brackets. - -For instance, `user.js`: - -```js -*!*export default*/!* class User { - constructor(name) { - this.name = name; - } -}; -``` - -...And in `login.js`: - -```js -import User from './user'; - -new User('John'); -``` - -The default export is technically just a syntax sugar. We can live without it. - -If `user.js` had the regular `export` without `default`, then `login.js` would need to import with figure brackets: - -```js -// if user.js had -// export class User { ... } - -// …then to import it we'd need figuree brackets: -import {User} from './user'; - -new User('John'); -``` - -In practice, such 'sugar' is very convenient, it allows to easily see what exactly is exported and omit extra characters while importing. - -Please note that default exports may be unnamed: -```js -// that's allowed: -export default function() {} -``` - -We can also export a regular value, like an array with days of week: -```js -// weekdays.js -export default ['Monday', 'Tuesday', ..., 'Sunday']; -``` - -That's fine, as the default export is only one per module, so `import` knows what to get: - -```js -// assuming export default is used -import weekdays from './weekdays'; - -alert(weekdays[0]); // Monday -``` - -Usually, there's a rule that the default export is imported under the name of the module itself, or under the name of the corresponding entity. Like `import weekdays from './weekdays'` or `import User from './user'`. - - -## Использование - -Современный стандарт ECMAScript описывает, как импортировать и экспортировать значения из модулей, но он ничего не говорит о том, как эти модули искать, загружать и т.п. - -Такие механизмы предлагались в процессе создания стандарта, но были убраны по причине недостаточной проработанности. Возможно, они появятся в будущем. - -Сейчас используются системы сборки, как правило, в сочетании с Babel.JS. - -Система сборки обрабатывает скрипты, находит в них `import/export` и заменяет их на свои внутренние JavaScript-вызовы. При этом, как правило, много файлов-модулей объединяются в один или несколько скриптов, смотря как указано в конфигурации сборки. - -Ниже вы можете увидеть полный пример использования модулей с системой сборки [webpack](http://webpack.github.io). - -В нём есть: - -- `nums.js` -- модуль, экспортирующий `one` и `two`, как описано выше. -- `main.js` -- модуль, который импортирует `one`, `two` из `nums` и выводит их сумму. -- `webpack.config.js` -- конфигурация для системы сборки. -- `bundle.js` -- файл, который создала система сборки из `main.js` и `nums.js`. -- `index.html` -- простой HTML-файл для демонстрации. - -[codetabs src='nums'] - -## Итого - -Современный стандарт описывает, как организовать код в модули, экспортировать и импортировать значения. - -Экспорт: - -- `export` можно поставить прямо перед объявлением функции, класса, переменной. -- Если `export` стоит отдельно от объявления, то значения в нём указываются в фигурных скобках: `export {…}`. -- Также можно экспортировать 'значение по умолчанию' при помощи `export default`. - -Импорт: - -- В фигурных скобках указываются значения, а затем -- модуль, откуда их брать: `import {a, b, c as d} from 'module'`. -- Можно импортировать все значения в виде объекта при помощи `import * as obj from 'module'`. -- Без фигурных скобок будет импортировано 'значение по умолчанию': `import User from 'user'`. - -На текущий момент модули требуют системы сборки на сервере. Автор этого текста преимущественно использует webpack, но есть и другие варианты. diff --git a/1-js/10-modules/03-modules-export-import/example/index.html b/1-js/10-modules/03-modules-export-import/example/index.html deleted file mode 100644 index deff2a7d..00000000 --- a/1-js/10-modules/03-modules-export-import/example/index.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - diff --git a/1-js/10-modules/03-modules-export-import/example/weekdays.js b/1-js/10-modules/03-modules-export-import/example/weekdays.js deleted file mode 100644 index d44ec6ba..00000000 --- a/1-js/10-modules/03-modules-export-import/example/weekdays.js +++ /dev/null @@ -1 +0,0 @@ -export default ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]; diff --git a/1-js/10-modules/03-modules-export-import/nums.view/bundle.js b/1-js/10-modules/03-modules-export-import/nums.view/bundle.js deleted file mode 100644 index 843371e4..00000000 --- a/1-js/10-modules/03-modules-export-import/nums.view/bundle.js +++ /dev/null @@ -1,70 +0,0 @@ -/******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; - -/******/ // The require function -/******/ function __webpack_require__(moduleId) { - -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; - -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ exports: {}, -/******/ id: moduleId, -/******/ loaded: false -/******/ }; - -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); - -/******/ // Flag the module as loaded -/******/ module.loaded = true; - -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } - - -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; - -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; - -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; - -/******/ // Load entry module and return exports -/******/ return __webpack_require__(0); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ function(module, exports, __webpack_require__) { - - 'use strict'; - - var _nums = __webpack_require__(1); - - document.write('Сумма импортов: ' + (_nums.one + _nums.two)); - -/***/ }, -/* 1 */ -/***/ function(module, exports) { - - "use strict"; - - Object.defineProperty(exports, "__esModule", { - value: true - }); - var one = 1; - - exports.one = one; - var two = 2; - - exports.two = two; - -/***/ } -/******/ ]); \ No newline at end of file diff --git a/1-js/10-modules/03-modules-export-import/nums.view/index.html b/1-js/10-modules/03-modules-export-import/nums.view/index.html deleted file mode 100644 index c2f2d57f..00000000 --- a/1-js/10-modules/03-modules-export-import/nums.view/index.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/1-js/10-modules/03-modules-export-import/nums.view/main.js b/1-js/10-modules/03-modules-export-import/nums.view/main.js deleted file mode 100644 index d5ad677d..00000000 --- a/1-js/10-modules/03-modules-export-import/nums.view/main.js +++ /dev/null @@ -1,3 +0,0 @@ -import {one, two} from './nums'; - -document.write(`Сумма импортов: ${one + two}`); \ No newline at end of file diff --git a/1-js/10-modules/03-modules-export-import/nums.view/nums.js b/1-js/10-modules/03-modules-export-import/nums.view/nums.js deleted file mode 100644 index 1cce84a7..00000000 --- a/1-js/10-modules/03-modules-export-import/nums.view/nums.js +++ /dev/null @@ -1,5 +0,0 @@ -export let one = 1; - -let two = 2; - -export {two}; \ No newline at end of file diff --git a/1-js/10-modules/03-modules-export-import/nums.view/webpack.config.js b/1-js/10-modules/03-modules-export-import/nums.view/webpack.config.js deleted file mode 100644 index 0d1553f3..00000000 --- a/1-js/10-modules/03-modules-export-import/nums.view/webpack.config.js +++ /dev/null @@ -1,22 +0,0 @@ -// Для использования нужен Node.JS -// Поставьте webpack: -// npm i -g webpack -// Поставьте babel-loader: -// npm i babel-loader -// Запустите его в директории с файлами: -// webpack - -module.exports = { - entry: './main', - - output: { - filename: 'bundle.js' - }, - - module: { - loaders: [ - { test: /\.js$/, loader: "babel" } - ] - } -}; - diff --git a/1-js/10-modules/03-modules-export-import/say.view/index.html b/1-js/10-modules/03-modules-export-import/say.view/index.html deleted file mode 100644 index 44b948f2..00000000 --- a/1-js/10-modules/03-modules-export-import/say.view/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - diff --git a/1-js/10-modules/03-modules-export-import/say.view/say.js b/1-js/10-modules/03-modules-export-import/say.view/say.js deleted file mode 100644 index ed409cb3..00000000 --- a/1-js/10-modules/03-modules-export-import/say.view/say.js +++ /dev/null @@ -1,7 +0,0 @@ -export function sayHi(user) { - alert(`Hello, ${user}!`); -} - -export function sayBye(user) { - alert(`Bye, ${user}!`); -} diff --git a/1-js/10-modules/04-modules-dynamic-imports/article.md b/1-js/10-modules/04-modules-dynamic-imports/article.md deleted file mode 100644 index a2a8d7ff..00000000 --- a/1-js/10-modules/04-modules-dynamic-imports/article.md +++ /dev/null @@ -1,4 +0,0 @@ - -# Dynos - -...test diff --git a/1-js/10-modules/index.md b/1-js/10-modules/index.md index edb7bfe8..78fb060e 100644 --- a/1-js/10-modules/index.md +++ b/1-js/10-modules/index.md @@ -1,3 +1,2 @@ # Modules -s diff --git a/4-frames-and-windows/01-popup-windows/article.md b/2-ui/5-frames-and-windows/01-popup-windows/article.md similarity index 100% rename from 4-frames-and-windows/01-popup-windows/article.md rename to 2-ui/5-frames-and-windows/01-popup-windows/article.md diff --git a/4-frames-and-windows/03-cross-window-communication/article.md b/2-ui/5-frames-and-windows/03-cross-window-communication/article.md similarity index 100% rename from 4-frames-and-windows/03-cross-window-communication/article.md rename to 2-ui/5-frames-and-windows/03-cross-window-communication/article.md diff --git a/4-frames-and-windows/03-cross-window-communication/postmessage.view/iframe.html b/2-ui/5-frames-and-windows/03-cross-window-communication/postmessage.view/iframe.html similarity index 100% rename from 4-frames-and-windows/03-cross-window-communication/postmessage.view/iframe.html rename to 2-ui/5-frames-and-windows/03-cross-window-communication/postmessage.view/iframe.html diff --git a/4-frames-and-windows/03-cross-window-communication/postmessage.view/index.html b/2-ui/5-frames-and-windows/03-cross-window-communication/postmessage.view/index.html similarity index 100% rename from 4-frames-and-windows/03-cross-window-communication/postmessage.view/index.html rename to 2-ui/5-frames-and-windows/03-cross-window-communication/postmessage.view/index.html diff --git a/4-frames-and-windows/03-cross-window-communication/sandbox.view/index.html b/2-ui/5-frames-and-windows/03-cross-window-communication/sandbox.view/index.html similarity index 100% rename from 4-frames-and-windows/03-cross-window-communication/sandbox.view/index.html rename to 2-ui/5-frames-and-windows/03-cross-window-communication/sandbox.view/index.html diff --git a/4-frames-and-windows/03-cross-window-communication/sandbox.view/sandboxed.html b/2-ui/5-frames-and-windows/03-cross-window-communication/sandbox.view/sandboxed.html similarity index 100% rename from 4-frames-and-windows/03-cross-window-communication/sandbox.view/sandboxed.html rename to 2-ui/5-frames-and-windows/03-cross-window-communication/sandbox.view/sandboxed.html diff --git a/4-frames-and-windows/06-clickjacking/article.md b/2-ui/5-frames-and-windows/06-clickjacking/article.md similarity index 100% rename from 4-frames-and-windows/06-clickjacking/article.md rename to 2-ui/5-frames-and-windows/06-clickjacking/article.md diff --git a/4-frames-and-windows/06-clickjacking/clickjacking-visible.view/facebook.html b/2-ui/5-frames-and-windows/06-clickjacking/clickjacking-visible.view/facebook.html similarity index 100% rename from 4-frames-and-windows/06-clickjacking/clickjacking-visible.view/facebook.html rename to 2-ui/5-frames-and-windows/06-clickjacking/clickjacking-visible.view/facebook.html diff --git a/4-frames-and-windows/06-clickjacking/clickjacking-visible.view/index.html b/2-ui/5-frames-and-windows/06-clickjacking/clickjacking-visible.view/index.html similarity index 100% rename from 4-frames-and-windows/06-clickjacking/clickjacking-visible.view/index.html rename to 2-ui/5-frames-and-windows/06-clickjacking/clickjacking-visible.view/index.html diff --git a/4-frames-and-windows/06-clickjacking/clickjacking.view/facebook.html b/2-ui/5-frames-and-windows/06-clickjacking/clickjacking.view/facebook.html similarity index 100% rename from 4-frames-and-windows/06-clickjacking/clickjacking.view/facebook.html rename to 2-ui/5-frames-and-windows/06-clickjacking/clickjacking.view/facebook.html diff --git a/4-frames-and-windows/06-clickjacking/clickjacking.view/index.html b/2-ui/5-frames-and-windows/06-clickjacking/clickjacking.view/index.html similarity index 100% rename from 4-frames-and-windows/06-clickjacking/clickjacking.view/index.html rename to 2-ui/5-frames-and-windows/06-clickjacking/clickjacking.view/index.html diff --git a/4-frames-and-windows/06-clickjacking/protector.view/iframe.html b/2-ui/5-frames-and-windows/06-clickjacking/protector.view/iframe.html similarity index 100% rename from 4-frames-and-windows/06-clickjacking/protector.view/iframe.html rename to 2-ui/5-frames-and-windows/06-clickjacking/protector.view/iframe.html diff --git a/4-frames-and-windows/06-clickjacking/protector.view/index.html b/2-ui/5-frames-and-windows/06-clickjacking/protector.view/index.html similarity index 100% rename from 4-frames-and-windows/06-clickjacking/protector.view/index.html rename to 2-ui/5-frames-and-windows/06-clickjacking/protector.view/index.html diff --git a/4-frames-and-windows/06-clickjacking/top-location.view/iframe.html b/2-ui/5-frames-and-windows/06-clickjacking/top-location.view/iframe.html similarity index 100% rename from 4-frames-and-windows/06-clickjacking/top-location.view/iframe.html rename to 2-ui/5-frames-and-windows/06-clickjacking/top-location.view/iframe.html diff --git a/4-frames-and-windows/06-clickjacking/top-location.view/index.html b/2-ui/5-frames-and-windows/06-clickjacking/top-location.view/index.html similarity index 100% rename from 4-frames-and-windows/06-clickjacking/top-location.view/index.html rename to 2-ui/5-frames-and-windows/06-clickjacking/top-location.view/index.html diff --git a/4-frames-and-windows/index.md b/2-ui/5-frames-and-windows/index.md similarity index 100% rename from 4-frames-and-windows/index.md rename to 2-ui/5-frames-and-windows/index.md