{"data":{"allWordpressWpJs":{"edges":[{"node":{"slug":"promisy-v-javascript-dlya-chainikov","content":"\n<p>Промисы в JavaScript на самом деле совсем не сложные. Тем не менее, многие люди находят затруднительным их понимание с первых моментов изучения. Поэтому, снизу всё будет описано способом для начинающих, чтобы читающий понял материал полностью и объемно. Помните, что промисы лежат в основе <code>async/await</code> и их понимание, можно сказать, что обязательно <a href=\"https://stasonmars.ru/javascript/polnoe-ponimanie-syncronnogo-i-asyncronnogo-javascript-s-async-await/\">для работы с асинхронным JavaScript</a>.</p>\n\n\n\n<p class=\"author\"><em>Адаптивный перевод статьи — </em><a href=\"https://scotch.io/tutorials/javascript-promises-for-dummies#why-promises-and-when-to-use-them\"><em>JavaScript Promises for Dummies</em></a></p>\n\n\n\n<h2 id=\"a85b\"><strong>Понимание промисов</strong></h2>\n\n\n\n<p id=\"26a0\">Итак, вкратце про промисы: “<em>Представьте, что вы ребенок. Ваша мама обещает вам, что вы получите новый телефон на следующей неделе.</em>”</p>\n\n\n\n<p id=\"848b\">Вы не знаете, получите ли вы его до следующей неделе. Ваша мама может купить вам совершенно новый телефон, а может просто этого не сделать, к примеру, потому что она будет не в настроении 🙁</p>\n\n\n\n<p id=\"7e10\">Это и есть промис. От английского promise — обещать.&nbsp;<em>Небольшое уточнение, пожалуйста, не усложняйте понимание другим с произношением, так как во всём русскоязычном мире принято говорить “промис” в случае с JavaScript.</em></p>\n\n\n\n<p id=\"b11e\">Итак, у промиса есть 3 состояния. Это:</p>\n\n\n\n<p id=\"a651\">1. Промис в состоянии ожидания (<code>pending</code>). Когда вы не знаете, получите ли вы мобильный телефон к следующей неделе или нет.</p>\n\n\n\n<p id=\"9518\">2. Промис решен (<code>resolved</code>). Вам реально купят новый телефон.</p>\n\n\n\n<p id=\"c5b4\">3. Промис отклонен (<code>rejected</code>). Вы не получили новый мобильный телефон, так как всё-таки, мама была не в настроении.</p>\n\n\n\n<h2 id=\"d00b\"><strong>Создание промиса</strong></h2>\n\n\n\n<p id=\"2ce1\">Давайте переведем все это в JavaScript.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>/_ ES5 _/\nvar isMomHappy = false;\n\n// Promise\nvar willIGetNewPhone = new Promise(\n    function (resolve, reject) {\n        if (isMomHappy) {\n            var phone = {\n                brand: 'Samsung',\n                color: 'black'\n            };\n            resolve(phone); // Всё выполнено\n        } else {\n            var reason = new Error('mom is not happy');\n            reject(reason); // reject\n        }\n\n    }\n);</code></pre>\n\n\n\n<p id=\"c15b\">Код выше довольно выразителен и говорит сам за себя.</p>\n\n\n\n<p id=\"e878\">1. У нас есть булин&nbsp;<code>isMomHappy</code>, чтобы определить в каком расположении духа мама.</p>\n\n\n\n<p id=\"f0cd\">2. У нас есть промис&nbsp;<code>willIGetNewPhone</code>. Этот промис может быть как в состоянии&nbsp;<code>resolved</code>, то есть, если вы получаете мобильный телефон, а также может быть в состоянии&nbsp;<code>rejected</code>, то есть если ваша мама не в настроении и вы не получаете мобильный телефон.</p>\n\n\n\n<p id=\"1855\">3. Тут у нас стандартный синтаксис для определения нового промиса, как в MDN документации. <a href=\"https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise\">То есть синтаксис промиса выглядит таким образом.</a></p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>new Promise(/* Выполняемая функция */ function (resolve, reject) { … } );</code></pre>\n\n\n\n<p>4. Когда вам нужно это запомнить, когда результат успешен, вызывайте <code>resolve</code>(ваше значение при успехе), если результат не успешен, вызывайте <code>reject</code>(ваше значение при неудаче, соответственно). В нашем случае мама в настроении и мы получим телефон. Следовательно, мы вызываем <code>resolve</code> функцию с переменной <code>phone</code>. Если ваша мама не в настроении, мы вызовем функцию <code>reject</code> с <code>reason</code>, то есть <code>reject</code>(<code>reason</code>).</p>\n\n\n\n<h2 id=\"bec3\"><strong>Применяем промисы</strong></h2>\n\n\n\n<p id=\"dc21\">Теперь у нас есть промис, давайте применим его:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>/_ ES5 _/\n...\n\n// Вызываем промис\nvar askMom = function () {\n    willIGetNewPhone\n        .then(function (fulfilled) {\n            // yay, you got a new phone\n            console.log(fulfilled);\n         // output: { brand: 'Samsung', color: 'black' }\n        })\n        .catch(function (error) {\n            // oops, mom don't buy it\n            console.log(error.message);\n         // output: 'mom is not happy'\n        });\n};\n\naskMom();</code></pre>\n\n\n\n<p id=\"5850\">1. Мы вызываем функцию в&nbsp;<code>askMom</code>. В этой функции, мы применим наш промис&nbsp;<code>willIGetNewPhone</code>.</p>\n\n\n\n<p id=\"eca8\">2. Нам надо сделать одно действие, чтобы промис был решен или отклонен, тут мы будем использовать&nbsp;<code>.then</code>&nbsp;и&nbsp;<code>.catch</code>.</p>\n\n\n\n<p id=\"3c5d\">3. В нашем примере, у нас&nbsp;<code>function(fulfilled) {…}&nbsp;</code>в&nbsp;<code>.then</code>. Какое значение у&nbsp;<code>fulfilled</code>?&nbsp;<code>fulfilled</code>&nbsp;значение это точное значение в вашем промисе&nbsp;<code>resolve</code>(значение при успехе). Следовательно, это будет&nbsp;<code>phone</code>.</p>\n\n\n\n<p id=\"c3c6\">4. У нас есть&nbsp;<code>function(error) {…}</code>&nbsp;в&nbsp;<code>.catch</code>. Какое значение будет у&nbsp;<code>error</code>? Как вы могли предположить,&nbsp;<code>error</code>&nbsp;значение именно то, которое вы указали в промисе&nbsp;<code>reject</code>(значение при неудаче). Следовательно, в этом случае это будет&nbsp;<code>reason</code>.</p>\n\n\n\n<p id=\"9064\">Давайте запустим этот пример и увидим результат!</p>\n\n\n\n<p id=\"cdf6\"><a href=\"https://jsbin.com/nifocu/1/edit?js,console\"><strong>Демка тут</strong></a></p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"1024\" height=\"469\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_HNCUJPfJkRfyEDLwNGEywQ-1024x469.gif\" alt=\"\" class=\"wp-image-246\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_HNCUJPfJkRfyEDLwNGEywQ-1024x469.gif 1024w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_HNCUJPfJkRfyEDLwNGEywQ-300x138.gif 300w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_HNCUJPfJkRfyEDLwNGEywQ-768x352.gif 768w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" /></figure>\n\n\n\n<h3 id=\"e0d0\"><strong>Цепочки промисов</strong></h3>\n\n\n\n<p id=\"5458\">Да, в промисах есть цепочки.</p>\n\n\n\n<p id=\"7c0d\">Давайте представим, что вы ребенок и обещали своему другу, что покажете ему новый телефон, когда вам его купят. Это будет ещё один промис.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// 2й промис\nvar showOff = function (phone) {\n    return new Promise(\n        function (resolve, reject) {\n            var message = 'Hey friend, I have a new ' +\n                phone.color + ' ' + phone.brand + ' phone';\n\n            resolve(message);\n        }\n    );\n};</code></pre>\n\n\n\n<p id=\"2bbd\">В этом примере вы уже наверное поняли, что мы не вызывали&nbsp;<code>reject</code>. Так как, в принципе, это опционально.</p>\n\n\n\n<p id=\"ce64\">Мы вообще можем сократить этот пример, используя <code>promise.resolve</code>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// 2й промис\nvar showOff = function (phone) {\nvar message = 'Hey friend, I have a new ' +\n  phone.color + ' ' + phone.brand + ' phone';\nreturn Promise.resolve(message);\n};</code></pre>\n\n\n\n<p>А теперь давайте свяжем наши промисы. Вы — ребенок и можете запустить <code>showOff</code> промис только после промиса <code>willIGetNewPhone</code>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// Вызываем промис\nvar askMom = function () {\n    willIGetNewPhone\n    .then(showOff) // связываем\n    .then(function (fulfilled) {\n            console.log(fulfilled);\n         // output: 'Hey friend, I have a new black Samsung phone.'\n        })\n        .catch(function (error) {\n            // oops, mom don't buy it\n            console.log(error.message);\n         // output: 'mom is not happy'\n        });\n};</code></pre>\n\n\n\n<p>Вот так легко связывать промисы.</p>\n\n\n\n<h2 id=\"d447\">Промисы и асинхронность</h2>\n\n\n\n<p id=\"34d8\">Промисы асинхронны. Давайте выведем сообщение перед и после вызовом промиса.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// вызываем наш промис\nvar askMom = function () {\n    console.log('before asking Mom'); // Выводим в консоль до\n    willIGetNewPhone\n        .then(showOff)\n        .then(function (fulfilled) {\n            console.log(fulfilled);\n        })\n        .catch(function (error) {\n            console.log(error.message);\n        });\n    console.log('after asking mom'); // Выводим в консоль после\n}</code></pre>\n\n\n\n<p>Какова последовательность ожидаемого вывода? Возможно вы ожидали.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>1. before asking Mom\n2. Hey friend, I have a new black Samsung phone.\n3. after asking mom</code></pre>\n\n\n\n<p>Но на самом деле вывод будет таким:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>1. before asking Mom\n2. after asking mom\n3. Hey friend, I have a new black Samsung phone.</code></pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"265\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_OvKCGPqCNejlME6LzY-edA.gif\" alt=\"\" class=\"wp-image-247\"/></figure>\n\n\n\n<p id=\"cbf5\"><strong><em>Почему? Потому что жизнь (или JS) никого не ждёт.</em></strong></p>\n\n\n\n<p id=\"64ef\">Вы, ребенок, не перестали бы играть в ожидании промиса от вашей мамы. Не так ли? Это то, что мы называем асинхронность, код будет запущен без блокирования или ожидания результата. Все что должно подождать промиса перед выполнением, вы вставляете в <code>.then</code> .</p>\n\n\n\n<h2 id=\"3452\"><strong>Промисы в ES5, ES6/2015, ES7/Next</strong></h2>\n\n\n\n<p id=\"a73a\"><strong>ES 5&nbsp;</strong>— поддерживают почти все браузеры. Демо код работает в ES5 среде (Все основные браузеры + NodeJS), если бы вы подключили библиотеку&nbsp;<a href=\"http://bluebirdjs.com/docs/getting-started.html\">промисов Bluebird</a>. Почему так? Потому что ES5 не поддерживает промисы&nbsp;<em>из коробки</em>. Другая знаменитая библиотека промисов это&nbsp;<a href=\"https://github.com/kriskowal/q\">Q</a>, от Криса Коваля.</p>\n\n\n\n<p id=\"a6f2\"><strong>ES6 / ES2015</strong> — демо код сработает прямо из коробки, так как ES6 поддерживает промисы естественным путём. Более того, с ES6 функциями, мы можем ещё круче упростить код с помощью <code>=></code> и использовать const и <code>let</code>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>/_ ES6 _/\nconst isMomHappy = true;\n\n// Промис\nconst willIGetNewPhone = new Promise(\n    (resolve, reject) => { // fat arrow\n        if (isMomHappy) {\n            const phone = {\n                brand: 'Samsung',\n                color: 'black'\n            };\n            resolve(phone);\n        } else {\n            const reason = new Error('mom is not happy');\n            reject(reason);\n        }\n\n    }\n);\n\nconst showOff = function (phone) {\n    const message = 'Hey friend, I have a new ' +\n                phone.color + ' ' + phone.brand + ' phone';\n    return Promise.resolve(message);\n};\n\n// Вызываем промис\nconst askMom = function () {\n    willIGetNewPhone\n        .then(showOff)\n        .then(fulfilled => console.log(fulfilled)) // fat arrow\n        .catch(error => console.log(error.message)); // fat arrow\n};\n\naskMom();</code></pre>\n\n\n\n<p id=\"b434\">Обратите внимание, что все&nbsp;<code>var</code>&nbsp;заменены на&nbsp;<code>const</code>. Все&nbsp;<code>function(resolve, reject)</code>&nbsp;были упрощены на&nbsp;<code>(resolve, reject) =&gt;</code>&nbsp;.</p>\n\n\n\n<p id=\"8932\"><strong>ES7</strong> — <code>Async/await</code> делают синтаксис визуально лучше. ES7 представил async и await синтаксис. Это делает асинхронный синтаксис визуально лучше и проще для понимания, без <code>.then</code> и <code>.catch</code> . Перепишем свой пример с ES7 синтаксисом.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>/_ ES7 _/\nconst isMomHappy = true;\n\n// Промис\nconst willIGetNewPhone = new Promise(\n    (resolve, reject) => {\n        if (isMomHappy) {\n            const phone = {\n                brand: 'Samsung',\n                color: 'black'\n            };\n            resolve(phone);\n        } else {\n            const reason = new Error('mom is not happy');\n            reject(reason);\n        }\n\n    }\n);\n\n// 2й промис\nasync function showOff(phone) {\n    return new Promise(\n        (resolve, reject) => {\n            var message = 'Hey friend, I have a new ' +\n                phone.color + ' ' + phone.brand + ' phone';\n\n            resolve(message);\n        }\n    );\n};\n\n// Вызываем промис\nasync function askMom() {\n    try {\n        console.log('before asking Mom');\n\n        let phone = await willIGetNewPhone;\n        let message = await showOff(phone);\n\n        console.log(message);\n        console.log('after asking mom');\n    }\n    catch (error) {\n        console.log(error.message);\n    }\n}\n\n(async () => {\n    await askMom();\n})();</code></pre>\n\n\n\n<p id=\"78b0\">1. Всегда, когда вам нужно возвратить промис в функцию, вы ставите спереди&nbsp;<code>async</code>&nbsp;к этой функции. Для примера,&nbsp;<code>async function showOff(phone)</code></p>\n\n\n\n<p id=\"72d5\">2. Всякий раз, когда вам надо вызвать промис, вам надо вставить&nbsp;<code>await</code>. Для примера,&nbsp;<code>let phone = await willIGetNewPhone;</code>&nbsp;и&nbsp;<code>let message = await showOff(phone);</code></p>\n\n\n\n<p id=\"07db\">3. Используйте&nbsp;<code>try { … }</code>&nbsp;<code>catch(error) { … }</code>&nbsp;, чтобы словить ошибку промиса, отклоненную промисом.</p>\n\n\n\n<h3 id=\"f5bd\"><strong>Почему промисы и когда их использовать?</strong></h3>\n\n\n\n<p id=\"08b2\">Зачем они нам нужны? Как выглядел мир до промисов? Перед ответом на эти вопросы, давайте вернемся к основам.</p>\n\n\n\n<h3 id=\"3ba7\"><strong>Нормальная функция против асинхронной.</strong></h3>\n\n\n\n<p id=\"a136\">Давайте посмотрим на эти два примера, каждый пример делает сложение двух чисел, один пример с нормальной функцией, другой с удаленной.</p>\n\n\n\n<p><strong>Нормальная функция для сложения чисел.</strong></p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// обычным образом складываем два числа\nfunction add (num1, num2) {\n  return num1 + num2;\n}\nconst result = add(1, 2); // сразу же получаем результат 3</code></pre>\n\n\n\n<p>Асинхронная функция для сложения двух чисел:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// удаленно складываем два числа\n// получаем результат вызывая API\nconst result = getAddResultFromServer('http://www.example.com?num1=1&amp;num2=2');\n// Получаем = \"undefined\"</code></pre>\n\n\n\n<p id=\"a02d\">Если вы сложите числа нормальной функцией, то вы сразу же получите результат. Тем не менее, если в вашем случае нужен удаленный запрос для получения результата, то вам нужно подождать, тут вы не сможете получить результат мгновенно.</p>\n\n\n\n<p id=\"ef17\">Или таким способом вы вообще не можете знать — получите ли вы результат, потому что сервер может просто упасть, тормознуть с ответом и т. п. Вам не нужно, чтобы весь процесс был заблокирован, пока вы ждете результат.</p>\n\n\n\n<p id=\"76ba\">Вызов API, скачивание файлов, чтение файлов — всё это те обычные async операции, которые вы можете выполнять.</p>\n\n\n\n<h2 id=\"8ba1\"><strong>Мир до промисов — колбэки.</strong></h2>\n\n\n\n<p id=\"01ad\">Должны ли мы использовать промисы для каждого асинхронного запроса? Нет. До промисов, мы используем колбэки. Колбэки это просто функция, которую вы вызываете, когда получаете отдаваемый результат. Давайте модифицируем предыдущий пример, чтобы разрешить колбэк.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// Удаленно прибавляем два числа\n// Получаем результат вызывая API\nfunction addAsync (num1, num2, callback) {\n    // Используем jQuery getJSON callback API\n    return $.getJSON('http://www.example.com', {\n        num1: num1,\n        num2: num2\n    }, callback);\n}\n\naddAsync(1, 2, success => {\n    // callback\n    const result = success; // Получаем 3\n});</code></pre>\n\n\n\n<p id=\"1466\">Синтаксис ок, зачем нам тогда промисы?</p>\n\n\n\n<p id=\"7d94\">Что если вы захотите сделать последующее асинхронное действие?</p>\n\n\n\n<p id=\"a04a\">Давайте представим, что вместо простого сложения чисел единожды, нам надо будет сделать это 3 раза. В обычной функции, мы делаем это:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// Добавляем два числа обычным способом\nlet resultA, resultB, resultC;\n\n function add (num1, num2) {\n    return num1 + num2;\n}\n\nresultA = add(1, 2); // resultA = 3\nresultB = add(resultA, 3); // resultB = 6\nresultC = add(resultB, 4); // resultC = 10\n\nconsole.log('total' + resultC);\nconsole.log(resultA, resultB, resultC);</code></pre>\n\n\n\n<p>Как это выглядит с колбэками?</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// Удаленно добавляется два числа\n// Получаем результат вызывая API\nlet resultA, resultB, resultC;\n\nfunction addAsync (num1, num2, callback) {\n    // use the famous jQuery getJSON callback API\n    return $.getJSON('http://www.example.com', {\n        num1: num1,\n        num2: num2\n    }, callback);\n}\n\naddAsync(1, 2, success => {\n    // callback 1\n    resultA = success; // Получаем 3\n\n    addAsync(resultA, 3, success => {\n        // callback 2\n        resultB = success; // Получаем 6\n\n        addAsync(resultB, 4, success => {\n            // callback 3\n            resultC = success; // Получаем 10\n\n            console.log('total' + resultC);\n            console.log(resultA, resultB, resultC);\n        });\n    });\n});</code></pre>\n\n\n\n<p id=\"9524\">Этот синтаксис менее дружелюбен. Он выглядит как пирамида, но люди обычно называют подобное «колбэк адом», потому что колбэки, вложенные в колбэки, кхм, представьте, что у вас 10 колбэков и ваш код будет вложен 10 раз.</p>\n\n\n\n<h2 id=\"ee65\"><strong>Побег из колбэк ада</strong></h2>\n\n\n\n<p id=\"99e3\">Промисы приходят на помощь. Давайте посмотрим на тот же код, но по версии промисов.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// Складываем два числа удаленно\nlet resultA, resultB, resultC;\nfunction addAsync(num1, num2) {\n// ES6 подтягивает API, который возвращает промис.\nreturn fetch(`http://www.example.com?num1=${num1}&amp;num2=${num2}`)\n        .then(x => x.json());\n}\n\naddAsync(1, 2)\n    .then(success => {\n        resultA = success;\n        return resultA;\n    })\n    .then(success => addAsync(success, 3))\n    .then(success => {\n        resultB = success;\n        return resultB;\n    })\n    .then(success => addAsync(success, 4))\n    .then(success => {\n        resultC = success;\n        return resultC;\n    })\n    .then(success => {\n        console.log('total: ' + success)\n        console.log(resultA, resultB, resultC)\n    });</code></pre>\n\n\n\n<p>С промисами, мы выравниваем колбэк с <code>.then</code>. В этом случае, это выглядит чище, так как нет вложенных колбэков. Конечно же с ES7 <code>async</code> синтаксисом, мы можем даже улучшить этот пример, но это уже на ваше усмотрение.</p>\n\n\n\n<h2 id=\"ab2f\"><strong>Новичок на районе: Observables</strong></h2>\n\n\n\n<p id=\"8b92\">Перед тем как закончить с промисами, есть кое-что, что пришло для того, чтобы облегчить работу с асинхронными данными — это Observables.</p>\n\n\n\n<p id=\"275a\"><code>Observables&nbsp;</code>— это ленивые потоки событий, которые могут выдать ноль или больше событий, а могут и вообще не закончиться.</p>\n\n\n\n<p id=\"df58\">Некоторые ключевые различия между промисами и observables:</p>\n\n\n\n<p id=\"c081\"><em>Они отменяемые</em></p>\n\n\n\n<p id=\"12be\"><em>Они ленивы/медленны</em></p>\n\n\n\n<p id=\"ac61\">Давайте посмотрим на тоже самое демо, только написанное с помощью <code>observables</code>. В этом примере, я использую <strong>RxJS</strong>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>let Observable = Rx.Observable;\nlet resultA, resultB, resultC;\n\nfunction addAsync(num1, num2) {\n    // Используем ES6 fetch API, который возвращает промис\n    const promise = fetch(`http://www.example.com?num1=${num1}&amp;num2=${num2}`)\n        .then(x => x.json());\n\n    return Observable.fromPromise(promise);\n}\n\naddAsync(1,2)\n  .do(x => resultA = x)\n  .flatMap(x => addAsync(x, 3))\n  .do(x => resultB = x)\n  .flatMap(x => addAsync(x, 4))\n  .do(x => resultC = x)\n  .subscribe(x => {\n    console.log('total: ' + x)\n    console.log(resultA, resultB, resultC)\n  });</code></pre>\n\n\n\n<p id=\"5b6a\"><code>Observable.fromPromise</code>&nbsp;конвертит промис в&nbsp;<code>observable</code>&nbsp;поток</p>\n\n\n\n<p id=\"8382\"><code>.do</code>&nbsp;и&nbsp;<code>.flatMap</code>&nbsp;среди некоторых операторов доступных для&nbsp;<code>Observables</code></p>\n\n\n\n<p id=\"f3ad\">Потоки ленивы. Наш&nbsp;<code>addAsync</code>&nbsp;запускается, когда мы&nbsp;<code>.subscribe</code>&nbsp;на него.</p>\n\n\n\n<p id=\"6e0d\"><code>Observables</code> могут делать много забавных вещей довольно легко. Для примера, delay добавляет функцию за 3 секунды с всего-лишь одной строкой кода или пробовать заново, так что вы можете делать запрос определенное количество раз.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>…\naddAsync(1,2)\n  .delay(3000) // Задержка в 3 секунды\n  .do(x => resultA = x)\n…</code></pre>\n\n\n\n<h2 id=\"9603\"><strong>Заключение</strong></h2>\n\n\n\n<p id=\"7a02\">Узнайте про колбэки и промисы. Поймите их и используйте их. Не беспокойтесь о Observables, пока что. Все трое могут повлиять процесс разработки, но всё это будет зависеть от ситуации.</p>\n","date":"2021-02-25T19:37:43.000Z","title":"Промисы в JavaScript для чайников","id":"844bc916-cd14-5c39-b6a5-4373d249aa0c","excerpt":"<p>В этой статье вы узнаете что такое промисы в JavaScript и как с ними работать</p>\n","type":"js","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2021/02/jspromisesfdsf.jpg"}}},{"node":{"slug":"vse-chto-nuzhno-znat-ob-async-await-tsikly-kontrol-potokov-ogranicheniya","content":"\n<p>В этой статье вы узнаете как использовать async/await в JavaScript, применять в них циклы и контролировать поток.</p>\n\n\n\n<p class=\"author\" id=\"d5c3\"><em>Перевод статьи </em><a href=\"https://hackernoon.com/async-await-essentials-for-production-loops-control-flows-limits-23eb40f171bd\"><em>Async/Await Essentials for Production: Loops, Control Flows &amp; Limits</em></a></p>\n\n\n\n<p id=\"0d7d\">С момента своего официального дебюта в ES8, <code>async/await</code> стал главным нововведением в плане будущего JavaScript. Каждый день новые NPM пакеты начинают поддерживать промисы, промисы которые всё ещё будучи новыми, приводят нас к относительно старому синтаксису ( <em>С# помните?</em>), в наши дни вы даже можете найти <code>util.promisify</code> в ядре Node.js, который позволяет упростить конверсию колбэков в промисы.</p>\n\n\n\n<p>Советую предварительно прочитать статью &#8212; <a href=\"https://stasonmars.ru/javascript/polnoe-ponimanie-syncronnogo-i-asyncronnogo-javascript-s-async-await/\">Полное понимание синхронного и асинхронного JavaScript с Async/Await</a></p>\n\n\n\n<p id=\"beba\"><code>Async/await</code> был неким универсальным решением, которого все так ждали при самом появлении Node. Но сейчас мы смотрим на него, как на будущее не только Node, а всего JavaScript. Пока что я не уверен в том, что есть достаточно ресурсов для того, чтобы окунуться в детали этого превосходного функционала. В этой статье мы сделаем именно это, посмотрим на ежедневные примеры использования и некоторые уловки, которые могли бы вам избавиться от зависимости <a href=\"https://github.com/caolan/async\">caolan/async</a>.</p>\n\n\n\n<h2 id=\"1644\"><strong>Основы</strong></h2>\n\n\n\n<p id=\"152f\">Перед тем как мы затронем темы параллельной работы и лимитирования в циклах, давайте вернёмся к основам. <a href=\"https://stasonmars.ru/javascript/polnoe-ponimanie-syncronnogo-i-asyncronnogo-javascript-s-async-await/\">Всем известный паттерн <code>async/await</code></a> представляет собой простое ожидание <a href=\"https://stasonmars.ru/javascript/promisy-v-javascript-dlya-chainikov/\">промиса</a>, получение значения и продолжение функции, давайте рассмотрим момент, когда нам надо получить данные пользователя и основываясь на объекте пользователя, получить конкретный новостной поток, это может быть легко реализовано с помощью добавления <code>async</code> нашей функции <code>getUser</code> и последующего использования <code>await</code> перед каждым запросом функции, возвращающей промис:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const getUser = async (query) => {\n  const user = await Users.findOne(query);\n  const feed = await Feeds.findOne({ user: user._id });\n  \n  return { user, feed };\n};\n\n// getUser will return a promise\ngetUser({ username: 'test' }).then(...);</code></pre>\n\n\n\n<p>Простой пример использования, который бы сработал на любой промисообразной функции или библиотеке, но что если мы хотим использовать старые добрые колбэки с промисами? Если вы уже применяли <a href=\"https://github.com/petkaantonov/bluebird\">petkaantonov/bluebird</a>, то вы возможно уже знакомы методом <code>promisify</code>, к большой радости, если вы используете <em>Node 8.0</em> и выше, то вы можете сэкономить несколько минут своего времени и не устанавливать этот модуль, а вместо этого использовать схожий функционал, доступный уже в самом Node, а именно <code>Util#promisify</code>, который конвертирует error first колбэки <em>(Это колбэки, которые передают ошибку и данные, первый аргумент сохраняется за объектом ошибки, то есть если произойдёт ошибка, то он вернётся с первым аргументом err. А за вторым аргументом колбэка сохраняются данные любой успешной операции, при этом err будет выставлен на null и все данные будут переданы во втором аргументе)</em></p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const fs = require('fs');\nconst { promisify } = require('util');\n\n// Function#bind as needed\nconst readFile = promisify(fs.readFile);\nconst writeFile = promisify(fs.writeFile);\n\nconst transform = () => /* ... */;\n\nconst transformFileAsync = async (source, dest) => {\n  const data = await readFile(source);\n  // Делаем некоторое изменение \n  const transformedData = tranform(data);\n  \n  await writeFile(dest, transformedData);\n};\n\ntransformFileAsync('x.js', 'y.js').then(...).catch(...);</code></pre>\n\n\n\n<p>Обратите внимание, что с <em>v9.4.0</em>, возвращение нескольких аргументов с <code>Util#promisify</code> доступно только внутри Node и если вы находитесь вне среды Node.js, то вы можете применить Bluebird, а именно <code>Promise#promisify</code>, как и указывалось выше.</p>\n\n\n\n<h2 id=\"81bd\"><strong>Обработка ошибок</strong></h2>\n\n\n\n<p id=\"0090\">Один факт, который вы должны помнить, невзирая на некоторые неверные представления, бушующие вокруг этой темы —&nbsp;<code>async/await</code>&nbsp;это не просто синтаксический сахар промисов, он ещё и несёт в себе свойства промисов, которые могут очень помочь при дебаггинге. Одним из огромных преимуществ в плане дебаггинга и возможностей обработки ошибок является всемогущий, но навряд ли когда-либо кем-то любимый&nbsp;<code>try/catch</code>&nbsp;блок. Отлов синхронных и асинхронных ошибок внутри одного блока кода ещё никогда не был так прост.</p>\n\n\n\n<p id=\"209c\">Чтобы показать это, давайте напишем промис, который сработает через 100 миллисекунд.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const PromiseThatThrows = (message) => new Promise((resolve, reject) => {\n  // Появится после 100мс с новой ошибкой\n  setTimeout(() => reject(new Error(message))), 100);\n};</code></pre>\n\n\n\n<p>Мы можем ловить ошибки из этого промиса в async функции, используя обычный <code>try/catch</code> блок, хоть следующая строка выкинет синхронную ошибку, она никогда не будет сработана:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const throwsLater = async () => {\n  await PromiseThatThrows('Some error');\n};\n\nasync () => {\n  try {\n    // Обратите внимание, что без await\n    // ошибка никогда не будет\n    // отловлена\n    await throwsLater;\n  } catch (error) {\n    console.log(error.message);\n    // Выведет: Some error\n  }\n}</code></pre>\n\n\n\n<p>Как и с <code>catch</code> в промисе, вы можете отловить ошибку, происходящую в потоке:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const throwsLater = async () => {\n  await PromiseThatThrows('Some error');\n};\n\nasync () => {\n  try {\n    // Обратите внимание, что без await\n    // ошибка никогда не будет\n    // отловлена\n    await throwsLater;\n  } catch (error) {\n    console.log(error.message);\n    // Выведет: Some error\n  }\n}</code></pre>\n\n\n\n<h2 id=\"c80f\"><strong>Контроль потока</strong></h2>\n\n\n\n<p id=\"2a6c\">Запускаете ли вы таски параллельно, планируете цикл или создаёте каскадируемую структуру или пайплайн,&nbsp;<code>async/await</code>&nbsp;может упростить то, во что превращается ваш процесс, в коде с эффективным и читаемым контролем потока. Давайте пробежимся по популярным паттернам:</p>\n\n\n\n<h3 id=\"abcd\"><strong>1. Параллельное выполнение</strong></h3>\n\n\n\n<p id=\"3f90\">Нет конкретного синтаксиса для параллельного выполнения с помощью <code>async/await</code>, но мы можем применить <code>Promise#all </code>с массивом промисов, чтобы получить ожидаемые результаты:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const &#91;user1, user2] = await Promise.all(&#91;db.get('user1'), db.get('user2')]);</code></pre>\n\n\n\n<p><code>Promise#all</code> комбинирует в себе список промисов в одном, другом промисе, который отдаст все готовые значения этих промисов в массиве, когда те будут выполнены. Это происходит параллельно и нам не нужно идти на какие-либо ухищрения и выходить за пределы этой простой и элегантной функции.</p>\n\n\n\n<h3 id=\"eff2\"><strong>2. Таймауты</strong></h3>\n\n\n\n<p id=\"5842\">Пожалуй самый малоизвестный герой саги об <code>async/await</code> это таймауты в промисах. Это эффективно и необходимо, особенно тогда, когда используется в контексте цикла (смотрите отложенный цикл ниже), мы можем оборачивать обычные таймеры (<code>setTimeout</code>, <code>setImmediate</code>) в промисы, например как тут:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const immediatePromise = () => new Promise((resolve) => setImmediate(resolve));\n\nconst timeoutPromise = (timeout) => new Promise((resolve) => setTimeout(resolve, timeout));</code></pre>\n\n\n\n<p>Мы можем пустить эти функции в дело, создав асинхронную паузу (без блокирования процесса), между двумя функциями, вне зависимости от того синхронные они или асинхронные:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const z = async () => {\n  await x();\n  await timeoutPromise(1000); // Wait 1 second\n  \n  //  Можете рекурсировать z, если надо\n  return y();\n}</code></pre>\n\n\n\n<p>Таким образом мы никогда не покинем контекст функции, что ведёт к более элегантному коду, который использовался должным образом.</p>\n\n\n\n<h2 id=\"da2c\"><strong>Циклы</strong></h2>\n\n\n\n<p id=\"acea\">Контролировать потоки невообразимо легко с помощью async/await, но моя любимая тема в них это циклы, простой асинхронный цикл может быть представлен несколькими способами и конечно же, он будет выполняться параллельно. Поехали.</p>\n\n\n\n<h3 id=\"f308\"><strong>1. Последовательный цикл</strong></h3>\n\n\n\n<p id=\"60bf\">Цикл по заданному количеству элементов, который делает ряд асинхронных операций, в нашем примере, который будет ниже, на каждом шаге цикл будет останавливаться, чтобы подтянуть нужную информацию из базы данных и вывести результат в консоль, а затем продолжить уже с следующим элементом, и таким образом один за одним создаётся последовательный цикл:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>async (items) => {\n  for (let i = 0; i &lt; items.length; i++) {\n    const result = await db.get(items&#91;i]);\n    console.log(result);\n  }\n}</code></pre>\n\n\n\n<h3 id=\"93d7\"><strong>2. Отложенный цикл</strong></h3>\n\n\n\n<p id=\"d250\">Мы можем смело применить концепцию таймаутов в нашем цикле, для примера, если нам нужно создать метод, который бы добавлял произвольное число в массив каждую секунду на протяжении десяти секунд, мы бы могли использовать <code>setTimeout</code> и <code>setImmediate</code> с счетчиком или цикл ожидающий <code>timeoutPromise</code>, который вы увидите ниже:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const randForTen = async () => {\n  let results = &#91;];\n  \n  for (let i = 0; i &lt; 10; i++) {\n    await timeoutPromise(1000);\n    results.push(Math.random());\n  }\n  \n  return results;\n}</code></pre>\n\n\n\n<p>И мы можем уйти ещё дальше, применив условные операторы с <code>setInterval</code>, на примере цикла <code>while</code>:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const runFor = async (time, func, interval) => {\n  // Запуск интервала до истечения времени\n  while (time > Date.now()) {\n    await timeoutPromise(interval);\n    //  Обратите внимание, что вам нужно учесть\n    //  время выполнения функции func()\n    //  если она асинхронная\n    func();\n  }\n};\n\nrunFor(Date.now() + 2000, () => console.count('time'), 1000);\n// Вывод:\n// time: 1\n// time: 2</code></pre>\n\n\n\n<h3 id=\"68a2\"><strong>3. Параллельный цикл</strong></h3>\n\n\n\n<p id=\"7f71\"><em>Если это работает параллельно, делайте это параллельно.</em> Параллельные циклы могут быть созданы добавлением промиса в массив. Сам промис при этом обратится в значение, следовательно все промисы запустятся в одно и тоже время и каждый будет иметь своё время для завершения, конечные результаты будут автоматически сгруппированы <code>Promise#all</code>:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>async (items) => {\n  let promises = &#91;];\n  \n  for (let i = 0; i &lt; items.length; i++) {\n    promises.push(db.get(items&#91;i]));\n  }\n  \n  const results = await Promise.all(promises);\n  console.log(results);\n}</code></pre>\n\n\n\n<p>Это можно сделать куда более элегантно с <code>Array#map</code> и это куда более функциональнее для применения в реальных кейсах, делая маппинг массива элементов в массив промисов и ожидая их значение.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>async (items) => {\n     // Помните, что асинхронные функции возвращают промисы\n  const promises = items.map(async (item) => {\n    const result = await db.get(item);\n    // Вывод в консоль результатов по их завершению\n    console.log(result);\n    return result;\n  });\n  const results = await Promise.all(promises);\n  console.log(results);\n}</code></pre>\n\n\n\n<h2 id=\"df55\"><strong>Ограничения промисов и race’ы</strong></h2>\n\n\n\n<p id=\"7c5d\">Ещё одной не очень изученной темой является выставление ограничений для контроля общего количества выполняемых задач параллельно с&nbsp;<code>async/await</code>. Если вы заядлый пользователь&nbsp;<em>coalan/async</em>, то скорее всего уже использовали&nbsp;<code>Async#parallelLimit</code>&nbsp;или&nbsp;<code>Async#eachLimit</code>, но не пугайтесь, установка ограничений возможна. Сейчас мы вернёмся к нашей магии промисов и начнём гонку (от&nbsp;<code>promise.race()</code>)!</p>\n\n\n\n<p id=\"4937\"><code>Promise#race</code> возвратит промис, который решится в тот момент, когда первый элемент из заданного списка промисов будет полностью выполнен.</p>\n\n\n\n<p>Подробно про промисы можно прочитатть в этой статье &#8212; <a href=\"https://stasonmars.ru/javascript/promisy-v-javascript-dlya-chainikov/\">Промисы для чайников</a></p>\n\n\n\n<h3 id=\"3ee2\"><strong>1.Простой race</strong></h3>\n\n\n\n<p id=\"d6d2\">Простой race можно создать, передав список промисов, который в нашем случае, вернёт асинхронную функцию, которая решится за произвольное количество времени:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const randAsyncTimer = (i) => {\n  //  Таймаут в одну секунду\n  const timeout = Math.floor(Math.random() * 1000);\n  return new Promise((resolve) => setTimeout(() => resolve(i), timeout));\n};\n\nasync () => {\n  let calls = &#91;randAsyncTimer(1), randAsyncTimer(2), randAsyncTimer(3)];\n   // Начинаем гонку\n  const result = await Promise.race(calls);\n  console.log(result);\n  //  Возможные выводы будут от 1 до 3\n}</code></pre>\n\n\n\n<p>Первый решенный промис и победит в гонке, став результатом выведенным в консоль.</p>\n\n\n\n<h3 id=\"7ba5\"><strong>2. Выставляем ограничения</strong></h3>\n\n\n\n<p id=\"ea0b\">Мы можем использовать почти всё, что мы обсудили выше, для создания функции, которая выполняет другую асинхронную функцию параллельно с заданным лимитом. Реальным примером тут будет процесс создания списка скриншотов страниц, но только 5 за раз.</p>\n\n\n\n<p id=\"5e66\">Чтобы сделать это с промисами и чистым <code>async/await</code>, нам понадобиться получить способ хранения промисов, которые уже сейчас запущены или другими словами, которые ещё не решены. К сожалению, это невозможно сделать при помощи стандартной спецификации промисов, поэтому мы будем использовать <code>Set</code> для хранения и удаления промисов, которые запущены в данный момент:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>async (promises) => {\n  let inFlight = new Set();\n  \n  return promises.map((promise) => {\n    // Добавляет промис в inFlight Set\n    inFlight.add(promise);\n    // Удаляет промис из Set, когда тот решён\n    promise.then(() => inFlight.delete(promise));\n  });\n}</code></pre>\n\n\n\n<p id=\"cc4c\">Далее мы применим&nbsp;<code>Set.size</code>, чтобы проверить общее число запущенных промисов, это позволит нам определить сколько ещё итераций нашего цикла мы можем продолжить.</p>\n\n\n\n<p id=\"e533\">Далее, мы используем <code>Promise#race</code> как часть нашего арсенала по контролю потока. Что нам нужно, так это способ остановить итерирование цикла (в этом случае <code>Array#map</code>) до момента, пока следующий промис будет решён (мы будем использовать race для этого) и проверить то каково количество запущенных промисов и не превышает ли оно нужный нам лимит, если да, то мы применим ещё один race. Это довольно легко сделать при помощи следующего <code>while</code> цикла:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>while(inFlight.size >= limit) {\n  await Promise.race(inFlight);\n}</code></pre>\n\n\n\n<p>Объединив оба, мы сможем закончить с <code>parallelLimit</code>:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const parallelLimit = async (funcList, limit = 10) => {\n  let inFlight = new Set();\n  \n  return funcList.map(async (func, i) => {\n    //  Придерживаем цикл, другим циклом\n    //  пока следующий промис решается\n    while(inFlight.size >= limit) {\n      await Promise.race(inFlight);\n    }\n    \n    console.log(`STARTING ROUND->${i} SIZE->${inFlight.size}`);\n    \n    const promise = func();\n    // Add promise to inFlight Set\n    inFlight.add(promise);\n    //  Добавляем промис inFlight Set\n    await promise;\n    inFlight.delete(promise);\n  });\n};\n(async () => {\n  const timeoutPromise = (timeout) => {\n    return new Promise((resolve) => setTimeout(resolve, timeout));\n  };\n  const waitTwoSeconds = async () => await timeoutPromise(2000);\n  const promises = await parallelLimit(&#91;\n    waitTwoSeconds,\n    waitTwoSeconds,\n    waitTwoSeconds,\n    waitTwoSeconds,\n    waitTwoSeconds\n  ], 2);\n  \n  await Promise.all(promises);\n  console.log(\"DONE\");\n})();</code></pre>\n","date":"2021-02-25T20:19:48.000Z","title":"Всё, что нужно знать об async/await. Циклы, контроль потоков, ограничения","id":"ca88330a-86c3-57ce-a105-cfd4a2c8d0c8","excerpt":"<p>В этой статье вы узнаете как использовать async/await в JavaScript, применять в них циклы и контролировать поток.</p>\n","type":"js","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2021/02/controlflownsk.jpg"}}},{"node":{"slug":"polnoe-ponimanie-syncronnogo-i-asyncronnogo-javascript-s-async-await","content":"\n<p>В этой статье вы узнаете о том, что такое синхронное и асинхронное программирование в JavaScript и как применяя эти знания работать с&nbsp;<code>Async/Await</code>.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"629\" height=\"522\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_WjaiS6QK3WvUeD6cNyB3rw.jpeg\" alt=\"\" class=\"wp-image-237\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_WjaiS6QK3WvUeD6cNyB3rw.jpeg 629w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_WjaiS6QK3WvUeD6cNyB3rw-300x249.jpeg 300w\" sizes=\"(max-width: 629px) 100vw, 629px\" /></figure>\n\n\n\n<p class=\"author\" id=\"6c18\">По факту это адаптированный перевод двух отличных статей:\n\n\n\n</p>\n\n\n\n<h2 id=\"78aa\">Выполнение синхронного и асинхронного кода в JavaScript</h2>\n\n\n\n<p id=\"085c\">Недавно мы вели беседу с несколькими начинающими JS разработчиками, относительно того, как JS распределяет память и как парсится код, ну и само собой как он выполняется. Это одна из самых важных тем, которая никогда не являлась частью какой-либо программы обучения, но её, в принципе и не обязательно знать, чтобы написать программу на JavaScript. Такие темы очень важны для любопытных разработчиков, которые серьёзно относятся к своему делу. Я решил написать о ней, так как я нахожу её довольно неоднозначной, а люди имеют свойство сравнивать вещи, в особенности это склонны делать те, кто знаком с такими языками программирования как PHP, C++, Java и т.д, но учтите, что JavaScript это&nbsp;<em>дикий зверь</em>&nbsp;и с самого начала у меня он забрал довольно прилично времени для того, чтобы осознать некоторые важные аспекты, например то, как будучи однопоточным, JavaScript может быть синхронным и неблокируемым процессом?</p>\n\n\n\n<p id=\"7bef\">Теперь перед тем как мы копнем глубже, давайте проясним основную концепцию и разницу между&nbsp;<strong>JavaScript Engine</strong>&nbsp;(движок) и&nbsp;<strong>JavaScript Run-time Environment</strong>.</p>\n\n\n\n<p id=\"7ae7\"><em>Движок JavaScript</em>&nbsp;это программа, которая используется для обработки заданного кода и конвертирования его в конкретные команды для их выполнения.</p>\n\n\n\n<p id=\"b955\">С другой стороны, JavaScript Run-time Environment это среда, отвечающая за создание экосистемы с возможностями, сервисами и поддержкой, такими как массивы, функции, ключевые библиотеки и тп, которые необходимы для того, чтобы код запустился верно.</p>\n\n\n\n<h3 id=\"bb6f\"><strong>Функциональная модель</strong></h3>\n\n\n\n<p id=\"46c3\">Почти все браузеры имеют на борту JavaScript движок. Самые популярные это V8 в Google Chrome и Node.js,&nbsp;<a href=\"https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey\">SpiderMonkey</a>&nbsp;от Мазилы, Chakra для IE и т.д. Хоть все эти браузеры и выполняют JavaScript по-разному, но под капотом, они все работают по старой доброй модели:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"683\" height=\"406\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_FpbITfdk2y8l2YnqXuY58w.png\" alt=\"\" class=\"wp-image-238\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_FpbITfdk2y8l2YnqXuY58w.png 683w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_FpbITfdk2y8l2YnqXuY58w-300x178.png 300w\" sizes=\"(max-width: 683px) 100vw, 683px\" /></figure>\n\n\n\n<p>Call Stack, Web APIs, Event loop, асинхронная очередь заданий, очередь на рендер и т.д. Все мы слышали эти шумные термины в нашей ежедневной работе. В совокупности, все они работают вместе, чтобы перевести и выполнить синхронные и асинхронные блоки кода, которые мы пишем каждый день. Давайте заглянем глубже в эту модель и попытаемся понять, что они делают и что самое важное —&nbsp;<strong>как они это делают</strong>.</p>\n\n\n\n<h3 id=\"30f6\"><strong>Синхронные задачи</strong></h3>\n\n\n\n<p id=\"038a\">Что означает синхронность? Скажем, что у нас есть 2 строчки кода. Первая идет за второй. Синхронность означает то, что строка 2 не может запуститься до тех пор, пока строка 1 не закончит своё выполнение.</p>\n\n\n\n<p id=\"a813\">JavaScript сам по себе однопоточный, что означает то, что только один блок кода может запускаться за раз. Так как движок JS выполняет наш код, обрабатывая строку за строкой, он использует один стек вызова, чтобы продолжать отслеживать код, который выполняется в соответствии с установленным порядком. Тоже самое, что и делает стек — структура данных, которая записывает строки выполняемых инструкций и выполняет их в стиле&nbsp;<code>LIFO</code>, то есть&nbsp;<code>Last In First Out</code>, что переводится как, “последний пришел — первый обслужен”. Давайте посмотрим на живом примере как это происходит и работает, вот&nbsp;<code>function foo() { foo()</code>&nbsp;отправляется в стек и затем, когда выполнение&nbsp;<code>foo()</code>&nbsp;доходит до&nbsp;<code>return;} foo()</code>&nbsp;прекращается и выкидывается из стека вызовов.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"624\" height=\"406\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_k62uibx1CIMcNkKwCq38iA.png\" alt=\"\" class=\"wp-image-239\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_k62uibx1CIMcNkKwCq38iA.png 624w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_k62uibx1CIMcNkKwCq38iA-300x195.png 300w\" sizes=\"(max-width: 624px) 100vw, 624px\" /></figure>\n\n\n\n<p id=\"9673\">Что происходит в&nbsp;<strong>Exercise 1</strong>: Итак, схема выше показывает нам типичное линейное выполнение кода. Когда код из трех&nbsp;<code>console.log</code>&nbsp;объявлений отдается в JS.</p>\n\n\n\n<p id=\"0028\">Шаг 1:&nbsp;<code>console.log(\"Print 1\")</code>&nbsp;отправляется в стек вызовов и выполняется, после того, как процесс завершится, он будет выкинут из стека. Теперь стек пуст и готов к следующим инструкциям на выполнение.</p>\n\n\n\n<p id=\"3ffe\">Шаг 2: Следующей инструкцией на выполнение является&nbsp;<code>console.log(\"Print 2\");</code>, который также отправляется в стек и после выполнения оттуда также выкидывается. Всё повторяется до тех пор, пока не останется ничего для выполнения.<br>Давайте посмотрим на следующий пример:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"593\" height=\"759\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_H7tHQial9jWqjWysxK_Ycg.png\" alt=\"\" class=\"wp-image-240\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_H7tHQial9jWqjWysxK_Ycg.png 593w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_H7tHQial9jWqjWysxK_Ycg-234x300.png 234w\" sizes=\"(max-width: 593px) 100vw, 593px\" /></figure>\n\n\n\n<p id=\"e46e\"><strong>Exercise 2</strong>: что же тут происходит на самом деле:<br>Шаг 1: В стек вызовов попадает первое выполняемое объявление нашего скрипта — вызов функции&nbsp;<code>First()</code>. Во время выполнения в области видимости функции&nbsp;<code>First()</code>, наш движок встречает вызов ещё одной функции —&nbsp;<code>Second()</code>.</p>\n\n\n\n<p id=\"5f4e\">Шаг 2: Следовательно, вызов функции&nbsp;<code>Second()</code>&nbsp;отправляется в стек вызовов и движок начинает выполнение её содержимого, снова встречаясь с ещё одной функцией&nbsp;<code>Third()</code>&nbsp;внутри&nbsp;<code>Second()</code>.</p>\n\n\n\n<p id=\"2860\">Шаг 3: Функция&nbsp;<code>Third()</code>&nbsp;также отправляется в стек запросов и движок начинается её выполнение. Пока функции&nbsp;<code>Second()</code>&nbsp;и&nbsp;<code>First()</code>&nbsp;находятся в стеке и ждут своей очереди в соответствии с порядком.</p>\n\n\n\n<p id=\"312b\">Шаг 4: Когда движок сталкивается с return; внутри функции&nbsp;<code>Third()</code>, то это означает завершение&nbsp;<code>Third()</code>. Следовательно&nbsp;<code>Third()</code>&nbsp;выкидывается из стека как завершенное исполнение. На этом моменте движок возвращается к выполнению&nbsp;<code>Second()</code>.</p>\n\n\n\n<p id=\"10e9\">Шаг 5: Итак, как только движок столкнется с&nbsp;<code>return;</code>, функция&nbsp;<code>Second()</code>&nbsp;будет выкинута из стека и начнется выполнение&nbsp;<code>First()</code>. Теперь тут нет объявления&nbsp;<code>return</code>&nbsp;внутри области видимости&nbsp;<code>First()</code>, так что выполнится только код до конца его области видимости и&nbsp;<code>First()</code>&nbsp;будет выкинут из стека на шаге 6.</p>\n\n\n\n<p id=\"2925\">Вот то, как браузер работает с синхронными задачами без привлечения чего-либо ещё, кроме “<em>легендарного</em>” стека вызовов. Но всё становится куда сложнее, когда JavaScript сталкивается с&nbsp;<strong>асинхронными</strong>&nbsp;задачами.</p>\n\n\n\n<h2 id=\"7285\"><strong>Асинхронные задачи</strong></h2>\n\n\n\n<p id=\"4be3\">Что такое вообще — асинхронность? В отличие от синхронности, асинхронность это модель поведения. Предположим, что у нас есть две строчки кода, первая за второй. Первая строка это код которому нужно время. Итак, первая строка начинает запуск в фоновом режиме, позволяя второй строке запуститься без ожидания завершения первой строки.</p>\n\n\n\n<p id=\"efc9\">Нам нужно такое поведение в случае, когда что-то подтормаживает и требует времени. Синхронность может казаться прямолинейной и незатейливой, но всё же может быть ещё и медленной. Такие задачи, как обработка изображений, операции с файлами, создание запросов сети и ожидание ответа — всё это может тормозить и быть долгим, производя огромные расчеты в&nbsp;<em>100 миллионов циклов итераций</em>. Так что такие вещи в стеке запросов превращаются в “задержку”, ну или “<em>blocking</em>” по-английски. Когда стек запросов заблокирован, браузер препятствует вмешательству пользователя и выполнению другого кода до тех пор, пока “<em>задержка</em>” не выполнится и не освободит стек запросов. Таким образом асинхронные колбэки (callback) используются в таких ситуациях.</p>\n\n\n\n<p id=\"ae43\">Пример: Видимо функция&nbsp;<code>setTimeout()</code>&nbsp;это простейший способ продемонстрировать основы асинхронного поведения.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"649\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_qjshm7qjEtLTPUDwjFuHBg.png\" alt=\"\" class=\"wp-image-241\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_qjshm7qjEtLTPUDwjFuHBg.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_qjshm7qjEtLTPUDwjFuHBg-300x278.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p id=\"8284\">Exercise 3: Давайте рассмотрим стек запросов, который только что увидели:<br>Шаг 1: Как и обычно&nbsp;<code>console.log(\"Hello \")</code>&nbsp;отправляется в стек первым и сразу же из него выкидывается после выполнения.</p>\n\n\n\n<p id=\"ef44\">Шаг 2:&nbsp;<code>setTimeout()</code>&nbsp;отправляется в стек, но обратите внимание на то, что&nbsp;<code>console.log(\"Siddhartha\")</code>&nbsp;не может сразу выполниться, так как стоит отсрочка на 2 секунды. Так что пока эта функция для нас исчезнет, но мы позже разберем этот вопрос.</p>\n\n\n\n<p id=\"9d88\">Шаг 3: Само собой, следующая строка это&nbsp;<code>console.log(\" I am \")</code>, которая отправляется в стек, выполняется и тут же выкидывается из него.</p>\n\n\n\n<p id=\"2c13\">Шаг 4: Сейчас стек запросов пуст и в ожидании.</p>\n\n\n\n<p id=\"02f5\">Шаг 5: Внезапно&nbsp;<code>console.log( \"Siddhartha\" )</code>&nbsp;обнаруживается в стеке, после 2-х секунд задержки. Далее&nbsp;<code>setTimeout()</code>&nbsp;выполняется и сразу после этого выкидывается из стека. На 6-м шаге, наш стек оказывается пустым.</p>\n\n\n\n<p id=\"a7f1\">Это говорит о том, что пусть даже JavaScript и однопоточный, мы можем достичь согласованности действий через асинхронное исполнение задач.</p>\n\n\n\n<p id=\"a771\">Теперь у нас осталось несколько вопросов:</p>\n\n\n\n<p id=\"9040\">Вопрос 1: Что случилось с&nbsp;<code>setTimeout()</code>?<br>Вопрос 2: Откуда оно вернулось?<br>Вопрос 3: И как это вообще произошло?</p>\n\n\n\n<p id=\"67ee\">И тут появляется&nbsp;<strong>Event Loop</strong>&nbsp;(Или цикл обработки событий) и Web API. Давайте представим каждого из вышесказанных и ответим на эти три вопроса в нашей следующей схеме.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"561\" height=\"1024\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_RkX7j_slzq7VC8_pwxG9jw-561x1024.png\" alt=\"\" class=\"wp-image-242\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_RkX7j_slzq7VC8_pwxG9jw-561x1024.png 561w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_RkX7j_slzq7VC8_pwxG9jw-164x300.png 164w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_RkX7j_slzq7VC8_pwxG9jw.png 647w\" sizes=\"(max-width: 561px) 100vw, 561px\" /></figure>\n\n\n\n<p id=\"71ad\">Exercise 4: Давайте разберемся.<br>Шаг 2: С этого момента&nbsp;<code>setTimeout(callback, 2000)</code>&nbsp;отправляется в стек запросов. Как мы можем видеть, тут имеются компоненты callback и задержка в 2000ms.&nbsp;<code>setTimeout()</code>&nbsp;не является частью JavaScript движка, это по сути Web API включенное в среду браузера как дополнительный функционал.</p>\n\n\n\n<p id=\"03b1\">Шаг 3: Итак, Web API браузера берет на себя&nbsp;<code>callback</code>&nbsp;и запускает таймер в 2000ms, оставляя на фоне&nbsp;<code>setTimeout()</code>, которое сделало свою работу и выкинуто из стека. Вот и ответ на первый вопрос.</p>\n\n\n\n<p id=\"a63f\">Шаг 4: Следующая строка в нашем скрипте это&nbsp;<code>console.log( \"I am\" )</code>, отправленное в стек и выкинутое оттуда после выполнения.</p>\n\n\n\n<p id=\"17a2\">Шаг 5: Теперь у нас есть callback в WebAPI, который собирается сработать по прошествии 2000ms. Но WebAPI не может напрямую как попало закидывать что-то в стек запросов, потому что это может создать прерывание для другого кода, выполняемого в JavaScript движке, именно в этот момент. Так что callback поставится в очередь выполнения задач после 2000ms. А теперь WebAPI пуст и свободен.</p>\n\n\n\n<p id=\"6435\">Шаг 6: Цикл событий или Event Loop — ответственный за взятие первого элемента из очереди задач и передачу его в стек запросов, только тогда, когда стек пуст и свободен. На этом шаге нашего уравнения, стек запросов пуст.</p>\n\n\n\n<p id=\"5c68\">Шаг 7: Итак, callback отправлен в стек запросов, так как он был пуст и свободен. И тут же выполнился. Так что ответ на второй вопрос готов.</p>\n\n\n\n<p id=\"957e\">Шаг 8: Далее идет выполнение кода&nbsp;<code>console.log(\"Siddhartha\")</code>, который находится в области видимости callback, следовательно,&nbsp;<code>console.log(\"Siddhartha\")</code>&nbsp;отправляется в стек запросов.</p>\n\n\n\n<p id=\"b408\">Шаг 9: После того, как&nbsp;<code>console.log(\"Siddhartha\")</code>&nbsp;выполнен, он выкидывается из стека запросов и JavaScript приходит к завершению выполнения callback. Который в свою очередь после своего завершения будет выкинут из стека запросов. А вот и ответ на вопрос как.</p>\n\n\n\n<p id=\"0c4e\">Итак, это была довольно простая демонстрация происходящего, но всё может стать сложнее в некоторых ситуациях, например тогда, когда есть несколько&nbsp;<code>setTimeout</code>&nbsp;в очереди — в общем результаты разнятся от того что обычно ожидается.</p>\n\n\n\n<h2 id=\"fde4\">Теперь давайте посмотрим на пример с Async/Await.</h2>\n\n\n\n<p id=\"1999\">Далее мы попытаемся понять синтаксис&nbsp;<code>async/await</code>, погружаясь ещё глубже в то, что же это на самом деле и как это работает.</p>\n\n\n\n<h3 id=\"5605\"><strong>Итак, вы знаете что он делает, но знаете ли вы как?</strong></h3>\n\n\n\n<p id=\"db77\">У большинства разработчиков неоднозначное отношение к JavaScript, отчасти из-за того, что они становятся жертвами одного из его лучших качеств: он легко учится, но тяжело применяется. Это легко подметить взглянув на то, сколько разработчиков склонны полагать, что этот язык работает сугубо однопоточно, но на самом деле всё происходит по-другому если взглянуть под капот. Именно эта разница проявляется в деталях и вызывает разочарование.</p>\n\n\n\n<p id=\"5293\">Для примера, я не сомневаюсь в том, что изменения в стандартах вызвали у многих из вас недопонимание о поведении языка, например как с классами. В JavaScript нет классов, в реальности JavaScript использует Prototypes, синглтон объекты, из которых наследуются другие объекты. По факту, все объекты в JavaScript имеют прототип из которого они наследуются. Это означает то, что классы в JS на самом деле не ведут себя как классы. Класс это схема для создания экземпляров объекта, а prototype это экземпляр, которому другие экземпляры объекта передают работу, prototype это не схема и не шаблон, он просто есть и всё.</p>\n\n\n\n<p id=\"9a86\">Именно поэтому вы можете добавить новый метод для Array и тут же все массивы смогут его использовать. Это можно сделать в среде выполнения, затронув объект, ставший экземпляром.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>var someArray = &#91;1, 2, 3];\nArray.prototype.newMethod = function() {\n console.log(‘I am a new method!’);\n};\n\nsomeArray.newMethod(); // I am a new method!\n\n// Код выше был бы невозможен с реальными классами, так как изменение схемы, не изменяет того, что было сделано с ним.</code></pre>\n\n\n\n<p id=\"2a47\">В общем, классы в JavaScript это синтаксический сахар для прототипизирования.</p>\n\n\n\n<p id=\"ac8a\">Я хочу тут сделать акцент на том, что вам надо выучить то, как язык работает на самом деле, кроме своего синтаксиса, если вы хотите полностью понять его возможности и ограничения.</p>\n\n\n\n<h3 id=\"7287\"><strong>Async/Await спецификации</strong></h3>\n\n\n\n<p id=\"5a22\">Асинхронные функции это дополнение к языку, уже включенное в последний драфт EcmaScript. Вы можете смело их использовать с применением Babel.</p>\n\n\n\n<p id=\"117e\"><code>async/await</code>&nbsp;пытается решить одну из главных головных болей языка со времен его появления: это асинхронность. То, как работает концепция асинхронного кода, вы прочитали в первой части этой статьи, если вы ещё не поняли, то обязательно перечитайте и поймите перед тем как читать дальше.</p>\n\n\n\n<p id=\"ded6\">На протяжении многих лет у нас было несколько способов работы с асинхронностью без всякого сумасшествия в коде. В большинстве случаев, мы полагались просто на&nbsp;<code>Callbacks</code>:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>setTimeout(function() {\n console.log(\"This runs after 5 seconds\");\n}, 5000);\n\nconsole.log(\"This runs first\");</code></pre>\n\n\n\n<p>Всё это хорошо, но что если мы столкнемся с последовательностью?</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>doThingOne(function() {\n  doThingTwo(function() {\n    doThingThree(function() {\n      doThingFour(function() {\n        // Oh no\n      });\n    });\n  });\n});</code></pre>\n\n\n\n<p id=\"d91e\">То, что вы видите выше иногда называется Pyramid of Doom и&nbsp;<strong>Callback Hell</strong>.</p>\n\n\n\n<h2 id=\"8ebb\">Узрите: промисы</h2>\n\n\n\n<p id=\"a4b9\">Промисы это очень мудрый и хороший способ работы с асинхронным кодом.</p>\n\n\n\n<p>В этой статье вы можете понять с самого начала, что такое промисы и как они работают &#8212; <a href=\"https://stasonmars.ru/javascript/promisy-v-javascript-dlya-chainikov/\">Промисы в JavaScript для чайников</a>.</p>\n\n\n\n<p id=\"a4b9\"><br>Промис это объект, который представляет собой асинхронный таск, который должен завершиться. При использовании это выглядит как-то так:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function buyCoffee() {\n  return new Promise((resolve, reject) => {\n    asyncronouslyGetCoffee(function(coffee) {\n      resolve(coffee);\n    });\n  });\n}</code></pre>\n\n\n\n<p id=\"a803\"><code>buyCoffee</code>&nbsp;возвращает промис, который является процессом покупки кофе. Функция&nbsp;<code>resolve</code>&nbsp;указывает промису на то, что он выполнен. Он получает значение как аргумент, который будет доступен в промисе позже.</p>\n\n\n\n<p id=\"d958\">В самом экземпляре промиса есть два основных метода:</p>\n\n\n\n<p id=\"b44f\"><code>then</code>&nbsp;— запускает колбек, который вы передали, когда промис завершен.</p>\n\n\n\n<p id=\"4ff5\"><code>catch</code>&nbsp;— запускает колбек, который вы передали, когда что-то идет не так, что вызывает&nbsp;<code>reject</code>&nbsp;вместо&nbsp;<code>resolve</code>.&nbsp;<code>Reject</code>&nbsp;вызывает как вручную, так и автоматически, если необработанное исключение появилось внутри кода промиса.<br><strong>Важно:&nbsp;</strong>промисы которые были выкинуты из-за исключения, поглотят это исключение. Это означает то, что если ваши промисы не связаны должным образом или нет вызова&nbsp;<code>catch</code>&nbsp;в каком-либо промисе из цепочки, то вы обнаружите, что ваш код просто втихую порушится, что может быть очень разочаровывающе, так что избегайте таких ситуаций.</p>\n\n\n\n<p id=\"c80b\">У промисов есть и другие очень интересные свойства, которые позволяют им быть связанными. Предположим, что у нас есть другие функции, которые отдают промис. Мы могли бы сделать так:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>buyCoffee()\n .then(function() {\n return drinkCoffee();\n })\n .then(function() {\n return doWork();\n })\n .then(function() {\n return getTired();\n })\n .then(function() {\n return goToSleep();\n })\n .then(function() {\n return wakeUp();\n });</code></pre>\n\n\n\n<p id=\"d1d0\">В этом случае использование колбеков было бы ужасным для поддержания кода и его чистоты.<br>Если вы не использовали промисы, то код выше может выглядеть непонятным, так как промисы, которые отдают промисы в своем методе&nbsp;<code>then</code>, вернут промис, который решается только когда возвращенный промис сам решается. И они сделают это со значением возвращенного промиса. В общем извините, по-другому это нельзя сказать.</p>\n\n\n\n<p id=\"333d\">А вот и пример:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const firstPromise = new Promise(function(resolve) {\n  return resolve(\"first\");\n});\nconst secondPromise = new Promise(function(resolve) {\n  resolve(\"second\");\n});\nconst doAllThings = firstPromise.then(function() {\n  return secondPromise;\n});\ndoAllThings.then(function(result) {\n  console.log(result); // This logs: \"second\"\n});</code></pre>\n\n\n\n<p>Итак, мы уже почти подошли к самому интересному.</p>\n\n\n\n<p>Async функции, это функции, которые возвращают промисы. Это так. Вот почему я выделил время, чтобы кратко объяснить, что же такое промисы, так как чтобы реально понять <code>Async/Await</code>, вам надо знать то, как работают эти самые промисы. Это как с примером про классы в JavaScript, где вам нужно понимать прототипирование.</p>\n\n\n\n<h3 id=\"b990\">Как это работает</h3>\n\n\n\n<p id=\"2f09\"><code>Async</code>&nbsp;функции. Они объявляются добавлением слова&nbsp;<code>async</code>, например&nbsp;<code>async function doAsyncStuff() { …code }</code></p>\n\n\n\n<p id=\"1b63\">Ваш код может встать на паузу в ожидании&nbsp;<code>Async</code>&nbsp;функции с&nbsp;<code>await</code></p>\n\n\n\n<p id=\"4e0e\"><code>Await</code>&nbsp;возвращает то, что асинхронная функция отдаёт при завершении.</p>\n\n\n\n<p id=\"a39a\"><code>Await</code>&nbsp;может быть использовано только внутри&nbsp;<code>async</code>&nbsp;функции.</p>\n\n\n\n<p id=\"3038\">Если асинхронная функция выдает исключение, то оно поднимется к родительской функции, как в обычном JavaScript и может быть перехвачено с&nbsp;<code>try/catch</code>. Как и в промисах, исключения будут проглочены, если они не будут перехвачены где-нибудь в цепочке кода. Это говорит о том, что вы всегда должны использовать&nbsp;<code>try/catch</code>, всякий раз когда запускается цепочка вызовов&nbsp;<code>Async</code>&nbsp;функций. Хорошей практикой является включение хотя бы одного&nbsp;<code>try/catch</code>&nbsp;в каждую цепочку, если только в игнорировании этого совета нет абсолютной необходимости. Это даст одно единственное место для работы с ошибками во время работы&nbsp;<code>async</code>&nbsp;и сподвигнет вас правильно связать ваши запросы&nbsp;<code>async</code>&nbsp;функций.</p>\n\n\n\n<p id=\"a6d0\">Давайте посмотрим на код:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// Просто рандомные асинхронные функции, работающие со значением\nasync function thingOne() { … }\nasync function thingTwo(value) { … }\nasync function thingThree(value) { … }\nasync function doManyThings() {\n var result = await thingOne();\n var resultTwo = await thingTwo(result);\n var finalResult = await thingThree(resultTwo);\n return finalResult;\n}\n// Вызовите doManyThings()</code></pre>\n\n\n\n<p id=\"e9de\">Это то, как выглядит&nbsp;<code>async/await</code>, он очень схож с синхронным кодом, а синхронный код куда проще понять.</p>\n\n\n\n<p id=\"9b41\">Итак, теперь&nbsp;<code>doManyThings()</code>&nbsp;это тоже асинхронная функция, как нам ожидать её? Да никак. Не с нашим новым синтаксисом. У нас есть три варианта:</p>\n\n\n\n<ol><li>Дайте оставшемуся коду выполниться и не ждать завершения, как нам и нужно во многих случаях.</li></ol>\n\n\n\n<p id=\"3f5f\">2. Запустите её внутри ещё одной асинхронной функции, обернутой в блок&nbsp;<code>try/catch</code>.</p>\n\n\n\n<p id=\"077e\">3. Или используйте как промис.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// Вариант 1:\ndoManyThings();\n// Вариант 2:\n(async function() {\n  try {\n    await doManyThings();\n  } catch (err) {\n    console.error(err);\n  }\n})();\n// Вариант 3:\ndoManyThings().then((result) => {\n  // Делаем штуки, которым нужно подождать нашей функции\n}).catch((err) => {\n  throw err;\n});</code></pre>\n\n\n\n<p id=\"3c4b\">Снова функции, которые возвращают промисы.<br>Итак, под конец я бы хотел показать несколько примеров того, как&nbsp;<code>async/await</code>&nbsp;приблизительно переходят в промисы. Я надеюсь, что это поможет вам увидеть то, как&nbsp;<code>async</code>&nbsp;функции выполняют роль синтаксического сахара для создания функций, которые отдают и ожидают промисы.</p>\n\n\n\n<p id=\"0408\">Простая&nbsp;<code>async</code>&nbsp;функция:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// Async/Await version\nasync function helloAsync() {\n return \"hello\";\n}\n// Promises version\nfunction helloAsync() {\n return new Promise(function (resolve) {\n   resolve(\"hello\");\n });\n}</code></pre>\n\n\n\n<p>Async функция, которая ожидает результат другой async функции:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// == Async/Await version ==\nasync function multiply(a, b) {\n return a * b;\n}\nasync function foo() {\n var result = await multiply(2, 5);\n return result;\n}\n// Ошибки полетят сюда\n(async function () {\n var result = await foo();\n console.log(result); // Logs 5\n})();\n// == Promises version ==\nfunction multiply(a, b) {\n return new Promise(function (resolve) {\n   resolve(a * b);\n });\n}\nfunction foo() {\n return new Promise(function(resolve) {\n   multiply(2, 5).then(function(result) {\n    resolve(result);\n  });\n );\n}\n// Ошибки полетят сюда\nnew Promise(function() {\n foo().then(function(result) {\n   console.log(result); // Logs 5\n   });\n});</code></pre>\n\n\n\n<p><strong>Пример, на который важно обратить внимание</strong><br>Вот пример того, почему понимание того, как работает&nbsp;<code>async/await</code>&nbsp;реально важно.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>async function foo() {\n someArray.forEach(function (value) {\n   doSomethingAsync(value);\n });\n}</code></pre>\n\n\n\n<p id=\"1221\">Пока что всё хорошо, мы параллельно выполняем&nbsp;<code>doSomethingAsync</code>&nbsp;несколько раз, так как мы не используем&nbsp;<code>await</code>. Но как бы мы это выполнили с ним?</p>\n\n\n\n<p id=\"5ebe\">Явно не так:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>async function foo() {\n someArray.forEach(function (value) {\n   await doSomethingAsync(value);\n });\n}</code></pre>\n\n\n\n<p id=\"5fa6\">Пример выше выдаст синтаксическую ошибку, так как мы передаем&nbsp;<code>forEach</code>&nbsp;синхронную функцию.</p>\n\n\n\n<p id=\"2062\">Не проблема, верно? Нам всего-лишь надо передать ей&nbsp;<code>async</code>&nbsp;функцию. А вот и нет.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>async function foo() {\n someArray.forEach(async function (value) {\n   await doSomethingAsync(value);\n });\n}</code></pre>\n\n\n\n<p>Что тут не так? Давайте посмотрим на то, как это интерпретируется. Я не будут многословным с промисами и объясню максимально просто то, как это было бы в случае с ними:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function foo() {\n  someArray.forEach(function () {\n    // отдаётся промис\n    return doSomethingAsync(value);\n  });\n}</code></pre>\n\n\n\n<p id=\"1191\">Проблема в том, что&nbsp;<code>forEach</code>&nbsp;не ожидает&nbsp;<code>async</code>&nbsp;функции или выражаясь промисами, она не ждет пока одна итерация вернет промис, чтобы завершить предыдущую.</p>\n\n\n\n<p id=\"04b4\">Также, в наших примерах, нам не надо было ожидать вызова&nbsp;<code>forEach</code>.</p>\n\n\n\n<p id=\"9a0a\">Так как теперь решить эту проблему? К сожалению, мы не можем использовать&nbsp;<code>forEach</code>. По факту, никакие синхронные итераторы не будут работать. Нам нужны итераторы, которые знают как работать с промисами.</p>\n\n\n\n<p id=\"631d\">И есть один, который будет. Это современная версия цикла for, “<code>for of</code>”, которая понимает&nbsp;<code>await</code>&nbsp;для промисов.</p>\n\n\n\n<p id=\"dec0\">Это сработает:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>for (item of someArray) {\n await foo();\n}</code></pre>\n\n\n\n<p>Если вы не можете использовать “<code>for of</code>”, то вы можете применить итератор, который поддерживает промисы или использовать библиотеку, такую как&nbsp;<a href=\"http://bluebirdjs.com/docs/api/promise.each.html\">bluebird</a>&nbsp;Promise.each</p>\n\n\n\n<p id=\"6c46\">В общем, поймите промисы и вы поймете&nbsp;<code>async/await</code>.</p>\n\n\n\n<h2 id=\"498e\">Заключение</h2>\n\n\n\n<p id=\"3596\">Я надеюсь, что это прояснило картину,&nbsp;<code>async/await</code>&nbsp;это просто, если вы хорошо понимаете промисы.</p>\n","date":"2021-02-25T18:59:30.000Z","title":"Полное понимание синхронного и асинхронного JavaScript с Async/Await","id":"f2a0dafd-292a-5dd3-8ab0-d3b280944d32","excerpt":"<p>В этой статье вы узнаете о том, что такое синхронное и асинхронное программирование в JavaScript и как применяя эти знания работать с Async/Await.</p>\n","type":"js","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2021/02/awaitpic.jpg"}}},{"node":{"slug":"samie-neobhodimie-strokovie-i-chislovie-metody-v-javascript","content":"\n<p>В этой статье, а скорее памятке, вы найдете все самые необходимые методы для работы со строками и числами (за исключением&nbsp;<code>Math</code>)в JavaScript, которые нужно просто знать, чтобы не городить огородов, а воспользоваться методами, доступными&nbsp;<em>“из коробки”</em>.</p>\n\n\n\n<p class=\"author\"><em>Перевод статьи:<br></em><a href=\"https://flaviocopes.com/javascript-string/\"><em>JavaScript Reference: String</em></a><em><br>+ числовые методы оттуда же</em></p>\n\n\n\n<h2 id=\"7bf7\"><strong>String</strong></h2>\n\n\n\n<p id=\"a2cb\">У объекта&nbsp;<code>String</code>&nbsp;есть один статический метод,&nbsp;<code>String.fromCharCode()</code>, который обычно используют для создания строкового представления последовательности Unicode символов. В этом примере мы делаем простую строку с использованием ASCII кодов:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>String.fromCodePoint(70, 108, 97, 118, 105, 111) //'Flavio'</code></pre>\n\n\n\n<p>Вы также&nbsp;можете использовать восьмеричные и шестнадцатеричные числа:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>String.fromCodePoint(0x46, 0154, parseInt(141, 8), 118, 105, 111) //'Flavio'</code></pre>\n\n\n\n<p>Все другие, описанные ниже методы, это методы&nbsp;<em>“из коробки”</em>, которые работают на строках.</p>\n\n\n\n<h2 id=\"ead1\">charAt()</h2>\n\n\n\n<p id=\"676c\">Отдаёт символ под заданным индексом&nbsp;<code>i</code>.</p>\n\n\n\n<p id=\"0a3f\">Примеры:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>'Flavio'.charAt(0) //'F'\n'Flavio'.charAt(1) //'l'\n'Flavio'.charAt(2) //'a'</code></pre>\n\n\n\n<p id=\"8e4f\">Если вы зададите индекс, который не подходит по строке, то на выходе вы получите уже пустую строку.</p>\n\n\n\n<p id=\"7957\">В JavaScript нет типа char, так что char это строка с длиной&nbsp;<code>1</code>.</p>\n\n\n\n<h2 id=\"18ca\">charCodeAt()</h2>\n\n\n\n<p id=\"3753\">Отдаёт код символа под индексом&nbsp;<code>i</code>. Как и с&nbsp;<code>charAt()</code>, отдаёт Unicode 16-битное целое число, представляющее символ:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>'Flavio'.charCodeAt(0) //70\n'Flavio'.charCodeAt(1) //108\n'Flavio'.charCodeAt(2) //97</code></pre>\n\n\n\n<p>Вызов&nbsp;<code>toString()</code>&nbsp;после него, отдаст шестнадцатеричное число, которое вы можете найти в любой Unicode таблице,&nbsp;<a href=\"https://apps.timwhitlock.info/emoji/tables/unicode\">такой как эта</a>.</p>\n\n\n\n<h2 id=\"e6b0\">codePointAt()</h2>\n\n\n\n<p id=\"fdfe\">Этот метод был представлен уже в ES2015, чтобы работать с Unicode символами, которые не могут быть представлены как единичная 16-ти битная Unicode единица и которым вместо этого нужно их две.</p>\n\n\n\n<p id=\"3489\">Используя&nbsp;<code>charCodeAt()</code>, вам надо получить первый и второй, и затем совместить их. Используя&nbsp;<code>codePointAt()</code>&nbsp;вы получаете весь символ в одном запросе.</p>\n\n\n\n<p id=\"c3fa\">К примеру, этот китайский символ “𠮷” состоит из двух UTF-16 частей:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>\"𠮷\".charCodeAt(0).toString(16) //d842\n\"𠮷\".charCodeAt(1).toString(16) //dfb7</code></pre>\n\n\n\n<p>Комбинируем эти два unicode символа:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>\"\\ud842\\udfb7\" //\"𠮷\"</code></pre>\n\n\n\n<p>Вы можете получить тот же результат, но только используя&nbsp;<code>codePointAt()</code>:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>\"𠮷\".codePointAt(0) //20bb7</code></pre>\n\n\n\n<p>Если вы создаете новый символ, комбинируя эти unicode символы:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>\"\\u{20bb7}\" //\"𠮷\"</code></pre>\n\n\n\n<h2 id=\"d9c9\">concat()</h2>\n\n\n\n<p id=\"c646\">Объединяет актуальную строку со строкой&nbsp;<code>str</code>.</p>\n\n\n\n<p id=\"a030\">Пример:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>'Flavio'.concat(' ').concat('Copes') //'Flavio Copes'</code></pre>\n\n\n\n<p>Вы можете указывать сколько угодно аргументов и в таком случае, все эти аргументы будут объединены в строку.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>'Flavio'.concat(' ', 'Copes') //'Flavio Copes'</code></pre>\n\n\n\n<h2 id=\"ac2e\">endsWith()</h2>\n\n\n\n<p id=\"b92e\">Проверяет заканчивается ли строка со значением другой строки&nbsp;<code>str</code>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>'JavaScript'.endsWith('Script') //true\n'JavaScript'.endsWith('script') //false</code></pre>\n\n\n\n<p>Вы можете передать второй параметр с целым числом и&nbsp;<code>endWith()</code>&nbsp;будет рассматривать оригинальную строку, как если бы она этой заданной длины:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>'JavaScript'.endsWith('Script', 5) //false\n'JavaScript'.endsWith('aS', 5) //true</code></pre>\n\n\n\n<h2 id=\"2ae4\">includes()</h2>\n\n\n\n<p id=\"b9b2\">Проверяет есть ли в строке значение строки&nbsp;<code>str</code>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>'JavaScript'.includes('Script') //true\n'JavaScript'.includes('script') //false\n'JavaScript'.includes('JavaScript') //true\n'JavaScript'.includes('aSc') //true\n'JavaScript'.includes('C++') //false</code></pre>\n\n\n\n<p><code>includes()</code>&nbsp;также принимает второй опциональный параметр, целое число, которое указывает на позицию с которой начинать поиск.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>'a nice string'.includes('nice') //true\n'a nice string'.includes('nice', 3) //false\n'a nice string'.includes('nice', 2) //true</code></pre>\n\n\n\n<h2 id=\"5db4\">indexOf()</h2>\n\n\n\n<p id=\"00b7\">Даёт позицию начала заданной строки&nbsp;<code>str</code>&nbsp;в строке, на которой применяется метод.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>'JavaScript'.indexOf('Script') //4\n'JavaScript'.indexOf('JavaScript') //0\n'JavaScript'.indexOf('aSc') //3\n'JavaScript'.indexOf('C++') //-1</code></pre>\n\n\n\n<p>Вы можете передать второй параметр, чтобы указать точку старта:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>'a nice string'.indexOf('nice') !== -1 //true\n'a nice string'.indexOf('nice', 3) !== -1 //false\n'a nice string'.indexOf('nice', 2) !== -1 //true</code></pre>\n\n\n\n<h2 id=\"904e\">lastIndexOf()</h2>\n\n\n\n<p id=\"f05e\">Даёт позицию последнего появления строки&nbsp;<code>str</code>&nbsp;в актуальной строке.</p>\n\n\n\n<p id=\"f791\">Отдаёт&nbsp;<code>-1</code>, если поисковая строка не найдена.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>'JavaScript is a great language. Yes I mean JavaScript'.lastIndexOf('Script') //47\n'JavaScript'.lastIndexOf('C++') //-1</code></pre>\n\n\n\n<h2 id=\"2001\">localeCompare()</h2>\n\n\n\n<p id=\"e31b\">Этот метод сравнивает строки и возвращает число (отрицательное или положительное), которое говорит, является ли данная строка меньше, равной или больше, чем строка переданная как аргумент, но в зависимости от языка.</p>\n\n\n\n<p id=\"bae2\">Язык определяется настоящим местоположением или вы можете указать его, как второй аргумент:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>'a'.localeCompare('à') //-1\n'a'.localeCompare('à', 'it-IT') //-1</code></pre>\n\n\n\n<p>Очень часто его используют для сортировки массивов:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&#91;'a', 'b', 'c', 'd'].sort((a, b) => a.localeCompare(b))</code></pre>\n\n\n\n<p>Где бы вы обычно использовали:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&#91;'a', 'b', 'c', 'd'].sort((a, b) => (a > b) ? 1 : -1)</code></pre>\n\n\n\n<p id=\"d71b\">Только тут мы можем это сделать с помощью localeCompare(), который позволит нам работать с алфавитами по всему миру.</p>\n\n\n\n<p id=\"fd2e\">Объект переданный как третий аргумент, может быть использован для передачи дополнительных условий. Посмотрите все возможные значения для этих условий&nbsp;<a href=\"https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare\">на MDN</a>.</p>\n\n\n\n<h2 id=\"7207\">match()</h2>\n\n\n\n<p id=\"0cb2\">А вот работа с регулярными выражениями RegEx.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>'Hi Flavio'.match(/avio/)\n// Array &#91; 'avio' ]\n\n'Test 123123329'.match(/\\d+/)\n// Array &#91; \"123123329\" ]\n\n'hey'.match(/(hey|ho)/)\n//Array &#91; \"hey\", \"hey\" ]\n\n'123s'.match(/^(\\d{3})(\\w+)$/)\n//Array &#91; \"123s\", \"123\", \"s\" ]\n\n'123456789'.match(/(\\d)+/)\n//Array &#91; \"123456789\", \"9\" ]\n\n'123s'.match(/^(\\d{3})(?:\\s)(\\w+)$/)\n//null\n\n'123 s'.match(/^(\\d{3})(?:\\s)(\\w+)$/)\n//Array &#91; \"123 s\", \"123\", \"s\" ]\n\n'I saw a bear'.match(/\\bbear/)    //Array &#91;\"bear\"]\n\n'I saw a beard'.match(/\\bbear/)   //Array &#91;\"bear\"]\n\n'I saw a beard'.match(/\\bbear\\b/) //null\n\n'cool_bear'.match(/\\bbear\\b/)     //null</code></pre>\n\n\n\n<h2 id=\"a6ea\">normalize()</h2>\n\n\n\n<p id=\"b1ed\">В Unicode есть четыре главные формы нормализации. Их коды это&nbsp;<code>NFC</code>,&nbsp;<code>NFD</code>,&nbsp;<code>NFKC</code>&nbsp;и&nbsp;<code>NFKD</code>. На Википедии есть хорошая&nbsp;<a href=\"https://en.wikipedia.org/wiki/Unicode_equivalence\">статья про это</a>.</p>\n\n\n\n<p id=\"e66b\">Метод&nbsp;<code>normalize()</code>&nbsp;возвращает строку, нормализованную в соответствии с указанной формой, которую вы передаёте как параметр. (<code>NFC</code>&nbsp;используется как стандарт, если она не указана в ручную).</p>\n\n\n\n<p id=\"26b4\">Вот пример с MDN:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>'\\u1E9B\\u0323'.normalize() //ẛ̣\n'\\u1E9B\\u0323'.normalize('NFD') //ẛ̣\n'\\u1E9B\\u0323'.normalize('NFKD') //ṩ\n'\\u1E9B\\u0323'.normalize('NFKC') //ṩ</code></pre>\n\n\n\n<h2 id=\"1859\">padEnd()</h2>\n\n\n\n<p id=\"2356\">Смысл этого метода в том, чтобы добавлять в строку символы и пробелы, пока она не достигнет заданной длины.</p>\n\n\n\n<p id=\"f18e\">padEnd() был представлен в ES2017, как метод добавляющий символы в конец строки.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>padEnd(targetLength &#91;, padString])</code></pre>\n\n\n\n<p>Простое применение:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"616\" height=\"235\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_JSuONO5pkEkHrtlPbayDUQ.png\" alt=\"\" class=\"wp-image-229\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_JSuONO5pkEkHrtlPbayDUQ.png 616w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_JSuONO5pkEkHrtlPbayDUQ-300x114.png 300w\" sizes=\"(max-width: 616px) 100vw, 616px\" /></figure>\n\n\n\n<h1 id=\"4bef\">padStart()</h1>\n\n\n\n<p id=\"ad26\">Смысл этого метода в том, чтобы добавлять строки или символы как в предыдущем методе, но уже с самого начала строки:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>padStart(targetLength &#91;, padString])</code></pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"623\" height=\"242\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_LeXUASRJJwHSpxc8fn02PA.png\" alt=\"\" class=\"wp-image-230\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_LeXUASRJJwHSpxc8fn02PA.png 623w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_LeXUASRJJwHSpxc8fn02PA-300x117.png 300w\" sizes=\"(max-width: 623px) 100vw, 623px\" /></figure>\n\n\n\n<h2 id=\"0917\">repeat()</h2>\n\n\n\n<p id=\"f8b3\">Этот метод был представлен в ES2015 и повторяет строки заданное количество раз:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>'Ho'.repeat(3) //'HoHoHo'</code></pre>\n\n\n\n<p>Отдает пустую строку, если параметр не указан или параметр равен нулю. А в случае с отрицательным числом вы получите&nbsp;<em>RangeError.</em></p>\n\n\n\n<h2 id=\"7fb9\">replace()</h2>\n\n\n\n<p id=\"e168\">Этот метод находит первое упоминание&nbsp;<code>str1</code>&nbsp;в заданной строке и заменяет его на&nbsp;<code>str2</code>.</p>\n\n\n\n<p id=\"07c0\">Отдаёт новую строку, не трогая оригинальную.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>'JavaScript'.replace('Java', 'Type') //'TypeScript'</code></pre>\n\n\n\n<p>Вы&nbsp;можете передать регулярное выражение как первый аргумент:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>'JavaScript'.replace(/Java/, 'Type') //'TypeScript'</code></pre>\n\n\n\n<p><code>replace()</code>&nbsp;заменяет только первое упоминание, но а если вы будете использовать regex как поиск строки, то вы можете использовать (<code>/g</code>):</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>'JavaScript JavaX'.replace(/Java/g, 'Type') //'TypeScript TypeX'</code></pre>\n\n\n\n<p id=\"8982\">Второй параметр может быть функцией. Эта функция будет вызвана с заданным количеством аргументов, когда найдётся совпадение (или каждое совпадение в случае с regex&nbsp;<code>/g</code>):</p>\n\n\n\n<ul><li>Нужная строка</li><li>Целое число, которое указывает позицию в строке, где произошло совпадение</li><li>Строка</li></ul>\n\n\n\n<p id=\"3d0d\">Отдающееся значение функции заменит совпадающую часть строки.</p>\n\n\n\n<p id=\"5a84\">Пример:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>'JavaScript'.replace(/Java/, (match, index, originalString) => {\n  console.log(match, index, originalString)\n  return 'Test'\n}) //TestScript</code></pre>\n\n\n\n<p>Это работает и для обычных строк, а не только для регулярок:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>'JavaScript'.replace('Java', (match, index, originalString) => {\n  console.log(match, index, originalString)\n  return 'Test'\n}) //TestScript</code></pre>\n\n\n\n<p>В случае c regex, когда выбираются группы, все эти значения будут переданы как аргументы прямо после параметра совпадения.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>'2015-01-02'.replace(/(?&lt;year>\\d{4})-(?&lt;month>\\d{2})-(?&lt;day>\\d{2})/, (match, year, month, day, index, originalString) => {\n  console.log(match, year, month, day, index, originalString)\n  return 'Test'\n}) //Test</code></pre>\n\n\n\n<h2 id=\"6b9d\">search()</h2>\n\n\n\n<p id=\"ea3a\">Отдаёт расположение первого совпадения строки&nbsp;<code>str</code>&nbsp;в заданной строке.</p>\n\n\n\n<p id=\"0162\">Этот метод отдаёт индекс начала упоминания или&nbsp;<code>-1</code>, если такого не было найдено.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>'JavaScript'.search('Script') //4\n'JavaScript'.search('TypeScript') //-1</code></pre>\n\n\n\n<p>Вы можете использовать регулярные выражения (и на самом деле, даже если вы передаёте строку, то внутренне оно тоже применяется как регулярное выражение).</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>'JavaScript'.search(/Script/) //4\n'JavaScript'.search(/script/i) //4\n'JavaScript'.search(/a+v/) //1</code></pre>\n\n\n\n<h1 id=\"58b1\">slice()</h1>\n\n\n\n<p><a href=\"https://stasonmars.ru/javascript/razbiraemsya-s-putanitsei-mezhdu-metodami-javascript-slice-splice-i-split/\">В этой статье подробно рассказывается про метод slice() и его родственников.</a></p>\n\n\n\n<p id=\"1c32\">Отдает новую строку, которая является частью строки на которой применялся метод, от позиций&nbsp;<code>begin</code>&nbsp;до&nbsp;<code>end</code>.</p>\n\n\n\n<p id=\"47b6\">Оригинальная строка не изменяется.</p>\n\n\n\n<p id=\"81d4\"><code>end</code>&nbsp;опциональна.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>'This is my car'.slice(5) //is my car\n'This is my car'.slice(5, 10) //is my</code></pre>\n\n\n\n<p>Если вы выставите первым параметром отрицательное число, то начальный индекс будет считаться с конца и второй параметр тоже должен быть отрицательным, всегда ведя отсчет с конца:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>'This is my car'.slice(-6) //my car\n'This is my car'.slice(-6, -4) //my</code></pre>\n\n\n\n<h2 id=\"0d64\">split()</h2>\n\n\n\n<p id=\"909f\">Этот метод вырезает строку при её нахождении в строке на которой применяется метод (<em>чувствительный к регистру</em>) и отдаёт массив с токенами.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const phrase = 'I love my dog! Dogs are great'\nconst tokens = phrase.split('dog')\n\ntokens //&#91;\"I love my \", \"! Dogs are great\"]</code></pre>\n\n\n\n<h2 id=\"6e3f\">startsWith()</h2>\n\n\n\n<p id=\"9d67\">Проверяет начинается ли строка со значения&nbsp;<code>str</code>.</p>\n\n\n\n<p id=\"8a6b\">Вы можете вызвать&nbsp;<code>startWith()</code>&nbsp;на любой строке, указать подстроку и проверить отдаёт результат&nbsp;<code>true</code>&nbsp;или&nbsp;<code>false</code>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>'testing'.startsWith('test') //true\n'going on testing'.startsWith('test') //false</code></pre>\n\n\n\n<p>Этот метод допускает второй параметр, который позволит вам указать с какого символа вам надо начать проверку:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>'testing'.startsWith('test', 2) //false\n'going on testing'.startsWith('test', 9) //true</code></pre>\n\n\n\n<h2 id=\"f0e9\">toLocaleLowerCase()</h2>\n\n\n\n<p id=\"6ecb\">Этот метод отдаёт новую строку, которая представляет собой изначальную строку в нижнем регистре, в соответствии с нормами разметки указанной локали.</p>\n\n\n\n<p id=\"5823\">Собственно, первый параметр представляет локаль, но он опционален. Если его пропустить, то будет использоваться актуальная локаль:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>'Testing'.toLocaleLowerCase() //'testing'\n'Testing'.toLocaleLowerCase('it') //'testing'\n'Testing'.toLocaleLowerCase('tr') //'testing'</code></pre>\n\n\n\n<p>Как и всегда, мы можем не осознавать все преимущества интернационализации, но я читал на MDN, что правила разметки текста в турецком языке отличаются от других языков, чьё описание основано на латинице.</p>\n\n\n\n<p>В общем, это как и&nbsp;<code>toLowerCase()</code>, но с учетом локали.</p>\n\n\n\n<h2 id=\"dfe5\">toLocaleUpperCase()</h2>\n\n\n\n<p id=\"91b6\">Этот метод отдаёт новую строку, которая представляет собой изначальную строку в верхнем регистре, в соответствии с нормами разметки указанной локали.</p>\n\n\n\n<p id=\"7cd5\">Первым параметром указывается локаль, но это опционально, как и в случае с методом выше:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>'Testing'.toLocaleUpperCase() //'TESTING'\n'Testing'.toLocaleUpperCase('it') //'TESTING'\n'Testing'.toLocaleUpperCase('tr') //'TESTİNG'</code></pre>\n\n\n\n<h2 id=\"8a5c\">toLowerCase()</h2>\n\n\n\n<p id=\"295f\">Этот метод отдаёт новую строку с текстом в нижнем регистре.</p>\n\n\n\n<p id=\"cd70\">Не изменяет изначальную строку.</p>\n\n\n\n<p id=\"34b3\">Не принимает параметры.</p>\n\n\n\n<p id=\"befc\">Использование:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>'Testing'.toLowerCase() //'testing'</code></pre>\n\n\n\n<p>Работает как и&nbsp;<code>toLocaleLowerCase()</code>, но не учитывает локали.</p>\n\n\n\n<h2 id=\"ad6d\">toString()</h2>\n\n\n\n<p id=\"0480\">Отдает строку из заданного строчного объекта.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const str = new String('Test')\nstr.toString() //'Test'</code></pre>\n\n\n\n<h2 id=\"ffd7\">toUpperCase()</h2>\n\n\n\n<p id=\"d317\">Отдаёт новую строку с текстом в верхнем регистре.</p>\n\n\n\n<p id=\"7dc5\">Не изменяет оригинальную строку.</p>\n\n\n\n<p id=\"4115\">Не принимает параметры.</p>\n\n\n\n<p id=\"ba5f\">Использование:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>'Testing'.toUpperCase() //'TESTING'</code></pre>\n\n\n\n<p id=\"f358\">Если вы передадите пустую строку, то он возвратит пустую строку.</p>\n\n\n\n<p id=\"6a06\">Метод похож на&nbsp;<code>toLocaleUpperCase()</code>, но не принимает параметры.</p>\n\n\n\n<h2 id=\"e0e1\">trim()</h2>\n\n\n\n<p id=\"d98e\">Отдает новую строку удаляя пробелы вначале и в конце оригинальной строки.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>'Testing'.trim() //'Testing'\n' Testing'.trim() //'Testing'\n' Testing '.trim() //'Testing'\n'Testing '.trim() //'Testing'</code></pre>\n\n\n\n<h2 id=\"203d\">trimEnd()</h2>\n\n\n\n<p id=\"9782\">Отдаёт новую строку, удаляя пробелы только из конца оригинальной строки.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>'Testing'.trimEnd() //'Testing'\n' Testing'.trimEnd() //' Testing'\n' Testing '.trimEnd() //' Testing'\n'Testing '.trimEnd() //'Testing'</code></pre>\n\n\n\n<h2 id=\"037e\">trimStart()</h2>\n\n\n\n<p id=\"5520\">Отдаёт новую строку, удаляя пробелы из начала оригинальной строки.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>'Testing'.trimStart() //'Testing'\n' Testing'.trimStart() //'Testing'\n' Testing '.trimStart() //'Testing '\n'Testing'.trimStart() //'Testing'</code></pre>\n\n\n\n<h2 id=\"ad10\">valueOf()</h2>\n\n\n\n<p id=\"2024\">Отдает строчное представление заданного строчного объекта:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const str = new String('Test')\nstr.valueOf() //'Test'</code></pre>\n\n\n\n<p id=\"679a\">Это тоже самое, что и&nbsp;<code>toString()</code></p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p>Теперь пройдемся по числовым методам.</p></blockquote>\n\n\n\n<h2 id=\"1fa4\">isInteger()</h2>\n\n\n\n<p id=\"e4f2\">Отдаст&nbsp;<code>true</code>, если переданное значение является целым числом. Всё иное, такое как, логические значения, строки, объекты, массивы, отдают&nbsp;<code>false</code>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>Number.isInteger(1) //true\nNumber.isInteger(-237) //true\nNumber.isInteger(0) //true\n\nNumber.isInteger(0.2) //false\nNumber.isInteger('Flavio') //false\nNumber.isInteger(true) //false\nNumber.isInteger({}) //false\nNumber.isInteger(&#91;1, 2, 3]) //false</code></pre>\n\n\n\n<h2 id=\"7a53\">isNaN()</h2>\n\n\n\n<p id=\"64e9\"><code>NaN</code>&nbsp;это особый случай. Число является&nbsp;<code>NaN</code>, только если оно&nbsp;<code>NaN</code>&nbsp;или если это выражения деления ноль на ноль, что отдаёт&nbsp;<code>NaN</code>. Во всех других случаях мы можем передать ему что захотим, но получим&nbsp;<code>false</code>:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>Number.isNaN(NaN) //true\nNumber.isNaN(0 / 0) //true\n\nNumber.isNaN(1) //false\nNumber.isNaN('Flavio') //false\nNumber.isNaN(true) //false\nNumber.isNaN({}) //false\nNumber.isNaN(&#91;1, 2, 3]) //false</code></pre>\n\n\n\n<h2 id=\"62af\">isSafeInteger()</h2>\n\n\n\n<p id=\"14b7\">Число может удовлетворять&nbsp;<code>Number.isInteger()</code>, но не&nbsp;<code>Number.isSafeInteger()</code>, если оно заходит за пределы безопасных целых чисел.</p>\n\n\n\n<p id=\"083d\">Так что, всё что выше 2⁵³ и ниже -2⁵³ не является безопасным.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>Number.isSafeInteger(Math.pow(2, 53)) // false\nNumber.isSafeInteger(Math.pow(2, 53) - 1) // true\nNumber.isSafeInteger(Math.pow(2, 53) + 1) // false\nNumber.isSafeInteger(-Math.pow(2, 53)) // false\nNumber.isSafeInteger(-Math.pow(2, 53) - 1) // false\nNumber.isSafeInteger(-Math.pow(2, 53) + 1) // true</code></pre>\n\n\n\n<h2 id=\"721b\">parseFloat()</h2>\n\n\n\n<p id=\"1baa\">Парсит аргумент как дробное число и отдаёт его. Аргумент при этом является строкой:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>Number.parseFloat('10') //10\nNumber.parseFloat('10.00') //10\nNumber.parseFloat('237,21') //237\nNumber.parseFloat('237.21') //237.21\nNumber.parseFloat('12 34 56') //12\nNumber.parseFloat(' 36 ') //36\nNumber.parseFloat('36 is my age') //36\n\nNumber.parseFloat('-10') //-10\nNumber.parseFloat('-10.2') //-10.2</code></pre>\n\n\n\n<p>Как вы видите&nbsp;<code>Number.parseFloat()</code>&nbsp;довольно гибок. Он также может конвертировать строки со словами, выделяя только первое число, но в этом случае строка должна начинаться с числа:</p>\n\n\n\n<pre class=\"wp-block-code\"><code>Number.parseFloat('I am Flavio and I am 36') //NaN</code></pre>\n\n\n\n<h2 id=\"9307\">parseInt()</h2>\n\n\n\n<p id=\"47fd\">Парсит аргумент как целое число и отдаёт его:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>Number.parseInt('10') //10\nNumber.parseInt('10.00') //10\nNumber.parseInt('237,21') //237\nNumber.parseInt('237.21') //237\nNumber.parseInt('12 34 56') //12\nNumber.parseInt(' 36 ') //36\nNumber.parseInt('36 is my age') //36</code></pre>\n\n\n\n<p>Как вы видите&nbsp;<code>Number.parseInt()</code>&nbsp;тоже гибок. Он также может конвертировать строки со словами, выделяя первое число, строка должна начинаться с числа.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>Number.parseInt('I am Flavio and I am 36') //NaN</code></pre>\n\n\n\n<p>Вы можете передать второй параметр, чтобы указать систему счисления. Десятичная стоит по-дефолту, но вы можете применять восьмеричные и шестнадцатеричные числовые конверсии:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>Number.parseInt('10', 10) //10\nNumber.parseInt('010') //10\nNumber.parseInt('010', 8) //8\nNumber.parseInt('10', 8) //8\nNumber.parseInt('10', 16) //16</code></pre>\n\n\n\n<p></p>\n","date":"2021-02-13T16:00:30.000Z","title":"Самые необходимые строковые и числовые методы в JavaScript","id":"b21e71f3-19bc-5e16-91b9-4ba8819192b9","excerpt":"<p>В этой статье, а скорее памятке, вы найдете все самые необходимые методы для работы со строками и числами (за исключением Math)в JavaScript, которые нужно просто знать, чтобы не городить огородов, а воспользоваться методами, доступными “из коробки”.</p>\n","type":"js","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2021/02/samieneobkjfnk.jpg"}}},{"node":{"slug":"recursivno-opredelyaem-chisla-fibonacci-s-pomoshiu-memoizacii-v-javascript","content":"\n<p>В этой статье рассказывается о том, как определить и оперировать числами Фибоначчи с помощью рекурсии и мемоизации на JavaScript.</p>\n\n\n\n<p>Я постепенно расскажу про каждый момент в этой задаче, с объяснениями и примерами кода.</p>\n\n\n\n<p><em>P.S Очень надеюсь, что эта статья поможет явисту Ростиславу узнать, что такое мемоизация и рекурсивный ряд чисел Фибоначчи.</em></p>\n\n\n\n<h2>Фибоначчи и рекурсия</h2>\n\n\n\n<p>Вообще, рекурсивный подход в решении этой задачи считается плохой практикой из-за высокого runtime complexity. Это решение будет O(log n). А если представить большие числа, то сложно представить насколько тяжелой будет операция.</p>\n\n\n\n<p>Давайте посмотрим на рекурсивное решение этой задачки:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const fibo = (n) => {  \n  if (n &lt; 2) {\n    return n;\n  }\n  return fibo(n - 1) + fibo(n - 2);\n};</code></pre>\n\n\n\n<p>Суть в том, что мы последовательно запускаем функцию внутри себя же, делая ряд вычислений. Но давайте разберемся, что же там происходит на самом деле. Вот визуальное представление:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"305\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/fibkjnfklj.jpeg\" alt=\"\" class=\"wp-image-220\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/fibkjnfklj.jpeg 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/fibkjnfklj-300x131.jpeg 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p>Давайте взглянем на три блока слева. А именно <code>f(2)</code> и затем на <code>f(1)</code> и <code>f(0)</code>. Тут мы находим второй элемент в ряде чисел, начинающимся с <code>0</code>.</p>\n\n\n\n<p>Напоминаю, ряд чисел Фибоначчи это:</p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p>0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144 и так далее.</p></blockquote>\n\n\n\n<p>Тут мы отдаем <code>fibo</code> значение <code>2</code>, так как мы хотим высчитать <code>fibo(2)</code>. Как вы видите сверху мы видим специальное условие когда число равно 2-м и не меньше двух.</p>\n\n\n\n<p>Дальше отработают следующие строчки кода:</p>\n\n\n\n<p><code>fibo(n - 1) + fibo(n - 2)</code></p>\n\n\n\n<p>Замените <code>n</code> на <code>2</code> и мы получим <code>fibo(1) + fibo(0)</code></p>\n\n\n\n<p>Следующим шагом будет нахождение значений двух условий, а именно <code>fibo(0)</code> и <code>fibo(1)</code>. Тут для каждого случая нам придётся заново запускать метод <code>fibo</code> и именно в этом моменте и начинается рекурсия.</p>\n\n\n\n<p>В общем, мы получаем буквально следующее:</p>\n\n\n\n<p><code>fibo(2) = fibo(1) + fibo(0) = 1 + 0 = 1</code></p>\n\n\n\n<p>Давайте ещё немного разберем рекурсию, но уже с <code>fibo(3)</code>.</p>\n\n\n\n<p><code>fibo(3) = fibo(2) + fibo(1)</code></p>\n\n\n\n<p>Используя рекурсию мы получаем мы получаем следующее продолжение:</p>\n\n\n\n<p><code>fibo(2) + fibo(1), где fibo(2)</code> рекурсивно станет <code>(fibo(1) + fibo(0)) + fibo(1)</code>, где в результате мы получим <code>1 + 0 + 1 = 2</code>.</p>\n\n\n\n<p>Сейчас структура древа, описанного выше должна стать для вас более понятной. Рекурсия будет происходить вплоть до конца каждой ветви пока значение не будет <code>1</code> или <code>0</code>.</p>\n\n\n\n<p>А теперь самое интересное. Посмотрите на количество одинаковых аргументов в этом древе. Их несколько: <code>4, 3, 2</code> и все они будут отрабатывать снова и снова при вызове рекурсии.</p>\n\n\n\n<p>И тут нам на помощь приходит <strong>мемоизация</strong>.</p>\n\n\n\n<h2 class=\"javascript\">Мемоизация</h2>\n\n\n\n<p>Мемоизация это имплементация сложных рекурсивных или же итеративных функций более быстрым способом. Как? Кэшируя значения отдаваемые функцией при её первоначальном запуске.</p>\n\n\n\n<p>Когда мы отдаём функции мемоизации уже использованное значение, то оно отдаст готовое значение, сохраненное в кэше и не будет запускать функцию снова. К чему это приведет? К тому ускорению производительности, очевидно же. Вашему коду не надо будет пересчитывать то, что уже давно посчитано.</p>\n\n\n\n<p>Круто звучит, да? Тогда давайте посмотрим на пример мемоизации, что понять его более детально:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function memo(func){\n  const cache = {};\n    return function(){\n      const key = JSON.stringify(arguments);\n      if (cache&#91;key]){\n        return cache&#91;key];\n      }\n      else{\n        val = func.apply(null, arguments);\n        cache&#91;key] = val;\n        return val; \n      }\n  }\n};</code></pre>\n\n\n\n<p>Мы отдаём так называемое анонимное замыкание, которое может наследовать любую переменную или в нашем случае функцию, переданную memo. Затем мы можем смело играться с объектом аргументов этой функции.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const memoFib = memo((n) => {\n    if (n &lt; 2) {\n        return n;\n    }\n    return memoFib(n - 1) + memoFib(n - 2);\n});</code></pre>\n\n\n\n<p>Например, запустив её с <code>memoFib(8)</code> мы получим <code>21</code>, а объект с мемоизированными значениями будет выглядеть так:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>{\n\t  {\"0\":0}: 0,\n\t  {\"0\":1}: 1,\n\t  {\"0\":2}: 1,\n\t  {\"0\":3}: 2,\n\t  {\"0\":4}: 3,\n\t  {\"0\":5}: 5,\n\t  {\"0\":6}: 8,\n\t  {\"0\":7}: 13\n}</code></pre>\n\n\n\n<p></p>\n","date":"2021-02-11T16:25:38.000Z","title":"Рекурсивно определяем числа Фибоначчи с помощью мемоизации в JavaScript","id":"6c644d43-c324-5c7e-b647-22e3724bb74f","excerpt":"<p>В этой статье рассказывается о том, как определить и оперировать числами Фибоначчи с помощью рекурсии и мемоизации на JavaScript.</p>\n","type":"js","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2021/02/recursivefibonaccikfjn.jpg"}}},{"node":{"slug":"kak-rabotaet-delegirovanie-sobityi-v-javascript","content":"\n<p>Очень доходчивая статья о том, как работает делегирование событий в JavaScript и как не запутаться в слушателях событий.</p>\n\n\n\n<p class=\"author\"><em>Перевод&nbsp;</em><a href=\"https://medium.com/@bretdoucette/part-4-what-is-event-delegation-in-javascript-f5c8c0de2983\"><em>Part 4: What is Event Delegation in JavaScript?</em></a></p>\n\n\n\n<p id=\"e942\">Чтобы понять делегирование событий в JavaScript, вам сначала надо понять работу слушателей самих событий (ну или event listeners).</p>\n\n\n\n<p id=\"fb4e\">Я не очень люблю описывать вещи словами из их названия, но тут уж некуда деваться, слушатели событий следят за срабатыванием самих событий на странице. Вот, собственно и всё.</p>\n\n\n\n<p id=\"3c2b\">Событием в&nbsp;JavaScript можно назвать то, что “<em>происходит с HTML элементом</em>”, а происходить с ним может много чего.</p>\n\n\n\n<h2 id=\"c270\">Вот некоторые популярные JavaScript события:</h2>\n\n\n\n<p id=\"796c\"><code>change&nbsp;</code>— срабатывает тогда, когда что-то поменялось в HTML элементе.</p>\n\n\n\n<p id=\"9be2\"><code>click&nbsp;</code>— когда пользователь кликает на элемент.</p>\n\n\n\n<p id=\"8ac4\"><code>mouseover</code>&nbsp;— когда пользователь наводит мышь на HTML элемент.</p>\n\n\n\n<p id=\"72ca\"><code>mouseout</code>&nbsp;— когда пользователь отводит мышку от элемента.</p>\n\n\n\n<p id=\"f78d\"><code>keydown</code>&nbsp;— когда пользователь кликает на клавиатуру.</p>\n\n\n\n<p id=\"58ed\"><code>load&nbsp;</code>— когда браузер заканчивает загрузку страницы.</p>\n\n\n\n<p id=\"b757\"><code>addEventListener()</code></p>\n\n\n\n<p id=\"fad0\">Чтобы добавить слушатель событий к HTML элементу, вы можете использовать&nbsp;<code>addEventListner()</code>&nbsp;метод.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>Пример addEventListener()\n\nconst character = document.getElementById(\"disney-character\");\ncharacter.addEventListener('click', showCharactersName);</code></pre>\n\n\n\n<p id=\"28e8\">Первая часть кода это то, что мы будем слушать, в нашем случае это просто HTML элемент. Но в JavaScript можно слушать просто неописуемое изобилие вещей на странице и не только. Это может быть HTML элемент на странице, это может быть сам документ или это может быть окно браузера. В общем, это объект высшего порядка в client-side JavaScript который охватывает почти всё. Но всё же, в большинстве случаев это HTML элементы. Вторая часть кода это уже сам слушатель.</p>\n\n\n\n<h3 id=\"466e\">Вот как работает&nbsp;<code>eventListener</code>:</h3>\n\n\n\n<p id=\"3321\">Когда пользователь кликает на HTML элемент, с&nbsp;<code>id</code>&nbsp;<code>disnay-character</code>, то слушатель событий срабатывает и вызывает функцию&nbsp;<code>showCharactersName</code>.</p>\n\n\n\n<p id=\"7bf6\">Слушатели событий выставляются после загрузки страницы. Так что, когда вы впервые открываете сайт, браузер скачивает, считывает и выполняет JavaScript.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const character = document.getElementById(\"disney-character\");\n\ncharacter.addEventListener('click', showCharactersName);</code></pre>\n\n\n\n<p id=\"95fe\">В коде выше, при загрузке страницы, слушатель событий находит HTML элемент с&nbsp;<code>id</code>&nbsp;<code>disnay-character</code>&nbsp;и выставляет на него слушатель события по клику.</p>\n\n\n\n<p id=\"8858\">Вся эта конструкция будет успешно работать, если элемент уже существует на странице. Но что происходит со слушателем событий, когда элемент добавляется в DOM уже после загрузки страницы?</p>\n\n\n\n<h2 id=\"7cb5\"><strong>Делегирование событий</strong></h2>\n\n\n\n<p id=\"ccbb\">Именно оно решает эту проблему. Чтобы понять принцип его работы, нам надо посмотреть ниже на список персонажей Disney.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"446\" height=\"457\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_OciPJyDlVzbNeYPNBfTIkA.png\" alt=\"\" class=\"wp-image-212\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_OciPJyDlVzbNeYPNBfTIkA.png 446w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_OciPJyDlVzbNeYPNBfTIkA-293x300.png 293w\" sizes=\"(max-width: 446px) 100vw, 446px\" /></figure>\n\n\n\n<p id=\"14a1\">У этого списка есть довольно простой функционал. Именно для наших нужд мы можем добавить несколько персонажей в этот список и проверить боксы рядом с именем персонажа.</p>\n\n\n\n<p id=\"fa3b\">Этот список также является динамическим. Инпуты (Mickey, Minnie, Goofy) были добавлены уже&nbsp;<strong>ПОСЛЕ</strong>&nbsp;загрузки страницы и следовательно, на них не были прикреплены слушатели событий.</p>\n\n\n\n<p id=\"e7fd\">Давайте посмотрим на этот код:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const checkBoxes = document.querySelectorAll('input');\n\ncheckBoxes.forEach(input => input.addEventListener('click', ()=> alert('hi!')));\n\n//Должно выскочить окно при клике на один из инпутов(Mickey, Minnie, или Goofy)</code></pre>\n\n\n\n<p>Но давайте посмотрим на HTML при загрузке страницы:</p>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;ul class=\"characters\">&lt;/ul></code></pre>\n\n\n\n<p>А теперь давайте взглянем на HTML после загрузки страницы (из локального веб-хранилища, API запроса и т.п.):</p>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;ul class=\"characters\">\n &lt;li>\n   &lt;input type=\"checkbox\" data-index=\"0\" id=\"item0\">\n   &lt;label for=\"item0\">Mickey&lt;/label>\n &lt;/li>\n \n &lt;li>\n   &lt;input type=\"checkbox\" data-index=\"1\" id=\"item1\">\n   &lt;label for=\"item1\">Minnie&lt;/label>\n &lt;/li>\n \n &lt;li>\n   &lt;input type=\"checkbox\" data-index=\"2\" id=\"item2\">\n   &lt;label for=\"item2\">Goofy&lt;/label>\n &lt;/li>\n&lt;/ul>\n** Инпуты были добавлены в DOM после загрузки страницы и на них не висят слушатели событий.</code></pre>\n\n\n\n<p>Если вы захотите кликнуть на инпуты&nbsp;персонажей — Mickey, Minnie, or Goody), то вы наверное ожидали бы увидеть всплывающее окно с надписью “hi!”, но так как они не были загружены на страницу при её инициализации, то и прослушиватели событий&nbsp;<strong>НЕ БЫЛИ</strong>&nbsp;добавлены на эти элементы и само собой ничего не произойдёт.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"284\" height=\"265\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_zzKjANG7YP9bnoDhqsm9ew.gif\" alt=\"\" class=\"wp-image-213\"/></figure>\n\n\n\n<h2 id=\"98d2\">Как же пофиксить эту проблему?</h2>\n\n\n\n<p id=\"03f2\">Делегированием событий.</p>\n\n\n\n<p id=\"b903\">Суть делегирования событий в том, что вместо прослушивания изменений на инпутах напрямую, нам нужно прослушивать HTML элемент, который был бы на странице при изначальной загрузке.</p>\n\n\n\n<p id=\"760a\">В нашем примере это список&nbsp;<code>ul</code>&nbsp;с классом&nbsp;<code>characters</code>, который появляется при загрузке страницы. Мы можем повесить слушатель событий прямо на него.</p>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;ul class=\"characters\"> // Родитель - всегда на странице\n &lt;li>\n   &lt;input type=\"checkbox\" data-index=\"0\" id=\"char0\"> //ПОТОМОК 1\n   &lt;label for=\"char0\">Mickey&lt;/label>\n &lt;/li>\n \n &lt;li>\n   &lt;input type=\"checkbox\" data-index=\"1\" id=\"char1\"> //ПОТОМОК 2\n   &lt;label for=\"char1\">Minnie&lt;/label>\n &lt;/li>\n \n &lt;li>\n   &lt;input type=\"checkbox\" data-index=\"2\" id=\"char2\"> //ПОТОМОК 3\n   &lt;label for=\"char2\">Goofy&lt;/label>\n &lt;/li>\n&lt;/ul></code></pre>\n\n\n\n<p id=\"9e85\">Лучше рассматривать делегирование событий, как ответственных родителей и нерадивых детишек. В этом случае родители это просто боги, а детям приходиться слушать всё, что говорят их родители. Прекрасный аспект тут в том, что если бы мы добавили больше детей (или инпутов), то родители бы остались такими же в правах — они были с самого начала или другими словами, прямо с загрузки страницы.</p>\n\n\n\n<p id=\"13a8\">Давайте прикрепим слушатель событий:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&lt;ul class=\"characters\">\n&lt;/ul>\n&lt;script>\n  function toggleDone (event) {\n    console.log(event.target)\n  } \n  const characterList = document.querySelector('.characters')\n  characterList.addEventListener('click', toggleDone)\n&lt;/script></code></pre>\n\n\n\n<p>Теперь у нас есть слушатель событий на&nbsp;<code>ul</code>, а не на каждом отдельном потомке. Так что же тогда произойдет, если мы кликнем на инпут после того, как загрузилась страница и выведем в консоль&nbsp;<code>event.target</code>?</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"88\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_0vj3yxDmqI-a1_s-rB3ETA.png\" alt=\"\" class=\"wp-image-214\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_0vj3yxDmqI-a1_s-rB3ETA.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_0vj3yxDmqI-a1_s-rB3ETA-300x38.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p id=\"dfb0\"><code>event.target</code>&nbsp;это отсылка к объекту, на котом сработало событие. Или другими словами, он указывает на HTML элемент на котором сработало событие.</p>\n\n\n\n<p id=\"89ec\">Событие в нашем случае это клик. Объект на котором отработало событие это&nbsp;<code>&lt;input/&gt;</code>.</p>\n\n\n\n<p id=\"f337\">**&nbsp;<code>label</code>&nbsp;рассматривается, как часть объекта&nbsp;<code>input</code>&nbsp;— поэтому мы видимо их обоих**</p>\n\n\n\n<h2 id=\"16c5\">Console.log(event.currentTarget)</h2>\n\n\n\n<p id=\"a45b\">Если мы выведем в консоль&nbsp;<code>event.currentTarget</code>&nbsp;— то увидим мы кое что другое.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"146\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_j2UgR5rfWILSuahqs4eMvg.png\" alt=\"\" class=\"wp-image-215\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_j2UgR5rfWILSuahqs4eMvg.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_j2UgR5rfWILSuahqs4eMvg-300x63.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p><code>event.currentTarget</code>&nbsp;указывает на данную цель события, так как сам ивент уходит дальше в DOM. Он всегда ссылается на элемент к которому был прикреплен&nbsp;<code>eventListener</code>. В нашем случае этим элементом являлся неупорядоченный список&nbsp;<code>characters</code>, так что это то, что мы увидим в консоле.</p>\n\n\n\n<h2 id=\"c264\">Пишем делегирование событий в JavaScript</h2>\n\n\n\n<p id=\"31f4\">Так как теперь мы знаем, что&nbsp;<code>event.target</code>&nbsp;указывает на элементы на которых отработало событие и также мы знаем, какой элемент нам нужно слушать, решение проблемы с делегированием для нас не является проблемой.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>//делегирование событий\nfunction toggleDone (event) {\n  if (!event.target.matches('input')) return\n  console.log(event.target)\n  //Теперь мы выбрали нужный инпут и можем начать манипуляции с DOM\n}</code></pre>\n\n\n\n<p id=\"eeef\">В общем, код выше говорит нам то, что если элемент на котором отработал клик не является инпутом, то мы выходим из функции.</p>\n\n\n\n<p id=\"bb06\">А если этот элемент является инпутом, то тогда мы выводим в консоль&nbsp;<code>event.target</code>&nbsp;и выполняем последующий JavaScript код на этом узле потомке.</p>\n\n\n\n<p id=\"713a\">Очень важно, что теперь мы можем быть уверены в том, что пользователь кликнул нужный узел потомок, пусть даже инпуты не были добавлены в DOM после начальной загрузки страницы.</p>\n\n\n\n<h2 id=\"8bf9\">Event Bubbling (Всплытие событий)</h2>\n\n\n\n<p id=\"a5ca\">Если вы хотите завершить чтение на этом моменте — то смело это делайте. Мы уже узнали основы делегирования событий. Но для глубокого понимания того, почему оно работает, нам нужно понять&nbsp;<strong><em>Event Bubbling</em></strong>.</p>\n\n\n\n<h3 id=\"a792\"><strong>Что происходит на самом деле при клике?</strong></h3>\n\n\n\n<p id=\"6353\">Всякий раз, когда пользователь кликает, этот самый клик отдаётся вверх на самую высь DOM и отрабатывает событие клика на всех элементах родителя по которому был сделан клик. Вы не всегда видите эти клики, так как вы не всегда слушаете (с&nbsp;<code>eventListener</code>) клики на этих элементах, но как бы то ни было, но такое “всплытие” действий имеет место быть.</p>\n\n\n\n<p id=\"e8a1\">Это называется&nbsp;<em>Event Bubbling (Всплытие событий)</em>&nbsp;или распространением события.</p>\n\n\n\n<p id=\"665e\">Это означает то, что всякий раз, когда вы кликаете на один из наших инпутов в DOM, вы по сути прокликиваете весь документ.</p>\n\n\n\n<p id=\"7412\">Вот пример:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&lt;div class=\"one\">\n  &lt;div class=\"two\">\n    &lt;div class=\"three\">\n    &lt;/div>\n  &lt;/div>\n&lt;/div>\n&lt;script>\n  const divs = document.querySelectorAll('div');  \n  function logClassName(event) {\n    console.log(this.classList.value);\n  }\n  divs.forEach(div => div.addEventListener('click', logClassName));\n&lt;/script></code></pre>\n\n\n\n<p>Выше у нас есть три дива: DIV #1, DIV #2, DIV #3. У каждого&nbsp;<code>div</code>’а есть свой прослушиватель событий и когда мы на него кликаем в браузере, то мы выводим в консоль имя класса, через функцию&nbsp;<code>logClassName()</code>.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"323\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_NwINqHz873kEH_2D9iX0ng.gif\" alt=\"\" class=\"wp-image-216\"/></figure>\n\n\n\n<p>Выше мы видим то, что мы бы увидели в браузере. Обратите внимание на то, как мышка кликает по третьему&nbsp;<code>div</code>’у. Как и ожидалось, когда я кликаю по нему, я вижу его класс в консоле. Но кликая по div #3, я также кликаю и по div #2 и div#1, который вывелись в консоль. Это и называется всплытием событий. Мы видим каждый класс, потому что мы добавили прослушиватель событий каждому родительскому <code>div</code>’у.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"392\" height=\"202\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_txz1UUG5qc8b_B6oyClgwQ.png\" alt=\"\" class=\"wp-image-217\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_txz1UUG5qc8b_B6oyClgwQ.png 392w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_txz1UUG5qc8b_B6oyClgwQ-300x155.png 300w\" sizes=\"(max-width: 392px) 100vw, 392px\" /></figure>\n\n\n\n<p>Но вернемся к нашему примеру с делегированием события:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&lt;ul class=\"characters\"> // Родитель -- где и находится слушатель события!\n &lt;li>\n   &lt;input type=\"checkbox\" data-index=\"0\" id=\"char0\"> //ПОТОМОК 1\n   &lt;label for=\"char0\">Mickey&lt;/label>\n &lt;/li>\n \n &lt;li>\n   &lt;input type=\"checkbox\" data-index=\"1\" id=\"char1\"> //ПОТОМОК 2\n   &lt;label for=\"char1\">Minnie&lt;/label>\n &lt;/li>\n \n &lt;li>\n   &lt;input type=\"checkbox\" data-index=\"2\" id=\"char2\"> //ПОТОМОК 3\n   &lt;label for=\"char2\">Goofy&lt;/label>\n &lt;/li>\n&lt;/ul>\n&lt;script>\n  const characterList = document.querySelector('.characters');\n  characterList.addEventListener('click', toggleDone);\n&lt;/script></code></pre>\n\n\n\n<p id=\"a7b4\">Вернёмся к нашему примеру с делегированием событий — у нас был только один слушатель события и он был выставлен на неупорядоченный список с классом&nbsp;<code>characters</code>. Тем не менее, мы кликнули на потомка этого родительского HTML элемента, элемент input, который запустил прослушиватель событий, который привязали к списку.</p>\n\n\n\n<p id=\"7b98\">В силу наличия всплытия событий, вы можете повесить&nbsp;<code>eventListener</code>&nbsp;на одном родительском HTML элементе, который находится выше потомков и этот прослушиватель событий будет срабатывать всякий раз, как заданное событие случиться на любом из его дочерних элементов — даже если они были добавлены после первоначальной загрузки страницы.</p>\n\n\n\n<h2 id=\"8cfb\">В завершение. А зачем использовать делегирование событий?</h2>\n\n\n\n<p id=\"9394\">Без делегирования событий, вам бы пришлось перепривязывать событие по клику на каждый новый&nbsp;<code>input</code>, добавленный на страницу. Делать такую писанину довольно проблематично и обременительно. Во первых, такой подход значительно увеличит количество слушателей событий на вашей странице и их большое количество увеличит объем памяти, потребляемое вашей страницей. Что приведет к снижению производительности, что само по себе уже плохо. Во вторых, могут произойти проблемы с утечкой памяти из-за циклической привязки и отвязки слушателей событий, и удаления элементов из DOM. Но это уже выходит за рамки данной статьи.</p>\n","date":"2021-02-10T14:37:38.000Z","title":"Делегирование событий в JavaScript","id":"7c43032e-ea51-587a-918b-8a514ff1854d","excerpt":"<p>Очень доходчивая статья о том, как работает делегирование событий в JavaScript и как не запутаться в слушателях событий.</p>\n","type":"js","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2021/02/eventdelegatlf.jpg"}}},{"node":{"slug":"kak-rabotat-s-localstorage-v-javascript","content":"\n<p id=\"53e8\">В этой статье вы узнаете о том, что такое&nbsp;<code>localStorage</code>&nbsp;и на рабочем примере узнаем то, как с ним работать в JavaScript.</p>\n\n\n\n<p class=\"author\" id=\"7410\">Перевод статьи&nbsp;<a href=\"https://www.taniarascia.com/how-to-use-local-storage-with-javascript/\">How to Use Local Storage with JavaScript</a></p>\n\n\n\n<p id=\"c112\">Мне нравится делать обучающие материалы о том, как создавать небольшие приложения буквально с нуля, используя чистый JavaScript. Создание&nbsp;<strong>to-do</strong>&nbsp;списка это распространенная идея для создания приложения, а без базы данных, в которую можно положить задачи, она становится особенной полезной, но добавляет некоторые сложности для начинающих.</p>\n\n\n\n<p id=\"1a3f\">Однако,&nbsp;даже без базы данных, мы можем использовать встроенное в браузер веб-хранилище, чтобы сохранять туда задачи из&nbsp;<strong>to-do</strong>&nbsp;списка.Такое приложение было бы особенно полезным для создания быстрых заметок. Вы бы просто установили ярлык на приложение при запуске новой вкладки и задачи&nbsp;<strong>to-do</strong>&nbsp;будут находиться на вашем компьютере пока вы не очистите кэш.</p>\n\n\n\n<p id=\"c6ec\">Вот то, что мы сегодня будем делать:</p>\n\n\n\n<p id=\"ee17\"><a href=\"https://taniarascia.github.io/sandbox/tab/\">Демка</a></p>\n\n\n\n<p id=\"a848\"><a href=\"https://github.com/taniarascia/sandbox/tree/master/tab\">Исходник</a></p>\n\n\n\n<p id=\"964a\">Для того, чтобы понимать статью, вам нужно знать основы HTML и CSS, понимать типы данных и синтаксис JavaScript, вместе с DOM манипуляциями.</p>\n\n\n\n<p id=\"25d6\">Целью этой статьи является создание быстрого приложения, которое будет хранить&nbsp;<strong>to-do</strong>&nbsp;элементы в веб-хранилище браузера на вашем компьютере и показывать их на фронте.&nbsp;<a href=\"https://taniarascia.github.io/sandbox/tab\">Посмотрите пример</a>.</p>\n\n\n\n<h2 id=\"7873\">Что такое веб-хранилище</h2>\n\n\n\n<p id=\"c135\">В веб-хранилище хранятся данные пользователя браузера. Есть два типа веб-хранилищ:</p>\n\n\n\n<p id=\"3c93\"><code>localStorage</code>&nbsp;— это данные, которые хранятся бессрочно и будут доступны даже после перезагрузки браузера.</p>\n\n\n\n<p id=\"5c51\"><code>sessionStorage&nbsp;</code>— это данные, которые стираются после того, как окно браузера закрывается.</p>\n\n\n\n<p id=\"83b2\">Веб-хранилище довольно удобно для сохранения данных, таких как предпочтения пользователей (светлая или темная цветовая схема на сайте и тп), сохранение товаров, положенных в корзину или запоминание того, что пользователь залогинен на сайте.</p>\n\n\n\n<p id=\"1953\">До этого, для запоминания такого рода локальных, временных данных, использовались только кукисы. В локальном веб-хранилище вы можете хранить значительно больше данных (5MB vs 4KB) и не обращаться к ним, при каждом HTTP вызове, таким образом, это может быть лучшим вариантом для хранилища данных на стороне клиента.</p>\n\n\n\n<p id=\"2d05\">Вот обзор методов&nbsp;<code>localStorage</code></p>\n\n\n\n<p id=\"bb62\"><code>setItem()</code>&nbsp;— добавляет пару ключ-значение в локальное веб-хранилище</p>\n\n\n\n<p id=\"f29f\"><code>getItem()</code>&nbsp;— получает значение по ключу</p>\n\n\n\n<p id=\"8aa1\"><code>removeItem()&nbsp;</code>— удаляет элемент по ключу</p>\n\n\n\n<p id=\"f12c\"><code>clear()</code>&nbsp;— очищает хранилище</p>\n\n\n\n<p id=\"b1ea\">Вы можете посмотреть то, что находится в локальном хранилище, зайдя в консоль и введя в неё&nbsp;<code>localStorage</code>.</p>\n\n\n\n<pre class=\"wp-block-code\"><code>Storage {length: 0}</code></pre>\n\n\n\n<p>Добавление данных в&nbsp;<code>localStorage</code>&nbsp;очень простой процесс, вы можете использовать&nbsp;<code>setItem()</code>&nbsp;метод. Я буду использовать общепринятые имена для пары <strong>ключ-значение</strong>, но они могут быть любой производной строкой.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>localStorage.setItem('key', 'value')</code></pre>\n\n\n\n<p>Теперь, если вы проверите&nbsp;<code>localStorage</code>&nbsp;в консоле, то вы там увидите новый ключ и значение.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>Storage {key: \"value\", length: 1}</code></pre>\n\n\n\n<p>Если вы хотите получить значение конкретного ключа, то вам надо будет использовать метод&nbsp;<code>getItem()</code>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>localStorage.getItem('key')\nvalue</code></pre>\n\n\n\n<p>И наконец, вы можете удалить данные с помощью&nbsp;<code>removeItem()</code>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>localStorage.removeItem('key')</code></pre>\n\n\n\n<p>А используя&nbsp;<code>clear()</code>, вы очистите всё веб-хранилище.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>localStorage.clear()</code></pre>\n\n\n\n<p>Теперь мы можем приступить к созданию приложения.</p>\n\n\n\n<h2 id=\"c968\">Подготавливаем фронт</h2>\n\n\n\n<p id=\"296c\">Сначала мы создадим простенькую HTML разметку в&nbsp;<code>index.html</code>. Я работаю в&nbsp;<em>Primitive(мой минималистический HTML Фреймворк)</em>&nbsp;для стилей, потому что это то, что я всегда использую, если мне нужен быстрый фронт.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&lt;!DOCTYPE html>\n&lt;html lang=\"en\">\n  &lt;head>\n    &lt;meta charset=\"utf-8\" />\n    &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n&lt;title>New Tab App&lt;/title>\n&lt;link rel=\"stylesheet\" href=\"https://unpkg.com/primitive-ui/dist/css/main.css\" />\n  &lt;/head>\n&lt;body>\n    &lt;div class=\"small-container\">\n      &lt;h1>New Tab App&lt;/h1>\n&lt;!-- more will go here -->\n    &lt;/div>\n  \n    &lt;script src=\"js/scripts.js\">&lt;/script>\n  &lt;/body>\n&lt;/html></code></pre>\n\n\n\n<p id=\"3f43\">Тут нам надо уделить внимание настройке трёх вещей:</p>\n\n\n\n<p id=\"ba79\"><strong>Текстовой&nbsp;</strong><code><strong>input</strong></code>— для добавления новых элементов.</p>\n\n\n\n<p id=\"0660\"><strong>Список</strong>&nbsp;— то место, куда будут добавляться новые элементы на фронте.</p>\n\n\n\n<p id=\"5d91\"><strong>Кнопка&nbsp;</strong>— для сброса всех элементов.</p>\n\n\n\n<p id=\"19bd\">Добавьте этот код туда, где стоит комментарий&nbsp;<strong>&lt;! — more will go here — &gt;</strong></p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&lt;form>\n  &lt;input id=\"item\" type=\"text\" placeholder=\"New\" required />\n&lt;/form>\n&lt;h2>Items&lt;/h2>\n&lt;ul>&lt;/ul>\n&lt;button>Clear All&lt;/button></code></pre>\n\n\n\n<p>И вот, как всё это будет выглядеть.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"445\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_Ik5BF_Om2vH9MbxVWf0u7g.png\" alt=\"\" class=\"wp-image-201\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_Ik5BF_Om2vH9MbxVWf0u7g.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_Ik5BF_Om2vH9MbxVWf0u7g-300x191.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p>Далее мы сосредоточимся на написании функционала в JavaScript.</p>\n\n\n\n<h2 id=\"02ec\">Пишем функционал на JavaScript</h2>\n\n\n\n<p id=\"0d05\">Перед тем, как интегрировать всё это с локальным веб-хранилищем, давайте подцепим на JS форму и список, через которые мы хотим добавлять данные в input и выводить их в&nbsp;<code>ul</code>.</p>\n\n\n\n<p id=\"be63\">Для начала, я собираюсь объявить несколько переменных для элементов на странице.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const form = document.querySelector('form')\nconst ul = document.querySelector('ul')\nconst button = document.querySelector('button')\nconst input = document.getElementById('item')</code></pre>\n\n\n\n<p>Далее, я напишу функцию, которая создаст элемент&nbsp;<code>li</code>, так как этот функционал нам потребуется очень часто. Я назову функцию&nbsp;<code>liMaker()</code>. Она просто будет создавать элемент&nbsp;<code>li</code>, выставлять ему текст, который будет как параметр и добавлять созданный&nbsp;<code>li</code>&nbsp;в&nbsp;<code>ul</code>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const liMaker = text => {\n  const li = document.createElement('li')\n  li.textContent = text\n  ul.appendChild(li)\n}</code></pre>\n\n\n\n<p id=\"5117\">Далее, я собираюсь добавить прослушиватель события на форму, которая связана с&nbsp;<code>submit</code>&nbsp;— событие, которое будет происходить всякий раз, как мы нажмем на enter в форме.<code>e.preventDefault()</code>&nbsp;предотвратит отправку формы при сабмите, это нам не нужно, так как мы не собираемся отправлять никаких данных на сервер.</p>\n\n\n\n<p id=\"5373\">Вместо этого, форма отправит значение&nbsp;<code>input</code>. Мы вызовем функцию&nbsp;<code>liMaker()</code>, которая создаст элемент с текстом, который будет значением&nbsp;<code>input</code>&nbsp;и далее, мы добавим это в DOM. И под конец, мы выставим значение&nbsp;<code>input</code>&nbsp;на пустую строку, таким образом вам не придётся вручную стирать то, что вы только написали.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>form.addEventListener('submit', function(e) {\n  e.preventDefault()\nliMaker(input.value)\n  input.value = ''\n})</code></pre>\n\n\n\n<p>Теперь, с буквально пустяковым количеством кода на борту, мы имеем небольшое приложение, которое добавляет&nbsp;<strong>to-do</strong>&nbsp;элементы в список задач.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"445\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_7-eKeSTYTZf-ie6kDdz9oQ.png\" alt=\"\" class=\"wp-image-202\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_7-eKeSTYTZf-ie6kDdz9oQ.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_7-eKeSTYTZf-ie6kDdz9oQ-300x191.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p>Но, так как мы нигде не сохраняем наши данные, то при закрытии или обновлении браузера, введенные нами элементы исчезнут. Последним шагом будет интеграция нашего приложения с локальным хранилищем, для того, чтобы данные оставались в нём и после перезагрузки страницы, и после перезагрузки браузера.</p>\n\n\n\n<h2 id=\"08f6\">Интегрируем локальное хранилище</h2>\n\n\n\n<p id=\"805c\">Сейчас мы добавим немного функционала в наше приложение. Во первых, каждый раз, когда форму будут сабмитить, значение из&nbsp;<code>input</code>&nbsp;будет добавлено в&nbsp;<code>localStorage</code>&nbsp;вместе с мгновенным отображением в списке задач. Также, нам нужно будет пробежаться циклом по всему локальному хранилищу и показать элементы этого хранилища сверху списка существующих задач. Ну и под конец, мы добавим кнопку&nbsp;<em>“Clear All”</em>, которая удалит все элементы не только из локального хранилища, но и из списка&nbsp;<code>ul</code>.</p>\n\n\n\n<p id=\"318e\">Давайте сначала создадим пустой массив и создадим в&nbsp;<code>localStorage</code>&nbsp;ключ под названием&nbsp;<code>items</code>.&nbsp;<code>localStorage</code>&nbsp;в виде значений ключей принимает только строки, к тому же, нам надо хранить задачи в массиве.</p>\n\n\n\n<p id=\"bc03\">Мы можем обойти это ограничение с помощью&nbsp;<code>JSON.stringify()</code>, чтобы конвертировать массив в строку. А уже потом мы применим&nbsp;<code>JSON.parse()</code>&nbsp;для конвертирования содержимого&nbsp;<code>localStorage</code>&nbsp;в какой-нибудь рабочий формат, который мы положим в переменную&nbsp;<code>data</code>. Вставьте этот код под всем, что мы написали выше.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>let itemsArray = &#91;]\n\nlocalStorage.setItem('items', JSON.stringify(itemsArray))\nconst data = JSON.parse(localStorage.getItem('items'))</code></pre>\n\n\n\n<p>В слушателе событий мы будем отправлять каждое новое значение&nbsp;<code>input</code>&nbsp;в массив, а затем добавлять в&nbsp;<code>localStorage</code>&nbsp;новое значение с уже обновленным массивом.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>e.preventDefault()\nitemsArray.push(input.value)\nlocalStorage.setItem('items', JSON.stringify(itemsArray))</code></pre>\n\n\n\n<p>Далее, мы собираемся пробежаться по всему содержимому переменной&nbsp;<code>data</code>, которая содержит всё из нашего&nbsp;<code>localStorage</code>&nbsp;в таком виде, в котором мы можем работать с этими данным в JavaScript. Затем мы заново запустим&nbsp;<code>liMaker()</code>. Это покажет нам всю нужную информацию в списке при каждом открытии приложения.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>data.forEach(item => {\n  liMaker(item)\n})</code></pre>\n\n\n\n<p>И под конец мы добавим событие по клику на кнопку, которая очистит все данные из&nbsp;<code>localStorage</code>&nbsp;и удалит все потомков у&nbsp;<code>ul</code>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>button.addEventListener('click', function() {\n  localStorage.clear()\n  while (ul.firstChild) {\n    ul.removeChild(ul.firstChild)\n  }\n})</code></pre>\n\n\n\n<p>Если всё пройдет хорошо, то данные запишутся в хранилище и покажутся в списке задач, а само хранилище вы сможете проверить введя&nbsp;<code>localStorage</code>&nbsp;в консоли.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>Storage {items:\n\"&#91;\"Welcome\",\"to\",\"the\",\"Thunderdome\"]\",\n  length: 1}</code></pre>\n\n\n\n<p id=\"153d\">Но у нас осталась последняя проблема. После закрытия браузера или перезагрузки страницы, вся существующая информация в&nbsp;<code>localStorage</code>&nbsp;пропадает и ничего не остается на нашем фронте. Почему?</p>\n\n\n\n<p id=\"8669\">Потому, что наш&nbsp;<code>itemsArray</code>&nbsp;сбрасывается каждый раз при запуске скрипта. Мы можем пофиксить эту проблемку, создав условие, которое проверит наличие доступного&nbsp;<code>localStorage</code>:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>let items\nif (localStorage.getItem('items')) {\n  items = JSON.parse(localStorage.getItem('items'))\n} else {\n  items = &#91;]\n}</code></pre>\n\n\n\n<p>Практичнее было бы использовать тернарный оператор.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>let itemsArray = localStorage.getItem('items') ? JSON.parse(localStorage.getItem('items')) : &#91;]</code></pre>\n\n\n\n<p>Теперь наше приложение завершено. И когда вы вводите какую-либо информацию, а затем обновляете или закрываете окно браузера, данные будут на месте, пока вы самостоятельно не очистите их в настройках браузера или запустив команду&nbsp;<code>localStorage.clear()</code>. Ну а вот и полный код JavaScript.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const form = document.querySelector('form')\nconst ul = document.querySelector('ul')\nconst button = document.querySelector('button')\nconst input = document.getElementById('item')\nlet itemsArray = localStorage.getItem('items') ? JSON.parse(localStorage.getItem('items')) : &#91;]\nlocalStorage.setItem('items', JSON.stringify(itemsArray))\nconst data = JSON.parse(localStorage.getItem('items'))\nconst liMaker = text => {\n  const li = document.createElement('li')\n  li.textContent = text\n  ul.appendChild(li)\n}\nform.addEventListener('submit', function(e) {\n  e.preventDefault()\nitemsArray.push(input.value)\n  localStorage.setItem('items', JSON.stringify(itemsArray))\n  liMaker(input.value)\n  input.value = ''\n})\ndata.forEach(item => {\n  liMaker(item)\n})\nbutton.addEventListener('click', function() {\n  localStorage.clear()\n  while (ul.firstChild) {\n    ul.removeChild(ul.firstChild)\n  }\n})</code></pre>\n\n\n\n<h2 id=\"1a70\"><strong>Заключение</strong></h2>\n\n\n\n<p id=\"1b42\">В этом руководстве мы узнали о том, как сделать простое&nbsp;<strong>to-do</strong>&nbsp;приложение, которое можно использовать для быстрого напоминания о текущих задачах, просто вызвав новую вкладку, используя HTML5 веб-хранилище. Я надеюсь, что теперь у вас появилось лучшее понимание локального хранилища и того, как интегрировать его в простое приложение.</p>\n\n\n\n<p><em>Почитайте про применение localStorage в следующей статье &#8212; <a href=\"https://stasonmars.ru/javascript/ispolzuem-localstorage-v-react/\">Используем localStorage в React</a></em></p>\n","date":"2021-02-08T17:20:32.000Z","title":"Как работать с localStorage в JavaScript","id":"42102be2-be86-5b0e-be2a-ec67d8a54f09","excerpt":"<p>В этой статье вы узнаете о том, что такое localStorage и на рабочем примере узнаем то, как с ним работать в JavaScript.</p>\n","type":"js","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2021/02/localstoragejshowkjfndsk.jpg"}}},{"node":{"slug":"ispolzuem-localstorage-v-react","content":"\n<p>Как использовать преимущества localStorage в React? Да легко! В этой статье вы узнаете об удобстве применения локального хранилища в React приложениях.</p>\n\n\n\n<p class=\"author\"><em>Перевод&nbsp;</em><a href=\"https://programmingwithmosh.com/react/localstorage-react/\"><em>How to use localStorage with React</em></a></p>\n\n\n\n<p>Сердцем каждого приложения на React является его стейт. Компоненты могут иметь свой собственный внутренний стейт и поверьте мне, несмотря на всю их простоту, вы можете делать с ними много невероятно крутых вещей. Но давайте представим, что вы создаёте приложение и в какой-то момент вам надо локально сохранить данные от пользователя или даже сохранить весь стейт для одного или нескольких других компонентов. И тут, возможно, вам захочется понять, а как же можно использовать&nbsp;<code>localStorage</code>&nbsp;в React приложении? Что же, начнем с того, что&nbsp;<code>setState</code>&nbsp;тут вам уже не помощник, но не переживайте, все будет довольно просто. Читаем дальше.</p>\n\n\n\n<p>Если вы не знаете про то, как работает localStorage, то вот отличная статья &#8212; <a href=\"https://stasonmars.ru/javascript/kak-rabotat-s-localstorage-v-javascript/\">Как работать с localStorage в JavaScript</a></p>\n\n\n\n<h2 id=\"e9e6\"><strong>Веб хранилище</strong></h2>\n\n\n\n<p id=\"9b4d\">Оно создано для того, чтобы хранить данные в браузере и оно потерпело значительное количество позитивных улучшений в сравнении со своим предшественником — кукисами. Сначала оно было как&nbsp;<strong>HTML5 API</strong>, ну а потом переросло уже в независимую рабочую единицу. Хранилище поддерживается буквально каждым современным браузером и даже некоторыми старичками, например такими как IE8. Веб хранилище реализовано двумя способами: первый —&nbsp;<code>localStorage</code>, постоянное хранилище данных, которое можно сравнить с постоянными кукисами, второе —<code>&nbsp;sessionStorage</code>, хранилище существующее только на время определенной сессии и на определенный период времени. Хоть эта статья и работает с&nbsp;<code>localStorage</code>, но вы также можете применить все описанные методики и на sessionStorage.</p>\n\n\n\n<h2 id=\"cf0c\">Наш компонент для рабочего примера</h2>\n\n\n\n<p id=\"37b2\">Итак, нам нужен компонент на котором мы будем все испытывать. Тут я думаю, что страница логина с опцией “<strong>Remember me</strong>” подойдет идеально. Для простоты и понятности, мы не будем добавлять поле пароля. Давайте посмотрим на метод&nbsp;<code>render()</code>:</p>\n\n\n\n<pre class=\"wp-block-code jsx\"><code>render() {\n  return (\n    &lt;form onSubmit={this.handleFormSubmit}>\n      &lt;label>\n        User: &lt;input name=\"user\" value={this.state.user} onChange={this.handleChange}/>\n      &lt;/label>\n      &lt;label>\n        &lt;input name=\"rememberMe\" checked={this.state.rememberMe} onChange={this.handleChange} type=\"checkbox\"/> Remember me\n      &lt;/label>\n      &lt;button type=\"submit\">Sign In&lt;/button>\n    &lt;/form>\n  );\n}</code></pre>\n\n\n\n<p>Как вы видите, это довольно простая форма с двумя инпутами и кнопкой. Код который должен обрабатывать стейт также очень легко понять:</p>\n\n\n\n<pre class=\"wp-block-code jsx\"><code>export default class SignIn extends Component {\n  state = {\n    user: '',\n    rememberMe: false\n  };\n \n  handleChange = (event) => {\n    const input = event.target;\n    const value = input.type === 'checkbox' ? input.checked : input.value;\n \n    this.setState({ &#91;input.name]: value });\n  };\n \n  handleFormSubmit = () => {};\n \n  render() { /*...*/ }\n}</code></pre>\n\n\n\n<p>В примере кода выше мы используем метод&nbsp;<code>setState</code>, чтобы сохранять актуальность стейта при каждом изменении в форме. Если вы запустите проект, то вот, что получите:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"351\" height=\"38\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_oSfU_wl3WttGAdZLUMH7Hg.png\" alt=\"\" class=\"wp-image-195\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_oSfU_wl3WttGAdZLUMH7Hg.png 351w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_oSfU_wl3WttGAdZLUMH7Hg-300x32.png 300w\" sizes=\"(max-width: 351px) 100vw, 351px\" /></figure>\n\n\n\n<p>Если вы заполните инпут для пользователя, а потом кликните на “<strong>Remember Me</strong>” чекбокс и под конец кликните на кнопку “<strong>Sign In</strong>”, то вы заметите, что форма снова опустеет:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"352\" height=\"28\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_gU6mXtUg4pfzPUOyYwJRgQ.gif\" alt=\"\" class=\"wp-image-196\"/></figure>\n\n\n\n<p>Это вполне нормальное поведение. Теперь мы должны узнать как же нам использовать&nbsp;<code>localStorage</code>&nbsp;в React и заставить форму работать должным образом.</p>\n\n\n\n<h2 id=\"a431\">Шаг 1: Сохраняем данные в localStorage</h2>\n\n\n\n<p id=\"923b\">В нашем примере нужно сохранить две вещи:</p>\n\n\n\n<p id=\"6d3f\">Значение опции&nbsp;<strong>Remember Me</strong></p>\n\n\n\n<p id=\"0cc4\">Имя пользователя, но только в том случае, если кликнули на опцию&nbsp;<strong>Remember Me</strong></p>\n\n\n\n<p id=\"a55c\">Для этих значений идеальным местом является метод&nbsp;<code>handleFormSubmit</code>:</p>\n\n\n\n<pre class=\"wp-block-code jsx\"><code>handleFormSubmit = () => {\n  const { user, rememberMe } = this.state;\n  localStorage.setItem('rememberMe', rememberMe);\n  localStorage.setItem('user', rememberMe ? user : '');\n};</code></pre>\n\n\n\n<p id=\"67db\">Что же происходит в этом методе?</p>\n\n\n\n<p id=\"95ad\">Сначала мы назначаем две переменные с помощью&nbsp;<a href=\"https://medium.com/@stasonmars/%D0%B4%D0%B5%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F-%D0%B2-es6-%D0%BF%D0%BE%D0%BB%D0%BD%D0%BE%D0%B5-%D1%80%D1%83%D0%BA%D0%BE%D0%B2%D0%BE%D0%B4%D1%81%D1%82%D0%B2%D0%BE-b865bb71f376\">деструктуризации</a></p>\n\n\n\n<p id=\"921e\">Далее, мы вызываем метод&nbsp;<code>localStorage.setItem</code>, чтобы хранить значение опции “<strong>Remember Me</strong>”.</p>\n\n\n\n<p id=\"3757\">И под конец мы сохраняем имя пользователя, но только в том случае, когда “<strong>Remember Me</strong>” выставлено на&nbsp;<code>true</code>.</p>\n\n\n\n<p id=\"b6a3\">Вот, что пока что у нас есть:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"600\" height=\"299\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_frlHF1ib5IHelm8clpXYYw.gif\" alt=\"\" class=\"wp-image-197\"/></figure>\n\n\n\n<p>Итак, полдела сделано. Теперь нам надо получить эти значения для компонента.</p>\n\n\n\n<h2 id=\"c2d0\">Шаг 2: Получаем данные из localStorage</h2>\n\n\n\n<p id=\"c54a\">Всё логику получения данных мы положим в&nbsp;<code>componentDidMount</code>, но вы можете спокойно положить её и в конструктор, если конечно захотите, так как её первоочередная цель — это выставление изначального стейта нашему компоненту.</p>\n\n\n\n<p id=\"02b7\">Обратите внимание, что вы не можете вызывать&nbsp;<code>setState</code>&nbsp;перед тем, как компонент монтируется, так что, если вы предпочитаете подход с конструктором, то выставьте свойство стейта напрямую. Я же предпочитаю аккуратный подход к коснтуктору, настолько аккуратный насколько это возможно, но это дело предпочтений.</p>\n\n\n\n<pre class=\"wp-block-code jsx\"><code>componentDidMount() {\n  const rememberMe = localStorage.getItem('rememberMe') === 'true';\n  const user = rememberMe ? localStorage.getItem('user') : '';\n  this.setState({ user, rememberMe });\n}</code></pre>\n\n\n\n<p id=\"464b\">Теперь давайте углубимся в код:</p>\n\n\n\n<p id=\"ca3b\">Первым делом мы получаем значение “<strong>Remember me</strong>”. Уже обратили внимание, что сравнение идёт со строкой “true”? Это потому что&nbsp;<code>localStorage</code>&nbsp;хранит данные как строки. Таким образом нам надо получить хранящееся значение и запарсить его обратно в логический тип данных, перед его непосредственным использованием. Вы бы также могли использовать&nbsp;<code>JSON.parse</code>, если бы были точно уверены в том, что там всегда будет храниться булево значение в виде строки. Но сейчас это нам не подойдет, так как само значение не выставлено при инициализации страницы.</p>\n\n\n\n<p id=\"dbd9\">Далее мы получаем имя пользователя, но только в том случае, если&nbsp;<code>remeberMe</code>&nbsp;имеет значение&nbsp;<code>true</code>.</p>\n\n\n\n<p id=\"06b4\">И под конец мы назначаем эти значения стейту компонента.</p>\n\n\n\n<p id=\"13b1\">И вот она магия!</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"600\" height=\"290\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_udpa03U52IDahtMogbbOiQ.gif\" alt=\"\" class=\"wp-image-198\"/></figure>\n\n\n\n<h2 id=\"88b1\">И ещё советик</h2>\n\n\n\n<p id=\"1e96\">Как я говорил выше,&nbsp;<code>localStorage</code>&nbsp;может хранить данные только в виде строк. Если вы имеете дело только с несколькими сохраненными значениями, то это не очень то и большая проблема. Но если вы хотите воспользоваться&nbsp;<code>localStorage</code>&nbsp;на полную катушку в вашем приложении, то я очень советую взять на вооружение библиотеку, которая облегчит сохранение и получение данных, обойдя стороной такие процессы, как парсинг и обращение в строку. В этом деле идеально может подойти проверенная в боях&nbsp;<a href=\"https://github.com/marcuswestin/store.js/\">Store.js</a>. Это моя личная рекомендация.</p>\n\n\n\n<h2 id=\"b7ea\">Заключение</h2>\n\n\n\n<p id=\"3a15\">В React&nbsp;<code>localStorage</code>&nbsp;очень просто использовать. Просто определите в каких случаях лучше сохранять и получать свои данные. Этот момент будет меняться от компонента к компоненту.</p>\n\n\n\n<p id=\"8e74\">Вообще, вы можете давать данные компонентам, как и через конструктор, так и через&nbsp;<code>componentDidMount</code>. Но учтите, что если вы собираетесь использовать конструктор, то вам надо определять стейт заранее, напрямую указав его свойства, так как&nbsp;<code>setState</code>&nbsp;метод не сработает пока не смонтируется компонент.</p>\n\n\n\n<p id=\"3744\">Если вам нужна хорошая библиотека для работы со значениями&nbsp;<code>localStorage</code>, то рассмотрите использование&nbsp;<a href=\"https://github.com/marcuswestin/store.js/\">Store.js</a>.</p>\n","date":"2021-02-08T15:11:36.000Z","title":"Используем localStorage в React","id":"9245901e-e7f4-50e1-ac50-cd5e0f8b1321","excerpt":"<p>Как использовать преимущества localStorage в React? Да легко! В этой статье вы узнаете об удобстве применения локального хранилища в React приложениях.</p>\n","type":"js","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2021/02/localStorageReactkfk.jpg"}}},{"node":{"slug":"12-luchih-i-prosih-praktik-v-react-kotorih-stoit-priderzhivatsya-v-2020-godu","content":"\n<p id=\"d17a\">В этой статье собраны 12 простых и хороших практик при работе в React, которых стоит придерживаться, имея дело с этой библиотекой в 2020 году.</p>\n\n\n\n<p class=\"author\" id=\"e9ba\"><em>Перевод статьи&nbsp;</em><a href=\"https://www.codeinwp.com/blog/react-best-practices/\"><em>12 React Best Practices You Need to Follow in 2020</em></a></p>\n\n\n\n<p id=\"1e54\">Если вы фронтэнд разработчик, вовлеченный в создание интерактивных пользовательских интерфейсов, то скорее всего вы работаете с React. Имея дело с проектами на этой библиотеке нужно быть крайне осторожным в написании кода таким образом, чтобы следовать лучшим практикам React, которые помогут лучше организовать ваш код.</p>\n\n\n\n<p id=\"2b41\">Как&nbsp;вы уже знаете, React это библиотека созданная в Facebook и она допускает интеграцию в&nbsp;<a href=\"https://www.codeinwp.com/blog/react-ui-component-libraries-frameworks/\">множеством уже готовых и интересных компонентов</a>. По факту, любой разработчик может создать свои собственные компоненты и сделать их доступными для сообщества.</p>\n\n\n\n<p id=\"fe76\">Но сегодня мы заострим внимание на самых основных из лучших практик при работе в React:</p>\n\n\n\n<h2 id=\"b182\">1. Делайте компоненты небольшими и отвечающими за конкретный функционал</h2>\n\n\n\n<p id=\"c576\">Как мы уже все знаем, в React можно создавать большие компоненты, которые будут выполнять несколько задач. Но лучше всего создавать компоненты, оставляя их небольшими, таким образом, чтобы каждый компонент отвечал за конкретный функционал. В идеале компонент должен рендерить конкретную часть вашей страницы или отвечать за определенное поведение. Вот несколько преимуществ такого подхода:</p>\n\n\n\n<p id=\"a9f2\">Такие компоненты существуют сами по себе, что делает их тестирование и поддержку гораздо проще.</p>\n\n\n\n<p id=\"e96d\">Каждый небольшой компонент может быть повторно использован на нескольких проектах.</p>\n\n\n\n<p id=\"1066\">Компоненты выполняющие общие функции можно легко сделать доступными на любого сообщества.</p>\n\n\n\n<p id=\"ba0b\">В небольших компонентах проще делать оптимизацию производительности.</p>\n\n\n\n<p id=\"0e0c\">Такие компоненты проще обновлять.</p>\n\n\n\n<p id=\"0831\">Большие компоненты нагружены в плане производительности и их может быть довольно тяжело поддерживать.</p>\n\n\n\n<p id=\"6ecb\">Баланс между созданием одного сжатого компонента и созданием нескольких, отвечающих только за свой функционал компонентов, может варьироваться от компании к компании. Но все же, вы можете наделать столько компонентов, сколько хотите и комбинировать их таким способом, чтобы достигнуть желаемого результата.</p>\n\n\n\n<h2 id=\"05f8\"><strong>2. Повторное использование это важный момент, старайтесь довести создание новых компонентов до возможного минимума</strong></h2>\n\n\n\n<p id=\"e5e3\">Придерживаясь правила “<em>одна функция = один компонент</em>”, вы можете улучшить повторное использование компонентов. Это означает то, что вам стоит избегать попыток создания новых компонентов для функционала, который уже существует в виде другой, уже готовой функции.</p>\n\n\n\n<p id=\"92cf\">Повторно используя компоненты по всему вашему проекту или по нескольким проектам, вы не только вы обретете связность и логичность в ваших проектах, но это также поможет и другим людям работающим с вашим кодом.</p>\n\n\n\n<p id=\"37a1\">С другой стороны, если любой компонент становится большим, громоздким и сложным в поддержке, то лучше всего разбить его на столько маленьких компонентов, насколько это возможно.</p>\n\n\n\n<p id=\"5b5f\">Для примера, вы можете создать компонент&nbsp;<code>Button</code>, который может принимать только нужные ему иконки. И каждый раз, когда вам понадобится кнопка, у вас уже будет под рукой нужный компонент. Модульный подход позволит вам покрыть множество рабочих моментов, применяя один и тот же кусок кода.&nbsp;<em>Вам нужно стремиться к золотой середине</em>. Компоненты должны быть достаточно абстрактными, но не очень уж загруженными.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>class IconButton extends React.Component {\n  &#91;...]\n  render() {\n    return (\n      &lt;button onClick={this.props.onClick()}>\n        &lt;i class={this.props.iconClass}>&lt;/i>\n      &lt;/button>\n    );\n  }\n}</code></pre>\n\n\n\n<h2 id=\"f9a8\">3. Консолидируйте повторяющийся код — придерживайтесь правила DRY (Don’t Repeat Yourself)</h2>\n\n\n\n<p id=\"6a6c\">Общее правило для написания любого кода — это держать его сжатым и стараться не раздувать по мере возможности.</p>\n\n\n\n<p id=\"e255\">Это собственно и есть одна из лучших практик React.&nbsp;<em>Избегайте дубликатов кода — ну или Don’t Repeat Yourself (DRY).</em></p>\n\n\n\n<p id=\"4660\">Этого можно достичь тщательно изучив код на паттерны и на повторения. Если таковые имеются, то возможно вы повторяете свой код и у вас явно есть место где нужно пресечь такое повторение. Скорее всего, немного переписав код, вы сделаете его более сжатым и оставите таким же понятным.</p>\n\n\n\n<p id=\"c9f9\">Этот момент опирается на принцип повторного использования в React. Давайте представим, что вам нужно добавить несколько кнопок, которые содержат в себе иконки, а вместо добавления разметки для каждой кнопки, вы можете просто применить компонент&nbsp;<code>IconButton</code>, показанный ниже. Вы можете зайти ещё дальше, отобразив все нужные кнопки с помощью массива с уже заготовленными для них данными.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const buttons = &#91;'facebook', 'twitter', 'youtube'];\n\nreturn (\n  &lt;div>\n    {\n      buttons.map( (button) => {\n        return (\n          &lt;IconButton\n            onClick={doStuff( button )}\n            iconClass={button}\n          />\n        );\n      } )\n    }\n  &lt;/div>\n);</code></pre>\n\n\n\n<h2 id=\"39b0\">4. Добавляйте комментарии только там, где это действительно нужно</h2>\n\n\n\n<p id=\"71df\">И ещё раз, добавляйте их только там, где это действительно нужно. Это касается не только React, таким образом вы убьете сразу двух зайцев:</p>\n\n\n\n<p id=\"2652\"><em>Ваш код визуально будет чист и приведен в порядок.</em></p>\n\n\n\n<p id=\"a6ac\"><em>Вы избежите потенциального конфликта между кодом и комментариями, если вам в будущем понадобится переписать код.</em></p>\n\n\n\n<h2 id=\"785b\">5. Именуйте компоненты в соответствии с их функционалом</h2>\n\n\n\n<p id=\"dbdb\">Это вообще хорошая идея, называть компоненты в соответствии с тем, что они делают, так вам проще будет их распознать в структуре приложения.</p>\n\n\n\n<p id=\"e425\">Ещё один пример, в котором предпочтительнее назвать компонент&nbsp;<code>Avatar</code>, так как он может использоваться везде в приложении — для авторов, пользователей или в комментариях. А вот если мы назовем компонент&nbsp;<code>AuthorAvatar</code>, сугубо в контексте использования, то мы как бы сократим полезность этого компонента до применения только у авторов.</p>\n\n\n\n<p id=\"e6c0\">Ну и более того, именование компонентов в соответствии с их функционалом станет полезными моментом для работы с любой командой или сообществом, сделав этот компонент доступнее в плане поиска.</p>\n\n\n\n<h2 id=\"0148\">6. Называйте компоненты с заглавной буквы</h2>\n\n\n\n<p id=\"c151\">Если вы, как и большинство других, используете JSX, то имена компонентов, создаваемых вами должны начинаться с заглавной буквы. К примеру, вам нужно называть компоненты как&nbsp;<code>SelectButton</code>, а не&nbsp;<code>selectbutton</code>&nbsp;или&nbsp;<code>Menu</code>, а не&nbsp;<code>menu</code>. Это делается для того, чтобы JSX определял их отдельно от стандартных HTML тегов.</p>\n\n\n\n<p id=\"dde7\">В ранних версиях React был список встроенных имён, чтобы различить их от кастомных названий. Но так как такому списку нужна была постоянная поддержка и обновления, этот подход был пересмотрен и заглавные буквы стали нормой.</p>\n\n\n\n<p id=\"cbd5\">Если же JSX не ваш выбор, то вы можете использовать буквы нижнего регистра. Но это может сократить возможность повторного использования компонентов по всему проекту.</p>\n\n\n\n<h2 id=\"64c8\">7. Разделяйте аспекты связанные со сменой стейта от рендеринга</h2>\n\n\n\n<p id=\"aa81\">Компоненты бывают со стейтом и без. Первые могут хранить информацию о стейте компонента и передавать необходимый контекст. А вторые, в свою очередь, не имеют памяти и не могут передавать контекст другим частям пользовательского интерфейса. Они только получают пропсы от родительских компонентов и отдают вам JSX элементы. Они масштабируемы и готовы к повторному использованию, а так же схожи с чистыми функциями в JavaScript.</p>\n\n\n\n<p id=\"a19b\">Одной из лучших практик в React является хранение состояния логики загрузки данных отдельно от рендеринга любой логики без стейта. Лучше всего иметь один компонент со стейтом, чтобы подгружать данные и ещё один компонент, но уже без стейта, чтобы эти данные выводить. Такой подход сократит запутанность среди компонентов.</p>\n\n\n\n<p id=\"128b\">Последние версии React 16.8 имеют на борту новую фичу, а именно хуки. Которые могут в конечном итоге вообще помочь избавиться от компонентов, основанных на классах.</p>\n\n\n\n<p id=\"ad48\">Для примера, ваше приложение подтягивает данные после монтирования. Тут вам нужно управлять данными с основном компоненте и передать комплексный таск на рендер подкомпоннету, но в виде пропса.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>import RenderTable from './RenderTable';\n\nclass Table extends Component {\n  state = { loading: true };\n\n  render() {\n    const { loading, tableData } = this.state;\n    return loading ? &lt;Loading/> : &lt;RenderTable data={tableData}/>;\n  }\n\n  componentDidMount() {\n    fetchTableData().then( tableData => {\n      this.setState( { loading: false, tableData } );\n    } );\n  }\n}</code></pre>\n\n\n\n<h2 id=\"4dd8\">8. Код должен выполняться как и от него ожидается, а также быть готовым к тестированию</h2>\n\n\n\n<p id=\"dbe8\">Ну тут реально, уже не надо никаких объяснений. Ваш код должен вести себя так, как от него и ожидают, а также должен быть готовым к тестированию в любой момент. Хорошей практикой является именование тестовых файлов также, как и исходных файлов, но с суффиксом&nbsp;<code>.test</code>.</p>\n\n\n\n<p id=\"5279\">Вы можете использовать&nbsp;<em>JEST</em>&nbsp;для тестирования вашего кода в React.</p>\n\n\n\n<h2 id=\"0dcd\"><strong>9. Все относящиеся к компоненту файлы должны находиться в одном месте</strong></h2>\n\n\n\n<p id=\"e7f1\">Держите все файлы для одного компонента в одной папке, даже включая файлы стилей.</p>\n\n\n\n<p id=\"a632\">В случае, если маленький компонент используется другим компонентом и только им, то есть смысл хранить такие компоненты вместе, в папке родительского компонента. Такую иерархию потом будет легче понять — большие компоненты имеют свои собственные директории, а все их мелкие части разделены на поддиректории. Таким образом вы можете легко извлечь нужный код в любой другой проект или улучшить его при малейшей надобности.</p>\n\n\n\n<p id=\"b0c2\">Для примера, для компонента&nbsp;<code>Form</code>, все составляющие части, такие как CSS файлы, иконки, изображения, тесты и любые прилегающие компоненты, относящиеся к&nbsp;<code>Form</code>, должны находиться в одной и той же папке. Если вы именуете файлы с умом и держите все относящиеся друг к другу файлы вместе, согласно логическому порядку, то у вас не будет проблем в их последующем поиске.</p>\n\n\n\n<h2 id=\"51e1\">10.&nbsp;<strong>Используйте инструменты, такие как Bit</strong></h2>\n\n\n\n<p id=\"377d\">Одной из лучших практик работы в React, которая поможет вам организовать ваши компоненты, это использование таких инструментов как Bit.</p>\n\n\n\n<p id=\"d24d\">Подобные сервисы помогают поддерживать и переиспользовать код. Более того, они помогают коду быть более доступным и способствуют коллективной разработке компонентов. Также, код может быть легко синхронизирован среди компонентов.</p>\n\n\n\n<h2 id=\"0791\"><strong>11. Библиотеки примеров кода</strong></h2>\n\n\n\n<p id=\"d5fb\">Сниппеты кода помогут вам оставаться на одной волне с лучшим кодом и самым продвинутом синтаксисом. Также они помогают вам относительно избавиться от багов, что делает их одной из лучших практик в React, которые вам явно не стоит пропускать.</p>\n\n\n\n<p id=\"7cf7\">Вообще, существует множество библиотек сниппетов, которые вы можете смело использовать, например ES7 React, Redux, JS Snippets и т.п.</p>\n\n\n\n<h2 id=\"c307\">12. Соблюдайте правила линтинга, разбивайте слишком длинные строки</h2>\n\n\n\n<p id=\"f951\">Линтинг это процесс в котором мы запускаем программу, анализирующую код на потенциальные ошибки.</p>\n\n\n\n<p id=\"27db\">В основном мы используем его для работы с конкретными языками. Но также мы можем фиксить и другие проблемы полностью автоматически, особенно со стилем написания кода. Используя линтер в React, мы делаем наш код относительно свободным от ошибок и багов.</p>\n\n\n\n<h2 id=\"483d\">Последние слова о лучших практиках React</h2>\n\n\n\n<p id=\"cc44\">Я надеюсь, что этот список лучших практик поможет вам правильно наладить работу с вашими проектами и избежать потенциальных проблем.</p>\n","date":"2021-02-05T14:49:21.000Z","title":"12 лучших и простых практик в React, которых стоит придерживаться в 2020 году","id":"49bb3e2d-911e-5bc7-8c6e-cebf5ad58b0a","excerpt":"<p>В этой статье собраны 12 простых и хороших практик при работе в React, которых стоит придерживаться, имея дело с этой библиотекой в 2020 году.</p>\n","type":"js","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2021/02/reactpractice2020fjs.jpg"}}},{"node":{"slug":"pogruzhaemsya-v-raboty-s-children-na-react","content":"\n<p>В этой статье мы погрузимся в работу с&nbsp;<code>children</code>&nbsp;на React и узнаем как можно с ними работать на реальных примерах.</p>\n\n\n\n<p class=\"author\"><em>Перевод&nbsp;</em><a href=\"https://mxstbr.blog/2017/02/react-children-deepdive/#child-components\"><em>A deep dive into children in React</em></a></p>\n\n\n\n<p id=\"1e54\">Основа React это компоненты. Вы можете вкладывать компоненты друг в друга также, как вы вкладываете друг в друга HTML теги, что упрощает работу с JSX, который собственно и напоминает HTML.</p>\n\n\n\n<p id=\"baa2\">Когда я впервые увидел React, то я подумал, что нужно просто использовать&nbsp;<code>props.children</code>&nbsp;и дело в шляпе. Но как же сильно я ошибался.</p>\n\n\n\n<p id=\"0bb8\">Так как мы работаем с JavaScript, то мы можем делать с дочерними элементами (<code>children</code>) буквально всё, что угодно. Мы можем смело задавать им конкретные свойства, решать нужно ли их рендерить, ну и конечно же, управлять ими так, как нам надо. Так что дело это полезное и уж давайте при случае как можно глубже познаем всю прелесть работы с&nbsp;<code>children</code>&nbsp;на React.</p>\n\n\n\n<p id=\"9ff5\">Поехали!</p>\n\n\n\n<h2 id=\"75c4\">Дочерние компоненты</h2>\n\n\n\n<p id=\"7de1\">Предположим, что у нас есть компонент&nbsp;<code>&lt;Grid /&gt;</code>, который может содержать в себе компоненты&nbsp;<code>&lt;Row /&gt;</code>. Мы бы написали это так:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>&lt;Grid>\n  &lt;Row />\n  &lt;Row />\n  &lt;Row />\n&lt;/Grid></code></pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"256\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_8qVzwdrogSF1hK-plv86bw.png\" alt=\"\" class=\"wp-image-183\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_8qVzwdrogSF1hK-plv86bw.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_8qVzwdrogSF1hK-plv86bw-300x110.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p>Эти три компонента&nbsp;<code>Row</code>&nbsp;передаются компоненту&nbsp;<code>Grid</code>&nbsp;как&nbsp;<code>props.children</code>. Используя контейнер для выражения (<em>expression container это технический термин для этих волнистых скобок в JSX</em>) родители могут рендерить свои дочерние элементы:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>class Grid extends React.Component {\n  render() {\n    return &lt;div>{this.props.children}&lt;/div>\n  }\n}</code></pre>\n\n\n\n<p>Родительские элементы также могут и не рендерить своих потомков или могут производить с ними какие-либо действия перед рендерингом. Для примера, этот компонент.&nbsp;<code>&lt;Fullstop /&gt;</code>&nbsp;вообще не будет рендерить свои дочерние элементы:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>class Fullstop extends React.Component {\n  render() {\n    return &lt;h1>Hello world!&lt;/h1>\n  }\n}</code></pre>\n\n\n\n<p id=\"87dd\">Совершенно неважно какие дочерние элементы будут переданы этому компоненту, он просто будет всегда показывать&nbsp;<code>\"Hello world!\"</code>&nbsp;и ничего более.</p>\n\n\n\n<p id=\"13b1\">Обратите внимание, что&nbsp;<code>h1</code>&nbsp;в примере выше рендерит свои дочерние элементы, в нашем случае это&nbsp;<code>\"Hello world!\"</code>.</p>\n\n\n\n<h3 id=\"b980\"><strong>Дочерним элементом может быть все, что угодно</strong></h3>\n\n\n\n<p id=\"d383\"><code>Children</code>&nbsp;в React не обязательно быть компонентами, они могут быть всем, чем угодно. Для примера, мы можем передать нашему вышеупомянутому компоненту&nbsp;<code>&lt;Grid /&gt;</code>&nbsp;какой-либо текст в виде&nbsp;<code>children</code>&nbsp;и всё будет прекрасно работать:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&lt;Grid>Hello world!&lt;/Grid></code></pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"69\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_BMyhht5dTdh2ncWJLdLezA.png\" alt=\"\" class=\"wp-image-184\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_BMyhht5dTdh2ncWJLdLezA.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_BMyhht5dTdh2ncWJLdLezA-300x30.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p id=\"fe2c\">JSX автоматически удалит пробелы вначале и конце строки, а вместе с ними и пустые строки. Также пустые строки в середине строкового литерала преобразуются в один пробел.</p>\n\n\n\n<p id=\"97a9\">Это означает то, что все эти примеры ниже отрендерят одно и тоже:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&lt;Grid>Hello world!&lt;/Grid>\n\n&lt;Grid>\n  Hello world!\n&lt;/Grid>\n\n&lt;Grid>\n  Hello\n  world!\n&lt;/Grid>\n\n&lt;Grid>\n\n  Hello world!\n&lt;/Grid></code></pre>\n\n\n\n<p>Вы также можете смежно использовать разные типы дочерних элементов:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&lt;Grid>\n  Here is a row:\n  &lt;Row />\n  Here is another row:\n  &lt;Row />\n&lt;/Grid></code></pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"265\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_g2Uq7Sd2nUKpCceozwKqjw.png\" alt=\"\" class=\"wp-image-185\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_g2Uq7Sd2nUKpCceozwKqjw.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_g2Uq7Sd2nUKpCceozwKqjw-300x114.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<h3 id=\"ff04\"><strong>Функция как дочерний элемент</strong></h3>\n\n\n\n<p id=\"7f02\">Мы можем передать любое JavaScript выражение, как дочерний элемент. И функции не исключение.</p>\n\n\n\n<p id=\"03c1\">Чтобы показать то, как это выглядит, посмотрите на этот компонент, который выполняет функцию, которая была передана как дочерний элемент:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>class Executioner extends React.Component {\n  render() {\n    // Обратите внимание на то, как мы вызываем дочерний элемент,    как функцию?\n    // ↓\n    return this.props.children()\n  }\n}</code></pre>\n\n\n\n<p>Вы бы могли вызвать этот компонент так:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&lt;Executioner>\n  {() => &lt;h1>Hello World!&lt;/h1>}\n&lt;/Executioner></code></pre>\n\n\n\n<p id=\"b1be\">Это конечно не совсем пригодный пример, но он показывает саму идею.</p>\n\n\n\n<p id=\"a28d\">Представьте, что вам надо подтянуть какие-либо данные с сервера. Вы могли бы сделать это несколькими способами и это возможно сделать с этим&nbsp;<em>function-as-a-child</em>&nbsp;паттерном:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&lt;Fetch url=\"api.myself.com\">\n  {(result) => &lt;p>{result}&lt;/p>}\n&lt;/Fetch></code></pre>\n\n\n\n<p>Не переживайте, если код выше смутил вас. Все, что я хотел сделать это то, чтобы вы не удивились увидев нечто подобное в реальной жизни. С&nbsp;<code>children</code>&nbsp;возможно всё.</p>\n\n\n\n<h2 id=\"3724\"><strong>Управление children</strong></h2>\n\n\n\n<p id=\"27ab\">Если вы посмотрите на документацию React, то вы увидите там , что “<em>children это непрозрачная структура данных</em>”. На самом деле они нам говорят о том, что&nbsp;<code>props.children</code>&nbsp;может быть любым типом данных, например таким как массив, функция, объект и тп. В общем, это может быть всем чем угодно.</p>\n\n\n\n<p id=\"d690\">В React есть несколько вспомогательных функций, которые могут помочь управлять&nbsp;<code>children</code>&nbsp;довольно легко и без лишних заморочек. Доступны они в&nbsp;<code>React.Children</code>.</p>\n\n\n\n<h3><strong>Проходимся циклом по</strong> children</h3>\n\n\n\n<p>Две самых очевидных из вышеупомянутых функций это&nbsp;<code>React.Children.map</code>&nbsp;и&nbsp;<code>React.Children.forEach</code>. Они работают так же как и их коллеги из методов массивов, за исключением того, что они также работают в момент передачи функции, объекта или чего-нибудь ещё непосредственно в&nbsp;<code>children</code>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>class IgnoreFirstChild extends React.Component {\n  render() {\n    const children = this.props.children\n    return (\n      &lt;div>\n        {React.Children.map(children, (child, i) => {\n          // игнорируем первого потомка\n          if (i &lt; 1) return\n          return child\n        })}\n      &lt;/div>\n    )\n  }\n}</code></pre>\n\n\n\n<p><code>&lt;IgnoreFirstChild /&gt;</code>&nbsp;компонент из кода выше, проходится по всем своим потомкам, игнорируя первый и возвращая всех остальных.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&lt;IgnoreFirstChild>\n  &lt;h1>First&lt;/h1>\n  &lt;h1>Second&lt;/h1> // &lt;- Only this is rendered\n&lt;/IgnoreFirstChild></code></pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"68\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_XAaXg_Pz8VUymyCAOAXoVw.png\" alt=\"\" class=\"wp-image-186\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_XAaXg_Pz8VUymyCAOAXoVw.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_XAaXg_Pz8VUymyCAOAXoVw-300x29.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p>В нашем случае мы бы могли также использовать&nbsp;<code>this.props.children.map</code>. Но чтобы произошло в случае, когда кто-нибудь бы передал функцию как потомка?&nbsp;<code>this.props.children</code>&nbsp;был бы функцией, а не массивом и мы бы словили ошибку.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"40\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_WxuWukVXXs5AJ4zfIi4Ltg.png\" alt=\"\" class=\"wp-image-187\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_WxuWukVXXs5AJ4zfIi4Ltg.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_WxuWukVXXs5AJ4zfIi4Ltg-300x17.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p>Но а с&nbsp;<code>React.Children.map</code>&nbsp;это не будет вообще проблемой:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&lt;IgnoreFirstChild>\n  {() => &lt;h1>First&lt;/h1>} // &lt;- Ignored 💪\n&lt;/IgnoreFirstChild></code></pre>\n\n\n\n<h3 id=\"6247\">Считаем children</h3>\n\n\n\n<p id=\"b944\">Так как&nbsp;<code>this.props.children</code>&nbsp;может быть совершенно любым типом данных, проверка количества потомков у компонента может быть довольно сложным процессом. Наивно написав&nbsp;<code>this.props.children.length</code>&nbsp;вы получите 12, если станете проверять строку&nbsp;<code>\"Hello World!\"</code>, хоть там и будет один потомок.</p>\n\n\n\n<p id=\"036b\">Именно поэтому у нас и есть&nbsp;<code>React.Children.count</code>:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>class ChildrenCounter extends React.Component {\n  render() {\n    return &lt;p>React.Children.count(this.props.children)&lt;/p>\n  }\n}</code></pre>\n\n\n\n<p>Так мы получим количество потомков, вне зависимости от их типа данных:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// Renders \"1\"\n&lt;ChildrenCounter>\n  Second!\n&lt;/ChildrenCounter>\n\n// Renders \"2\"\n&lt;ChildrenCounter>\n  &lt;p>First&lt;/p>\n  &lt;ChildComponent />\n&lt;/ChildrenCounter>\n\n// Renders \"3\"\n&lt;ChildrenCounter>\n  {() => &lt;h1>First!&lt;/h1>}\n  Second!\n  &lt;p>Third!&lt;/p>\n&lt;/ChildrenCounter></code></pre>\n\n\n\n<h3 id=\"5702\">Конвертируем children в массив</h3>\n\n\n\n<p id=\"8415\">Ну и под конец, если ни один из методов выше вам не подходит, то вы можете конвертировать&nbsp;<code>children</code>&nbsp;в массив при помощи метода&nbsp;<code>React.Children.toArray</code>. Это было бы полезно в случае сортировки, например:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>class Sort extends React.Component {\n  render() {\n    const children = React.Children.toArray(this.props.children)\n    return &lt;p>{children.sort().join(' ')}&lt;/p>\n  }\n}\n&lt;Sort>\n  // Тут мы используем контейнеры выражений, чтобы убедиться в том,    что наши строки\n  // переданы как три отдельных потомка, а не как одна строка\n  {'bananas'}{'oranges'}{'apples'}\n&lt;/Sort></code></pre>\n\n\n\n<p id=\"b88c\">Пример выше рендерит строки, но уже отсортированные:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"70\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_KuWvpsCo-OlyVOt6sMtXyQ.png\" alt=\"\" class=\"wp-image-188\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_KuWvpsCo-OlyVOt6sMtXyQ.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_KuWvpsCo-OlyVOt6sMtXyQ-300x30.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p id=\"a6e1\">Обратите внимание, что возвращаемый&nbsp;<code>React.Children.toArray</code>&nbsp;массив не содержит потомков с типом функция, а только&nbsp;<code>React.Element</code>&nbsp;или строки.</p>\n\n\n\n<h3 id=\"7457\"><strong>Один единственный потомок</strong></h3>\n\n\n\n<p id=\"abbc\">Если вы вспомните о предыдущем компоненте&nbsp;<code>&lt;Executioner /&gt;</code>, то он работает с одним потомком, который является функцией.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>class Executioner extends React.Component {\n  render() {\n    return this.props.children()\n  }\n}</code></pre>\n\n\n\n<p>Мы можем уточнить это условие с помощью&nbsp;<code>propTypes</code>, что будет выглядеть примерно таким образом:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>Executioner.propTypes = {\n  children: React.PropTypes.func.isRequired,\n}</code></pre>\n\n\n\n<p>Тут выйдет сообщение в консоль, которое в принципе будет проигнорировано разработчиком. Вместо этого мы можем использовать&nbsp;<code>React.Children.only</code>&nbsp;внутри рендера.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>class Executioner extends React.Component {\n  render() {\n    return React.Children.only(this.props.children)()\n  }\n}</code></pre>\n\n\n\n<p>В этом случае отрендерится только один единственный потомок в&nbsp;<code>this.props.children</code>. Если их будет больше, чем один, то нам выкинет ошибку, следовательно, работа приложения будет приостановлена — идеально для тех случаев, когда ленивый разработчик пытается разобраться с вашим приложением.</p>\n\n\n\n<h3 id=\"91e5\">Редактирование children</h3>\n\n\n\n<p id=\"b437\">Мы можем рендерить произвольные компоненты как&nbsp;<code>children</code>. Но продолжать контролировать их из родителя, а не из компонента из которого мы их рендерим. Давайте посмотрим на этот момент повнимательнее. Представим, что у нас есть компонент&nbsp;<code>RadioGroup</code>, который может включать в себя несколько компонентов&nbsp;<code>RadioButton</code>. (которые рендерят&nbsp;<code>&lt;input type=\"radio\"&gt;</code>)</p>\n\n\n\n<p id=\"7621\">RadioButton’ы не рендерятся из&nbsp;<code>RadioGroup</code>&nbsp;сами по себе, а используются как&nbsp;<code>Children</code>. Что говорит о том, что где-то в нашем приложении у нас есть такой код:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>render() {\n  return(\n    &lt;RadioGroup>\n      &lt;RadioButton value=\"first\">First&lt;/RadioButton>\n      &lt;RadioButton value=\"second\">Second&lt;/RadioButton>\n      &lt;RadioButton value=\"third\">Third&lt;/RadioButton>\n    &lt;/RadioGroup>\n  )\n}</code></pre>\n\n\n\n<p>В этом коде есть небольшая проблемка. Инпуты не сгруппированы, что приводит к такому результату:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"339\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_c-_IqGC8PTEfLUMg8CXM5Q.png\" alt=\"\" class=\"wp-image-189\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_c-_IqGC8PTEfLUMg8CXM5Q.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_c-_IqGC8PTEfLUMg8CXM5Q-300x145.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p>Чтобы их сгруппировать им всем нужно иметь одинаковый атрибут&nbsp;<code>name</code>. Мы бы конечно могли бы сразу назначить&nbsp;<code>name</code>&nbsp;каждому&nbsp;<code>RadioButton</code>:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&lt;RadioGroup>\n  &lt;RadioButton name=\"g1\" value=\"first\">First&lt;/RadioButton>\n  &lt;RadioButton name=\"g1\" value=\"second\">Second&lt;/RadioButton>\n  &lt;RadioButton name=\"g1\" value=\"third\">Third&lt;/RadioButton>\n&lt;/RadioGroup></code></pre>\n\n\n\n<p>Но это скучно и возможно приведёт к ошибкам. А ведь у нас в руках вся сила JavaScript! Можем ли мы использовать её, чтобы автоматически указать&nbsp;<code>RadioGroup</code>&nbsp;нужное нам&nbsp;<code>name</code>&nbsp;для всех его&nbsp;<code>children</code>?</p>\n\n\n\n<h3 id=\"fecc\"><strong>Меняем props у Children</strong></h3>\n\n\n\n<p id=\"d5a2\">Итак, в&nbsp;<code>RadioGroup</code>&nbsp;мы добавим новый метод под названием renderChildren, который будет редактировать пропсы у&nbsp;<code>children</code>:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>class RadioGroup extends React.Component {\n  constructor() {\n    super()\n    this.renderChildren = this.renderChildren.bind(this)\n  }\n\n  renderChildren() {\n    return this.props.children\n  }\n\n  render() {\n    return (\n      &lt;div className=\"group\">\n        {this.renderChildren()}\n      &lt;/div>\n    )\n  }\n}</code></pre>\n\n\n\n<p>Давайте пробежимся по всем потомкам, чтобы получить каждого из них по отдельности:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>renderChildren() {\n  return React.Children.map(this.props.children, child => {\n    return child\n  })\n}</code></pre>\n\n\n\n<p>Отлично, но как теперь мы можем редактировать их свойства?</p>\n\n\n\n<h3 id=\"c5da\">Имутабельно клонируем элементы</h3>\n\n\n\n<p id=\"17a0\">И вот тут в игру вступает последний вспомогательный метод. Как и подразумевается под его названием,&nbsp;<code>React.cloneElement</code>&nbsp;клонирует элемент. Мы передаём ему элемент, который желаем скопировать, как первый аргумент, а затем вторым аргументом передаём объект с пропсами, которые должны быть выставлены уже склонированному элементу:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const cloned = React.cloneElement(element, {\n  new: 'yes!'\n})</code></pre>\n\n\n\n<p id=\"3db0\">Теперь элемент&nbsp;<code>cloned</code>&nbsp;будет иметь пропс&nbsp;<code>new</code>&nbsp;со значением&nbsp;<code>\"yes!\"</code>.</p>\n\n\n\n<p id=\"8c5b\">И это именно то, что нам нужно для завершения&nbsp;<code>RadioGroup</code>. Мы клонируем каждого потомка и выставляем ему пропс&nbsp;<code>name</code>&nbsp;со значением&nbsp;<code>this.props.name</code>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>renderChildren() {\n  return React.Children.map(this.props.children, child => {\n    return React.cloneElement(child, {\n      name: this.props.name\n    })\n  })\n}</code></pre>\n\n\n\n<p>Последним шагом мы передадим уникальный&nbsp;<code>name</code>&nbsp;к&nbsp;<code>RadioGroup</code>:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&lt;RadioGroup name=\"g1\">\n  &lt;RadioButton value=\"first\">First&lt;/RadioButton>\n  &lt;RadioButton value=\"second\">Second&lt;/RadioButton>\n  &lt;RadioButton value=\"third\">Third&lt;/RadioButton>\n&lt;/RadioGroup></code></pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"338\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_IvXCEAgQmDEKAMiMk3-qmA.png\" alt=\"\" class=\"wp-image-190\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_IvXCEAgQmDEKAMiMk3-qmA.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_IvXCEAgQmDEKAMiMk3-qmA-300x145.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p>Работает! Вместо указания вручную атрибутов для каждого&nbsp;<code>RadioButton</code>, мы просто можем указать&nbsp;<code>RadioGroup</code>&nbsp;то, что нам нужно, чтобы было name и дальше он позаботиться об этом.</p>\n\n\n\n<h2 id=\"5167\"><strong>Заключение</strong></h2>\n\n\n\n<p id=\"2961\"><code>Children</code>&nbsp;заставляют компоненты в React вести себя как элементы разметки, а не отдельные объекты. Используя силу JavaScript и некоторые вспомогательные функции React, мы можем смело с ними работать для создания декларативных API и вообще для упрощения в целом для упрощения рабочего процесса.</p>\n","date":"2021-02-04T15:28:14.000Z","title":"Погружаемся в работу с children на React","id":"1cd8d816-e812-5b16-8a98-56445f23c179","excerpt":"<p>В этой статье мы погрузимся в работу с children на React и узнаем как можно с ними работать на реальных примерах.</p>\n","type":"js","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2021/02/reactchildrenksdjnfk.jpg"}}},{"node":{"slug":"5-sovetov-kak-luchshe-pisat-uslovnie-konstrukcii-v-javascript","content":"\n<p>В этой статье рассказывается о том, как писать условные конструкции лучше, чем вы к этому скорее всего привыкли и наглядно, прямо на примерах показывается, как это делать в сравнении с обычными методами.</p>\n\n\n\n<p class=\"author\"><em>Перевод статьи&nbsp;</em><a href=\"https://scotch.io/bar-talk/5-tips-to-write-better-conditionals-in-javascript\"><em>5 Tips to Write Better Conditionals in JavaScript</em></a></p>\n\n\n\n<h2><strong>Используйте Array.includes в случае с множественным критерием</strong> выборки</h2>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// условие\nfunction test(fruit) {\n  if (fruit == 'apple' || fruit == 'strawberry') {\n    console.log('red');\n  }\n}</code></pre>\n\n\n\n<p id=\"86d4\">На первый взгляд пример выше выглядит вполне хорошо. Однако, что же будет, если у нас станет больше красных фруктов. К примеру ещё добавится вишня (<code>cherry</code>) или клюква (<code>cranberries</code>)? Будем ли мы расширять условие с помощью дополнительных&nbsp;<code>||</code>?</p>\n\n\n\n<p id=\"c6a3\">Мы можем&nbsp;свободно переписать условие,&nbsp;<a href=\"https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/includes\">с использованием&nbsp;</a><code><a href=\"https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/includes\">Array.includes</a></code>. Смотрите, как это просто:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function test(fruit) {\n  //  Выгружаем условия в массив\n  const redFruits = &#91;'apple', 'strawberry', 'cherry', 'cranberries'];\n\n  if (redFruits.includes(fruit)) {\n    console.log('red');\n  }\n}</code></pre>\n\n\n\n<p>Тут мы выгружаем список красных фруктов (<code>redFruits</code>) в массив. Так наш код будет выглядеть чище.</p>\n\n\n\n<h2><strong>Меньше вложений с ранним выходом из функции</strong></h2>\n\n\n\n<p id=\"f3df\">Давайте расширим предыдущий пример и включим в него ещё два условия.</p>\n\n\n\n<p id=\"d2a4\">Если нет фруктов, то выкинем ошибку.</p>\n\n\n\n<p id=\"3122\">Выведем в консоль сообщение, что фруктов больше 10.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function test(fruit, quantity) {\n  const redFruits = &#91;'apple', 'strawberry', 'cherry', 'cranberries'];\n\n  //  Условие 1: fruit должен иметь значение\n  if (fruit) {\n    //  Условие 2: он должен быть красным\n    if (redFruits.includes(fruit)) {\n      console.log('red');\n\n      //  Условие 3: должно быть большое количество\n      if (quantity > 10) {\n        console.log('big quantity');\n      }\n    }\n  } else {\n    throw new Error('No fruit!');\n  }\n}\n\n// test results\ntest(null); // error: No fruits\ntest('apple'); // print: red\ntest('apple', 20); // print: red, big quantity</code></pre>\n\n\n\n<p id=\"cb35\">А теперь, посмотрите на код выше, что у нас есть?</p>\n\n\n\n<p id=\"eefa\">1&nbsp;<code>if/else</code>, который фильтрует неверные условия</p>\n\n\n\n<p id=\"f771\">3 уровня вложения (условия 1, 2 и 3)</p>\n\n\n\n<p id=\"2a98\">Главное правило которому лично я стараюсь следовать &#8212; это всегда делать ранний выход из функции при обнаружении изначально неверного условия.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>/_ Раннее завершение функции, если найдено неверное условие _/\n\nfunction test(fruit, quantity) {\n  const redFruits = &#91;'apple', 'strawberry', 'cherry', 'cranberries'];\n\n  //  Условие 1: выдача ошибки сразу\n  if (!fruit) throw new Error('No fruit!');\n\n  //  Условие 2: должно быть красным\n  if (redFruits.includes(fruit)) {\n    console.log('red');\n\n    //  Условие 3: большое количество\n    if (quantity > 10) {\n      console.log('big quantity');\n    }\n  }\n}</code></pre>\n\n\n\n<p id=\"6f9b\">Таким образом у нас на один уровень вложения меньше. Такой подход особенно хорош тогда, когда у вас реально длинное условие&nbsp;<code>if</code>&nbsp;(представьте, если бы вам пришлось скролить к самому концу кода, чтобы узнать, есть ли там else. Это же обалдеть можно)</p>\n\n\n\n<p id=\"6118\">Дальше мы можем ещё больше сократить вложения&nbsp;<code>if</code>, инвертируя условие с ранним выходом из функции. Посмотрите на второе условие ниже и всё увидите:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>/_ ранний выход из функции, если найдено неверное условие _/\nfunction test(fruit, quantity) {\n  const redFruits = &#91;'apple', 'strawberry', 'cherry', 'cranberries'];\n\n  if (!fruit) throw new Error('No fruit!');  // Условие 1: выдача ошибки сразу\n  if (!redFruits.includes(fruit)) return;  Условие 2: стоп, если фрукт не красный\n\n  console.log('red');\n\n  //  Условие 3: количество должно быть больше 10\n  if (quantity > 10) {\n    console.log('big quantity');\n  }\n}</code></pre>\n\n\n\n<p id=\"7b61\">Инвертируя условия во втором случае, наш код становится свободным от вложений. Этот подход полезен тогда, когда у нас довольно длинная логика условия и нам надо отменить последующий процесс если условие не удовлетворено.</p>\n\n\n\n<p id=\"4ff6\">Однако, это не то правило, которого нужно безукоризненно придерживаться. Спросите себя сами, эта версия (без вложения) лучше/более читабельная, чем предыдущая (второе условие с вложением)?</p>\n\n\n\n<p id=\"e011\">Лично для меня подходит предыдущая версия (второе условие с вложением). И вот почему:</p>\n\n\n\n<p id=\"f6bc\">Код короче и проще, он куда понятнее с вложенным&nbsp;<code>if</code>.</p>\n\n\n\n<p id=\"b50c\">Инвертирование условия может нагрузить в плане логики и заставить лишний раз подумать.</p>\n\n\n\n<p id=\"ed9b\">Как вывод, всегда стремитесь к наименьшему вложению и раннему выходу из функции, но не пренебрегайте ими.</p>\n\n\n\n<h1 id=\"12df\"><strong>Применение дефолтных параметров функции и деструктуризация</strong></h1>\n\n\n\n<p id=\"6b67\">Я полагаю, что код ниже может выглядеть для вас вполне знакомым, нам часто нужно проверять&nbsp;<code>null</code>/<code>undefined</code>&nbsp;и назначать дефолтные значения во время работы с JavaScript:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function test(fruit, quantity) {\n  if (!fruit) return;\n  const q = quantity || 1; //  Если не указывается количество, то по-дефолту будет 1\n\n  console.log(`We have ${q} ${fruit}!`);\n}\n\n//test results\ntest('banana'); // We have 1 banana!\ntest('apple', 2); // We have 2 apple!</code></pre>\n\n\n\n<p>На самом деле мы можем избавиться от переменной&nbsp;<code>q</code>, указав дефолтные параметры функции.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function test(fruit, quantity = 1) { // Если не указывается количество, до по-дефолту будет 1\n  if (!fruit) return;\n  console.log(`We have ${quantity} ${fruit}!`);\n}\n\n//test results\ntest('banana'); // We have 1 banana!\ntest('apple', 2); // We have 2 apple!</code></pre>\n\n\n\n<p>Куда проще и интуитивно понятнее, не так ли? Пожалуйста, обратите внимание на то, что каждый параметр может иметь своё собственное дефолтное значение. Для примера, мы можем указать дефолтное значение для&nbsp;<code>fruit</code>:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function test(fruit = 'unknown', quantity = 1)</code></pre>\n\n\n\n<p>А что если&nbsp;<code>fruit&nbsp;</code>это объект? Можем ли мы назначить дефолтный параметр?</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function test(fruit) { \n  //  выводим название фрукта, если его указывают\n  if (fruit &amp;&amp; fruit.name)  {\n    console.log (fruit.name);\n  } else {\n    console.log('unknown');\n  }\n}\n\n//test results\ntest(undefined); // unknown\ntest({ }); // unknown\ntest({ name: 'apple', color: 'red' }); // apple</code></pre>\n\n\n\n<p>Посмотрите на пример выше, там нам надо вывести имя фрукта, если оно доступно или мы выведем в консоль&nbsp;<code>unknown</code>. Мы можем смело избежать объявления условия&nbsp;<code>fruit &amp;&amp; fruit.name</code>&nbsp;с помощью дефолтных параметров функции и деструктуризации.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>//  назначаем дефолтный пустой объект {}\nfunction test({name} = {}) {\n  console.log (name || 'unknown');\n}\n\n//test results\ntest(undefined); // unknown\ntest({ }); // unknown\ntest({ name: 'apple', color: 'red' }); // apple</code></pre>\n\n\n\n<p id=\"b51f\">Так как нам нужно только свойство name от&nbsp;<code>fruit</code>, мы можем деструктуризировать параметр, используя&nbsp;<code>{name}</code>, затем мы можем использовать name, как переменную в нашем коде, вместо fruit.name.</p>\n\n\n\n<p id=\"18b6\">Мы также назначаем пустой объект&nbsp;<code>{}</code>, как дефолтное значение. Если мы так не сделаем, то получим ошибку при выполнении&nbsp;<code>test(undefined)&nbsp;</code>— Cannot destructure property name of ‘<code>undefined</code>’ or ‘<code>null</code>’. Потому что тут нет свойства name в&nbsp;<code>undefined</code>.</p>\n\n\n\n<p id=\"35be\">Если вы не против использовать сторонние библиотеки, то есть несколько способов сократить проверку&nbsp;<code>null</code>:</p>\n\n\n\n<p id=\"ba45\">Используйте функцию&nbsp;<code><a href=\"https://lodash.com/docs/4.17.10#get\">get</a></code><a href=\"https://lodash.com/docs/4.17.10#get\">&nbsp;из Lodash</a></p>\n\n\n\n<p id=\"fea3\">Используйте&nbsp;<a href=\"https://github.com/facebookincubator/idx\">idx от Facebook (c Babeljs)</a></p>\n\n\n\n<p id=\"dcbb\">Вот пример с Lodash:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function test(fruit) {\n  console.log(__.get(fruit, 'name', 'unknown'); //  Получает name у fruit, если его нет, то назначается ‘unknown’.\n}\n\n//test results\ntest(undefined); // unknown\ntest({ }); // unknown\ntest({ name: 'apple', color: 'red' }); // apple</code></pre>\n\n\n\n<p>Вы можете запустить&nbsp;<a href=\"http://jsbin.com/bopovajiye/edit?js,console\">демо код тут</a>. Кроме того, если вы фанат Функционального Програмирования, вы можете&nbsp;<a href=\"https://github.com/lodash/lodash/wiki/FP-Guide\">выбрать Lodash fp</a>, функциональную версию Lodash. Там метод изменится с&nbsp;<code>get</code>&nbsp;на&nbsp;<code>getOr</code>).</p>\n\n\n\n<h2 id=\"0cc6\">Предпочитайте Map / Объект  вместо Switch</h2>\n\n\n\n<p id=\"18ee\">Давайте посмотрим на пример ниже, тут нам надо получить фрукты по их цвету:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function test(color) {\n  //  используйте case, для выбора фруктов по цвету\n  switch (color) {\n    case 'red':\n      return &#91;'apple', 'strawberry'];\n    case 'yellow':\n      return &#91;'banana', 'pineapple'];\n    case 'purple':\n      return &#91;'grape', 'plum'];\n    default:\n      return &#91;];\n  }\n}\n\n//test results\ntest(null); // &#91;]\ntest('yellow'); // &#91;'banana', 'pineapple']</code></pre>\n\n\n\n<p>Кажется, что в коде выше всё правильно, но мне он кажется довольно громоздким. Тот же результат можно получить с помощью объект литерала и более чистого синтаксиса:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>//  применяем объект литерал, чтобы найти фрукты по цвету\n  const fruitColor = {\n    red: &#91;'apple', 'strawberry'],\n    yellow: &#91;'banana', 'pineapple'],\n    purple: &#91;'grape', 'plum']\n  };\n\nfunction test(color) {\n  return fruitColor&#91;color] || &#91;];\n}</code></pre>\n\n\n\n<p>Или вы можете использовать&nbsp;<code>Map</code>, чтобы достичь того же результата:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>//  используйте Map, чтобы найти фрукты по цвету\n  const fruitColor = new Map()\n    .set('red', &#91;'apple', 'strawberry'])\n    .set('yellow', &#91;'banana', 'pineapple'])\n    .set('purple', &#91;'grape', 'plum']);\n\nfunction test(color) {\n  return fruitColor.get(color) || &#91;];\n}</code></pre>\n\n\n\n<p id=\"c6f7\"><code>Map</code>&nbsp;это тип объекта, который появился в ES2015 и позволяет вам хранить данные как&nbsp;<strong>key</strong>&nbsp;<strong>value</strong>&nbsp;(ключ и его значение).</p>\n\n\n\n<p id=\"9f16\">А теперь вопрос. Нужно ли нам прекратить использование&nbsp;<code>switch</code>? Не ограничивайте себя этим. Лично я использую объект литералы, когда это возможно, но я бы не стал выставлять жесткие ограничения в этом плане, используйте то, что больше подходит под конкретный случай.</p>\n\n\n\n<p id=\"7568\">У Todd Motto есть интересная статья, в которой он углубляется в вопрос использования switch и объект литералов,&nbsp;<a href=\"https://toddmotto.com/deprecating-the-switch-statement-for-object-literals/\">тут вы можете её прочитать</a>.</p>\n\n\n\n<h2 id=\"526a\"><strong>TL;DR Рефакторим</strong></h2>\n\n\n\n<p id=\"f5f8\">Для примера выше, на самом деле, мы можем отрефакторить код с помощью <code>Array.filter</code>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const fruits = &#91;\n    { name: 'apple', color: 'red' }, \n    { name: 'strawberry', color: 'red' }, \n    { name: 'banana', color: 'yellow' }, \n    { name: 'pineapple', color: 'yellow' }, \n    { name: 'grape', color: 'purple' }, \n    { name: 'plum', color: 'purple' }\n];\n\nfunction test(color) {\n  //  используем Array.filter, чтобы найти фрукты по цвету\n\n  return fruits.filter(f => f.color == color);\n}</code></pre>\n\n\n\n<p>Всегда есть больше одного способа достигнуть одного и того же результата. Мы увидели 4 для одного и того же примера. В общем, кодить очень даже весело!</p>\n\n\n\n<h2>Используйте Array.every или Array.some для всех или для частичных критериев</h2>\n\n\n\n<p>Последний совет скорее касается применения сравнительно новой функции массивов, с помощью которой можно значительно сократить ваш код. Посмотрите на пример ниже, тут мы хотим проверить все ли фрукты красного цвета:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const fruits = &#91;\n    { name: 'apple', color: 'red' },\n    { name: 'banana', color: 'yellow' },\n    { name: 'grape', color: 'purple' }\n  ];\n\nfunction test() {\n  let isAllRed = true;\n\n  //  Условие: все фрукты должны быть красными\n  for (let f of fruits) {\n    if (!isAllRed) break;\n    isAllRed = (f.color == 'red');\n  }\n\n  console.log(isAllRed); // false\n}</code></pre>\n\n\n\n<p>Тут всё так долго, мы вполне можем сократить число строк с помощью&nbsp;<code>Array.every</code>:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const fruits = &#91;\n    { name: 'apple', color: 'red' },\n    { name: 'banana', color: 'yellow' },\n    { name: 'grape', color: 'purple' }\n  ];\n\nfunction test() {\n  //  Короткий способ выставления условия\n  const isAllRed = fruits.every(f => f.color == 'red');\n\n  console.log(isAllRed); // false\n}</code></pre>\n\n\n\n<p>Теперь всё куда опрятнее, да? Таким же образом мы можем проверить есть ли в нашем массиве красные фрукты, для этого мы можем просто использовать <code>Array.some</code> в одну строку.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const fruits = &#91;\n    { name: 'apple', color: 'red' },\n    { name: 'banana', color: 'yellow' },\n    { name: 'grape', color: 'purple' }\n];\n\nfunction test() {\n  //  Условие: есть ли красные фрукты в массиве\n  const isAnyRed = fruits.some(f => f.color == 'red');\n\n  console.log(isAnyRed); // true\n}</code></pre>\n\n\n\n<p></p>\n","date":"2021-02-03T19:56:19.000Z","title":"5 советов как лучше писать условные конструкции в JavaScript","id":"c821764c-39f6-52e4-bbfe-9635eb426503","excerpt":"<p>В этой статье рассказывается о том, как писать условные конструкции лучше, чем вы к этому скорее всего привыкли и наглядно, прямо на примерах показывается, как это делать в сравнении с обычными методами.</p>\n","type":"js","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2021/02/uslconstrukciifkjnsdkj.jpg"}}},{"node":{"slug":"ponimaem-carrirovanie-v-javascript","content":"\n<p>В этой статье вы простым языком поймете работу с каррированием в JavaScript и увидите рабочие примеры его применения.</p>\n\n\n\n<p class=\"author\"><a href=\"https://blog.bitsrc.io/understanding-currying-in-javascript-ceb2188c339\"><em>Перевод статьи Understanding&nbsp;Currying&nbsp;in JavaScript</em></a></p>\n\n\n\n<p id=\"b4e4\">Функциональное программирование это стиль написания кода, в котором функции передают как аргументы (колбэки) и отдают тоже функции без сайд-эффектов(изменения состояния приложения).</p>\n\n\n\n<p id=\"d01f\">Множество языков приняли такую стилистику в своей работе с кодом. Самые популярные из них это: JavaScript, Haskell, Clojure, Erlang и Scala.</p>\n\n\n\n<p id=\"4ab5\">Возможность передавать и возвращать функции породила много других концепций:</p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p>Чистые функции</p><p>Каррирование</p><p>Функции высшего порядка</p></blockquote>\n\n\n\n<p>И сейчас&nbsp;мы разберем одну из них. А именно каррирование, ну или карринг. Кому как удобно.</p>\n\n\n\n<h2 id=\"23c2\"><strong>Что такое каррирование?</strong></h2>\n\n\n\n<p id=\"e854\">Это процесс в функциональном программировании при котором мы можем трансформировать функцию с несколькими аргументами в упорядоченную последовательность вложенных друг в друга совершенно разных функций. Она возвращает новую функцию, которая ожидает уже следующий аргумент.</p>\n\n\n\n<p id=\"6171\">Она будет отдавать новую функцию до тех пор, пока не закончится количество аргументов. Аргументы остаются доступными в области видимости и используются при запуске кода, когда завершающая функция в цепочке каррирования отдаётся и запускается.</p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p>Каррирование это процесс превращения функции с множественной арностью в функцию с меньшей арностью — Кристина Брэйнвэйв.</p></blockquote>\n\n\n\n<p>Обратите внимание, что термин арность относится напрямую к количеству аргументов которое берет функция. Для примера:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function fn(a, b) {\n    //...\n}function _fn(a, b, c) {\n    //...\n}</code></pre>\n\n\n\n<p id=\"e7a1\">У функции&nbsp;<code>fn</code>&nbsp;два аргумента (2х арная функция), а&nbsp;<code>_fn</code>&nbsp;имеет три аргумента(3х арная функция).</p>\n\n\n\n<p id=\"3046\">Так что каррирование трансформирует функцию с несколькими аргументами в последовательную серию связанных функций, каждая из которых берет один из нужных аргументов.</p>\n\n\n\n<p id=\"b990\">Давайте посмотрим на простой пример:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function multiply(a, b, c) {\n    return a * b * c;\n}</code></pre>\n\n\n\n<p>Функция берёт три аргумента, умножает числа и отдаёт результат:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>multiply(1,2,3); // 6</code></pre>\n\n\n\n<p>Посмотрите как мы вызвали функцию умножения с полным набором аргументов. Теперь давайте создадим каррированную версию этой функции и посмотрим, как бы мы могли вызвать ту же функцию, но уже через серию запросов:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function multiply(a) {\n    return (b) => {\n        return (c) => {\n            return a * b * c\n        }\n    }\n}log(multiply(1)(2)(3)) // 6</code></pre>\n\n\n\n<p id=\"7563\">Мы превратили функцию&nbsp;<code>multiply(1,2,3)</code>&nbsp;в несколько вызовов других вызовов&nbsp;<code>multiply(1)(2)(3)</code>.</p>\n\n\n\n<p id=\"d8bd\">Просто напросто одна простая функция была переделана в серию последовательных функций. Чтобы получить результат умножения трёх чисел&nbsp;<em>1, 2 и 3</em>, числа передаются одно за другим, каждое число передаётся следующей функции для запуска.</p>\n\n\n\n<p id=\"e5db\">Мы могли бы разделить&nbsp;<code>multiply(1)(2)(3)</code>&nbsp;на несколько функций, чтобы вы лучше поняли процесс:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const mul1 = multiply(1);\nconst mul2 = mul1(2);\nconst result = mul2(3);\nlog(result); // 6</code></pre>\n\n\n\n<p>Давайте рассмотрим всё по последовательности. Мы передали&nbsp;<code>1</code>&nbsp;функции&nbsp;<code>multiply</code>:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>let mul1 = multiply(1);</code></pre>\n\n\n\n<p>Она отдаёт функцию:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>return (b) => {\n        return (c) => {\n            return a * b * c\n        }\n   }</code></pre>\n\n\n\n<p>Теперь&nbsp;<code>mul1</code>&nbsp;это функция с аргументом&nbsp;<code>b</code>.</p>\n\n\n\n<p>Далее мы берём функцию&nbsp;<code>mul1</code>, передавая ей&nbsp;<code>2</code>:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>let mul2 = mul1(2);</code></pre>\n\n\n\n<p><code>mul1</code> отдаст третью функцию:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>return (c) => {\n            return a * b * c\n        }</code></pre>\n\n\n\n<p id=\"0a44\">Отданная функция теперь хранится в переменной&nbsp;<code>mul2</code>.</p>\n\n\n\n<p id=\"13cf\">По-сути&nbsp;<code>mul2</code>&nbsp;будет:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>mul2 = (c) => {\n            return a * b * c\n    }</code></pre>\n\n\n\n<p>Где&nbsp;<code>mul2</code>&nbsp;вызывается с&nbsp;<code>3</code>&nbsp;как параметром:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const result = mul2(3);</code></pre>\n\n\n\n<p>Что делает вычисления вместе с параметрами, переданными ранее:&nbsp;<code>a=1</code>,&nbsp;<code>b=2</code>. В итоге получаем&nbsp;<code>6</code>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>log(result); // 6</code></pre>\n\n\n\n<p id=\"0974\">Будучи вложенной функцией,&nbsp;<code>mul2</code>&nbsp;имеет доступ к области видимости других функций,&nbsp;<code>multiply</code>&nbsp;и&nbsp;<code>mul1</code>.</p>\n\n\n\n<p id=\"4524\">Вот так&nbsp;<code>mul2</code>&nbsp;будет делать вычисления с переменными указанными в фунциях из которых уже вышли. Хоть функции уже давно и были отданы и зачищены в памяти, но переменные из них ещё остаются доступными.</p>\n\n\n\n<p id=\"ac9e\">Вы видите, что три числа были применены одна за другой каждый раз и каждый раз новая функция отдавалась, но до тех пор, пока все числа не иссякнут.</p>\n\n\n\n<p id=\"1ff5\">Давайте посмотрим на другой пример:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function volume(l,w,h) {\n    return l * w * h;\n}\nconst aCylinder = volume(100,20,90) // 180000l</code></pre>\n\n\n\n<p id=\"b333\">У нас есть функция&nbsp;<code>volume</code>, которая высчитывает объем любой твёрдой формы.</p>\n\n\n\n<p id=\"368b\">Подход с каррированием будет принимать один аргумент и отдавать функцию, которая также будет принимать ещё один аргумент и отдавать тоже функцию. Это будет продолжаться до последнего аргумента и пока не вернется последняя функция, в которой произойдут уже все операции с умножением предыдущих аргументов вместе с последним.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function volume(l) {\n    return (w) => {\n        return (h) => {\n            return l * w * h\n        }\n    }\n}\nconst aCylinder = volume(100)(20)(90) // 180000</code></pre>\n\n\n\n<p>Тоже, что и в функции&nbsp;<code>multiply</code>, последняя функция принимает только&nbsp;<code>h</code>, но произведет операции с другими переменными, которые были в уже завершившихся функциях. Это работает вне зависимости от&nbsp;замыканий.</p>\n\n\n\n<p>В общем, суть каррирования в том, что мы берём функцию и извлекаем другую функцию, которая отдаёт уже специализированную функцию.</p>\n\n\n\n<h1 id=\"5ddb\"><strong>Каррирование в математике</strong></h1>\n\n\n\n<p id=\"6a9e\">Мне нравится математическая иллюстрация на&nbsp;<a href=\"https://ru.wikipedia.org/wiki/%D0%9A%D0%B0%D1%80%D1%80%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5\">Википедии</a>, показывающая концепцию каррирования. Давайте посмотрим на неё с нашим собственными примером.</p>\n\n\n\n<p id=\"2814\">У нас есть уравнение.</p>\n\n\n\n<pre class=\"wp-block-code\"><code>f(x,y) = x^2 + y = z</code></pre>\n\n\n\n<p id=\"167a\">Есть две переменные x и y. Если бы двум переменным было&nbsp;выдано&nbsp;<code>x=3</code>&nbsp;и&nbsp;<code>y=4</code>, то каким было бы&nbsp;<code>z</code>.</p>\n\n\n\n<p id=\"4d50\">Если мы заменим y на 4 и x на 3 в&nbsp;<code>f(x,y)</code>:</p>\n\n\n\n<pre class=\"wp-block-code\"><code>f(x,y) = f(3,4) = x^2 + y = 3^2 + 4 = 13 = z</code></pre>\n\n\n\n<p id=\"2653\">То мы получим результат —&nbsp;<code>13</code>.</p>\n\n\n\n<p id=\"ca75\">Мы можем каррировать <code>f(x,y)</code>, чтобы получить переменные из последовательности функций:</p>\n\n\n\n<pre class=\"wp-block-code\"><code>h = x^2 + y = f(x,y)\nhy(x) = x^2 + y = hx(y) = x^2 + y\n&#91;hx => w.r.t x] and &#91;hy => w.r.t y]</code></pre>\n\n\n\n<p id=\"d307\">Если мы поправим&nbsp;<code>x=3</code>&nbsp;в уравнении&nbsp;<code>hx(y) = x² + y</code>, то оно отдаст новое уравнение у которого есть y как переменная:</p>\n\n\n\n<p id=\"74d2\">h3(y) = 3² + y = 9 + y</p>\n\n\n\n<p id=\"4889\">Это тоже самое, что и:</p>\n\n\n\n<pre class=\"wp-block-code\"><code>h3(y) = 3^2 + y = 9 + y</code></pre>\n\n\n\n<p id=\"c54d\">Значение не было решено, оно отдало новое уравнение&nbsp;<code>9 + y</code>, ожидая ещё одну переменную&nbsp;<code>y</code>.</p>\n\n\n\n<p id=\"a9e0\">Далее мы передадим&nbsp;<code>y=4</code>:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>h3(4) = h(3)(4) = f(3,4) = 9 + 4 = 13</code></pre>\n\n\n\n<p id=\"bb5f\"><code>y</code>&nbsp;это последняя переменная в цепочке, сложение происходит с предыдущей переменной&nbsp;<code>x=3</code>&nbsp;и получается 13.</p>\n\n\n\n<p id=\"d1c4\">Мы просто напросто каррировали уравнение<code>&nbsp;f(x,y) = 3² + y</code>&nbsp;в последовательность других уравнений.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>h3(y) = h(3)(y) = f(3,y) = 3^2 + y = 9 + y</code></pre>\n\n\n\n<p id=\"549d\">Перед тем как получить результат.</p>\n\n\n\n<p id=\"b44b\">Тут немного математики и вы можете не совсем понять, что там происходит. Почитайте все детали на Википедии.</p>\n\n\n\n<h2 id=\"ace0\">Каррирование и частичное применение функций</h2>\n\n\n\n<p id=\"2368\">Сейчас некоторые могут подумать, что количество вложенных функций в карированной функции зависит от числа получаемых аргументов. Ну, собственно в карировании так оно и есть.</p>\n\n\n\n<p id=\"bad3\">Сейчас я могу сделать функцию&nbsp;<code>volume</code>&nbsp;таким образом:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function volume(l) {\n    return (w, h) => {\n        return l * w * h\n    }\n}</code></pre>\n\n\n\n<p>И теперь её можно вызывать так:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const hCy = volume(70);\nhCy(203,142);\nhCy(220,122);\nhCy(120,123);</code></pre>\n\n\n\n<p>Или вот так:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>volume(70)(90,30);\nvolume(70)(390,320);\nvolume(70)(940,340);</code></pre>\n\n\n\n<p id=\"9a86\">Мы только что сделали специальную функцию, которая считает объем любого цилиндрического объекта длинной (<code>l</code>), 70.</p>\n\n\n\n<p id=\"c137\">Она принимает 3 аргумента и имеет 2 вложенные функции в отличие от предыдущей версии, которой нужно 3 аргумента и у которой 3 вложенные функции.</p>\n\n\n\n<p id=\"7eb3\">Но эта версия без каррирования. Там мы просто сделали частичное применение функции&nbsp;<code>volume</code>.</p>\n\n\n\n<p id=\"7bca\">Собственно каррирование и частичное применение схожи, но подразумевают под собой разные концепции.</p>\n\n\n\n<p id=\"244a\">Частичное применение преобразует функцию в другую функцию с меньшей арностью.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function acidityRatio(x, y, z) {\n    return performOp(x,y,z)\n}\n|\nV\nfunction acidityRatio(x) {\n    return (y,z) => {\n        return performOp(x,y,z)\n    }\n}</code></pre>\n\n\n\n<p id=\"a686\">Обратите внимание, что тут я оставил в покое детали выполнения функции&nbsp;<code>peroformOp</code>. Она не очень важна. Всё, что вам нужно знать, это концепции применения каррирования и частичного применения.</p>\n\n\n\n<p id=\"56d3\">Это частичное применение функции&nbsp;<code>acidityRatio</code>. Тут нет каррирования. Эта функция частично применена, чтобы получить меньшую арность, ожидая меньшее количество аргументов, чем изначальная функция.</p>\n\n\n\n<p id=\"c978\">Чтобы применить каррирование, мы могли бы сделать так:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function acidityRatio(x) {\n    return (y) = > {\n        return (z) = > {\n            return performOp(x,y,z)\n        }\n    }\n}</code></pre>\n\n\n\n<p>Каррирование создаёт вложенные функции в соответствии с числом аргументов в ней. Каждая функция тут получает свой аргумент. Если нет аргумента, то нет и каррирования.</p>\n\n\n\n<p id=\"90b9\">Каррирование работает для функций с числом аргументов больше двух — Wikipedia.</p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p>Каррирование преобразует функцию в последовательность других функций, каждая из которых берёт по одному аргументу каррированной функции.</p></blockquote>\n\n\n\n<p>Могут быть случаи в которых карррование и частичное применение пересекаются. Предположим, что у нас есть такая функция:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function div(x,y) {\n    return x/y;\n}</code></pre>\n\n\n\n<p>Если мы применим частичное применение, то получим вот что:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function div(x) {\n    return (y) => {\n        return x/y;\n    }\n}</code></pre>\n\n\n\n<p>И каррирование даст нам такой же результат:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function div(x) {\n    return (y) => {\n        return x/y;\n    }\n}</code></pre>\n\n\n\n<p id=\"044e\">Хоть эти два подхода и дают схожий результат, все же по сути они разные.</p>\n\n\n\n<p id=\"9765\">Как мы раньше говорили, каррирование и частичное применение схожи, но внутри у них всё по-другому. Общее у них то, что при работе они зависят от замыканий.</p>\n\n\n\n<h2 id=\"748a\">А каррирование действительно полезно?</h2>\n\n\n\n<p id=\"b6f0\">Естественно, этот подход очень удобен если вам надо:</p>\n\n\n\n<p id=\"4408\"><strong>Написать небольшие модули кода, которые можно переиспользовать и конфигурировать с легкостью, как и с npm:</strong></p>\n\n\n\n<p id=\"3300\">Для примера у вас есть магазин и вы хотите дать 10% скидку вашим любимым клиентам:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function discount(price, discount) {\n    return price * discount\n}</code></pre>\n\n\n\n<p>Когда один из таких клиентов что-нибудь покупает на 500$, то вы её даёте ему:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const price = discount(500,0.10); // $50 \n// $500  - $50 = $450</code></pre>\n\n\n\n<p>Тут вы понимаете, что этот процесс будет происходить ежедневно:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const price = discount(1500,0.10); // $150\n// $1,500 - $150 = $1,350\nconst price = discount(2000,0.10); // $200\n// $2,000 - $200 = $1,800\nconst price = discount(50,0.10); // $5\n// $50 - $5 = $45\nconst price = discount(5000,0.10); // $500\n// $5,000 - $500 = $4,500\nconst price = discount(300,0.10); // $30\n// $300 - $30 = $270</code></pre>\n\n\n\n<p>Мы можем просто каррировать функцию скидки, чтобы нам не пришлось всегда добавлять&nbsp;<code>0.10</code>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function discount(discount) {\n    return (price) => {\n        return price * discount;\n    }\n}\n\nconst tenPercentDiscount = discount(0.1);</code></pre>\n\n\n\n<p>Теперь нам нужна только цена для расчета стоимости со скидкой:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>tenPercentDiscount(500); // $50\n// $500 - $50 = $450</code></pre>\n\n\n\n<p id=\"461e\">И снова, так получается, что некоторые клиенты уж очень нам важны, важнее других. И мы хотим им дать скидку уже в 20%.</p>\n\n\n\n<p id=\"5c1f\">Тут мы будем использовать нашу каррированую функцию скидки:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const twentyPercentDiscount = discount(0.2);</code></pre>\n\n\n\n<p id=\"449c\">Мы делаем новую функцию для наших очень важных клиентов, вызывая функцию каррирования со значением&nbsp;<code>0.2</code>, что есть 20%.</p>\n\n\n\n<p id=\"cd48\">Отдаваемая функция&nbsp;<code>twentyPercentDiscount</code>&nbsp;будет использоваться для расчета скидок у таких важных клиентов:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>twentyPercentDiscount(500); // 100\n// $500 - $100 = $400\ntwentyPercentDiscount(5000); // 1000\n// $5,000 - $1,000 = $4,000\ntwentyPercentDiscount(1000000); // 200000\n// $1,000,000 - $200,000 = $600,000</code></pre>\n\n\n\n<p id=\"93b4\"><strong>Ещё мы можем избегать частых вызовов функций с одним и тем же аргументом:</strong></p>\n\n\n\n<p id=\"d984\">Для примера, у нас есть функция для расчета объема цилиндрического объекта:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function volume(l, w, h) {\n    return l * w * h;\n}</code></pre>\n\n\n\n<p>Так получается, что все они с высотой в 100m. Это приведет к вызову функции с повторяющимся аргументом&nbsp;<code>h = 100</code>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>volume(200,30,100) // 2003000l\nvolume(32,45,100); //144000l\nvolume(2322,232,100) // 53870400l</code></pre>\n\n\n\n<p>Чтобы решить эту проблему, мы каррируем функцию&nbsp;<code>volume</code>:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function volume(h) {\n    return (w) => {\n        return (l) => {\n            return l * w * h\n        }\n    }\n}</code></pre>\n\n\n\n<p>Теперь мы можем сделать специальную функцию для цилиндров с конкретной высотой:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const hCylinderHeight = volume(100);\nhCylinderHeight(200)(30); // 600,000l\nhCylinderHeight(2322)(232); // 53,870,400l</code></pre>\n\n\n\n<h2 id=\"1dec\">Основа для создания каррирования</h2>\n\n\n\n<p id=\"5a3f\">Давайте сделаем функцию, которая берёт любую функцию и отдаёт каррированную версию этой функции.</p>\n\n\n\n<p id=\"587e\">Для этого мы можем сделать так:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function curry(fn, ...args) {\n    return (..._arg) => {\n        return fn(...args, ..._arg);\n    }\n}</code></pre>\n\n\n\n<p id=\"039b\">Что тут произошло? Наша функция каррирования принимает функцию (<code>fn</code>), которую мы хотим, собственно, каррировать и также неизвестное число параметров(<code>…args</code>). Rest оператор используется, чтобы собрать все параметры после&nbsp;<code>fn</code>&nbsp;в&nbsp;<code>…args</code>.</p>\n\n\n\n<p id=\"2c37\">Далее, мы отдаём функцию, которая также собирает все остаточные параметры как&nbsp;<code>…_args</code>. Эта функция вызывает изначальную функцию fn, передавая ей&nbsp;<code>…args</code>&nbsp;и&nbsp;<code>…_args</code>&nbsp;используя&nbsp;<a href=\"https://medium.com/@stasonmars/%D0%BE%D0%BF%D0%B5%D1%80%D0%B0%D1%82%D0%BE%D1%80-spread-%D0%B8-rest-%D0%BF%D0%B0%D1%80%D0%B0%D0%BC%D0%B5%D1%82%D1%80%D1%8B-%D0%B2-javascript-22eb33cb0825\">spread оператор</a>&nbsp;для параметров, далее значение отдаётся пользователю.</p>\n\n\n\n<p id=\"7880\">Теперь мы можем использовать нашу собственную функцию для каррирования нужных функций.</p>\n\n\n\n<p id=\"27e5\">Давайте применим эту функцию для создания более специфичной функции по расчёту объёма стометровых цилиндров:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function volume(l,h,w) {\n    return l * h * w\n}\nconst hCy = curry(volume,100);\nhCy(200,900); // 18000000l\nhCy(70,60); // 420000l</code></pre>\n\n\n\n<h2 id=\"a1b9\">Заключение</h2>\n\n\n\n<p id=\"9f2e\">Замыкания делают каррирование возможным. Возможность сохранять состояние уже выполненных функций даёт нам возможность для создания фэктори-функций, которые могут давать точное значение аргументу.</p>\n\n\n\n<p id=\"71a2\">Каррирование очень коварное дело поначалу, учитывая замыкания и функциональное программирование. Но я убеждаю вас, что со временем и постоянной практикой, вы полностью его поймете и увидите всю его ценность.</p>\n\n\n\n<p id=\"358d\">Ссылки:</p>\n\n\n\n<p id=\"5be8\"><a href=\"https://ru.wikipedia.org/wiki/%D0%9A%D0%B0%D1%80%D1%80%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5\">Каррирование</a></p>\n\n\n\n<p id=\"6183\"><a href=\"https://ru.wikipedia.org/wiki/%D0%A7%D0%B0%D1%81%D1%82%D0%B8%D1%87%D0%BD%D0%BE%D0%B5_%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5\">Частичное применение</a></p>\n","date":"2021-02-01T16:48:24.000Z","title":"Понимаем каррирование в JavaScript","id":"6a1ff13a-ed43-5409-ac7c-2badd1566a47","excerpt":"<p>В этой статье вы простым языком поймете работу с каррированием в JavaScript и увидите рабочие примеры его применения.</p>\n","type":"js","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2021/02/curryingjskfds.jpg"}}},{"node":{"slug":"podrobnoe-rukovodstvo-po-jsx-v-react","content":"\n<p>Почему-то довольно мало внимания уделяется именно глубокому понимаю JSX, хотя он необходим для полноценной и быстрой работы с React. Я не нашел в рунете действительно подробного руководства по JSX в React и перевел эту статью, добавив немного от себя.</p>\n\n\n\n<p class=\"author\"><em>Перевод статьи&nbsp;</em><a rel=\"noreferrer noopener\" href=\"https://flaviocopes.com/jsx/#introduction-to-jsx\" target=\"_blank\"><em>GETTING STARTED WITH JSX</em></a></p>\n\n\n\n<h2 id=\"0e9b\">Введение в JSX</h2>\n\n\n\n<p id=\"474d\">JSX это технология, которая была представлена React.</p>\n\n\n\n<p id=\"2f20\">Хоть React может работать без использования JSX, это всё же идеальный помощник для работы с компонентами, так что React во многом выигрывает, применяя JSX.</p>\n\n\n\n<p id=\"4704\">Сначала вы можете подумать, что использование JSX это смесь HTML и JavaScript (И как вы далее заметите еще и CSS).</p>\n\n\n\n<p id=\"4861\">Но это не так, так как то, что вы реально делаете при использовании JSX синтаксиса, это написание того же самого декларативного синтаксиса, но только тем, чем должен быть компонент UI.</p>\n\n\n\n<p id=\"2d9d\">И вы обрисовываете UI не используя строки, а используя JavaScript, с которым можно делать много всего интересного и полезного.</p>\n\n\n\n<h2 id=\"cf39\">Этюд к JSX</h2>\n\n\n\n<p id=\"5794\">Вот как вы обозначите&nbsp;<code>h1</code>&nbsp;тег, включающий в себя строку:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const element = &lt;h1>Hello, world!&lt;/h1></code></pre>\n\n\n\n<p id=\"4cbe\">Это смахивает на странный микс JavaScript и HTML, но в реальности это всё чистый JavaScript.</p>\n\n\n\n<p id=\"ca35\">А то, что похоже на HTML, на самом деле является&nbsp;<em>синтаксическим сахаром</em>&nbsp;для определения компонентов и их позиционирования внутри разметки.</p>\n\n\n\n<p id=\"13d6\">Внутри JSX выражения можно совершенно легко вставить любые атрибуты:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const myId = 'test'\nconst element = &lt;h1 id={myId}>Hello, world!&lt;/h1></code></pre>\n\n\n\n<p>Вам достаточно только обратить внимание тогда, когда у атрибута есть тире, что конвертирует его в&nbsp;<em>горбатый регистр</em>&nbsp;и обратите внимание ещё на эти два&nbsp;<strong>специальных случая</strong>:</p>\n\n\n\n<p id=\"8172\"><code>class</code>&nbsp;становится&nbsp;<code>className</code></p>\n\n\n\n<p id=\"454a\"><code>for</code>&nbsp;становится&nbsp;<code>htmlFor</code></p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p>Так как это зарезервированные слова в&nbsp;JavaScript.</p></blockquote>\n\n\n\n<p>Вот пример JSX, который заключает два компонента в&nbsp;<code>div</code>&nbsp;тег:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&lt;div>\n  &lt;BlogPostsList />\n  &lt;Sidebar />\n&lt;/div></code></pre>\n\n\n\n<p id=\"0a2e\">Тег всегда должен быть закрыт, так как это скорее XML, чем HTML (если вы помните деньки с XHTML, было схоже, но затем простой и понятный синтаксис HTML5 все таки взял верх). В этом случае используется самозакрывающийся тег.</p>\n\n\n\n<p id=\"97b2\">Обратите внимание на то, как я обернул два компонента в&nbsp;<code>div</code>. Почему? Потому, что функция&nbsp;<code>render()</code>&nbsp;может отдать только один узел, так что в случае, когда вам надо вернуть двух потомков, просто добавьте родителя. Это может быть вообще любой тег, не только&nbsp;<code>div</code>.</p>\n\n\n\n<h2 id=\"ad09\">Транспиляция JSX (трансформирование в читаемый браузером формат)</h2>\n\n\n\n<p id=\"99af\">Браузер не может понимать JS файлы, которые содержат JSX код. Сначала они должны быть трансформированы в обычный и понятный JavaScript.</p>\n\n\n\n<p><strong><em>Как это сделать? В процессе транспиляции.</em></strong></p>\n\n\n\n<p id=\"a031\">Мы уже говорили, что JSX опционален и в принципе, необязателен в React, потому что для каждой JSX строки, есть соответствующая JavaScript альтернатива и в конечном итоге именно в нее трансформируется наш JSX.</p>\n\n\n\n<p id=\"9d9b\">Для примера, следующие две конструкции полностью равнозначны:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>ReactDOM.render(\n  React.createElement('div', { id: 'test' },\n    React.createElement('h1', null, 'A title'),\n    React.createElement('p', null, 'A paragraph')\n  ),\n  document.getElementById('myapp')\n)</code></pre>\n\n\n\n<p><em>А это уже JSX:</em></p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>ReactDOM.render(\n  &lt;div id=\"test\">\n    &lt;h1>A title&lt;/h1>\n    &lt;p>A paragraph&lt;/p>\n  &lt;/div>,\n  document.getElementById('myapp')\n)</code></pre>\n\n\n\n<p id=\"16ef\">Это очень простой пример для начала понимания, но вы уже можете представить, то как более сложный синтаксис на чистом JS может быть сравним с использованием JSX.</p>\n\n\n\n<p id=\"2fd9\">Во время написания, самым популярным способом была транспиляция с использованием&nbsp;<strong>Babel</strong>, что является дефолтной опцией при запуске&nbsp;<code>create-react-app</code>, так что, если вы её используете, то вам не стоит беспокоиться, там все произойдет само собой.</p>\n\n\n\n<p id=\"0636\">А если вы не используете&nbsp;<code>create-react-app</code>, то вам придется настраивать Babel самому.</p>\n\n\n\n<h2 id=\"0e9f\">JS в JSX</h2>\n\n\n\n<p id=\"3506\">JSX допускает использование любого, вставленного в него JavaScript.</p>\n\n\n\n<p id=\"0a23\">Всякий раз когда вам нужно добавить какой-либо JS, просто вставьте его в фигурные скобки&nbsp;<code>{}</code>.</p>\n\n\n\n<p id=\"0d85\">Для примера, вот как использовать переменную, которую будет доступна отовсюду:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const paragraph = 'A paragraph'\nReactDOM.render(\n  &lt;div id=\"test\">\n    &lt;h1>A title&lt;/h1>\n    &lt;p>{paragraph}&lt;/p>\n  &lt;/div>,\n  document.getElementById('myapp')\n)</code></pre>\n\n\n\n<p>Это простой пример. Фигурные скобки принимают любой JS код:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const paragraph = 'A paragraph'\nReactDOM.render(\n  &lt;table>\n    {rows.map((row, i) => {\n      return &lt;tr>{row.text}&lt;/tr>\n    })}\n  &lt;/table>,\n  document.getElementById('myapp')\n)</code></pre>\n\n\n\n<p>Как вы видите, мы вложили JavaScript в JSX, объявленный внутри JavaScript, который вложен в JSX. В общем то тут вы можете пойти настолько глубоко, насколько захотите.</p>\n\n\n\n<h2 id=\"1806\">HTML в JSX</h2>\n\n\n\n<p id=\"7ffa\">JSX напоминает HTML, но на самом деле это XML синтаксис.</p>\n\n\n\n<p id=\"f817\">В конечном итоге получается, что вы рендерите HTML, так что вам всего-лишь нужно знать несколько различий между тем, как вы определите некоторые вещи в HTML и как вы это сделаете в JSX.</p>\n\n\n\n<h3 id=\"6034\">Вам нужно закрывать все теги</h3>\n\n\n\n<p id=\"c636\">JSX это как XHTML, если вы когда-либо его использовали, то вы уже знаете, что в нём надо закрывать все теги: забудьте про&nbsp;<code>&lt;br&gt;</code>, а вместо этого используйте самозкрывающийся тег&nbsp;<code>&lt;br /&gt;</code>. Ну и также делайте с другими тегами.</p>\n\n\n\n<h3 id=\"1814\">Горбатый регистр это новый стандарт</h3>\n\n\n\n<p id=\"80d3\">В HTML вы найдете атрибуты без каких-либо изменений. В JSX они переименованы в свою вариацию на горбатом регистре:</p>\n\n\n\n<p id=\"4826\"><code>onchange</code>&nbsp;=&gt;&nbsp;<code>onChange</code></p>\n\n\n\n<p id=\"68ff\"><code>onclick</code>&nbsp;=&gt;&nbsp;<code>onClick</code></p>\n\n\n\n<p id=\"131b\"><code>onsubmit</code>&nbsp;=&gt;&nbsp;<code>onSubmit</code></p>\n\n\n\n<h3 id=\"af9f\">class стал className</h3>\n\n\n\n<p id=\"420f\">Так как JSX это JavaScript и&nbsp;<code>class</code>&nbsp;это зарезервированное слово, вы не можете написать:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&lt;p class=\"description\"></code></pre>\n\n\n\n<p>Но вам нужно использовать:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&lt;p className=\"description\"></code></pre>\n\n\n\n<p id=\"a569\">Тоже самое применяется к&nbsp;<code>for</code>, который превращается в&nbsp;<code>htmlFor</code>.</p>\n\n\n\n<h2 id=\"7627\">Атрибуты стилей изменяют свою семантику</h2>\n\n\n\n<p id=\"21ae\">Атрибут&nbsp;<code>style</code>&nbsp;в HTML позволяет указывать инлайновые стили. В JSX это больше не принимается как строка, а в разделе&nbsp;<strong>CSS в React&nbsp;</strong>вы узнаете почему это так удобно.</p>\n\n\n\n<h3 id=\"b688\">CSS в React</h3>\n\n\n\n<p id=\"affb\">JSX даёт клевый способ указывать CSS стили.</p>\n\n\n\n<p id=\"74ff\">Если у вас есть небольшой опыт работы с инлайновым HTML, то на первый взгляд вам покажется, что вас отправили лет на 10–15 назад, в мир, где инлайновый CSS был абсолютной нормой.</p>\n\n\n\n<p id=\"c0ca\">Но стилизация с JSX это не тоже самое: во первых, вместо принятия строки, содержащей свойства CSS, JSX атрибут&nbsp;<code>style</code>&nbsp;принимает только объект. Это означает, то что вы определяете свойства в объекте:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>var divStyle = {\n  color: 'white'\n}\n\nReactDOM.render(&lt;div style={divStyle}>Hello World!&lt;/div>, mountNode)</code></pre>\n\n\n\n<p>Или</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>ReactDOM.render(&lt;div style={{ color: 'white' }}>Hello World!&lt;/div>, mountNode)</code></pre>\n\n\n\n<p id=\"d3e6\">CSS значения, которые вы пишите в JSX, слегка другие, чем чистый CSS:</p>\n\n\n\n<p id=\"3c45\">Основные названия свойств пишутся в горбатом регистре</p>\n\n\n\n<p id=\"e749\">Значения это просто строки</p>\n\n\n\n<p id=\"ae76\">Вы разделяете каждое “определение” с помощью запятой</p>\n\n\n\n<h3 id=\"f29d\">Почему это предпочтительнее над чистым CSS/SASS/LESS?</h3>\n\n\n\n<p id=\"b98b\">CSS это нерешенная проблема. После его появления, появились десятки инструментов, связанных с ним, которые стремительно взлетали и также быстро были забыты. Главная проблема с JS в том, что тут нет областей видимости и довольно легко написать CSS, который не работает так, как надо, следовательно, “грязные быстрые решения” могут повлиять на те элементы, которые вообще не должны быть затронуты.</p>\n\n\n\n<h3 id=\"9bd7\">JSX позволяет компонентам полностью инкапсулировать их стили.</h3>\n\n\n\n<p id=\"c0c8\"><strong>Решение ли это?</strong></p>\n\n\n\n<p id=\"6dbc\">Инлайновые стили в JSX конечно хороши, пока вам не надо: написать медиа запросы, стили анимаций, сослаться на псевдо-классы, сослаться на псевдо-элементы.</p>\n\n\n\n<p id=\"6d42\">Вкратце, они покрывают основы, но это далеко не конечное решение.</p>\n\n\n\n<h2 id=\"293b\">Формы в JSX</h2>\n\n\n\n<p id=\"a5e4\">JSX добавляет некоторые изменения в то, как работают формы в HTML, с целью того, чтобы упростить жизнь разработчику.</p>\n\n\n\n<h3 id=\"b19a\">value и defaultvalue</h3>\n\n\n\n<p id=\"3a36\">Атрибут&nbsp;<code>value</code>, всегда содержит дефолтное значение, которое было указано при создании поля.</p>\n\n\n\n<p id=\"60c5\">Это помогает решить некоторые неординарные моменты в поведении регулярного взаимодействия с DOM, когда проверка&nbsp;<code>input.value</code>&nbsp;и&nbsp;<code>input.getAttribute('value')</code>&nbsp;возвращает одно настоящее значение и одно изначальное дефолтное значение.</p>\n\n\n\n<p id=\"d365\">Это также применимо к полю&nbsp;<code>textarea</code>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&lt;textarea>Some text&lt;/textarea></code></pre>\n\n\n\n<p>Но вместо:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&lt;textarea defaultValue={'Some text'} /></code></pre>\n\n\n\n<p>Для полей&nbsp;<code>select</code>, вместо этого:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&lt;select>\n  &lt;option value=\"x\" selected>\n    ...\n  &lt;/option>\n&lt;/select></code></pre>\n\n\n\n<p id=\"17c9\">Более последовательный&nbsp;<code>onChange</code></p>\n\n\n\n<p id=\"8cd7\">Передавая функции атрибуту&nbsp;<code>onChange</code>, вы можете подписаться на события в полях формы.</p>\n\n\n\n<p id=\"2f90\">Это работает последовательно через поля, даже&nbsp;<code>radio</code>,&nbsp;<code>select</code>&nbsp;и&nbsp;<code>checkbox</code>&nbsp;срабатывают по&nbsp;<code>onChange</code>.</p>\n\n\n\n<p id=\"a8d9\"><code>onChange</code>&nbsp;также срабатывает при написании символов в&nbsp;<code>input</code>&nbsp;или&nbsp;<code>textarea</code>.</p>\n\n\n\n<h2 id=\"fac8\">JSX автоматическое экранирование</h2>\n\n\n\n<p id=\"a940\">Чтобы смягчить любой возможный риск XSS искплойтов, JSX принудительно автоматически экранирует выражения.</p>\n\n\n\n<p id=\"845d\">Это означает то, что вы можете столкнуться с некоторыми затруднениями во время использования HTML в строчном выражении.</p>\n\n\n\n<p id=\"d094\">Для примера, вы ожидаете, что выдаст&nbsp;<code>© 2017</code>:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&lt;p>{'&amp;copy; 2019'}&lt;/p></code></pre>\n\n\n\n<p id=\"ead2\">Но увы, вам выдаст&nbsp;<code>&amp;copy; 2017</code>, так как строка экранизирована.</p>\n\n\n\n<p id=\"6b92\">Чтобы исправить эту проблему, вы можете какбы вынести все за пределы выражения:</p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;p>&amp;copy; 2017&lt;/p></code></pre>\n\n\n\n<p>Так и использовать константу, которая выведет Unicode представление, соответствующее HTML который вам нужно вывести:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&lt;p>{‘\\u00A9 2017’}&lt;/p></code></pre>\n\n\n\n<h2 id=\"581b\">Пробел в JSX</h2>\n\n\n\n<p id=\"c5a3\">Чтобы добавить пробел в JSX есть два правила:</p>\n\n\n\n<h3 id=\"e0fa\">Горизонтальный пробел сокращается до одного.</h3>\n\n\n\n<p id=\"7392\">Если у вас есть пробел между элементами на одной линии, то всё это сократится до одного пробела.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&lt;p>Something       becomes               this&lt;/p></code></pre>\n\n\n\n<p>Это станет:</p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;p>Something becomes this&lt;/p></code></pre>\n\n\n\n<p>Вертикальные пробелы стираются:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&lt;p>\n  Something\n  becomes\n  this\n&lt;/p></code></pre>\n\n\n\n<p>Это станет:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&lt;p>Somethingbecomesthis&lt;/p></code></pre>\n\n\n\n<p>Чтобы пофиксить эту проблему, вам надо явно добавить пробел, добавив выражения как тут:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&lt;p>\n  Something\n  {' '}becomes\n  {' '}this\n&lt;/p></code></pre>\n\n\n\n<p>Или вставив строку в выражении:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&lt;p>\n  Something\n  {' becomes '}\n  this\n&lt;/p></code></pre>\n\n\n\n<h3 id=\"6c3d\">Добавление комментариев в JSX</h3>\n\n\n\n<p id=\"219c\">Вы можете добавлять комментарии в JSX, используя обычные JavaScript комментарии внутри выражения:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&lt;p>\n  {/* коммент */}\n  {\n    //еще один коммент\n  }\n&lt;/p></code></pre>\n\n\n\n<h3 id=\"3155\">Атрибуты расширения</h3>\n\n\n\n<p id=\"9a61\">В JSX довольно частой операцией является назначение значений атрибутам. Вместо того, чтобы делать это вручную:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&lt;div>\n  &lt;BlogPost title={data.title} date={data.date} />\n&lt;/div></code></pre>\n\n\n\n<p>Вы можете передать их с помощью <a href=\"https://stasonmars.ru/javascript/operator-spread-i-rest-parametry-v-javascript/\">оператора расширения Spread</a>:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&lt;div>\n  &lt;BlogPost {...data} />\n&lt;/div></code></pre>\n\n\n\n<p>И свойства из объекта&nbsp;<code>data</code>, будут использоваться, как атрибуты в автоматическом порядке, спасибо тут оператору расширения из ES2015.</p>\n\n\n\n<h2 id=\"456e\">Циклы в JSX</h2>\n\n\n\n<p id=\"f695\">Если у вас есть есть коллекция элементов по которой вам нужно пройтись циклом для создания JSX части компонента, то вы можете спокойно запустить цикл и затем добавить JSX в массив.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const elements = &#91;] //..какой то массив\n\nconst items = &#91;]\n\nfor (const &#91;index, value] of elements.entries()) {\n  items.push(&lt;Element key={index} />)\n}</code></pre>\n\n\n\n<p>Теперь отрендеря JSX вы можете вставить массив&nbsp;<code>items</code>, обернув его в фигурные скобки.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const elements = &#91;'one', 'two', 'three'];\n\nconst items = &#91;]\n\nfor (const &#91;index, value] of elements.entries()) {\n  items.push(&lt;li key={index}>{value}&lt;/li>)\n}\n\nreturn (\n  &lt;div>\n    {items}\n  &lt;/div>\n)\n</code></pre>\n\n\n\n<p>Вы можете сделать тоже самое напрямую в JSX, применяя&nbsp;<code>map</code>, вместо&nbsp;<code>for-of</code>&nbsp;цикла.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const elements = &#91;'one', 'two', 'three'];\nreturn (\n  &lt;ul>\n    {elements.map((value, index) => {\n      return &lt;li key={index}>{value}&lt;/li>\n    })}\n  &lt;/ul>\n)</code></pre>\n","date":"2021-01-28T17:06:15.000Z","title":"Подробное руководство по JSX в React","id":"56a08646-2927-5902-9ae4-5718aafb7999","excerpt":"<p>Почему-то довольно мало внимания уделяется именно глубокому понимаю JSX, хотя он необходим для полноценной и быстрой работы с React. Я не нашел в рунете действительно подробного руководства по JSX в React и перевел эту статью, а ещё добавил немного от себя.</p>\n","type":"js","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2021/01/jsxreactnkjnk.jpg"}}},{"node":{"slug":"razbiraemsya-s-putanitsei-mezhdu-metodami-javascript-slice-splice-i-split","content":"\n<p>Очень полезная статья про то, как работают методы&nbsp;<code>slice()</code>,&nbsp;<code>splice()</code>&nbsp;и&nbsp;<code>split()</code>. В реальном мире даже опытные разработчики делают в них ошибки.</p>\n\n\n\n<p class=\"author\" id=\"2192\"><em>Перевод статьи&nbsp;</em><a rel=\"noreferrer noopener\" target=\"_blank\" href=\"https://medium.com/free-code-camp/lets-clear-up-the-confusion-around-the-slice-splice-split-methods-in-javascript-8ba3266c29ae\"><em>Let’s clear up the confusion around the slice( ), splice( ), &amp; split( ) methods in JavaScript</em></a></p>\n\n\n\n<p id=\"0d7d\">Встроенные в JavaScript методы действительно сильно помогают в процессе разработки, особенно если мы понимаем принцип их работы должным образом. Я бы хотел объяснить функционал трёх из них: это&nbsp;<code>splice()</code>,&nbsp;<code>slice()</code>&nbsp;и&nbsp;<code>split()</code>. Возможно потому, что их имена очень похожи — их зачастую путают даже опытные разработчики.</p>\n\n\n\n<p id=\"af1d\">Я настоятельно рекомендую студентам и джуниорам читать эту статью внимательно, потому что эти три метода могут быть включены в процесс собеседования.</p>\n\n\n\n<p id=\"192e\">Вы найдете обобщенные описания методов в конце статьи. Ну а теперь давайте начнем.</p>\n\n\n\n<h2 id=\"b556\"><strong>JavaScript массивы</strong></h2>\n\n\n\n<p id=\"c52c\">Во первых, вам необходимо понять как работают массивы в JavaScript. Как и в других языках программирования, мы используем массивы для хранения разнообразных данных в JS.</p>\n\n\n\n<p id=\"3c5f\">Иногда нам нужно выполнять какие-либо операции на этих массивах. И тогда мы прибегаем к JavaScript методам, например к&nbsp;<code>slice()</code>&nbsp;или&nbsp;<code>splice()</code>. Ниже вы видите, как объявлять массив в JavaScript:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>let arrayDefinition = &#91;]; // Объявление массива</code></pre>\n\n\n\n<p>А теперь давайте объявим ещё один массив с разными типами данных. Ниже, в своих&nbsp;примерах, я буду использовать именно его :</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>let array = &#91;1, 2, 3, \"hello world\", 4.12, true];</code></pre>\n\n\n\n<p>Такое возможно в JavaScript. Массив с разными типами данных: строка, число и булево значение.</p>\n\n\n\n<h2 id=\"76bb\"><strong>slice()</strong></h2>\n\n\n\n<p id=\"af2b\">Метод&nbsp;<code>slice()</code>&nbsp;копирует заданную часть массива и возвращает её в виде совершенно нового массива. Этот метод вообще не трогает оригинальный массив:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>array.slice(from, until);</code></pre>\n\n\n\n<p id=\"264f\"><strong>From</strong>: с индекса какого элемента начинается нарезка массива</p>\n\n\n\n<p id=\"ead9\"><strong>Until</strong>: до какого элемента массива нарезается массив</p>\n\n\n\n<p id=\"0248\">Для примера, нам нужно нарезать первые три элемента из вышеуказанного массива. Так как первый элемент в массиве всегда имеет индекс 0, то начнём мы нарезку именно с него.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>array.slice(0, until);</code></pre>\n\n\n\n<p>А теперь хитрый момент. Когда мне надо нарезать первые три элемента, мне надо задать параметр&nbsp;<code>until = 3</code>. Почему? Потому что&nbsp;<code>slice()</code>&nbsp;не затрагивает последний заданный элемент.</p>\n\n\n\n<pre class=\"wp-block-preformatted\"></pre>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>array&#91;0] --> 1              // включён\narray&#91;1] --> 2              // включён\narray&#91;2] --> 3              // включён\narray&#91;3] --> \"hello world\"  // уже не включён\n</code></pre>\n\n\n\n<p>Это может создать некое недопонимание. Именно по этому я назвал второй параметр&nbsp;<code>until</code>&nbsp;(до).</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>let newArray = array.slice(0, 3); // Отдаётся также массив</code></pre>\n\n\n\n<p>И наконец, я назначаю нарезанный массив на переменную&nbsp;<code>newArray</code>. Давайте посмотрим, что получается:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"466\" height=\"103\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_ppPGRgqMpZHQzB3P8oDCog.png\" alt=\"\" class=\"wp-image-158\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_ppPGRgqMpZHQzB3P8oDCog.png 466w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_ppPGRgqMpZHQzB3P8oDCog-300x66.png 300w\" sizes=\"(max-width: 466px) 100vw, 466px\" /></figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"506\" height=\"75\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_bsh2j7UulR4s3I2WNSFt5A.png\" alt=\"\" class=\"wp-image-159\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_bsh2j7UulR4s3I2WNSFt5A.png 506w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_bsh2j7UulR4s3I2WNSFt5A-300x44.png 300w\" sizes=\"(max-width: 506px) 100vw, 506px\" /></figure>\n\n\n\n<p><strong>Важное замечание:</strong>&nbsp;метод&nbsp;<code>slice()</code>&nbsp;также можно использовать и на строках.</p>\n\n\n\n<h2 id=\"54ea\"><strong>splice()</strong></h2>\n\n\n\n<p id=\"4a1a\">Название этой функции очень похоже на&nbsp;<code>slice()</code>. Такая схожесть зачастую сбивает разработчиков с толку. Метод&nbsp;<code>splice()</code>&nbsp;изменяет массив, добавляя или удаляя элементы в нем. Давайте посмотрим, как мы можем удалить элементы с помощью&nbsp;<code>splice()</code>:</p>\n\n\n\n<h3 id=\"71ed\">Удаление элементов</h3>\n\n\n\n<p id=\"b7a0\">Для их удаления нам надо задать параметр&nbsp;<code>index</code>&nbsp;и число элементов, которые будут удалены:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>array.splice(index, number of elements);</code></pre>\n\n\n\n<p>Тут&nbsp;<code>index</code>&nbsp;— это начальная точка для удаления элементов. Элементы, которые имеют индекс ниже заданного не будут удалены:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>array.splice(2); // Каждый элемент, начиная с 3го будет удалён</code></pre>\n\n\n\n<p>Если мы не указываем второй параметр, то будут удалены все элементы, начиная с заданного значения&nbsp;<code>index</code>.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"398\" height=\"102\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_VB2SB-PcqfpOc6NCprj3DA.png\" alt=\"\" class=\"wp-image-160\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_VB2SB-PcqfpOc6NCprj3DA.png 398w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_VB2SB-PcqfpOc6NCprj3DA-300x77.png 300w\" sizes=\"(max-width: 398px) 100vw, 398px\" /></figure>\n\n\n\n<p>Во втором примере я задам вторым параметром число&nbsp;<code>1</code>, что говорит о том, что элементы в массиве, начиная с числа&nbsp;<code>index</code>&nbsp;будут удалены по одному, при каждом вызове метода&nbsp;<code>splice()</code>:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>array.splice(2, 1);</code></pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"412\" height=\"27\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_eGMPlB-7wsZ8AZOYTm4GoQ.png\" alt=\"\" class=\"wp-image-161\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_eGMPlB-7wsZ8AZOYTm4GoQ.png 412w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_eGMPlB-7wsZ8AZOYTm4GoQ-300x20.png 300w\" sizes=\"(max-width: 412px) 100vw, 412px\" /></figure>\n\n\n\n<p><strong>После 1-го вызова:</strong></p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"362\" height=\"43\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_kVAntaGUhGgYQxvTss280g.png\" alt=\"\" class=\"wp-image-162\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_kVAntaGUhGgYQxvTss280g.png 362w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_kVAntaGUhGgYQxvTss280g-300x36.png 300w\" sizes=\"(max-width: 362px) 100vw, 362px\" /></figure>\n\n\n\n<p><strong>После 2-го вызова:</strong></p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"336\" height=\"57\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_jXkzRgcIpRsWdDQUzeIVkw.png\" alt=\"\" class=\"wp-image-163\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_jXkzRgcIpRsWdDQUzeIVkw.png 336w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_jXkzRgcIpRsWdDQUzeIVkw-300x51.png 300w\" sizes=\"(max-width: 336px) 100vw, 336px\" /></figure>\n\n\n\n<p id=\"d587\">В общем, это будет продолжаться пока вообще не останется элементов под индексом 2.</p>\n\n\n\n<h3 id=\"7b88\">Добавление элементов</h3>\n\n\n\n<p id=\"c153\">Для добавления элементов нам нужно указать 3, 4 и 5й параметры (в зависимости от того, сколько мы хотим добавить) методу&nbsp;<code>splice()</code>:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>array.splice(index, number of elements, element, element);</code></pre>\n\n\n\n<p>Как пример, я добавляю&nbsp;<code>a</code>&nbsp;и&nbsp;<code>b</code>&nbsp;в самое начала массива, при этом ничего не удаляя:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>array.splice(0, 0, 'a', 'b');</code></pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"474\" height=\"100\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_ehL_z84tfMd-HLNDUN2KUw.png\" alt=\"\" class=\"wp-image-164\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_ehL_z84tfMd-HLNDUN2KUw.png 474w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_ehL_z84tfMd-HLNDUN2KUw-300x63.png 300w\" sizes=\"(max-width: 474px) 100vw, 474px\" /></figure>\n\n\n\n<h2 id=\"2636\">split()</h2>\n\n\n\n<p id=\"695d\">Методы&nbsp;<code>slice()</code>&nbsp;и&nbsp;<code>splice()</code>&nbsp;для массивов. А вот метод&nbsp;<code>split()</code>&nbsp;используется для строк. Он делит строку на подстроки и отдаёт их в виде массива. Ему нужны 2 параметра и оба они опциональны.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>string.split(separator, limit);</code></pre>\n\n\n\n<p id=\"7d85\"><strong>Separator</strong>: определяет как разделять строку. Запятой, символом или тп.</p>\n\n\n\n<p id=\"5f22\"><strong>Limits</strong>: ограничивает количество разделений, опираясь на заданное число.</p>\n\n\n\n<p id=\"0d4f\">Этот метод не работает с массивами напрямую. Но однако, мы сначала можем конвертировать элементы массива в строку, а потом уже использовать метод&nbsp;<code>split()</code>.</p>\n\n\n\n<p id=\"b004\">Давайте посмотрим как это работает.</p>\n\n\n\n<p id=\"531b\">Сначала мы конвертируем наш массив в строку при помощи метода&nbsp;<code>toString()</code>:</p>\n\n\n\n<pre class=\"wp-block-code\"><code>let myString = array.toString();</code></pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"303\" height=\"97\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_2IsKWAZB6HV27l8ZvINePA.png\" alt=\"\" class=\"wp-image-165\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_2IsKWAZB6HV27l8ZvINePA.png 303w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_2IsKWAZB6HV27l8ZvINePA-300x96.png 300w\" sizes=\"(max-width: 303px) 100vw, 303px\" /></figure>\n\n\n\n<p>Теперь давайте разделим&nbsp;<code>myString</code>&nbsp;по запятым, ограничив его до 3 подстрок и возвратим его, как массив:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>let newArray = myString.split(\",\", 3);\n</code></pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"274\" height=\"58\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_vaN5R2yodR0o7fpfpw3TMg.png\" alt=\"\" class=\"wp-image-166\"/></figure>\n\n\n\n<p id=\"c1a3\">Как мы видим,&nbsp;<code>myString</code>&nbsp;разделен запятыми. А так как мы ограничиваем разбитие строки до 3-х элементов в массиве, то только первые 3 из них будут возвращены.</p>\n\n\n\n<p id=\"745e\">Обратите внимание, что если бы мы использовали&nbsp;<code>array.split(\"\")</code>, то каждый символ в строке был бы разделен на подстроки:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"463\" height=\"82\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_ddeJQxxJ3XUFR5Fp4pudhg-1.png\" alt=\"\" class=\"wp-image-167\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_ddeJQxxJ3XUFR5Fp4pudhg-1.png 463w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_ddeJQxxJ3XUFR5Fp4pudhg-1-300x53.png 300w\" sizes=\"(max-width: 463px) 100vw, 463px\" /></figure>\n\n\n\n<h2 id=\"90de\"><strong>Подводим итоги</strong></h2>\n\n\n\n<h3 id=\"649a\"><strong>Slice()</strong></h3>\n\n\n\n<ul><li>Копирует элементы из массива</li><li>Отдаёт их как новый массив</li><li>Не трогает изначальный массив</li><li>Начинает нарезку с … до заданного индекса:&nbsp;<code>array.slice (from, until)</code></li><li>Последний параметр не нарезается методом&nbsp;<code>Slice()</code></li><li>Может использоваться как и для массивов, так и для строк</li></ul>\n\n\n\n<h3 id=\"200f\"><strong>Splice()</strong></h3>\n\n\n\n<ul><li>Используется для добавления/удаления элементов из массива</li><li>Отдаёт массив удаленных элементов</li><li>Изменяет массив</li><li>Для добавления элементов используйте:&nbsp;<code>array.splice (index, number of elements, element)</code></li><li>Для удаления элементов:&nbsp;<code>array.splice (index, number of elements)</code></li><li>Может использоваться только для массивов</li></ul>\n\n\n\n<h3 id=\"5e8e\"><strong>Split()</strong></h3>\n\n\n\n<ul><li>Разделяет строку на подстроки</li><li>Отдаёт их в массив</li><li>Берёт 2 параметра, оба опциональны:&nbsp;<code>string.split(separator, limit)</code></li><li>Не изменяет изначальную строку</li><li>Может использоваться только для строк</li></ul>\n\n\n\n<p id=\"f7c6\">Конечно же есть и другие встроенные JavaScript методы для работы с массивами и строками. Если вы поймете как их использовать, то они значительно упростят ваш процесс разработки.</p>\n","date":"2021-01-27T21:14:20.000Z","title":"Разбираемся с путаницей между JavaScript методами slice(), splice() и split()","id":"d3649fe4-c4f6-5d60-8269-f291cca2e0e9","excerpt":"<p>Очень полезная статья про то, как работают методы slice(), splice() и split(). В реальном мире даже опытные разработчики делают в них ошибки.</p>\n","type":"js","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2021/01/splitsplicekfjdsn.jpg"}}},{"node":{"slug":"ponimaem-nemedlenno-vyzyvaemie-funkcii-iife-i-nemnogo-bolshe","content":"\n<p>В этой статье вы подробно узнаете, что такое IIFE, какие они бывают и как их использовать в JavaScript.</p>\n\n\n\n<p class=\"author\"><em>Перевод статьи&nbsp;</em><a rel=\"noreferrer noopener\" target=\"_blank\" href=\"https://medium.com/@vvkchandra/essential-javascript-mastering-immediately-invoked-function-expressions-67791338ddc6\"><em>Essential JavaScript: Mastering Immediately-invoked Function Expressions</em></a></p>\n\n\n\n<p id=\"0d7d\">Понимание принципов работы функций и последующее осознание того, как их использовать при написании современного, понятного JavaScript’а — является необходимым критерием для оттачивания мастерства в этом языке программирования.</p>\n\n\n\n<p id=\"3f05\">Один из часто используемых паттернов, связанных с функциями имеет причудливое название:&nbsp;<strong>Immediately-invoked Function Expression</strong>&nbsp;или по-русски&nbsp;<strong>Немедленно вызываемое функциональное выражение</strong>. Или, как с любовью говорят в народе —<em>&nbsp;IIFE, произнося, как “Ифи”.</em></p>\n\n\n\n<p id=\"8204\">Перед тем как понять, что такое IIFE и зачем они нам вообще нужны, стоит быстренько рассмотреть несколько основополагающих концепций, связанных с функциями в JavaScript.</p>\n\n\n\n<h2 id=\"876d\"><strong>Объявление функции обычным способом</strong></h2>\n\n\n\n<p id=\"0e3f\">Новички в JavaScript обычно чувствуют себя комфортно, имея дело с синтаксисом функций.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function sayHi() {\n    alert(\"Hello, World!\");\n}\n\nsayHi();  // Покажет \"Hello, World!\" в alert браузера.</code></pre>\n\n\n\n<p id=\"d436\">Строки 1–3 объявляют функцию <code>sayHi</code>.</p>\n\n\n\n<p id=\"bf9b\">На 5 строке мы вызываем её с обычными скобками&nbsp;<code>()</code>.</p>\n\n\n\n<p id=\"0300\">Такой способ создания функции называется “определением функции” или “объявлением функции”, ну или “указанием функции”. Обычно, новые разработчики в JavaScript не испытывают с ним проблем, так как он ну уж очень сильно напоминает функции/методы в других популярных языках программирования.</p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p><em>Такие объявления функций всегда начинаются со слова&nbsp;</em><code>function</code><em>&nbsp;и всегда за ним идет название этой самой функции. Вы не можете пропустить указание имени, так как это уже будет неверным синтаксисом.</em></p></blockquote>\n\n\n\n<h2 id=\"f81e\"><strong>Функциональные выражения</strong></h2>\n\n\n\n<p id=\"1954\">Тут уже все становится интереснее. Давайте посмотрим на то, как выглядят функциональные выражения в JavaScript.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>var msg = \"Hello, World!\";\nvar sayHi = function() {\n    alert(msg);\n};\n\nsayHi();  // Покажет \"Hello, World!\" в alert браузера.</code></pre>\n\n\n\n<p id=\"2114\">Этот вроде бы простой пример может помочь вам прокачать скиллы в JavaScript до следующего уровня.</p>\n\n\n\n<p id=\"b370\">На первой строке объявляется переменная&nbsp;<code>msg</code>&nbsp;и ей назначается строковое значение.</p>\n\n\n\n<p id=\"16c8\">Строки 2–4 объявляют переменную&nbsp;<code>sayHi</code>&nbsp;и назначают ей значение, являющееся функцией.</p>\n\n\n\n<p id=\"ca63\">На шестой строке мы вызываем эту самую функцию&nbsp;<code>sayHi</code>.</p>\n\n\n\n<p id=\"7b4b\">Первую строку легко понять. Но когда разработчики видят строки 2–4 в первый раз, то это обычно вызывает затруднения, если они зашли из другого языка программирования, например из Java.</p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p>Обычно, в строках 2–4 мы указываем значение, которое является функцией для переменной&nbsp;<code>sayHi</code>.</p><p>В примере выше, функция с левой стороны оператора назначения зачастую называется “<em>функциональным выражением</em>”. Они буквально везде в JavaScript. Большинство колбэков, которые вы бы написали, были бы этими самыми функциональными выражениями.</p></blockquote>\n\n\n\n<p>Вы возможно уже использовали их, но без понимания того, как это работает под капотом. Но поняв принцип их работы, вы обретёте некую скрытую суперсилу, доступную в JavaScript.</p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p><em>Так что, тут важно запомнить само понятие того, что в этом случае функции, являются почти такими же значениями, как и все другое в JavaScript. Они могут быть с правой стороны оператора назначения или они могут быть переданы, как аргументы другим функциям.</em></p></blockquote>\n\n\n\n<h2 id=\"f7d8\"><strong>Анонимные функциональные выражения</strong></h2>\n\n\n\n<p id=\"52b9\">Итак, вы уже знаете, что это такое. Пример выше и был анонимным функциональным выражением. Анонимными они являются потому, что у них не указано имя после слова&nbsp;<code>function</code>.</p>\n\n\n\n<h2 id=\"527b\"><strong>Проименованные функциональные выражения</strong></h2>\n\n\n\n<p id=\"2a05\">Да, функциональные выражения могут иметь имена. Самое обыденное и всюду объясняемое использование проименованных функциональных выражений — это рекурсия. Пока что не беспокойтесь о них, вы вполне можете понять IIFE и так.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>var fibo = function fibonacci() {\n    // тут вы можете использовать \"fibonacci()\"\n};\n\n // fibonacci() не сработает, а fibo() да.</code></pre>\n\n\n\n<p>Разница тут в том, что функциональное выражение имеет имя “<strong>fibonacci</strong>”, которое можно использовать внутри самого выражения рекурсивным способом. (Тут вообще есть много всего интересного, например то, что имя функции всплывает в стектрейсе и т.п., но об этом нам не стоит беспокоиться в этом руководстве).</p>\n\n\n\n<h2 id=\"a5f7\"><strong>Так, всё! Показывайте мне уже IIFE или я сваливаю!</strong></h2>\n\n\n\n<p id=\"fa6b\">Спасибо за терпение при объяснении этого&nbsp;<em>важнейшего</em>&nbsp;скилла, который так важен в JavaScript.</p>\n\n\n\n<p id=\"5349\">Теперь, когда вы узнали про функциональные выражения и объявления функций, давайте погрузимся в тайный мир IIFE, мир немедленно вызываемых функций. Они могут иметь несколько стилистический вариаций. Сначала посмотрим на самую простую.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>!function() {\n    alert(\"Hello from IIFE!\");\n}();\n// Покажет alert “Hello from IIFE!”</code></pre>\n\n\n\n<p>Это, друзья мои, наша ненаглядная IIFE функция в действии. Когда вы скопируете этот код и вставите его в консоль браузера, вы увидите&nbsp;<code>alert</code>&nbsp;из второй строчки кода. Вот и всё, собственно. Никто никогда не увидит этот&nbsp;<code>alert</code>&nbsp;снова.</p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p><em>Это функция, которая исчезает сразу же после того, как увидит свет.</em></p></blockquote>\n\n\n\n<p id=\"75ca\">А теперь давайте разберем этот не совсем интуитивно понятный синтаксис: я знаю, вы обратили внимание на “<code>!</code>”, если же нет, то не переживайте, вы обратили внимание на это сейчас.</p>\n\n\n\n<p id=\"7444\">Как мы видели до этого, объявление функции всегда начиналось со слова&nbsp;<code>function</code>. Всякий раз, когда JavaScript видит слово&nbsp;<code>function</code>, как вводное слово, он ожидает того, что сейчас будет объявлена функция. Чтобы этого не случилось, мы префиксим “!” перед словом function на первой строке. Это просто подталкивает JavaScript рассматривать всё, что идёт после восклицательного знака, как выражение.</p>\n\n\n\n<p id=\"6561\">Но самое интересное происходит на 3 сроке, где мы уже <em>мгновенно </em>вызываем это выражение.</p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p><em>Итак, у нас есть функциональное выражение, которое сразу же вызывается после создания. И это, друзья мои, называется IIFE, не смотря на стилистику исполнения, используемую для достижения эффекта.</em></p></blockquote>\n\n\n\n<p id=\"bef3\">Вообще, в такой вариации можно использовать не только “!”, а заменить его на&nbsp;<code>+</code>,&nbsp;<code>—</code>&nbsp;или&nbsp;<code>~</code>. В общем, подойдет любой унарный оператор.</p>\n\n\n\n<p id=\"e7d5\">А теперь, попробуйте это всё в консоли. Поиграйтесь с IIFE в своё удовольствие.</p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p><em>Единственное, что тут делает символ&nbsp;</em><code>!</code><em>, так это превращает функцию в выражение, вместо объявления функции. И потом, сразу же, мы выполняем эту функцию.</em></p></blockquote>\n\n\n\n<p>Ещё один быстрый пример:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>void function() {\n    alert(\"Hello from IIFE!\");\n}();</code></pre>\n\n\n\n<p id=\"5aae\">И снова,&nbsp;<code>void</code>&nbsp;просто принуждает функцию к тому, чтобы ее рассматривали как выражение.</p>\n\n\n\n<p id=\"454e\">Все подходы описанные выше могут быть полезны тогда, когда вам не нужно получать никакого значения от IIFE.</p>\n\n\n\n<p id=\"b534\">Но что делать, если вам нужно его получить и ещё потом где-то использовать? Читайте дальше, чтобы увидеть ответ на этот вопрос.</p>\n\n\n\n<h2 id=\"2b5c\"><strong>Классический стиль IIFE</strong></h2>\n\n\n\n<p id=\"5799\">Паттерн IIFE, который мы видели выше, довольно легко понять. Поэтому я начал с него, а не с других, куда более часто используемых подходов.</p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p><em>Как мы видели в примерах IIFE выше, суть паттерна в том, чтобы взять функцию и превратить её в выражение, а затем тут же его запустить.</em></p></blockquote>\n\n\n\n<p>Сначала давайте посмотрим на ещё один пример функционального выражения!</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>(function() {\n    alert(\"I am not an IIFE yet!\");\n});</code></pre>\n\n\n\n<p>В примере выше функциональное выражение на строках 1–3 обернуто в скобки. Пока что, это не IIFE, так как это функциональное выражение никогда не запускалось и не запуститься. А теперь давайте доделаем этот код и превратим его в IIFE, для этого у нас есть два варианта стилизации:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// Variation 1\n(function() {\n    alert(\"I am an IIFE!\");\n}());\n\n// Variation 2\n(function() {\n    alert(\"I am an IIFE, too!\");\n})();</code></pre>\n\n\n\n<p id=\"8bd8\">Теперь у нас есть две рабочие IIFE. Может быть немного тяжеловато подметить разницу между ними. Так что давайте я вам сейчас её объясню.</p>\n\n\n\n<p id=\"07f1\">В первом варианте, на строке 4, скобки&nbsp;<code>()</code>&nbsp;для запуска функционального выражения содержат еще и внешние скобки. Они нужны для того, чтобы создать функцию за пределами этой функции.</p>\n\n\n\n<p id=\"4034\">Во втором варианте, на строке 9, скобки для запуска функционального выражения находятся за пределами оборачивающих функцию кавычек.</p>\n\n\n\n<p id=\"00c2\">Оба вариант широко используют. Лично я предпочитаю первый. Если мы начнем придираться и капнем глубже, то оба варианта слегка отличаются друг от друга в плане работы под капотом. Но для практических целей и для того, чтобы хоть как-то сократить этот туториал, то скажу я вам так &#8212; используйте просто любой из этих способов на ваше усмотрение.</p>\n\n\n\n<p id=\"516f\">Давайте снова разберем всё на рабочих примерах. Мы начнем с раздачи имён нашим IIFE, так как использование анонимных функций никогда не было хорошей идеей в этом случае.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// Правильная IIFE\n(function initGameIIFE() {\n     // Весь код тут\n}());\n\n // Дальше будут два неправильных примера\nfunction nonWorkingIIFE() {\n // Теперь понятно зачем нужны эти скобки вокруг меня\n // Без них я объявление функции, а не выражение\n // Тут вы схватите синтаксическую ошибку\n}();\n\nfunction () {\n     // И тут тоже\n}();</code></pre>\n\n\n\n<p id=\"e1f8\">Теперь вы знаете почему странные обертывающие скобки вокруг функционального выражения нужны в паттерне IIFE.</p>\n\n\n\n<p id=\"d867\">Запомните, вам нужно функциональное выражение, чтобы сформировать IIFE. Объявления/определения функции никогда не используются для создания IIFE.</p>\n\n\n\n<h2 id=\"0822\"><strong>IIFE и приватные переменные</strong></h2>\n\n\n\n<p id=\"800a\">В чем действительно хороши IIFE, так это в возможности создания области видимости.</p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p><em>Любые переменные внутри IIFE не видимы для внешнего мира.</em></p></blockquote>\n\n\n\n<p>Давайте посмотрим на пример.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>(function IIFE_initGame() {\n     // Приватные переменные к которым нет доступа за пределами IIFE\n    var lives;\n    var weapons;\n    \n    init();\n\n     // Приватные функции к которым нет доступа за пределами IIFE\n    function init() {\n        lives = 5;\n        weapons = 10;\n    }\n}());</code></pre>\n\n\n\n<p>В этом примере мы объявили две переменные внутри IIFE и тут они приватные, то есть только для самой IIFE. Никто за пределами IIFE не имеет к ней доступа. Так же, у нас есть функция&nbsp;<code>init</code>, к которой ни у кого нет доступа за пределами IIFE. Но функция&nbsp;<code>init</code>&nbsp;имеет доступ к приватным переменным.</p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p><em>В следующий раз, когда вы будете создавать группу переменных и функций в глобальной области видимости, которые никто не использует за пределами вашего кода, просто оберните все их в IIFE и получит в ответочку много хорошей JavaScript кармы за такие дела. Ваш код будет также работать, но только теперь вы не будете загрязнять глобальную область видимости. А еще вы защитите ваш код от тех, кто может случайно внести изменения в глобальные переменные, ну а может быть и не случайно.</em></p></blockquote>\n\n\n\n<p>Когда мы доберемся до модульного паттерна, тогда я объясню то, как раздать привилегии и контролировать доступ к таким приватным переменным, даже за пределами IIFE. В общем, читаем дальше, пусть даже если вы уже чувствуете себя IIFE ниндзей!</p>\n\n\n\n<h2 id=\"89ae\"><strong>IIFE с отдаваемым значением</strong></h2>\n\n\n\n<p id=\"68c4\">Если вам не нужно отдавать никаких значений в IIFE, то тогда вы могли бы просто использовать первый вариант стилизации, увиденный в этой статье, подразумевающий использование унарных операторов&nbsp;<code>!</code>,&nbsp;<code>+</code>,&nbsp;<code>void</code>&nbsp;и т.п.</p>\n\n\n\n<p id=\"610a\">Но ещё одной реально важной и полезной фичей IIFE является то, что с их помощью вы можете отдавать значение, которое будет назначено переменной.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>var result = (function() {\n    return \"From IIFE\";\n}());\n\nalert(result); // alerts \"From IIFE\"</code></pre>\n\n\n\n<p id=\"4016\">В этой вариации у нас есть IIFE, которая отдаёт значение на второй строке.</p>\n\n\n\n<p id=\"7c2a\">Когда мы выполняем код выше, то строка 5 показывает&nbsp;<code>alert</code>&nbsp;с отдаваемым значением от IIFE.</p>\n\n\n\n<p id=\"30ec\">В общем, тут мгновенно выполнилась IIFE и потом отдало значение, которое назначилось переменной&nbsp;<code>result</code>.</p>\n\n\n\n<p id=\"257b\">Это очень крутой паттерн, который мы будем использовать в примере с модульным паттерном.</p>\n\n\n\n<h2 id=\"0444\"><strong>IIFE с параметрами</strong></h2>\n\n\n\n<p id=\"eed4\">IIFE не только могут отдавать значения, но ещё и брать аргументы во время своего вызова. Давайте посмотрим на этот короткий пример.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>(function IIFE(msg, times) {\n    for (var i = 1; i &lt;= times; i++) {\n        console.log(msg);\n    }\n}(\"Hello!\", 5));</code></pre>\n\n\n\n<p id=\"fe49\">В примере выше, а именно на 1й строке, IIFE чисто формально имеет два параметра с именами&nbsp;<code>msg</code>&nbsp;и&nbsp;<code>times</code>.</p>\n\n\n\n<p id=\"4428\">Когда мы выполняем её на 5й строке, то вместо пустых скобок, мы в них передаём аргументы IIFE.</p>\n\n\n\n<p id=\"7672\">Строки 2 и 3 используют эти параметры уже внутри IIFE.</p>\n\n\n\n<p id=\"a225\">Это тоже довольно полезный паттерн и мы часто его видим в jQuery, да и в других библиотеках тоже.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>(function($, global, document) {\n    // используем баксик для jQuery, а global для window\n}(jQuery, window, document));</code></pre>\n\n\n\n<p id=\"bd05\">В пример выше, мы передаём&nbsp;<code>jQuery</code>,&nbsp;<code>window</code>&nbsp;и&nbsp;<code>document</code>, как аргументы к IIFE на строке 3. Код внутри IIFE может ссылаться к ним, как к&nbsp;<code>$</code>,&nbsp;<code>global</code>,&nbsp;<code>document</code>.</p>\n\n\n\n<p id=\"9651\">Вот несколько преимуществ такой передачи параметров к IIFE.</p>\n\n\n\n<p id=\"c815\">JavaScript всегда делает поиск по области видимости заданной функции и продолжает поиск в области видимости выше, пока не найдёт указанный идентификатор. Когда мы передаём&nbsp;<code>document</code>&nbsp;на 3 строке, то это один и единственный раз, когда мы делаем поиск вне локальной области видимости. Любые отсылки к&nbsp;<code>document</code>&nbsp;в IIFE, никогда не должны искаться за пределами локальной области видимости самой IIFE. Так же и с&nbsp;<code>jQuery</code>. Даже в зависимости от сложности кода, рост производительности может быть не слишком высок, но всё равно эту фишку полезно знать.</p>\n\n\n\n<p id=\"b9f3\">Также, минифаеры JS могут безопасно минифицировать имена параметров, указанных в функции. Если мы не передавали эти параметры, то минифаеры не будут отсылаться к&nbsp;<code>document</code>&nbsp;или&nbsp;<code>jQuery</code>, так как они находятся вне области видимости этой функции.</p>\n\n\n\n<h2 id=\"01e2\"><strong>Классический модульный паттерн в JavaScript</strong></h2>\n\n\n\n<p id=\"19b5\">Теперь, когда вы отточили навыки работы с IIFE, давайте посмотрим на пример модульного паттерна, который раскрывают всю мощь совместного применения замыканий и IIFE функций.</p>\n\n\n\n<p id=\"4757\">Тут мы применим классический синглтон объект&nbsp;<code>Sequence</code>, в котором всё стабильно отрабатывает без возможности непреднамеренного изменения значения.</p>\n\n\n\n<p id=\"a2e3\">Мы разделим код на два шага, чтобы постепенно понять то, что происходит под капотом.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>var Sequence = (function sequenceIIFE() {\n    \n    // приватная переменная для хранения значения счетчика\n    var current = 0;\n    \n    // объект, возвращаемый IIFE\n    return {\n    };\n    \n}());\n\nalert(typeof Sequence); // alerts \"object\"</code></pre>\n\n\n\n<p id=\"8bc0\">В этом примере, наша IIFE отдаёт объект. Смотрите строки 7 и 8.</p>\n\n\n\n<p id=\"af48\">Также тут есть локальная переменная под названием&nbsp;<code>current</code>.</p>\n\n\n\n<p id=\"ec05\">Отдаваемое IIFE значение, которое является объектом и назначается на переменную&nbsp;<code>Sequence</code>.</p>\n\n\n\n<p id=\"3551\">А теперь давайте усложним код, добавив несколько функций в отдаваемый нами объект.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>var Sequence = (function sequenceIIFE() {\n    \n    // приватная переменная для хранения значения счетчика\n    var current = 0;\n    \n    // объект, возвращаемый IIFE\n    return {\n        getCurrentValue: function() {\n            return current;\n        },\n        \n        getNextValue: function() {\n            current = current + 1;\n            return current;\n        }\n    };\n    \n}());\n\nconsole.log(Sequence.getNextValue()); // 1\nconsole.log(Sequence.getNextValue()); // 2\nconsole.log(Sequence.getCurrentValue()); // 2</code></pre>\n\n\n\n<p id=\"df43\">В этом примере мы добавили две функции нашему отдаваемому объекту.</p>\n\n\n\n<p id=\"2ca2\">Строки 8–10 хранят функцию&nbsp;<code>getCurrentValue</code>, которая отдаёт значение из переменной&nbsp;<code>current</code>.</p>\n\n\n\n<p id=\"8c1c\">Строки 12–15 добавляют функцию&nbsp;<code>getNextValue</code>, которая увеличивает значение&nbsp;<code>current</code>&nbsp;на 1 и затем отдаёт его значение.</p>\n\n\n\n<p id=\"52c9\">Так как переменная&nbsp;<code>current</code>&nbsp;является приватной в IIFE, то никто кроме функций, имеющих доступ к IIFE через замыкание, не имеет к ней доступа.</p>\n\n\n\n<p id=\"023d\">Теперь вы узнали реально мощный паттерн JavaScript. Он включает в себя мощь использования IIFE и замыканий вместе.</p>\n\n\n\n<p id=\"9536\">Это очень простая вариация модульного паттерна. Есть и другие паттерны такого плана, но почти все из них используют IIFE для создания закрытой области видимости.</p>\n\n\n\n<h2 id=\"69ec\"><strong>Когда можно пренебречь скобками</strong></h2>\n\n\n\n<p id=\"a654\">Скобки вокруг функционального выражения обычно принуждают функцию к виду выражения, вместо обычного объявления функции.</p>\n\n\n\n<p id=\"02c4\">Но когда JavaScript движку понятно, что это функциональное выражение и нам технически просто не нужны оборачивающие скобки, как показано в примере ниже.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>var result = function() {\n    return \"From IIFE!\";\n}();</code></pre>\n\n\n\n<p id=\"3720\">В примере выше, слово&nbsp;<code>function</code>&nbsp;это не первое слово в объявлении. Поэтому JavaScript не воспринимает его, как указание функции. Также есть и другие случаи, в которых вы можете избежать кавычек, когда вы знаете то, что это выражение.</p>\n\n\n\n<p id=\"6ac1\">Но даже в этом случае я пытаюсь использовать скобки. Они улучшают читабельность, прямо с первых строк стилистически подсказывая человеку, что это будет IIFE. И никому не надо будет скроллить к последней строке функции, чтобы понять то, что только что они прочитали не простую функцию, а именно IIFE.</p>\n\n\n\n<p id=\"07be\">Это всё, что вам нужно знать для начала работы с IIFE. Они не только помогают организовывать и изображать ваш код в приятной и понятной манере, они также помогают сократить количество багов, избегая создания совершенно ненужных элементов глобальной области видимости.</p>\n\n\n\n<p id=\"04a4\">Ну всё, теперь вы, можно сказать, что сертифицированный IIFE ниндзя!</p>\n","date":"2021-01-26T00:56:07.000Z","title":"Понимаем немедленно вызываемые функции IIFE и немного больше","id":"0106d270-fa32-58a4-80d7-04d2c536af00","excerpt":"<p>В этой статье вы подробно узнаете, что такое IIFE, какие они бывают и как их использовать в JavaScript.</p>\n","type":"js","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2021/01/iifejsnfdks.jpg"}}},{"node":{"slug":"7-poleznyh-ulovok-s-rest-parametrami-i-spread-operatorom-na-javascript-objectah","content":"\n<p>7 удобных трюков с rest и spread, которые значительно упростят ваш процесс написания кода.</p>\n\n\n\n<p class=\"author\"><a rel=\"noreferrer noopener\" href=\"https://blog.bitsrc.io/6-tricks-with-resting-and-spreading-javascript-objects-68d585bdc83\" target=\"_blank\"><em>Перевод 7 Tricks with Resting and Spreading JavaScript Objects</em></a></p>\n\n\n\n<p>Если у вас есть время, то советую сначала прочитать&nbsp;<a rel=\"noreferrer noopener\" target=\"_blank\" href=\"https://stasonmars.ru/javascript/operator-spread-i-rest-parametry-v-javascript/\">Оператор spread и rest параметры в JavaScript</a></p>\n\n\n\n<p id=\"345d\">Rest параметры и оператор spread можно использовать не только для простой работы с остаточными аргументами и для создании массивов.</p>\n\n\n\n<p id=\"ee8b\">Ниже вы узнаете 7 малоизвестных трюков с использованием вышеупомянутых операторов в JavaScript.</p>\n\n\n\n<h2 id=\"3411\">1. Добавление свойств</h2>\n\n\n\n<p id=\"07db\">Вы можете клонировать объект, параллельно добавляя дополнительные свойства клонированному объекту.</p>\n\n\n\n<p id=\"d0b3\">В этом примере&nbsp;<code>user</code>&nbsp;клонирован и к нему добавлен&nbsp;<code>password</code>&nbsp;в&nbsp;<code>userWithPass</code>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const user = { id: 100, name: 'Howard Moon'}\nconst userWithPass = { ...user, password: 'Password!' }\n\nuser //=> { id: 100, name: 'Howard Moon' }\nuserWithPass //=> { id: 100, name: 'Howard Moon', password: 'Password!' }</code></pre>\n\n\n\n<h2 id=\"baad\">2. Слияние объектов</h2>\n\n\n\n<p id=\"f331\">Ещё вы можете слить два объекта в один новый.</p>\n\n\n\n<p id=\"731a\"><code>part1</code>&nbsp;и&nbsp;<code>part2</code>&nbsp;сливаются в&nbsp;<code>user1</code>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const part1 = { id: 100, name: 'Howard Moon' }\nconst part2 = { id: 100, password: 'Password!' }\n\nconst user1 = { ...part1, ...part2 }\n//=> { id: 100, name: 'Howard Moon', password: 'Password!' }</code></pre>\n\n\n\n<p>Объекты также можно слить и с таким синтаксисом:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const partial = { id: 100, name: 'Howard Moon' }\nconst user = { ...partial, id: 100, password: 'Password!' }\n\nuser //=> { id: 100, name: 'Howard Moon', password: 'Password!' }</code></pre>\n\n\n\n<h2>3. Исключить свойства объекта</h2>\n\n\n\n<p>Свойства можно удалить используя деструктуризацию в комбинации с rest оператором. Тут мы деструктуризируем&nbsp;<code>password</code>&nbsp;и остальные свойства объекта отдаются как rest.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const noPassword = ({ password, ...rest }) => rest\nconst user = {\n  id: 100,\n  name: 'Howard Moon',\n  password: 'Password!'\n}\n\nnoPassword(user) //=> { id: 100, name: 'Howard moon' }</code></pre>\n\n\n\n<h2 id=\"14da\">4. Динамическое исключение свойств</h2>\n\n\n\n<p id=\"8b9d\">Функция removeProperty берёт&nbsp;<code>props</code>&nbsp;как аргумент. Используя вычисление имен свойств&nbsp;<code>prop</code>&nbsp;может быть исключен динамически из объекта клона.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const user1 = {\n  id: 100,\n  name: 'Howard Moon',\n  password: 'Password!'\n}\nconst removeProperty = prop => ({ &#91;prop]: _, ...rest }) => rest\n//                     ----       ------\n//                          \\   /\n//                dynamic destructuring\n\nconst removePassword = removeProperty('password')\nconst removeId = removeProperty('id')\n\nremovePassword(user1) //=> { id: 100, name: 'Howard Moon' }\nremoveId(user1) //=> { name: 'Howard Moon', password: 'Password!' }</code></pre>\n\n\n\n<h2 id=\"5a0d\">5. Организация свойств</h2>\n\n\n\n<p id=\"8f3e\">Иногда свойства находятся не в нужном нам порядке. Используя несколько трюков мы можем поставить нужные свойства в самый верх списка или же наоборот, в самый низ.</p>\n\n\n\n<p id=\"fb85\">Чтобы отправить&nbsp;<code>id</code>&nbsp;на первое место, добавьте&nbsp;<code>id: undefined</code>&nbsp;новому объекту перед оператором расширения.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const user3 = {\n  password: 'Password!',\n  name: 'Naboo',\n  id: 300\n}\n\nconst organize = object => ({ id: undefined, ...object })\n//                            -------------\n//                          /\n//  move id to the first property\n\norganize(user3)\n//=> { id: 300, password: 'Password!', name: 'Naboo' }</code></pre>\n\n\n\n<p>Чтобы отправить&nbsp;<code>password</code>&nbsp;на последнее место, то сначала деструктуризируйте&nbsp;<code>password</code>&nbsp;из&nbsp;<code>object</code>. Далее, выставьте&nbsp;<code>password</code>&nbsp;за оператором расширения.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const user3 = {\n  password: 'Password!',\n  name: 'Naboo',\n  id: 300\n}\n\nconst organize = ({ password, ...object }) =>\n  ({ ...object, password })\n//              --------\n//             /\n// move password to last property\n\norganize(user3)\n//=> { name: 'Naboo', id: 300, password: 'Password!' }</code></pre>\n\n\n\n<h2 id=\"ae18\">6. Дефолтные свойства</h2>\n\n\n\n<p id=\"3057\">Дефолтные свойства это значения, которые будут выставлены только когда они не включены в оригинальный объект.</p>\n\n\n\n<p id=\"3d9e\">В нашем примере&nbsp;<code>user2</code>&nbsp;не включает в себя&nbsp;<code>quotes</code>. Функция&nbsp;<code>setDefaults</code>&nbsp;проверяет есть ли в объектах&nbsp;<code>quotes</code>, если нет, то он будет выставлен на&nbsp;<code>[]</code>.</p>\n\n\n\n<p id=\"0dbe\">Вызывая&nbsp;<code>setDefaults(user2)</code>, отдающееся значение будет включать в себя&nbsp;<code>quotes: []</code>.</p>\n\n\n\n<p id=\"7c92\">Вызывая&nbsp;<code>setDefaults(user4)</code>&nbsp;ничего не поменяется, потому что&nbsp;<code>user4</code>&nbsp;уже содержит&nbsp;<code>quotes</code>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const user2 = {\n  id: 200,\n  name: 'Vince Noir'\n}\n\nconst user4 = {\n  id: 400,\n  name: 'Bollo',\n  quotes: &#91;\"I've got a bad feeling about this...\"]\n}\n\nconst setDefaults = ({ quotes = &#91;], ...object}) =>\n  ({ ...object, quotes })\n\nsetDefaults(user2)\n//=> { id: 200, name: 'Vince Noir', quotes: &#91;] }\n\nsetDefaults(user4)\n//=> {\n//=>   id: 400,\n//=>   name: 'Bollo',\n//=>   quotes: &#91;\"I've got a bad feeling about this...\"]\n//=> }</code></pre>\n\n\n\n<p>Это также может быть написано таким образом:</p>\n\n\n\n<pre class=\"wp-block-code\"><code>const setDefaults = ({ ...object}) => ({ quotes: &#91;], ...object })</code></pre>\n\n\n\n<h2 id=\"304f\">7. Переименовывание свойств</h2>\n\n\n\n<p id=\"e6e4\">Совмещая методики описанные выше, мы можем создать функцию которая переименовывает свойства.</p>\n\n\n\n<p id=\"4caf\">Представьте, что у вас есть несколько объектов с&nbsp;<code>ID</code>&nbsp;в верхнем регистре, которые должны быть в нижнем. Начните с деструктуризации&nbsp;<code>ID</code>&nbsp;из объекта. Далее, верните его в объект как&nbsp;<code>id</code>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const renamed = ({ ID, ...object }) => ({ id: ID, ...object })\n\nconst user = {\n  ID: 500,\n  name: \"Bob Fossil\"\n}\n\nrenamed(user) //=> { id: 500, name: 'Bob Fossil' }</code></pre>\n\n\n\n<h2 id=\"26fb\">8. БОНУС! Добавляем свойства по условию</h2>\n\n\n\n<p id=\"f80f\">Спасибо&nbsp;<a rel=\"noreferrer noopener\" href=\"http://twitter.com/vinialbano\" target=\"_blank\">@vinialbano</a>&nbsp;за то, что указал на то, что вы можете ещё и добавлять свойства в зависимости от условий. В этом примере,&nbsp;<code>password</code>&nbsp;будет добавлен только если&nbsp;<code>password</code>&nbsp;определен.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const user = { id: 100, name: 'Howard Moon' }\nconst password = 'Password!'\nconst userWithPassword = {\n  ...user,\n  id: 100,\n  ...(password &amp;&amp; { password })\n}\n\nuserWithPassword //=> { id: 100, name: 'Howard Moon', password: 'Password!' }</code></pre>\n\n\n\n<p></p>\n","date":"2021-01-22T12:02:18.000Z","title":"7 полезных уловок с rest параметрами и spread операторами на JavaScript объектах","id":"39b80613-6819-585a-a827-3d313393adaf","excerpt":"<p>7 удобных трюков с rest и spread, которые значительно упростят ваш процесс написания кода.</p>\n","type":"js","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2021/01/restspreadkjnkjn.jpg"}}},{"node":{"slug":"operator-spread-i-rest-parametry-v-javascript","content":"\n<p id=\"86ff\">В этой статье вы узнаете про возможности применения, такого функционала, как spread оператор и rest параметры. И как при помощи первого, без особого труда можно конвертировать итерируемые объекты в массивы.</p>\n\n\n\n<p id=\"e4f3\">Можно переводить эти названия, а можно и нет. Но я лично считаю, что в этом случае лучше придерживаться англоязычной терминологии, так как такой термин, как “<em>оператор расширения</em>” могут понять не все и вообще это довольно грубый перевод, а “<em>остаточные параметры</em>” может выходить из контекста данного применения. Но в тексте будут звучать два варианта.</p>\n\n\n\n<p class=\"author\" id=\"090f\">Переводы статей&nbsp;<a rel=\"noreferrer noopener\" href=\"https://www.vojtechruzicka.com/spread-javascript/\" target=\"_blank\">Javascript spread operator and rest parameters (…)</a> и&nbsp;<a rel=\"noreferrer noopener\" target=\"_blank\" href=\"https://medium.com/@samanthaming/convert-iterables-to-array-using-spread-in-javascript-b6ccd4e858b1\">Convert&nbsp;Iterables to Array using Spread in JavaScript</a></p>\n\n\n\n<h2 id=\"1577\"><strong>Переменное количество параметров</strong></h2>\n\n\n\n<p id=\"6ff6\">Обычно при работе с JavaScript функциями у нас имеется конкретное число параметров для каждой функции. Если вы хотите посчитать квадратный корень числа с помощью&nbsp;<code>Math.sqrt(x)</code>, то вам всегда нужно вводить один параметр. Само собой, некоторые функции могут требовать и несколько параметров. Но в некоторых случаях с большим количеством оных, вы можете спокойно пропустить несколько последних из них, в силу их опциональности. Во всех этих случаях, все параметры указываются, как часть сигнатуры функции:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function doSomething(first, second, third) { \n    // Do something cool\n}</code></pre>\n\n\n\n<p id=\"3198\">Но что, если количество параметров вообще неизвестно заранее и их может быть вообще неизвестно сколько?</p>\n\n\n\n<p id=\"027b\">Для примера, давайте возьмём&nbsp;<code>Math.min()</code>&nbsp;и&nbsp;<code>Math.max()</code>. Они работают с любым количеством параметров, хоть с 0, 2-мя или 30-ю.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>Math.Min(); // Infinity\nMath.Min(1); // 1\nMath.Min(1,2,3,4,3,1,5,7,9,0,-9,18,37,81); // -9</code></pre>\n\n\n\n<p>Как бы вы написали такую функцию?</p>\n\n\n\n<h2>Arguments — традиционный подход </h2>\n\n\n\n<p>Когда вам приходится работать с переменным количеством параметров в функции, то обычно вашим единственным вариантом был бы объект arguments. Внутри каждой функции существует объект argument, который имеет массивоподобную структуру, содержащую все аргументы, переданные функции. Каждый из которых вы можете получить начиная с нулевого индекса, также вы можете проверить количество параметров, как и с любым другим массивом.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function doSomething() { \n    arguments&#91;0]; // \"A\"\n    arguments&#91;1]; // \"B\"\n    arguments&#91;2]; // \"C\"\n    arguments.length; // 3\n}\n\ndoSomething(\"A\",\"B\",\"C\");</code></pre>\n\n\n\n<h3 id=\"a46c\"><strong>Ограничения arguments</strong></h3>\n\n\n\n<p id=\"ed48\">Обратите внимание на то, что&nbsp;<code>arguments</code>&nbsp;это массивоподобный объект, а не полноценный массив. Это говорит о том, что такие полезные методы, как&nbsp;<code>arguments.sort()</code>,&nbsp;<code>arguments.map()</code>&nbsp;или&nbsp;<code>arguments.filter()</code>&nbsp;будут вам недоступны. В этом случае у вас будет только свойство&nbsp;<code>length</code>.</p>\n\n\n\n<p id=\"fa91\">Еще одно ограничение в том, что в стрелочных функциях недоступен объект&nbsp;<code>arguments</code>. В случае, если бы вы использовали&nbsp;<code>arguments</code>&nbsp;в стрелочной функции, то она бы перенаправила вас к коллекции аргументов вложенной функции (если таковая бы имелась).</p>\n\n\n\n<h2>Rest параметры (остаточные параметры) </h2>\n\n\n\n<p>К нашей радости, начиная с ES6, объект arguments больше не является единственным способом работы с переменным количеством параметров. ES6 дал нам такую концепцию, как <em>rest параметры</em>. Это означает то, что вы просто можете вставить <code>…</code> перед последним параметром функции.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function doSomething(first, second, ...rest) {\n    // do something cool\n}</code></pre>\n\n\n\n<p>Теперь, в этом примере вы можете получить доступ к первым двум именованным параметрам как и обычно. А вот уже к другим аргументам, переданным функции начиная с третьего, вы сможете получить доступ через массив под названием&nbsp;<code>rest</code>, куда все они автоматически будут собираться.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function doSomething(first, second, ...rest) {\n    console.log(first); // Первый аргумент\n    console.log(second); // Второй аргумент\n    console.log(rest&#91;0]); // Третий аргумент\n    console.log(rest&#91;1]); // Четвертый\n    // Etc.\n}</code></pre>\n\n\n\n<p>Если вы передадите меньше, чем 3 параметра, то&nbsp;<code>rest</code>&nbsp;будет просто пустым массивом.</p>\n\n\n\n<p>В отличие от объекта <code>arguments</code>, <code>rest</code> параметры отдают реальный массив, так что вы в этом случае сможете использовать буквально все доступные в этом случае методы. Более того, в отличие от <code>arguments</code>, они работают в стрелочных функциях.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>let doSomething = (...rest) => {\n    rest&#91;0]; // Доступ к первому аргументу\n};\n\nlet doSomething = () => {\n    arguments&#91;0]; // У стрелочных функций нет аргументов\n};</code></pre>\n\n\n\n<p>В придачу к преимуществам описанным выше, есть ещё одно, которое делает&nbsp;<code>rest</code>&nbsp;параметры круче&nbsp;<code>arguments</code>.&nbsp;<code>Rest</code>&nbsp;параметры являются частью функциональной сигнатуры. Это означает то, что прямо с “шапки” функции вы можете сразу понять, что она применяет остаточные параметры и следовательно, доступна для переменного количества аргументов. С объектом&nbsp;<code>arguments</code>, такого трюка не получится. С ним нам придется вчитываться в тело функции или в комментарии, которые будут нам говорить о возможности добавления переменного количества параметров. Что ещё важно, так это то, что редакторы кода могут определять остаточные параметры в сигнатуре и ещё лучше помогать вам при разработке.</p>\n\n\n\n<h3 id=\"8650\"><strong>Ограничения</strong></h3>\n\n\n\n<p id=\"5bf4\"><code>Rest</code>&nbsp;параметры берут все оставшиеся аргументы функции и складывают их в массив. Этот подход влечет собой два ограничения. Вы можете использовать указание&nbsp;<code>rest</code>&nbsp;параметров только единожды при написании функции, большее их количество будет просто недопустимо:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// Так делать нельзя, нужен только один параметр rest\nfunction doSomething(first, ...second, ...third) {\n}</code></pre>\n\n\n\n<p>И вы можете использовать эти параметры только, как последние параметры функции:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// Тут ничего не выйдет, rest параметры не находятся в конце функции\nfunction doSomething(first, ...second, third) {\n}</code></pre>\n\n\n\n<h2 id=\"cf84\"><strong>Spread оператор (оператор расширения)</strong></h2>\n\n\n\n<p id=\"b612\">Что тут смущает, так это такое же троеточие&nbsp;<code>…</code>, как и в&nbsp;<code>rest</code>&nbsp;параметрах. Но называется уже по-другому, а именно&nbsp;<code>spread</code>&nbsp;оператором. Его назначение почти противоположно вышеупомянутым остаточным параметрам. Вместо сбора нескольких значений в один массив, он позволяет расширить заданный массив (или другой итерируемый объект) в несколько значений. Давайте посмотрим на разнообразные способы его применения:</p>\n\n\n\n<h3 id=\"84c1\"><strong>Вызовы функций</strong></h3>\n\n\n\n<p id=\"93ac\">Давайте предположим, что у нас есть массив с тремя элементами и функция, которой нужно три параметра.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>let myArray = &#91;1, 2, 3];\n\nfunction doSomething(first, second, third) {\n}</code></pre>\n\n\n\n<p>Как вы передадите три значения нашего массива, как три отдельных аргумента для функции&nbsp;<code>doSomething()</code>? Есть довольно наивный подход к этому делу:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>doSomething(myArray&#91;0], myArray&#91;1], myArray&#91;2]);</code></pre>\n\n\n\n<p>Очевидно, что это не очень хороший подход, особенно с учетом большого количества параметров и работать он будет только если мы будем знать количество этих самых параметров заранее. Давайте попробуем что-нибудь другое. Перед появлением оператора расширения, вот такой подход использовался для вызова функции и передачи массива в виде раздельных параметров:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>doSomething.apply(null, myArray);</code></pre>\n\n\n\n<p id=\"d508\">Первым параметром в&nbsp;<code>apply()</code>&nbsp;является то, что мы собираемся использовать, как&nbsp;<code>this</code>. Вторым параметром тут будет массив, который мы хотим передать функции, как аргументы.</p>\n\n\n\n<p id=\"48ec\">Но с оператором расширения вы можете достигнуть тех же результатов с помощью:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>doSomething(...myArray);\n// то же самое\ndoSomething(myArray&#91;0], myArray&#91;1], myArray&#91;2]);</code></pre>\n\n\n\n<p id=\"22b3\">Обратите внимание, что этот метод работает с любым итерируемым объектом, а не только с массивами. Для примера, оператор расширения разделит строку на отдельные символы из которых состоит слово или предложение.&nbsp;<em>Но об этом немного дальше.</em></p>\n\n\n\n<p id=\"7aa2\">А еще это можно совмещать вместе с передачей отдельных параметров. В отличие от&nbsp;<code>rest</code>&nbsp;параметров, вы можете применить несколько&nbsp;<code>spread</code>&nbsp;операторов в одном вызове функции и им не обязательно быть последним элементом в переданных параметрах.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// Всё это возможно\ndoSomething(1, ...myArray);\ndoSomething(1, ...myArray, 2);\ndoSomething(...myArray, ...otherArray);\ndoSomething(2, ...myArray, ...otherArray, 3, 7);</code></pre>\n\n\n\n<h2 id=\"0141\"><strong>Массив литералы</strong></h2>\n\n\n\n<p id=\"17a1\">Оператор расширения также можно использовать при создании массива. Этим способом вы сможете вставить элементы из других массивов (или перечисляемые объекты, такие как строки) на указанные места в будущем массиве.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>let firstArray = &#91;\"A\", \"B\", \"C\"];\nlet secondArray = &#91;\"X\", ...firstArray, \"Y\", \"Z\"];\n// вторым массивом будет &#91; \"X\", \"A\", \"B\", \"C\", \"Y\", \"Z\" ]</code></pre>\n\n\n\n<p>Используя оператор расширения в массив литерале, мы как бы говорим: второй массив должен иметь “X”, как первый аргумент, а далее уже идут все элементы массива&nbsp;<code>firstArray</code>, вне зависимости от их количества. И под конец у нас два элемента “Y” и “Z”.</p>\n\n\n\n<h2 id=\"e871\"><strong>Объединение массивов</strong></h2>\n\n\n\n<p id=\"115d\">Естественно, вы можете использовать оператор расширения в массив литерале множество раз. Это может пригодиться, к примеру, для объединения нескольких уже существующих массивов, что было бы затруднительнее, при использовании традиционного императивного подхода.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>let mergedArray = &#91;…firstArray, …secondArray, …thirdArray];</code></pre>\n\n\n\n<h2 id=\"4962\">Копирование массивов</h2>\n\n\n\n<p id=\"a5ba\">Иногда также полезно создать копию существующего массива с таким же набором элементов, как и у оригинального. Это можно легко и просто сделать с помощью&nbsp;<code>spread</code>&nbsp;оператора.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>var original = &#91;1, 2, 3];\nvar copy = &#91;...original];</code></pre>\n\n\n\n<h2 id=\"6846\"><strong>Объект литералы</strong></h2>\n\n\n\n<p id=\"bdcc\">Оператор расширения очень схоже используется при создании объектов. Вы можете взять свойства одного объекта и включить их в новый объект, созданный объект литералом. Этот функционал доступен с ES2018 версии.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>let firstObject = {a: 1, b: 2};\n\nlet secondObject = {...firstObject, c: 3, d: 4};\n\nconsole.log(secondObject); // { a: 1, b: 2, c: 3, d: 4 }</code></pre>\n\n\n\n<p>Имейте ввиду, что&nbsp;<code>spread</code>&nbsp;берет только собственные (не наследуемые) и перечислимые свойства объекта, все другие свойства будут попросту игнорироваться.</p>\n\n\n\n<h3>Поверхностная копия</h3>\n\n\n\n<p>Тут всё очень схоже с массивами. Вы можете смело склеивать и клонировать объекты.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>let clone = {…original};</code></pre>\n\n\n\n<p>Это может быть хорошей альтернативой для клонирования объектов с помощью&nbsp;<code>Object.assign()</code>. Но обратите внимание, что это поверхностная копия. Новый объект создастся, но клонированные свойства все равно будут от оригинала, а не клонами.</p>\n\n\n\n<h3 id=\"a25c\">Потерянный прототип</h3>\n\n\n\n<p id=\"ff1e\">Клонируя объект способом выше вам стоит знать то, что прототип оригинального объекта не сохранится. Там просто копируются свойства исходного объекта и создастся совершенно новый объект, используя объект литерал, у которого прототип&nbsp;<code>Object.prototype</code>.</p>\n\n\n\n<h3 id=\"ebe4\">Конфликты свойств</h3>\n\n\n\n<p id=\"f4cf\">Что случиться когда вы укажите свойство через оператор расширения, но это свойство уже будет существовать в объекте? Это не приведет к ошибке. Просто напросто, если будет несколько свойств объекта с одним и тем же именем, но разными свойствами, то победит последний.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>let firstObject = {a: 1};\nlet secondObject = {a: 2};\n\nlet mergedObject = {...firstObject, ...secondObject};\n// a: 2 is after a: 1 so it wins\nconsole.log(mergedObject); // { a: 2 }</code></pre>\n\n\n\n<h3 id=\"63b6\">Изменение иммутабельных объектов</h3>\n\n\n\n<p id=\"689f\">Момент, когда ранее объявленное свойство с тем же именем перезаписывает другое, можно применить при изменении иммутабельных объектов. Когда вы работаете с таковыми или не хотите напрямую изменять изменять объекты, вы можете смело применить оператор расширения для создания нового объекта, как измененного варианта исходной копии.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>let original = {\n      someProperty: \"oldValue\", \n      someOtherProperty: 42\n    };\n\nlet updated = {...original, someProperty: \"newValue\"};\n// Теперь { someProperty: \"newValue\", someOtherProperty: 42 }</code></pre>\n\n\n\n<p>Так как в оригинальной копии есть&nbsp;<code>someProperty</code>&nbsp;и в дальнейшем оно также используется, то будет взято значение при последнем её упоминании. Исходный объект не изменится в любом случае, но создастся новый объект.</p>\n\n\n\n<h2 id=\"6e35\"><strong>Деструктурирующее присваивание</strong></h2>\n\n\n\n<p id=\"f557\">Если кратко, то деструктурирующее присваивание это способ назначения свойств объекта или значений из массивов в отдельные переменные.</p>\n\n\n\n<h3 id=\"0aea\"><strong>Деструктуризация массивов</strong></h3>\n\n\n\n<p id=\"81b1\">Предположим, что у нас есть массив из трех элементов и каждый из них нам надо назначить как самостоятельную переменную.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>let myArray = &#91;1, 2, 3];\nlet a,b,c; //Мы хотим назначить a=1, b=2, c=3</code></pre>\n\n\n\n<p>Мы это можем легко сделать с помощью деструктуризации:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>let myArray = &#91;1,2,3];\nlet &#91;a, b, c] = myArray;\n\nconsole.log(a); // 1\nconsole.log(b); // 2\nconsole.log(c); // 3</code></pre>\n\n\n\n<p>Но как это вообще связано с синтаксисом из трех точек, про который мы говорили выше? Помните остаточные параметры? Так же, как и все оставшиеся аргументы пакуются в один массив, мы можем назначить все оставшиеся после деструктурирующего присваивания элементы в новую переменную, которая будет являться массивом:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>let myArray = &#91;1, 2, 3, 4, 5];\nlet &#91;a, b, c, ...d] = myArray;\n\nconsole.log(a); // 1\nconsole.log(b); // 2\nconsole.log(c); // 3\nconsole.log(d); // &#91;4, 5]</code></pre>\n\n\n\n<h2 id=\"4fb9\"><strong>Деструктуризация объектов</strong></h2>\n\n\n\n<p id=\"1b19\">Тут все очень похоже на тему с массивами. Имя каждой переменной совпадает с именем свойства из деструктуризированного объекта.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>let myObject = { a: 1, b: 2, c: 3, d: 4};\nlet {b, d} = myObject;\n\nconsole.log(b); // 2\nconsole.log(d); // 4</code></pre>\n\n\n\n<p>И также, как и с массивами, вы можете использовать троеточие для сбора всех оставшихся свойств, которые не были назначены на переменные, которые в последствии будут представлять собой отдельный объект.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>let myObject = { a: 1, b: 2, c: 3, d: 4};\nlet {b, d, ...remaining} = myObject;\n\nconsole.log(b); // 2\nconsole.log(d); // 4\nconsole.log(remaining); // { a: 1, c: 3 }</code></pre>\n\n\n\n<h2><strong>Конвертируем итерируемые в массив при помощи Spread</strong></h2>\n\n\n\n<p>Тут все это очень легко делается при помощи оператора расширения. Зачастую итерируемые объекты ограничены в выборе доступных для них методов. Но конвертируя их в массив, вы сразу же получаете доступ ко&nbsp;<strong>ВСЕМ</strong>&nbsp;прекрасным методам, доступным для массивов, таким как&nbsp;<code>filter</code>,&nbsp;<code>map</code>,&nbsp;<code>reduce</code>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&#91; ...'hi' ]; // // &#91;'h', 'i']\n&#91; ...new Set(&#91;1,2,3]) ]; // &#91;1,2,3]\n&#91; ...new Map(&#91;&#91;1, 'one']]) ]; // &#91;&#91;1, 'one']]\n&#91; ...document.querySelectorAll('div') ] // &#91; div, div, div]</code></pre>\n\n\n\n<h3 id=\"b37e\"><strong>Уже готовые итерируемые</strong></h3>\n\n\n\n<p id=\"aa8a\">В JavaScript у нас есть несколько уже готовых итерируемых объектов, которые мы можем конвертировать в массив при помощи&nbsp;<code>spread</code>:</p>\n\n\n\n<p id=\"d706\">Строки</p>\n\n\n\n<p id=\"d928\">Массивы</p>\n\n\n\n<p id=\"48c7\">Map</p>\n\n\n\n<p id=\"c6b1\">Set</p>\n\n\n\n<p id=\"27cb\">Есть ещё один, но мы о нем пока не будем говорить это —&nbsp;<code>TypedArray</code>.</p>\n\n\n\n<h3><strong>Что такое итерируемые?</strong></h3>\n\n\n\n<blockquote class=\"wp-block-quote\"><p><em>Это структуры данных, которые предоставляют механизм для доступа сторонних операторов данных, в виде общедоступного доступа к своим элементам последовательным образом.</em></p></blockquote>\n\n\n\n<h3><strong>Строка&nbsp;</strong>→<strong>&nbsp;Массив</strong></h3>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const myString = 'hello';\nconst array = &#91;...myString] // &#91; 'h', 'e', 'l', 'l', 'o' ]</code></pre>\n\n\n\n<p>Мы можем конвертировать массив обратно в строку, используя <code>join()</code>:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>array.join(''); // 'hello'</code></pre>\n\n\n\n<h3><strong>Set&nbsp;</strong>→<strong>&nbsp;Массив</strong></h3>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const mySet = new Set(&#91;1, 2, 3]);\nconst array = &#91;...mySet] // &#91;1, 2, 3]</code></pre>\n\n\n\n<p>Мы можем конвертировать массив обратно в&nbsp;<code>set</code>, передав его&nbsp;<code>new Set</code></p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>new Set(array); // Set { 1, 2, 3 }</code></pre>\n\n\n\n<h3><strong>Map&nbsp;</strong>→<strong>&nbsp;Массив</strong></h3>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const myMap = new Map(&#91;&#91;1, 'one'], &#91;2, 'two']]);\nconst array = &#91;...myMap] // &#91; &#91; 1, 'one' ], &#91; 2, 'two' ] ]</code></pre>\n\n\n\n<p>Так же, как и с&nbsp;<code>Set</code>, мы можем конвертировать массив обратно в Map, передав его в&nbsp;<code>new Map</code></p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>new Map(array); // Map { 1 => 'one', 2 => 'two' }</code></pre>\n\n\n\n<h3><strong>NodeList&nbsp;</strong>→<strong>&nbsp;Массив</strong></h3>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const nodeList = document.querySelectorAll('div');\nconst array = &#91; ...document.querySelectorAll('div') ];\n// &#91; div, div, div] *</code></pre>\n\n\n\n<p>Тут я думаю, что понятно, то что настоящую выдачу можно увидеть только в браузере</p>\n\n\n\n<h3><strong>Array.from vs Spread</strong></h3>\n\n\n\n<p>Ещё один очень схожий с&nbsp;<code>Spread</code>&nbsp;синтаксисом метод это&nbsp;<code>Array.from</code>. По факту, мы можем смело заменить наши примеры вот так:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>Array.from('hi') // // &#91;'h', 'i']\nArray.from(new Set(&#91;1,2,3])) // &#91;1,2,3]\nArray.from(new Map(&#91;&#91;1, 'one']])) // &#91;&#91;1, 'one']]\nArray.from(document.querySelectorAll('div')) // &#91; div, div, div]</code></pre>\n\n\n\n<h3 id=\"af8f\"><strong>Так в чем разница?</strong></h3>\n\n\n\n<p id=\"481b\">Разница в определении.</p>\n\n\n\n<p id=\"1c83\"><strong><code>Array.from</code>&nbsp;работает для:</strong></p>\n\n\n\n<p id=\"02ff\">Массивоподобных объектов (объекты с свойством длины и индексированными элементами)</p>\n\n\n\n<p id=\"39e0\">Итерируемых объектов</p>\n\n\n\n<p id=\"de2f\"><strong><code>Spread</code>&nbsp;работает только для:</strong></p>\n\n\n\n<p id=\"a890\">Итерируемых объектов</p>\n\n\n\n<p id=\"7f8c\">Итак, давайте посмотрим на этот массивоподобный объект:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const arrayLikeObject = {\n  0: 'a', // indexed element\n  1: 'b', // indexed element\n  length: 1, // length property\n};\nArray.from(arrayLikeObject); // &#91; 'a', 'b' ]\n&#91;...arrayLikeObject]; // TypeError: arrayLikeObject is not iterable</code></pre>\n\n\n\n<p>Тут мы получаем ошибку о том, что&nbsp;<code>arrayLikeObject</code>&nbsp;не является итерируемым.</p>\n\n\n\n<h2 id=\"1893\"><strong>Заключение</strong></h2>\n\n\n\n<p id=\"cfc1\">Троеточие в JS может много чего означать в зависимости от контекста.</p>\n\n\n\n<p id=\"a11f\">Вы можете использовать её, как остаточные параметры в функции, таким образом упростив себе работу с переменным числом аргументов в ней. Ещё вы можете применять схожий подход с массивами или объектами при деструктуризации, где элементы на которых не было применено деструктурирующее назначение будут собраны в отдельный массив.</p>\n\n\n\n<p id=\"381b\">В свою очередь, оператор расширения может быть использован для распаковки итерируемых элементов в отдельные элементы, которые уже потом можно будет использовать при создании объектов, массивов и вызовов функций.</p>\n","date":"2021-01-20T22:20:34.000Z","title":"Оператор spread и rest параметры в JavaScript","id":"cfde9335-8e75-52cb-b095-b1136e372aed","excerpt":"<p>В этой статье вы узнаете про возможности применения, такого функционала, как spread оператор и rest параметры. И как при помощи первого, без особого труда можно конвертировать итерируемые объекты в массивы.</p>\n","type":"js","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2021/01/spreadnkdjnf.jpg"}}},{"node":{"slug":"5-rasprostranennyh-oshibok-kotorie-delaet-kazhdyi-novyi-programmist-v-javascript","content":"\n<p>На самом деле не всё, описанное ниже является ошибками, но если вы будете разбираться с описанными ниже проблемами, то значительно продвинетесь в изучении программирования.</p>\n\n\n\n<p class=\"author\"><em>Перевод статьи&nbsp;</em><a rel=\"noreferrer noopener\" href=\"https://codeburst.io/5-common-mistakes-that-every-new-javascript-programmer-does-d0559770d345\" target=\"_blank\"><em>5 Common mistakes that every new JavaScript programmer does</em></a></p>\n\n\n\n<h2 id=\"e0cb\"><strong>True и False значения</strong></h2>\n\n\n\n<p id=\"9ae2\">Эта одна из самых распространенных ошибок, которую каждый программист делал хотя бы один раз в своей карьере. Давайте посмотрим на код ниже. Но это и не ошибка в общем-то, просто настоятельная рекомендация.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>let foo = 0;\nlet boo = 0;\nif (foo === 0) {\n  boo = 1;\n} else {\n  boo = 2;\n}\n</code></pre>\n\n\n\n<p>Код выше выглядит правильным, так? Так и есть, но есть кое что ещё, что мы можем с ним сделать. Теперь посмотрите дальше:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>let foo = 0;\nlet boo = 0;\n\nif (!foo) {\n  boo = 1;\n} else {\n  boo = 2;\n}</code></pre>\n\n\n\n<p>Выглядит получше? По факту, нам не нужно проверять&nbsp;<code>0,</code>&nbsp;как на&nbsp;<code>false</code>&nbsp;значение. Мы можем просто проверить в условии&nbsp;<code>!foo</code>, отдаёт ли оно&nbsp;<code>false</code>. Давайте посмотрим на верные и неверные значения в JavaScript:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// false значения в JavaScript\nundefined --> \"undefined\" отдаст true, если является строкой\nnull --> \"null\" тоже что и \"undefined\"\n0 --> \"0\" тоже что и \"undefined\"\nfalse --> \"false\" тоже что и \"undefined\"\nNaN --> \"NaN\" тоже что и \"undefined\"\n'' or \"\" --> пустая строка\n// true значения в JavaScript\n\"String\" -->  Любая строка\n&#91;] --> Пустой массив\n{} --> Пустой объект\nfunction() {} --> Пустая функция</code></pre>\n\n\n\n<h2 id=\"3af0\">Условный (тернарный) оператор</h2>\n\n\n\n<p id=\"3ee2\">Каждый программист использовал&nbsp;<code>if</code>&nbsp;условие хотя бы раз в жизни, но в местах где не очень много сложной логики внутри условий, мы можем просто заменить их тернарным оператором.&nbsp;</p>\n\n\n\n<p id=\"3ee2\"><strong>Зачем?</strong>&nbsp;Чтобы избежать писанины 😉 и конечно для удобной читабельности. Давайте посмотрим на тот же пример повыше и сделаем его с использованием тернарного оператора.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>let foo = 0;\nlet boo = 0;\n!foo ? boo = 1 : boo = 2;\n// и ещё лучше\nboo = !foo ? 1 : 2;</code></pre>\n\n\n\n<p>В коде выше, вместо пяти строчек кода, мы просто воспроизвели ту же логику в одной строчке. Давайте посмотрим на другой кусок кода.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>if (любое условие) {\n  ----------------\n  что-то тут происходит\n  ----------------\n  return foo ? true : false;\n}</code></pre>\n\n\n\n<p>С кодом выше все правильно, но вам нужно просто в данном случае постараться избегать тернарного оператора. Как? Посмотрите на код ниже.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>if (любое условие) {\n  ----------------\n  что-то тут происходит\n  ----------------\nreturn foo; // если вы уверены, что foo это булево значение\nreturn !!foo; // если foo может быть чем угодно, но не им\n}</code></pre>\n\n\n\n<p>И так, выше мы видим, что нам не всегда нужен тернарный оператор и не всегда нужно стараться использовать их во вложенном виде.</p>\n\n\n\n<h2 id=\"72e0\"><strong>Проверка равенства</strong></h2>\n\n\n\n<p id=\"0ce0\">Давайте внимательно посмотрим на код, чтобы лучше его понять.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>if (false == 0) {\n  return true;\n} else {\n  return false;\n}\nif (false === 0) {\n  return true;\n} else {\n  return false;\n}</code></pre>\n\n\n\n<p>Оба условия вернут&nbsp;<code>true</code>? Извините, что расстрою вас, но первое условие вернет&nbsp;<code>true</code>, а второе вернет&nbsp;<code>false</code>. Что же это за магия такая? Разница в обоих случаях в одном ‘<code>=</code>’, которое всё меняет в значительной степени. ‘<code>==</code>’ делает проверку на равенство с приведением типов, а ‘<code>===</code>’ смотрит на строгое соответствие.</p>\n\n\n\n<h2 id=\"a242\"><strong>Прибавление и конкатенация</strong></h2>\n\n\n\n<p id=\"2350\">Прибавление и связывание зависят от типа данных пока мы явно не укажем переменные с типом данных в JavaScript.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>var a = 10;\nvar b = '20';\nvar c = 30;\nreturn a + b; // отдаст \"1020\"\nreturn b + c; // отдаст \"2030\"\nreturn a + c; // отдаст 40\n</code></pre>\n\n\n\n<p>Как мы видим на примере выше, если мы попытаемся прибавить строку к целому числу, то это возвратит связанную строку, но в случае с двумя целыми числами вернется сумма обоих.</p>\n\n\n\n<h2 id=\"42cb\"><strong>Использование переменной как ключа в объекте</strong></h2>\n\n\n\n<p id=\"addc\">Есть определенные кейсы, в которых нам нужно использовать переменные как ключи. Давайте посмотрим на пример ниже.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const a = 1;\nlet b = '';\nif(a) {\n  b = 'first Name';\n} else {\n  b = 'Last Name';\n}\nconst myObject = {\n  b : 'Emily'\n};\nreturn myObject;</code></pre>\n\n\n\n<p>В примере выше мы хотели вернуть объект как&nbsp;<code>{ 'first Name' : 'Emily' }</code>, но что возвращает код это&nbsp;<code>{ b: 'Emily' }&nbsp;</code>из-за того, что&nbsp;<code>b</code>&nbsp;используется как ключ. Чтобы решить эту проблему, мы используем квадратные скобки&nbsp;<code>[]</code>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>if(a) {\n  b = 'first Name';\n} else {\n  b = 'Last Name';\n}\nconst myObject = {\n  &#91;b] : 'Emily'\n};\nreturn myObject;</code></pre>\n\n\n\n<p>Теперь код возвращает то, что мы хотели —&nbsp;<code>{ 'first Name' : 'Emily' }</code></p>\n","date":"2021-01-18T16:28:07.000Z","title":"5 распространенных ошибок, которые делает каждый новый программист в JavaScript","id":"5418706f-0eeb-5257-bb3d-021d4c60831e","excerpt":"<p>На самом деле не всё, описанное ниже является ошибками, но если вы будете разбираться с описанными ниже проблемами, то значительно продвинетесь в изучении программирования.</p>\n","type":"js","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2021/01/fjdnfkjsnkjlfbsdjhkbsjkhfbdsjfb.jpg"}}},{"node":{"slug":"metody-javascript-kotorie-uluchshat-vashi-umenia-za-neskolko-minut","content":"\n<p>В наши дни большинство приложений, которые мы делаем, нуждаются в возможности оперирования данными, которые они получают. Обработка элементов в любом объеме данных это обычное дело, с которым вы столкнетесь с высокой долей вероятности. Пора уже забыть устаревшие способы работы с&nbsp;<code>for-loop</code>, такие как&nbsp;<code>(let i=0; i &lt; value.length; i++ )</code>.</p>\n\n\n\n<p class=\"author\"><em>Перевод статьи&nbsp;</em><a rel=\"noreferrer noopener\" href=\"https://medium.freecodecamp.org/7-javascript-methods-that-will-boost-your-skills-in-less-than-8-minutes-4cc4c3dca03f\" target=\"_blank\"><em>These JavaScript methods will boost your skills in just a few minutes</em></a></p>\n\n\n\n<p id=\"cbfd\">Обратите внимание, что использование&nbsp;<code>const</code>&nbsp;в&nbsp;<code>for-loop</code>&nbsp;выдаст вам ошибку. Причиной тому будет то, что при переназначении значения, каждое следующее&nbsp;<code>i</code>, модифицируется&nbsp;<code>i++</code>. Так что перед тем, как использовать&nbsp;<code>const</code>&nbsp;или&nbsp;<code>let</code>, спросите себя —&nbsp;<em>Будет ли это значение изменено?</em>&nbsp;Если ответ да, то используйте&nbsp;<code>let</code>, если нет, то тогда вам нужна&nbsp;<code>const</code>.</p>\n\n\n\n<p id=\"d1de\">Итак, представим, что вам нужно вывести список товаров, а также категоризировать, отфильтровать, найти, модифицировать или обновить этот список товаров. Или возможно вам надо выполнить быстрые вычисления, такие как сложение, умножение и так далее.&nbsp;<strong>Какой самый оптимальный способ это сделать?</strong></p>\n\n\n\n<p id=\"02bf\">Может быть вам не нравятся стрелочные функции, вы не хотите тратить слишком много времени на изучение чего-либо нового или они просто вам не по душе. Не переживайте, вы не один такой. Сейчас я покажу вам, как это сделать в&nbsp;<strong>ES5 (объявление функции)</strong>&nbsp;и в&nbsp;<strong>ES6 (стрелочные функции)</strong>.</p>\n\n\n\n<p id=\"7da9\"><em>Будьте осторожны:</em>&nbsp;стрелочные функции и выражение/объявление функции это не одно и тоже и их нельзя просто так брать и заменять друг другом. Помните, что между ними&nbsp;<code>this</code>&nbsp;работает у каждого по разному.</p>\n\n\n\n<p id=\"e382\">Методы, которые мы рассмотрим:</p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p></p><cite>Spread operator<br>for…of iterator<br>includes()<br>some()<br>every()<br>filter()<br>map()<br>reduce()</cite></blockquote>\n\n\n\n<h2 id=\"d223\">1. Оператор расширения</h2>\n\n\n\n<p id=\"7d31\">Этот оператор расширяет массив по его элементам. Он также может использоваться для объект литералов.</p>\n\n\n\n<h3 id=\"9a36\">Зачем его использовать?</h3>\n\n\n\n<p id=\"6d0d\">Это простой и быстрый способ показать элементы массива.</p>\n\n\n\n<p id=\"503f\">Он работает с массивами и объект литералами.</p>\n\n\n\n<p id=\"7be0\">Это быстрый и удобный способ передать аргументы.</p>\n\n\n\n<p id=\"dee1\">Для него нужно всего-то три точки.</p>\n\n\n\n<h3 id=\"aba5\">Пример:</h3>\n\n\n\n<p id=\"cb01\">Предположим, что вам надо показать список вашей любимой еды без создания функции цикла. Для этого используйте именно оператор расширения:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"816\" height=\"217\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_OQpjtOAdVeh3Gs3WYgrGzA.png\" alt=\"\" class=\"wp-image-104\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_OQpjtOAdVeh3Gs3WYgrGzA.png 816w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_OQpjtOAdVeh3Gs3WYgrGzA-300x80.png 300w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_OQpjtOAdVeh3Gs3WYgrGzA-768x204.png 768w\" sizes=\"(max-width: 816px) 100vw, 816px\" /></figure>\n\n\n\n<h2 id=\"7e0a\">2. Итератор for…of</h2>\n\n\n\n<p id=\"4375\">Оператор&nbsp;<code>for…of</code>&nbsp;итерирует/проходится циклом по коллекции данных и дает вам возможность изменять конкретные элементы. Он заменяет традиционный способ проведения цикла&nbsp;<code>for</code>.</p>\n\n\n\n<h3 id=\"f31e\">Зачем его использовать?</h3>\n\n\n\n<p id=\"4182\">Это простой способ добавления и обновления элементов.</p>\n\n\n\n<p id=\"c29f\">Отличный способ проводить вычисления. (Сложение, умножение и т.п.)</p>\n\n\n\n<p id=\"6779\">Подходит для работы с условными операторами (<code>if</code>,&nbsp;<code>while</code>,&nbsp;<code>switch</code>&nbsp;и т.д.).</p>\n\n\n\n<p id=\"881f\">Ведёт к чистому и читаемому коду.</p>\n\n\n\n<h3 id=\"df17\">Пример:</h3>\n\n\n\n<p id=\"7bf9\">Итак, предположим, что у нас есть коробка инструментов и вам надо показать все инструменты внутри неё. С помощью итератора&nbsp;<code>for…of</code>&nbsp;вы это сделаете очень легко:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"322\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_ORy2fs8TPhGPTDAUUd_6Kw.png\" alt=\"\" class=\"wp-image-105\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_ORy2fs8TPhGPTDAUUd_6Kw.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_ORy2fs8TPhGPTDAUUd_6Kw-300x138.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<h2 id=\"9a05\">3. Метод Includes()</h2>\n\n\n\n<p id=\"388a\">Этот метод используется для того, чтобы проверить есть ли конкретная строка в коллекции данных и в соответствии с ответом он возвращает&nbsp;<code>true</code>&nbsp;или&nbsp;<code>false</code>. Помните, что он чувствителен к регистру и если элемент внутри коллекции данных есть SCHOOL, а вы ищете school, то он вернет&nbsp;<code>false</code>.</p>\n\n\n\n<h3 id=\"b028\">Зачем его использовать?</h3>\n\n\n\n<p id=\"2243\">Чтобы сделать простой поисковый функционал.</p>\n\n\n\n<p id=\"9753\">Это удобный подход для поиска нужной строки</p>\n\n\n\n<p id=\"c667\">Можно использовать условные операторы, чтобы изменять, фильтровать и так далее.</p>\n\n\n\n<p id=\"d421\">Делает код читабельным.</p>\n\n\n\n<h3 id=\"c617\">Пример:</h3>\n\n\n\n<p id=\"a3b2\">Давайте представим, что у вас в гараже есть много машин и по каким-то причинам вы не знаете, какие именно. Вам нужна система, чтобы проверить есть ли определенная машина или нет. И тут вам поможет&nbsp;<code>includes()</code>!</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"223\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_pMjkVg5t5w2uBnbBe9OpgA.png\" alt=\"\" class=\"wp-image-106\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_pMjkVg5t5w2uBnbBe9OpgA.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_pMjkVg5t5w2uBnbBe9OpgA-300x96.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<h2 id=\"e433\">4. some() метод</h2>\n\n\n\n<p id=\"d2f2\">Этот метод проверяет есть ли нужные элементы в массиве и возвращает&nbsp;<code>true</code>&nbsp;и&nbsp;<code>false</code>. Это очень похоже по концепции на метод&nbsp;<code>includes()</code>, за исключением того, что аргументом является функция, а не строка.</p>\n\n\n\n<h3 id=\"fa6b\">Зачем это использовать?</h3>\n\n\n\n<p id=\"dc60\">Для уверенности, что&nbsp;<strong>некоторые элементы</strong>&nbsp;подходят заданным критериям.</p>\n\n\n\n<p id=\"5afa\">Он выполняет условные операторы, используя функции.</p>\n\n\n\n<p id=\"5efe\">Делает ваш код описательным.</p>\n\n\n\n<p id=\"fd65\">Some достаточно хорош.</p>\n\n\n\n<h3 id=\"dedf\">Пример:</h3>\n\n\n\n<p id=\"a673\">Предположим, что вы владелец клуба и вы вообще не заботитесь о том, кто входит в ваш клуб. Но некоторым все таки это недозволено, к примеру, потому что они уже много выпили или по возрастным ограничениям. Посмотрите разницу в написании кода в ES5 и в ES6:</p>\n\n\n\n<p id=\"653e\">ES5:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"248\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_7BY-hU4fRzXCItTX-9M38g.png\" alt=\"\" class=\"wp-image-107\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_7BY-hU4fRzXCItTX-9M38g.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_7BY-hU4fRzXCItTX-9M38g-300x106.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p>ES6:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"204\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_ZVMlvrUfBWWN__oq2lti_g.png\" alt=\"\" class=\"wp-image-108\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_ZVMlvrUfBWWN__oq2lti_g.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_ZVMlvrUfBWWN__oq2lti_g-300x87.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<h2 id=\"34c3\">5. every() метод</h2>\n\n\n\n<p id=\"6e60\">Этот метод проходится по массиву, проверяет элемент и возвращает&nbsp;<code>true</code>&nbsp;или&nbsp;<code>false</code>. Та же концепция, что и с&nbsp;<code>some()</code>. Кроме того, что каждый элемент должен удовлетворять параметрам условия, иначе метод возвратит&nbsp;<code>false</code>.</p>\n\n\n\n<h3 id=\"6f1f\">Зачем это использовать?</h3>\n\n\n\n<p id=\"63bd\">Для уверенности, что все элементы проходят тест.</p>\n\n\n\n<p id=\"903e\">Вы можете выполнять условные операторы, используя функции.</p>\n\n\n\n<p id=\"5a75\">Делает ваш код описательным.</p>\n\n\n\n<h3 id=\"7312\">Пример:</h3>\n\n\n\n<p id=\"2837\">В последний раз с помощью&nbsp;<code>some()</code>, вы позволяли некоторым недорослям проходить в клуб и кто-то уже рассказал об этом и вы попали в полицию. В следующий раз вы не хотите, чтобы это повторилось и вы точно убедитесь, что каждый проходит по лимиту возраста с помощью оператора&nbsp;<code>every()</code>.</p>\n\n\n\n<p id=\"40ee\">ES5:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"266\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_zdmC-Dj6dJi4ONUwoPZzeQ.png\" alt=\"\" class=\"wp-image-109\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_zdmC-Dj6dJi4ONUwoPZzeQ.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_zdmC-Dj6dJi4ONUwoPZzeQ-300x114.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p>ES6:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"204\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_Yn51W_xqaPJbjf4V9gFISA.png\" alt=\"\" class=\"wp-image-110\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_Yn51W_xqaPJbjf4V9gFISA.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_Yn51W_xqaPJbjf4V9gFISA-300x87.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<h2 id=\"75e3\">6. Метод filter()</h2>\n\n\n\n<p id=\"d501\">Этот метод создаёт новый массив из элементов, которые соответствуют условиям.</p>\n\n\n\n<h3 id=\"1a04\">Зачем это использовать?</h3>\n\n\n\n<p id=\"c6e5\">Так вы можете избежать изменений в основном массиве.</p>\n\n\n\n<p id=\"3f9f\">Вы сможете отфильтровать элементы, которые вам не нужны.</p>\n\n\n\n<p id=\"2da0\">Даёт вам более читабельный код.</p>\n\n\n\n<h3 id=\"eeb7\">Пример:</h3>\n\n\n\n<p id=\"a565\">Давайте скажем, к примеру, что вам нужно вернуть цены, которые выше или равны 30. Отфильтруйте все другие цены:</p>\n\n\n\n<p id=\"8260\">ES5:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"267\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_Sb3f5FANbbghMq8qGHh1Qg.png\" alt=\"\" class=\"wp-image-111\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_Sb3f5FANbbghMq8qGHh1Qg.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_Sb3f5FANbbghMq8qGHh1Qg-300x114.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p>ES6:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"204\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_Ktjh1lVLWBhuVx50gY2blg.png\" alt=\"\" class=\"wp-image-112\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_Ktjh1lVLWBhuVx50gY2blg.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_Ktjh1lVLWBhuVx50gY2blg-300x87.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<h2 id=\"a822\">7. Метод map()</h2>\n\n\n\n<p id=\"0e67\">Этот метод схож с&nbsp;<code>filter()</code>&nbsp;в плане выдачи нового массива. Однако, разница тут в том, что он используется только для изменения элементов.</p>\n\n\n\n<h3 id=\"23b5\">Зачем это использовать?</h3>\n\n\n\n<p id=\"dca5\">Вы можете избежать изменений в основном массиве</p>\n\n\n\n<p id=\"703c\">Вы можете модифицировать элементы, которые захотите</p>\n\n\n\n<p id=\"85f9\">Даёт вам читабельный код</p>\n\n\n\n<h3 id=\"f593\">Пример:</h3>\n\n\n\n<p id=\"ae5a\">Давайте скажем, что у вас есть список продуктов с ценами. Вашему менеджеру нужен список, чтобы показать новые цены после налога в 25%. И вам тут поможет этот метод, метод&nbsp;<code>map()</code>.</p>\n\n\n\n<p id=\"3819\">ES5:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"262\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_shRzvhJYB2ktU1cVXKDpcA.png\" alt=\"\" class=\"wp-image-113\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_shRzvhJYB2ktU1cVXKDpcA.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_shRzvhJYB2ktU1cVXKDpcA-300x112.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p>ES6:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"185\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_MnBLykkUrhb6JoCh4AECuQ.png\" alt=\"\" class=\"wp-image-114\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_MnBLykkUrhb6JoCh4AECuQ.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_MnBLykkUrhb6JoCh4AECuQ-300x79.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<h2 id=\"3bf9\">8. Метод reduce()</h2>\n\n\n\n<p id=\"811a\">Этот метод может использоваться для трансформации массива в целое число, объект, цепочку промисов (последовательное выполнение промисов) и т.п. По практическим причинам, будет простой пример использования — сложение списка целых чисел. Вообще кратко, этот метод&nbsp;<em>сокращает(от reduce — сокращать, но на самом деле&nbsp;</em><strong><em>складывает</em></strong><em>)</em>&nbsp;весь массив в одно целое значение.</p>\n\n\n\n<h3 id=\"9cf8\">Зачем мне это использовать?</h3>\n\n\n\n<p id=\"b345\">Для выполнения вычислений</p>\n\n\n\n<p id=\"6116\">Вычисления значений</p>\n\n\n\n<p id=\"9915\">Учета дубликатов</p>\n\n\n\n<p id=\"ee1f\">Группировки объектов по свойствам</p>\n\n\n\n<p id=\"c326\">Выполнения цепочки промисов</p>\n\n\n\n<p id=\"c929\">Это быстрый способ выполнения вычислений</p>\n\n\n\n<h3 id=\"4e03\">Пример:</h3>\n\n\n\n<p id=\"c4db\">Допустим вам надо найти общее число трат за неделю. Используйте&nbsp;<code>reduce()</code>, чтобы получить это значение:</p>\n\n\n\n<p id=\"7f8d\">ES5:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"285\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_IuREBog9uHTmnP3MorrSQw.png\" alt=\"\" class=\"wp-image-115\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_IuREBog9uHTmnP3MorrSQw.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_IuREBog9uHTmnP3MorrSQw-300x122.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p>ES6:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"211\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_trULhRY3omdYlCVE6-70Bg.png\" alt=\"\" class=\"wp-image-116\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_trULhRY3omdYlCVE6-70Bg.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_trULhRY3omdYlCVE6-70Bg-300x90.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p></p>\n","date":"2021-01-17T14:31:36.000Z","title":"Методы JavaScript, которые улучшат ваши умения за несколько минут","id":"9ed3a585-afa3-5927-ab8f-95147f150eef","excerpt":"<p>В этой статье вы узнаете про методы JavaScript, которые улучшат ваши умения за несколько минут и сделают процесс разработки максимально быстрым в разумных пределах</p>\n","type":"js","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2021/01/nkjlnfndsjkfnsjkdnflkjsn.jpg"}}},{"node":{"slug":"ponimaem-komponenty-vysshego-poryadka-v-react-na-realnom-primere","content":"\n<p>В этой статье вы пошагово узнаете как создать компонент высшего порядка в React и как применить этот паттерн на реальном примере.</p>\n\n\n\n<p class=\"author\"><em>Перевод&nbsp;</em><a rel=\"noreferrer noopener\" href=\"https://levelup.gitconnected.com/understanding-react-higher-order-components-by-example-95e8c47c8006\" target=\"_blank\"><em>Understanding React Higher-Order Components by Example</em></a></p>\n\n\n\n<p>В этом руководстве мы пройдемся по концепциям, которые необходимы для создания компонентов высшего порядка. Мы применим HOC, чтобы сохранить стэйт в&nbsp;<code>localStorage</code>, вызывая&nbsp;<code>withStorage</code>, с помощью которого мы сможем вставить функционал в другие компоненты без дублирования логики по всему приложению.</p>\n\n\n\n<h2 id=\"77e4\"><strong>Что такое компонент высшего порядка(HOC)</strong></h2>\n\n\n\n<p id=\"12fb\">Компонент высшего порядка в React это паттерн, используемый для того, чтобы делить функционал между компонентами без повторения кода. Такие компоненты, по факту, не совсем являются компонентами, это скорее функции. Такая функция берёт компонент как аргумент и отдаёт уже готовый компонент. Она переделывает заданный компонент в другой компонент и добавляет дополнительные данные, либо фунционал. Вот краткий пример:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const NewComponent = (BaseComponent) => {\n  // ... создает новый компонент, обновляя старый и отдавая результат\n}</code></pre>\n\n\n\n<p>Две подобных имплементации, с которыми вы возможно уже знакомы благодаря экосистеме React, это&nbsp;<code>connect</code>&nbsp;из Redux и&nbsp;<code>withRouter</code>&nbsp;в React Router. Функция&nbsp;<code>connect</code>&nbsp;из Redux используется, чтобы раздать компонентам доступ к глобальному стейту в Redux сторе и она передаёт значения компонентам в виде пропсов. Функция&nbsp;<code>withRouter</code>&nbsp;добавляет информацию о роутинге и функциональности в компонент, позволяя разработчику иметь доступ к роутеру с возможностью изменения самого роута.</p>\n\n\n\n<h2 id=\"4015\"><strong>Паттерн компонентов высшего порядка(HOC)</strong></h2>\n\n\n\n<p id=\"eef3\">Такие компоненты это функции, которые берут компонент как аргумент и возвращают уже &#171;переработанный&#187; компонент. Это говорит о том, что HOC будет всегда иметь вид как тут:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>import React from 'react';\n\nconst higherOrderComponent = (WrappedComponent) => {\n  class HOC extends React.Component {\n    render() {\n      return &lt;WrappedComponent />;\n    }\n  }\n    \n  return HOC;\n};</code></pre>\n\n\n\n<p>Тут&nbsp;<code>higherOrderComponent</code>&nbsp;это функция, которая берёт компонент под названием&nbsp;<code>WrappedComponent</code>&nbsp;как аргумент. Мы создаём новый компонент под названием HOC, который отдаёт из рендера&nbsp;<code>&lt;WrappedComponent /&gt;</code>. Пока тут нет никакого функционала, этот пример просто описывает общий паттерн, которому должна следовать любая функция HOC. Мы можем вызвать HOC таким образом:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const SimpleHOC = higherOrderComponent(MyComponent);</code></pre>\n\n\n\n<h2 id=\"ff4f\"><strong>Простой пример HOC</strong></h2>\n\n\n\n<p id=\"c439\">Теперь мы расширим наш компонент высшего порядка, чтобы добавить данные во вставленный компонент.</p>\n\n\n\n<p id=\"12f5\">Наша команда выяснила, что <em>secretToLife</em> является число 42. Некоторые из наших компонентов должны поделиться этой информацией и нам нужно создать HOC под именем&nbsp;<code>withSecretToLife</code>, чтобы передать его как пропс нашим компонентам.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>import React from 'react';\n\nconst withSecretToLife = (WrappedComponent) => {\n  class HOC extends React.Component {\n    render() {\n      return (\n        &lt;WrappedComponent\n          {...this.props}\n          secretToLife={42}\n        />\n      );\n    }\n  }\n    \n  return HOC;\n};\n\nexport default withSecretToLife;</code></pre>\n\n\n\n<p id=\"1960\">Обратите внимание, что этот пример практически идентичен первому. Всё, что мы сделали, так это просто проп&nbsp;<code>secretToLife={42}</code>, который позволил обернутому компоненту получить доступ к значению через&nbsp;<code>this.props.secretToLife</code>.</p>\n\n\n\n<p id=\"4965\">Ещё стоит обратить внимание, что используем оператор расширения на пропсах переданных компоненту. Так мы точно будем уверены в том, что любой пропс переданный обернутому компоненту будет доступен через&nbsp;<code>this.props</code>, так же, как и если бы мы вызывали этот компонент не через компонент высшего порядка.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>import React from 'react';\nimport withSecretToLife from 'components/withSecretToLife';\n\nconst DisplayTheSecret = props => (\n  &lt;div>\n    The secret to life is {props.secretToLife}.\n  &lt;/div>\n);\n\nconst WrappedComponent = withSecretToLife(DisplayTheSecret);\n\nexport default WrappedComponent;</code></pre>\n\n\n\n<p>Наш компонент&nbsp;<code>WrappedComponent</code>, который по сути является прокачанной версией&nbsp;<code>&lt;DisplayTheSecret/&gt;</code>, позволит нам получить доступ к&nbsp;<code>SecretToLife</code>&nbsp;как к пропсу.</p>\n\n\n\n<h2 id=\"e977\"><strong>Практический пример</strong></h2>\n\n\n\n<p id=\"ab43\">Теперь у нас есть четкое понимание основ создания компонентов высшего порядка и мы можем сделать такой же, но реально имеющий практическое применение в реальном приложении. HOC имеет доступ ко всем дефолтным API Реакта, включая state и методы жизненного цикла.</p>\n\n\n\n<p id=\"e93e\">Функциональность нашего компонента <code>withStorage</code> будет в том, чтобы сохранять/загружать стейт компонента, позволяя нам как можно быстрее получать к нему доступ и рендерить на странице.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>import React from 'react';\n\nconst withStorage = (WrappedComponent) => {\n  class HOC extends React.Component {\n    state = {\n      localStorageAvailable: false, \n    };\n  \n    componentDidMount() {\n       this.checkLocalStorageExists();\n    }\n  \n    checkLocalStorageExists() {\n      const testKey = 'test';\n\n      try {\n          localStorage.setItem(testKey, testKey);\n          localStorage.removeItem(testKey);\n          this.setState({ localStorageAvailable: true });\n      } catch(e) {\n          this.setState({ localStorageAvailable: false });\n      } \n    }\n  \n    load = (key) => {\n      if (this.state.localStorageAvailable) {\n        return localStorage.getItem(key); \n      }\n      \n      return null;\n    }\n    \n    save = (key, data) => {\n      if (this.state.localStorageAvailable) {\n        localStorage.setItem(key, data);\n      }\n    }\n    \n    remove = (key) => {\n      if (this.state.localStorageAvailable) {\n        localStorage.removeItem(key);\n      }\n    }\n    \n    render() {\n      return (\n        &lt;WrappedComponent\n          load={this.load}\n          save={this.save}\n          remove={this.remove}\n          {...this.props}\n        />\n      );\n    }\n  }\n    \n  return HOC; \n}\n\nexport default withStorage;</code></pre>\n\n\n\n<p id=\"8f87\">На самом верху&nbsp;<code>withStorage</code>&nbsp;у нас один элемент в стейте компонента, который отслеживает доступность локального хранилища в браузере. Мы используем&nbsp;<code>componentDidMount</code>, который проверяет наличие&nbsp;<code>localStorage</code>&nbsp;в&nbsp;<code>checkLocalStorageExists</code>&nbsp;функции. Тут он будет тестировать сохранение элемента и ставить стейт на&nbsp;<code>true</code>, если процесс был успешным.</p>\n\n\n\n<p id=\"d0ad\">Мы также добавили три функции —&nbsp;<code>load</code>,&nbsp;<code>save</code>&nbsp;и&nbsp;<code>remove</code>. Они применяются для прямого доступа к&nbsp;<code>localStorage</code>&nbsp;API, в случае его доступности. Наши три функции в HOC передались обернутому компоненту, чтобы там уже они и отработали.</p>\n\n\n\n<p id=\"80cf\">Теперь мы создадим ещё один компонент, который будет внутри&nbsp;<code>withStorage</code>. Он будет использоваться для отображения имени пользователя и его любимого фильма. Но нужно учесть, что API запрос для получения этой информации берет много времени. Мы также учитываем, что эти значения никогда не будут выставлены.</p>\n\n\n\n<p id=\"9d0b\">Чтобы обеспечить наилучший опыт взаимодействия с приложением, мы сделаем этот API запрос только тогда, когда значения не будут сохранены. Теперь всякий раз когда пользователь возвращается на страницу, он может получить доступ к данным незамедлительно, а не ждать ответа API.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>import React from 'react';\nimport withStorage from 'components/withStorage';\n\nclass ComponentNeedingStorage extends React.Component {\n  state = {\n    username: '',\n    favoriteMovie: '',\n  }\n\n  componentDidMount() {\n    const username = this.props.load('username');\n    const favoriteMovie = this.props.load('favoriteMovie');\n    \n    if (!username || !favoriteMovie) {\n      // This will come from the parent component\n      // and would be passed when we spread props {...this.props}\n      this.props.reallyLongApiCall()\n        .then((user) => {\n          this.props.save('username', user.username || '');\n          this.props.save('favoriteMovie', user.favoriteMovie || '');\n          this.setState({\n            username: user.username,\n            favoriteMovie: user.favoriteMovie,\n          });\n        }); \n    } else {\n      this.setState({ username, favoriteMovie })\n    }\n  }\n\n  render() {\n    const { username, favoriteMovie } = this.state;\n    \n    if (!username || !favoriteMovie) {\n      return &lt;div>Loading...&lt;/div>; \n    }\n    \n    return (\n      &lt;div>\n        My username is {username}, and I love to watch {favoriteMovie}.\n      &lt;/div>\n    )\n  }\n}\n\nconst WrappedComponent = withStorage(ComponentNeedingStorage);\n\nexport default WrappedComponent;</code></pre>\n\n\n\n<p>Внутри&nbsp;<code>componentDidMount</code>&nbsp;обернутого компонента мы сначала пытаемся получить доступ к&nbsp;<code>username</code>&nbsp;и&nbsp;<code>favoriteMovie</code>&nbsp;из&nbsp;<code>localStorage</code>. Если этих значений нет, то мы делаем API запрос&nbsp;<code>this.props.reallyLongApiCall</code>. Как только получаем ответ, то сохраняем данные в локальное хранилище и обновляем стейт компонента, чтобы вывести его на экран.</p>\n\n\n\n<h2 id=\"f902\"><strong>Соображения по поводу HOC</strong></h2>\n\n\n\n<p id=\"3d4b\">Компоненты высшего порядка должны быть чистыми функциями без сайд эффектов. Они не должны делать никаких изменений, а просто формировать изначальный компонент, обертывая его другим компонентом.</p>\n\n\n\n<p id=\"ea04\">Не используйте HOC в рендере компонента. Получайте доступ к HOC только за пределами определения компонента.</p>\n\n\n\n<p id=\"666e\">Статичные методы должны быть скопированы, чтобы к ним оставался доступ. Очень простой способ сделать это — использовать&nbsp;<code>hoist-non-react-statics</code>&nbsp;пакет.</p>\n\n\n\n<p id=\"5b9c\"><code>Ref</code>‘сы не передаются.</p>\n","date":"2021-01-16T15:23:48.000Z","title":"Понимаем компоненты высшего порядка в React на реальном примере","id":"0deb49e4-622e-5f33-b8b5-d3c2456c3846","excerpt":"<p>В этой статье вы пошагово узнаете как создать компонент высшего порядка в React и как применить этот паттерн на реальном примере.</p>\n","type":"js","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2021/01/nfkdjbfkjshbdhjf.jpg"}}},{"node":{"slug":"samoe-ponyatnoe-rukovodstvo-po-iteratoram-v-es6-javascript-s-primerami","content":"\n<p>В этой статье мы попытаемся понять и проанализировать итераторы в JS. Это сравнительно новые способы для того, чтобы пройтись по любой коллекции данных. Итераторы были представлены в ES6 и стали действительно популярны, так как оказались ну уж очень полезными и могут широко использоваться во многих рабочих кейсах.</p>\n\n\n\n<p class=\"author\"><em>Адаптивный перевод статьи —&nbsp;</em><a rel=\"noreferrer noopener\" href=\"https://codeburst.io/a-simple-guide-to-es6-iterators-in-javascript-with-examples-189d052c3d8e\" target=\"_blank\"><em>A Simple Guide to ES6 Iterators in JavaScript with Examples</em></a></p>\n\n\n\n<p>Мы собираемся понять&nbsp;концепцию того, чем являются итераторы и где их можно использовать, всё будет конечно же с примерами. Также в статье мы увидим несколько примеров рабочего кода на JavaScript.</p>\n\n\n\n<h1 id=\"e2c6\"><strong>Введение</strong></h1>\n\n\n\n<p id=\"3ab8\">Представим, что у нас есть массив:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const myFavouriteAuthors = &#91;\n  'Neal Stephenson',\n  'Arthur Clarke',\n  'Isaac Asimov', \n  'Robert Heinlein'\n];\n</code></pre>\n\n\n\n<p>Рано или поздно, вам понадобится получить все отдельные значения массива для их: последующего вывода на страницу, манипулирования или для вообще, любого действия связанного с ними. Если я спрошу вас, как вы это всё сделаете? Вы ответите — да легко! Вы просто пустите цикл по всему массиву с помощью&nbsp;<code>for</code>,&nbsp;<code>while</code>,&nbsp;<code>for-of</code>&nbsp;или&nbsp;<a rel=\"noreferrer noopener\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration\" target=\"_blank\">одним из этих методов цикла.</a>&nbsp;Пример выполнения был бы таким:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"405\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_3pgJ-bgoGegF5o0t95E7Ug.png\" alt=\"\" class=\"wp-image-93\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_3pgJ-bgoGegF5o0t95E7Ug.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_3pgJ-bgoGegF5o0t95E7Ug-300x174.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p>Теперь представьте, что вместо предыдущего массива, у нас есть кастомная структура данных, которая хранит ваших любимых авторов. Как тут:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"320\" height=\"455\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_cKH3C2unSGdfsV1a_gQa5g.png\" alt=\"\" class=\"wp-image-94\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_cKH3C2unSGdfsV1a_gQa5g.png 320w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_cKH3C2unSGdfsV1a_gQa5g-211x300.png 211w\" sizes=\"(max-width: 320px) 100vw, 320px\" /></figure>\n\n\n\n<p>Теперь&nbsp;<code>myFavoriteAuthors</code>&nbsp;это объект, который содержит другой объект&nbsp;<code>allAuthors</code>.&nbsp;<code>AllAuthors</code>&nbsp;содержит три массива с ключами&nbsp;<code>fiction</code>,&nbsp;<code>scienceFiction</code>&nbsp;и&nbsp;<code>fantasy</code>. Теперь, если я попрошу вас пройтись по&nbsp;<code>myFavouriteAuthors</code>, чтобы получить всех авторов, как вы это сделаете? Вы можете попробовать какие-нибудь комбинации циклов, чтобы получить все нужные данные. </p>\n\n\n\n<p>Тем не менее, если вы сделаете так, то:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>for (let author of myFavouriteAuthors) { \n  console.log(author)\n}\n// TypeError: {} is not iterable \n// Хоба, а так нельзя!</code></pre>\n\n\n\n<p>То вы получите&nbsp;<code>TypeError</code>, говорящую о том, что объект нельзя проитерировать. Давайте посмотрим, что мы можем итерировать и как мы можем сделать сам объект таковым. В конце статьи вы узнаете как использовать&nbsp;<code>for-of</code>&nbsp;цикл на кастомных объектах, а в нашем случае на&nbsp;<code>myFavoriteAuthors</code>.</p>\n\n\n\n<h2 id=\"09a1\"><strong>Итераторы и итерируемые</strong></h2>\n\n\n\n<p id=\"00e1\">Вы уже видели проблему в предыдущем параграфе. Там нет простого способа пройтись по всем авторам заданного кастомного объекта. Нам понадобится какой-нибудь метод с помощью которого мы можем последовательно извлечь все нужные нам данные.</p>\n\n\n\n<p id=\"f76e\">Давайте добавим метод&nbsp;<code>getAllAuthors</code>&nbsp;в&nbsp;<code>myFavouriteAuthors</code>, который отдаст нам всех авторов. Например:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"583\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_2MBNj80NDfNTVs7C_btnmA.png\" alt=\"\" class=\"wp-image-95\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_2MBNj80NDfNTVs7C_btnmA.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_2MBNj80NDfNTVs7C_btnmA-300x250.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p id=\"901e\">Это довольно простой подход. Он решает нашу задачу в том, чтобы получить всех авторов. Тем не менее, несколько проблем всё таки всплывают в такой имплементации. Некоторые из них:</p>\n\n\n\n<p id=\"d8d4\">Имя&nbsp;<code>getAllAuthors</code>&nbsp;очень специфичное. Если кто-то ещё сделает свой&nbsp;<code>myFavouriteAuthors</code>, то они могут назвать его&nbsp;<code>retrieveAllAuthors</code>.</p>\n\n\n\n<p id=\"6eea\">Мы как разработчики, всегда должны знать конкретные методы, которые возвращают все требуемые данные. В нашем случае, это&nbsp;<code>getAllAuthors</code>.</p>\n\n\n\n<p id=\"6b4c\"><code>GetAllAuthors</code>&nbsp;возвращает массив строк, состоящий из всех авторов. А что если другой разработчик возвращает массив объектов в таком формате:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&#91; {name: 'Agatha Christie'}, {name: 'J. K. Rowling'}, ... ]</code></pre>\n\n\n\n<p id=\"e5c7\">Разработчику нужно будет точно знать имя и тип метода, которые возвращает все данные.</p>\n\n\n\n<p id=\"9434\"><em>Что если мы сделаем правило, в котором имя метода и его тип будут фиксированными и неизменными?</em></p>\n\n\n\n<p id=\"9a0f\">Давайте назовем этот метод —&nbsp;<code><strong>iteratorMethod</strong></code>.</p>\n\n\n\n<p id=\"5a16\"><a href=\"https://en.wikipedia.org/wiki/Ecma_International\" target=\"_blank\" rel=\"noreferrer noopener\">Подобный шаг был сделан ECMA</a>, чтобы стандартизировать этот процесс проведения цикла по кастомным объектам. Однако, вместо использования имени&nbsp;<code>iteratorMethod</code>, ECMA использовала имя&nbsp;<code>Symbol.iterator</code>.&nbsp;<a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol\" target=\"_blank\" rel=\"noreferrer noopener\">Symbols</a>&nbsp;предлагают имена, которые уникальны и не могут конфликтовать с именами других свойств. Также,&nbsp;<code>Symbol.iterator</code>&nbsp;вернет объект именуемый&nbsp;<code>iterator</code>. У этого итератора будет метод, под названием&nbsp;<code>next</code>, который возвращает объект с ключами&nbsp;<code>value</code>&nbsp;и&nbsp;<code>done</code>.</p>\n\n\n\n<p id=\"a041\">Ключ&nbsp;<code>value</code>, будет содержать актуальное значение. Это может быть всё, что угодно. А&nbsp;<code>done&nbsp;</code>— это булево значение(<em>логический тип данных</em>). Он определяет все ли значения были отданы.</p>\n\n\n\n<p id=\"0a02\">Схема нарисованная ниже может помочь с выстраиванием отношений между итерируемыми, итераторами и next. Эти отношения называются&nbsp;<strong>Iteration Protocol</strong>, то есть протокол итерации.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"666\" height=\"356\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_6OAbAJwoe2vORDLC0gxfpg.png\" alt=\"\" class=\"wp-image-96\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_6OAbAJwoe2vORDLC0gxfpg.png 666w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_6OAbAJwoe2vORDLC0gxfpg-300x160.png 300w\" sizes=\"(max-width: 666px) 100vw, 666px\" /></figure>\n\n\n\n<p id=\"5442\"><em>Согласно книге ExploringJS от Dr Axel Rauschmayer</em>&nbsp;&#8212;</p>\n\n\n\n<p id=\"1341\"><strong>Итерируемые</strong>&nbsp;— это структура данных, которой нужно сделать свои элементы доступными для вне. Это делается выполнением метода, чей ключ —&nbsp;<code>Symbol.iterator</code>. Этот метод является основой для итераторов. Вот так, он создаст итераторы.</p>\n\n\n\n<p id=\"6cd2\"><strong>Итератор</strong>&nbsp;— это указатель для навигации по элементам структуры данных.</p>\n\n\n\n<h2 id=\"88d9\"><strong>Делаем объекты итерируемыми</strong></h2>\n\n\n\n<p id=\"4740\">Как мы уже узнали в предыдущей секции, нам нужно выполнить метод под названием&nbsp;<code>Symbol.iterator</code>. Мы будем использовать синтаксис&nbsp;<a rel=\"noreferrer noopener\" href=\"http://es6-features.org/#ComputedPropertyNames\" target=\"_blank\">вычисления свойств</a>. Короткий пример:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"789\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_JU_gs02jm2MRqw9PEgKypA.png\" alt=\"\" class=\"wp-image-97\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_JU_gs02jm2MRqw9PEgKypA.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_JU_gs02jm2MRqw9PEgKypA-266x300.png 266w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p id=\"20e8\">На 4й строке мы сделали итератор. Это объект с методом&nbsp;<code>next</code>. Этот метод возвращает значение в соответствии с переменной&nbsp;<code>step</code>. На строке 25, мы получаем iterator. На 27й, мы вызываем&nbsp;<code>next</code>. И мы продолжаем вызывать&nbsp;<code>next</code>, пока&nbsp;<code>done</code>&nbsp;не станет&nbsp;<code>true</code>.</p>\n\n\n\n<p id=\"a28e\">Это именно то, что происходит в&nbsp;<code>for-of</code>&nbsp;цикле. Циклы&nbsp;<code>for-of</code>&nbsp;берут итерируемое и создают их итератор.&nbsp;<code>Next()</code>&nbsp;же продолжает вызываться до то момента, пока&nbsp;<code>done</code>, не станет&nbsp;<code>true</code>.</p>\n\n\n\n<h3 id=\"0951\"><strong>Итерируемые в JavaScript</strong></h3>\n\n\n\n<p id=\"fd58\">Много всего является итерируемым в JavaScript. Это может быть заметным не сразу, но если вы начнете внимательно вглядываться, то итерируемые начнут постепенно представляться вашему взору.</p>\n\n\n\n<p id=\"208b\">Вот это всё итерируемые-</p>\n\n\n\n<p id=\"b98e\"><strong>Массивы (Arrays)</strong>&nbsp;и&nbsp;<strong>Типизированные массивы (TypedArrays)</strong></p>\n\n\n\n<p id=\"78d9\"><strong>Строки (Strings)</strong>&nbsp;— итерируются по каждому символу или кодовому символу в Unicode.</p>\n\n\n\n<p id=\"da91\"><strong>Maps</strong>&nbsp;— итерируется по всем парам ключевых значений.</p>\n\n\n\n<p id=\"e484\"><strong>Set</strong>&nbsp;— итерируется по всем элементам.</p>\n\n\n\n<p id=\"ffb0\"><strong>Arguments&nbsp;</strong>— массиво-подобная специальная переменная в функциях.</p>\n\n\n\n<p id=\"851e\"><strong>Элементы DOM&nbsp;</strong>— тут над этим ещё ведется работа</p>\n\n\n\n<h3 id=\"e46a\"><strong>Другие итерируемые конструкции в JS это &#8212;</strong></h3>\n\n\n\n<p id=\"dad5\"><code>for-of</code>&nbsp;цикл —для&nbsp;<strong>for-of&nbsp;</strong>нужны итерируемые элементы. В противном случае, он выкинет ошибку&nbsp;<code>TypeError</code>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>for (const value of iterable) { ... }</code></pre>\n\n\n\n<p><em>Деструктурицизация массивов&nbsp;</em>— деструктуризация происходит из-за итерируемых. Давайте посмотрим как:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const array = &#91;'a', 'b', 'c', 'd', 'e'];\nconst &#91;first, ,third, ,last] = array;</code></pre>\n\n\n\n<p>Это по сути следующий код:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const array = &#91;'a', 'b', 'c', 'd', 'e'];\nconst iterator = array&#91;Symbol.iterator]();\nconst first = iterator.next().value\niterator.next().value // Так как оно пропущено, то не назначается\nconst third = iterator.next().value\niterator.next().value // Так как оно пропущено, то не назначается\nconst last = iterator.next().value</code></pre>\n\n\n\n<p><em>Оператор расширения spread.&nbsp;</em>Вот код:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const array = &#91;'a', 'b', 'c', 'd', 'e'];\nconst newArray = &#91;1, ...array, 2, 3];</code></pre>\n\n\n\n<p>Его можно записать вот так:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const array = &#91;'a', 'b', 'c', 'd', 'e'];\nconst iterator = array&#91;Symbol.iterator]();\nconst newArray = &#91;1];\nfor (let nextValue = iterator.next(); nextValue.done !== true; nextValue = iterator.next()) {\n  newArray.push(nextValue.value);\n}\nnewArray.push(2)\nnewArray.push(3)</code></pre>\n\n\n\n<p><code>Promise.all</code>&nbsp;и&nbsp;<code>Promise.race</code>&nbsp;принимают итерируемые.</p>\n\n\n\n<p><strong>Maps и Set.</strong></p>\n\n\n\n<p>Конструктор&nbsp;<strong>Map</strong>&nbsp;делает итерируемыми<code>[key, value]&nbsp;</code>пары в Map, а конструктор Set делает итерируемыми элементы в Set.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const map = new Map(&#91;&#91;1, 'one'], &#91;2, 'two']]);\nmap.get(1) \n// one\nconst set = new Set(&#91;'a', 'b', 'c]);\nset.has('c');\n// true</code></pre>\n\n\n\n<p>Итераторы также обязательны для понимания функций генераторов</p>\n\n\n\n<h2 id=\"e248\"><strong>Делаем myFavouriteAuthors итерируемыми</strong></h2>\n\n\n\n<p id=\"cc46\">Вот код, который сделает&nbsp;<code>myFavouriteAuthors</code>&nbsp;итерируемым:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const myFavouriteAuthors = {\n  allAuthors: {\n    fiction: &#91;\n      'Agatha Christie', \n      'J. K. Rowling',\n      'Dr. Seuss'\n    ],\n    scienceFiction: &#91;\n      'Neal Stephenson',\n      'Arthur Clarke',\n      'Isaac Asimov', \n      'Robert Heinlein'\n    ],\n    fantasy: &#91;\n      'J. R. R. Tolkien',\n      'J. K. Rowling',\n      'Terry Pratchett'\n    ],\n  },\n  &#91;Symbol.iterator]() {\n    // Получаем все жанры\n    const genres = Object.values(this.allAuthors);\n    \n    // Индекс заданного жанра и автора\n    let currentAuthorIndex = 0;\n    let currentGenreIndex = 0;\n    \n    return {\n      // Выполнение next()\n      next() {\n        // Авторы в соответствии с индексом заданного автора\n        const authors = genres&#91;currentGenreIndex];\n        \n        // doNotHaveMoreAuthors будет true, когда закончатся все авторы в массиве.\n        // Вот и всё, собственно, всех авторов взяли.\n        const doNothaveMoreAuthors = !(currentAuthorIndex &lt; authors.length);\n        if (doNothaveMoreAuthors) {\n          // Когда это происходит, мы двигаем индекс жанра к следующему жанру\n          currentGenreIndex++;\n          // И сбрасываем индекс автора на 0, чтобы получить новый набор авторов\n          currentAuthorIndex = 0;\n        }\n        \n        // Если мы прошлись по всем жанрам, то нам нужно сказать всем итераторам о том,\n        // что мы больше не можем дать значений.\n        const doNotHaveMoreGenres = !(currentGenreIndex &lt; genres.length);\n        if (doNotHaveMoreGenres) {\n          // Следовательно, мы возвращаем done со значением true.\n          return {\n            value: undefined,\n            done: true\n          };\n        }\n        \n        // Если всё верно, возвращаем автора из данного жанра \n        // и увеличиваем currentAuthorindex\n        // так что в следующий раз, будет отдам уже следующий автор.\n        return {\n          value: genres&#91;currentGenreIndex]&#91;currentAuthorIndex++],\n          done: false\n        }\n      }\n    };\n  }\n};\nfor (const author of myFavouriteAuthors) {\n  console.log(author);\n}\nconsole.log(...myFavouriteAuthors)</code></pre>\n\n\n\n<p>Со знаниями, полученными в этой статье, вы сможете легко понять то, как работают итераторы. Логика может быть немного сложна. Поэтому тут есть комментарии в коде. Но лучшим способом усвоить и понять эту концепцию, является игра с кодом в бразуере или ноде.</p>\n","date":"2021-01-14T20:36:35.000Z","title":"Самое понятное руководство по итераторам в ES6 JavaScript. С примерами","id":"3889467e-5af7-5c28-8b11-f37c92e12ae3","excerpt":"<p>В этой статье мы собираемся понять и проанализировать итераторы в JS. Это сравнительно новые способы для того, чтобы пройтись по любой коллекции данных в JavaScript. Они были представлены в ES6.</p>\n","type":"js","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2021/01/fjkdnkjlnsfkjdnsfkjsnjkdbkjsfb.jpg"}}},{"node":{"slug":"useeffect-eto-ne-novyi-componentdidmount","content":"\n<p>Они почти одинаковые. Но существует достаточно различий, которые возможно доставят вам неудобства, особенно если вы делаете рефакторинг с классов.</p>\n\n\n\n<p class=\"author\"><a href=\"https://reacttraining.com/blog/useEffect-is-not-the-new-componentDidMount/#summary\"><em>Перевод статьи useEffect(fn, []) is not the new componentDidMount()</em></a></p>\n\n\n\n<p>Мы часто делаем какие-нибудь настройки в компоненте при первом монтировании, например запросы в сеть или начинаем слушать события. Так мы приучили себя думать в границах&nbsp;<em>“моментов времени”</em>, таких как&nbsp;<code>componentDidMount()</code>,&nbsp;<code>componentDidUpdate()</code>&nbsp;и&nbsp;<code>componentWillUnmount()</code>. Вполне естественно брать предыдущие знания за основу и искать их аналоги при реализации на хуках. Я сам так делал и да, думаю, что каждый так делал. Часто я слышу на своих воркшопах такую фразу:</p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p><em>‘Какой эквиалент в хуках у [любой метод жизненного цикла]’</em></p></blockquote>\n\n\n\n<p>Быстрый ответ&nbsp;тут таков, что хуки это сдвиг парадигмы от того, чтобы думать в “<em>жизненных циклах и времени</em>” к ведению рассуждений в&nbsp;<em>“основываясь на стейте и синхронизации в DOM”</em>. Если вы возьмете старую парадигму и примените её к хукам, то она просто не будет работать как надо и вполне может застопорить всю вашу работу.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"230\" height=\"278\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_5AGbGZDRF6BjQx0jJn41wQ.gif\" alt=\"\" class=\"wp-image-86\"/></figure>\n\n\n\n<p id=\"d959\">Но эта тема полна свойственной React терминологии и без глубокого и осязаемого объяснения она просто забудется.</p>\n\n\n\n<p id=\"2865\">Когда разработчики только начинают изучать хуки, до этого имея опыт работы только на классах, то они склонны думать, что мол&nbsp;<em>“ага мне нужно запустить какой-либо код единожды при монтировании как с&nbsp;</em><code><em>componentDidMount()</em></code><em>. Ааа, я вижу, что&nbsp;</em><code><em>useEffect</em></code><em>&nbsp;имеет пустой массив как зависимость. Окей, я знаю как это работает.”</em></p>\n\n\n\n<p id=\"5e3d\">Такой ход мыслей приведет нас к нескольким проблемам:</p>\n\n\n\n<p id=\"978a\">Они просто по сути исполнения совершенно разные, так что вы можете не получить желаемого эффекта, рассматривая их как эквиваленты друг другу.</p>\n\n\n\n<p id=\"f452\">Если вы будете рассуждать в стиле:&nbsp;<em>“ага, сейчас вызову сайд эффект разок при монтировании”</em>, то к сожалению это значительно притормозит ваш процесс захода в хуки.</p>\n\n\n\n<p id=\"c024\">Поймите, что рефакторинг из классов на хуки не будет означать банальной замены&nbsp;<code>componentDidMount</code>&nbsp;на&nbsp;<code>useEffect(fn, [])</code>.</p>\n\n\n\n<h2 id=\"da9b\"><strong>Они запускаются в разные временные отрезки</strong></h2>\n\n\n\n<p id=\"67b2\">Сначала давайте поговорим о моменте времени выполнения каждого из них.&nbsp;<code>componentDidMount</code>&nbsp;запускается после монтирования компонента. По документации, если вы сразу же выставляете стэйт(синхронно), то React уже знает как инициировать дополнительный рендер и использовать второй респонс как изначальный UI, чтобы пользователь не увидел мигание между ререндерингом компонентов. Представьте, что вам надо узнать ширину DOM элемента с&nbsp;<code>componentDidMount</code>&nbsp;и вам надо обновить стэйт, чтобы что-нибудь отработало в зависимости от ширины взятого элемента. Вот последовательность действий:</p>\n\n\n\n<p id=\"9714\">Компонент рендерится впервые</p>\n\n\n\n<p id=\"c39e\">Отдаваемое значение&nbsp;<code>render()</code>&nbsp;используется для монтирования нового DOM.</p>\n\n\n\n<p id=\"a8a5\"><code>componentDidMount</code>&nbsp;срабатывает и сразу же выставляет стэйт. </p>\n\n\n\n<p id=\"c216\">Изменение стэйта означает то, что&nbsp;<code>render()</code>&nbsp;вызывается снова и отдаёт новый JSX, который заменяет предыдущий рендер.</p>\n\n\n\n<p id=\"e363\">Браузер показывает только второй рендер, чтобы избежать мигания промежуточных рендеров.</p>\n\n\n\n<p id=\"a4e1\"><a href=\"https://codesandbox.io/s/pensive-hamilton-p3qdd?from-embed=&amp;file=/src/index.js\">Вот пример</a></p>\n\n\n\n<p id=\"c56f\">Отлично, что это так работает когда нам это вообще нужно. Но большинство времени нам не нужен такой предоптимизированный подход, потому что мы делаем асинхронные запросы в сеть и уже потом выставляем стэйт после отрисовки экрана.</p>\n\n\n\n<p id=\"74ca\"><code>componentDidMount</code>&nbsp;и&nbsp;<code>useEffect</code>&nbsp;запускаются после монтирования. Но&nbsp;<code>useEffect</code>&nbsp;запускается после отрисовки экрана, а не как описано выше. Это говорит о том, что в этом случае будет мерцание экрана, если вам надо прочитать что-то из DOM и затем синхронно выставить стэйт, что сделать новый UI.</p>\n\n\n\n<p id=\"9a57\">Как же тогда получить старое поведение когда нам это нужно?</p>\n\n\n\n<p id=\"9786\"><code>useLayoutEffect</code>&nbsp;был разработан для того, чтобы иметь такой же тайминг как и у&nbsp;<code>componentDidMount</code>. В общем&nbsp;<code>useLayoutEffect(fn, [])</code>&nbsp;куда ближе по поведению к&nbsp;<code>componentDidMount()</code>, чем&nbsp;<code>useEffect(fn, [])</code>. Ну по крайней мере с точки зрения тайминга.</p>\n\n\n\n<h3 id=\"0339\"><strong>Означает ли это, что нам надо использовать useLayoutEffect?</strong></h3>\n\n\n\n<p id=\"7a50\">Возможно нет.</p>\n\n\n\n<p id=\"3734\">Если вы хотите избежать такого мерцания, синхронно выставляя стэйт, то используйте&nbsp;<code>useLayoutEffect</code>. Но так как это довольно редкий случай, то используйте просто&nbsp;<code>useEffect</code>.</p>\n\n\n\n<h2 id=\"ec04\"><strong>“Подхватывание” пропсов и стэйтов</strong></h2>\n\n\n\n<p id=\"a16b\">Применение асинхронного кода неизбежно в React. Когда такой код завершается, то значения полученных пропсов и стэйта могут быть немного смущающими. Давайте представим, что у нас был определенный асинхронный код, которому при отработке нужно было знать стэйт каунтера.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>class App extends React.Component {\n  state = {\n    count: 0\n  };\n\n  componentDidMount() {\n    longResolve().then(() => {\n      alert(this.state.count);\n    });\n  }\n\n  render() {\n    return (\n      &lt;div>\n        &lt;button\n          onClick={() => {\n            this.setState(state => ({ count: state.count + 1 }));\n          }}\n        >\n          Count: {this.state.count}\n        &lt;/button>\n      &lt;/div>\n    );\n  }\n}</code></pre>\n\n\n\n<p>При загрузке страницы у нас есть три секунды, чтобы кликнуть на кнопку несколько раз, перед тем как&nbsp;<code>longResolve</code>&nbsp;завершится. Далее выскочит алерт, говорящий актуальное значение&nbsp;<code>count</code>. С этим класс-компонентом, кликнув пять раз вы получите&nbsp;<code>5</code>&nbsp;в алерте.</p>\n\n\n\n<p>Теперь давайте отрефакторим это в хуках.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function App() {\n  const &#91;count, setCount] = useState(0);\n\n  useEffect(() => {\n    longResolve().then(() => {\n      alert(count);\n    });\n  }, &#91;]);\n\n  return (\n    &lt;div>\n      &lt;button\n        onClick={() => {\n          setCount(count + 1);\n        }}\n      >\n        Count: {count}\n      &lt;/button>\n    &lt;/div>\n  );\n}</code></pre>\n\n\n\n<p><a href=\"https://codesandbox.io/s/bold-sinoussi-ff42j\">Поиграться</a></p>\n\n\n\n<p id=\"dbd1\">Кажется, что это отличный рефакторинг на хуки, но поведение тут будет другое. В этом примере вне зависимости от количества кликов вы будете получать&nbsp;<code>0</code>.</p>\n\n\n\n<p id=\"8e67\">Разница тут в том, что&nbsp;<code>useEffect</code>&nbsp;хватает значение каунтера когда он создаётся. Когда мы отдаем коллбэк к&nbsp;<code>useEffect</code>, он задерживается в памяти, где он только знает то, что&nbsp;<code>count</code>&nbsp;равен&nbsp;<code>0</code>&nbsp;когда был создан. С кодом на классах,&nbsp;<code>componentDidMount</code>&nbsp;не имеет замыканий в стэйте, так что он просто читает актуальное значение.</p>\n\n\n\n<p id=\"92b0\">Чтобы помочь это понять, представьте, что JS хранит коллбэк в памяти примерно так:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// Это память, мне тут надо попридержать функцию. А и когда она создастся, там будут значения, такие как `count: 0`. Их надо тоже запомнить\n() => {\n// Хоть это и не так работает, но с точки зрения ментальной модели это как бы как будто count это просто переменная с указанным значением 0.\nconst count = 0\n  longResolve().then(() => {\n    alert(count);\n  });\n}</code></pre>\n\n\n\n<h3>Вот ещё один пример того, как&nbsp;<code>useEffect</code>&nbsp;захватывает значения.</h3>\n\n\n\n<p>В статье Дэна Абрамова&nbsp;<a href=\"https://overreacted.io/a-complete-guide-to-useeffect/\">“A Complete Guide to useEffect”</a>, примеры схожи и показывают поведение&nbsp;<code>setInterval</code>&nbsp;которое вы бы могли ожидать в классах, но не в хуках:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// Версия на классах:\nclass App extends React.Component {\n  state = { count: 0 }\n\n  componentDidMount() {\n    setInterval(() => {\n      this.setState({ count: this.state.count + 1 })\n    }, 1000);\n  }\n\n  render() {\n    return &lt;div>{this.state.count}&lt;/div>\n  }\n}\n\n// То, что нам кажется эквивалентном на хуках:\nfunction App() { \n  const &#91;count, setCount] = useState(0)\n\n  useEffect(() => {\n    const id = setInterval(() => {\n      setCount(count + 1)\n    }, 1000);\n    return () => clearInterval(id)\n  }, &#91;])\n\n  return &lt;div>{count}&lt;/div>\n}</code></pre>\n\n\n\n<p id=\"6f20\">В примере с классом наш каунтер увеличивается каждую секунду. А в примере с хуками он увеличивается только с 0 до 1 и затем останавливается. Но тут интересно то, что сам интервал на самом деле не останавливается. Причиной такого поведения является то, что коллбэк&nbsp;<code>useEffect</code>&nbsp;как бы “захватывает” то, что он видит как&nbsp;<code>count</code>&nbsp;при создании. Этот колбэк всегда думает, что&nbsp;<code>count</code>&nbsp;равен&nbsp;<code>0</code>&nbsp;и следовательно мы всегда будем к нулю прибавлять единицу.</p>\n\n\n\n<p id=\"c158\">Если это кажется довольно сложным, то дайте ка я вам объясню как тут что происходит, это очень поможет вам в избежании будущих багов.</p>\n\n\n\n<p id=\"95c1\">Помните, что это не урок того, как работает&nbsp;<code>setInterval</code>&nbsp;с хуками, это скорее о том как применить ментальную модель с классов на хуки и о том как&nbsp;<code>useEffect</code>&nbsp;<em>“захватывает”</em>&nbsp;значения.</p>\n\n\n\n<p id=\"9a83\">Для начала нам надо понять почему массив с зависимостями так назван.</p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p><em>Если ваш эффект “зависит” от чего то, то оно должно быть указано в вышеупомянутом массиве.</em></p></blockquote>\n\n\n\n<p>Наш код зависит от переменной c каунтером в стэйте. Вообще, нам надо было так сделать уже давным давно.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>useEffect(() => {\n    const id = setInterval(() => {\n      setCount(count + 1)\n    }, 1000)\n    return () => clearInterval(id)\n  }, &#91;count])</code></pre>\n\n\n\n<p>Теперь код работает так, как нам надо, потому что мы хотим, чтобы коллбэк в&nbsp;<code>useEffect</code>&nbsp;запускался только тогда, когда каунт меняется. Когда это происходит, то предыдущий коллбэк в памяти очистится и следовательно&nbsp;<code>setInterval</code>&nbsp;будет удален. Затем React создаст совершенно новый callback в памяти, который уже будет знать, что count равен&nbsp;<code>1</code>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// Эй память, нам тут надо функцию сохранить...\n() => {\n  const count = 0\n  const id = setInterval(() => {\n    setCount(count + 1)\n  }, 1000)\n  return () => clearInterval(id)}\n\n// Потом при смене каунта...\n// Эй память, очисти первую функцию  \n// и потом нам надо захостить вторую...\n() => {\n  const count = 1\n  const id = setInterval(() => {\n    setCount(count + 1)\n  }, 1000)\n  return () => clearInterval(id)\n}</code></pre>\n\n\n\n<p>Если мы хотим узнать актуальное значение, а не которое “захватили”, то вы всегда можете&nbsp;<a href=\"https://reactjs.org/docs/hooks-faq.html#is-there-something-like-instance-variables\">использовать рефы</a>.</p>\n\n\n\n<p>Я думаю, что пример с&nbsp;<code>setInterval</code>&nbsp;это отличный способ понять суть “<em>захватывания</em>” в&nbsp;<code>useEffect</code>, хотя стоит отметить, что есть ещё одно API для указания стэйта, в котором мы передаём функцию, а не значение. React вызовет функцию с существующим стэйтом:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>useEffect(() => {\n  const id = setInterval(() => {\n    // Когда мы передаем функцию, React вызывает её с\n    // актуальным стейтом и всякий раз в этом случае она же и становится актуальным стэйтом.\n    setCount(count => count + 1)\n  }, 1000)\n  return () => clearInterval(id)\n}, &#91;])</code></pre>\n\n\n\n<p>Теперь наш эффект не “стесняет” переменную&nbsp;<code>count</code>&nbsp;и теперь нам не нужно добавлять массив с зависимостями, и мы не стесняем его, следовательно ничего не указывается как исходное значение при запуске эффекта. Хоть это уже немного и отклонение от основной темы, но сейчас мы хотя бы понимаем суть “захватывания” для эффектов и то, что есть другой способ выставить стэйт — будем надеятся, что это&nbsp;<strong>win-win</strong>&nbsp;при обучении хукам.</p>\n\n\n\n<h2 id=\"d6e5\"><strong>“Захват” это хорошо или плохо?</strong></h2>\n\n\n\n<p id=\"f13f\">Есть некоторые баги, которых можно избежать во время использования “<em>захвата</em>”, а не актуального значения. Посмотрите этот пример от Дэна Абрамова&nbsp;<a href=\"https://codesandbox.io/s/pjqnl16lm7\">https://codesandbox.io/s/pjqnl16lm7</a>, где он показывает как “<em>захват</em>” отдаёт вам ожидаемое поведение с поведением компонента класса, который отдаёт актуальный стэйт. В этом примере мы можем подписаться на кого-нибудь и затем быстро менять профайлы. Когда мы меняем профайлы перед получением ответа из сети, существует баг, когда показывается имя нашего последнего подписчика. Это баг с версией на классах, а не с версией на хуках. Почитайте&nbsp;<a href=\"https://overreacted.io/how-are-function-components-different-from-classes/\">тут</a>&nbsp;про это.</p>\n\n\n\n<h2 id=\"56a3\"><strong>Что там с рефакторингом с классов на хуки?</strong></h2>\n\n\n\n<p id=\"4223\">Предположим, что вы написали такой код:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>class UserProfile extends React.Component {\n  state = { user: null }\n\n  componentDidMount() {\n    getUser(this.props.uid).then(user => {\n      this.setState({ user })\n    })\n  }\n\n  render() {\n    // ...\n  }\n}</code></pre>\n\n\n\n<p id=\"d2cd\">Видите баг?</p>\n\n\n\n<p id=\"2559\">Что случиться если проп&nbsp;<code>uid</code>&nbsp;изменится? Мы не увидим нового пользователя, потому что мы не обрабатываем это изменение в&nbsp;<code>componenDidUpdate</code>. Обычно, если&nbsp;<code>componentDidMount</code>&nbsp;делает сайд-эффекты, зависящие от пропсов или стэйта, то вам в помощь тогда придет&nbsp;<code>componentDidUpdate</code>, чтобы обработать сайд-эффект уже тогда, когда проп или стэйт изменится. Но иногда получается не совсем так идеально и мы можем напороться на баг, забыв о вышеописанном.</p>\n\n\n\n<p id=\"88c1\">Если вы делаете рефакторинг с классов на хуки и вы просто меняете&nbsp;<code>componentDidMount</code>&nbsp;на&nbsp;<code>useEffect</code>&nbsp;с пустым массивом зависимостей, то вы почти всегда будете ловить баги в новом коде. Давайте представим, что мы отрефакторили код выше в это:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function UserProfile({ uid }) {\n  const &#91;user, setUser] = useState(null)\n\n  useEffect(() => {\n    getUser(uid).then(user => {\n      setUser(user)\n    })\n  }, &#91;]) // buggy without `uid` in this array\n  // ...\n}</code></pre>\n\n\n\n<p id=\"af23\">Этот код будет работать как надо до тех пор, пока у&nbsp;<code>UserProfile</code>&nbsp;не поменяется пропс&nbsp;<code>uid</code>. Если у вас уже на борту есть дополнительные правила по листингу хуков, то вы будете получать предупреждения пока не добавите&nbsp;<code>[uid]</code>, как массив зависимостей. Учитывая это, версия с хуками будет делать тоже самое, что делали бы&nbsp;<code>componentDidMount&nbsp;</code>и&nbsp;<code>componentDidUpdate</code>. В общем вы видите, что сам вопрос&nbsp;<em>“Является ли useEffect с пустым массивом зависимостей новой версией componentDidMount?”</em>&nbsp;Сам по себе некорректен и тут стоит сразу начинать с того, что&nbsp;<code>componentDidMount</code>&nbsp;зачастую просто не может быть отрефакторен в&nbsp;<code>useEffect(fn, [])</code>.</p>\n\n\n\n<p id=\"c9d6\">К слову, не забудь сделать функцию очистки. Это предостережет от багов выставления стэйта на демонтированный компонент и выставление старого стэйта, когда&nbsp;<code>uid</code>&nbsp;изменяется.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>useEffect(() => {\n  let isCurrent = true\n  getUser(uid).then(user => {\n    if (isCurrent) {\n      setUser(user)\n    }\n  })\n  return () => {\n    isCurrent = false\n  }\n}, &#91;uid])</code></pre>\n\n\n\n<h2 id=\"1c08\"><strong>Заключение</strong></h2>\n\n\n\n<p id=\"0931\">Думать во временных границах это то, как мы делали с компонентами класса. Теперь нам надо думать “<em>как выглядит UI с этим стейтом?</em>” и “<em>когда стэйт изменяется, какие сайд-эффекты надо перезапускать.</em>” Попробуйте отталкиваться от стэйта, а не от “<em>тайминга жизненного цикла</em>” компонента.</p>\n","date":"2021-01-11T14:17:28.000Z","title":"useEffect(fn, []) это не новый componentDidMount()","id":"14236f35-b58a-56dc-a1cc-4d6b44cc05d1","excerpt":"<p>Они почти одинаковые. Но существует достаточно различий, которые возможно доставят вам неудобства, особенно если вы делаете рефакторинг с классов.</p>\n","type":"js","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2021/01/fjdnsjklfnsdjklnfsknlj.jpg"}}},{"node":{"slug":"trailing-commas-v-javascript-es-2017","content":"\n<p>Маленькая, но уж очень полезная статья о том, как использовать замыкающие запятые в JavaScript.</p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p><em>Кто-то называет их просто&nbsp;</em><strong>Trailing Commas</strong><em>, без перевода. Кто-то говорит, что это&nbsp;</em><strong>висящие запятые</strong><em>,&nbsp;</em><strong>конечные запятые</strong><em>&nbsp;или&nbsp;</em><strong>последние запятые</strong><em>. Слышал даже, что её называют&nbsp;</em><strong>гуляющей запятой</strong><em>. Я же сторонник более подходящего варианта в техническом отношении, а именно за&nbsp;</em><strong>замыкающую запятую</strong><em>. Использование англоязычного варианта мне кажется неуместным в этом случае.</em></p></blockquote>\n\n\n\n<p class=\"author\"><em>Перевод статьи&nbsp;</em><a href=\"https://codeburst.io/learn-javascript-es-2017-trailing-commas-4534891f3f90\"><em>Learn JavaScript ES 2017 — Trailing Commas</em></a></p>\n\n\n\n<p>Вообще, некоторые замыкающие запятые можно было использовать, своеобразно конечно, ещё с самого зарождения JavaScript. Но эти совершенно новые и ниже вы узнаете буквально всё про них.</p>\n\n\n\n<h2 id=\"e19a\">Что такое замыкающая запятая и почему она полезна?</h2>\n\n\n\n<p id=\"39cd\">Предположим, что у вас есть список домашних дел и вы скорее всего разделяете эти самые дела запятыми:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>dishes, vacuum, tidy</code></pre>\n\n\n\n<p>Замыкающая запятая это просто запятая, которая идёт после последнего элемента в списке. Она необязательна, но в некоторых случаях использования в JS, мы можем её использовать:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>dishes, vacuum, tidy,</code></pre>\n\n\n\n<p id=\"2eff\">И знаете, есть несколько случаев, когда вам всё таки понадобится её использовать. Предположим, что вам надо программно добавлять элементы в массив:</p>\n\n\n\n<p id=\"4d21\">Без замыкающей запятой большинство значений может быть добавлено в массив, как&nbsp;<code>value + ','</code>. Но тут надо немного доработать логику в коде и убедиться в том, что последний элемент будет добавлен в массив без запятой в конце.</p>\n\n\n\n<p id=\"940b\">С замыкающей запятой, все элементы могут быть добавлены в массив, как&nbsp;<code>value + ','</code>.</p>\n\n\n\n<h2 id=\"71b1\"><strong>Массивы</strong></h2>\n\n\n\n<p id=\"4eb3\">С самого зарождения JavaScript, замыкающие запятые можно было использовать при создании массивов:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// Оба варианта одинаковы:\nlet arr = &#91; 1, 2 ];\nlet arr = &#91; 1, 2 , ];\narr.length; // 2</code></pre>\n\n\n\n<h2 id=\"b722\"><strong>Объекты</strong></h2>\n\n\n\n<p id=\"d601\">Замыкающие запятые также вполне можно использовать и в объектах:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// Оба варианта одинаковы:\nlet obj = { \n  a: 95, \n  b: 23\n};\nlet obj = { \n  a: 95, \n  b: 23,\n};</code></pre>\n\n\n\n<h2 id=\"f854\"><strong>Указание параметров и вызовы функции</strong></h2>\n\n\n\n<p id=\"1f00\">Начиная с ES 2017, замыкающие запятые можно использовать в указании параметров и вызовах функции:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// Оба варианта одинаковы:\nfunction f(a,b) {}\nfunction f(a,b,) {}\n// Оба варианта одинаковы:\nf(1,2);\nf(1,2,);</code></pre>\n\n\n\n<p>Однако, если в аргументе для функции будет только замыкающая запятая, то вы получите синтаксическую ошибку:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function f(,) {}; \n// SyntaxError: missing formal parameter\nf(,); \n// SyntaxError: expected expression, got ','</code></pre>\n\n\n\n<h2 id=\"6e41\"><strong>Rest параметры</strong></h2>\n\n\n\n<p id=\"9c83\">При использовании&nbsp;<code>rest</code>&nbsp;параметров нельзя применять замыкающие запятые, так как получите в ответ&nbsp;<code>SyntaxError</code>:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function f(...a,) {};\n// SyntaxError: parameter after rest parameter\nlet &#91;a, ...b,] = &#91;1, 2, 3, 4, 5];\n// SyntaxError: rest element may not have a trailing comma</code></pre>\n\n\n\n<h2 id=\"5fe8\">JSON</h2>\n\n\n\n<p id=\"3563\">В JSON нельзя использовать замыкающие запятые. Попытаясь спарсить JSON с такой запятой, вы получите синтаксическую ошибку:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>JSON.parse('&#91;\"a\", \"b\",]');\n// SyntaxError JSON.parse: unexpected character</code></pre>\n\n\n\n<p></p>\n","date":"2020-12-15T16:15:18.000Z","title":"Замыкающие запятые (Trailing Commas) в JavaScript ES 2017","id":"a2025c77-4589-5863-8d1d-845abc118856","excerpt":"<p>Маленькая, но уж очень полезная статья о том, как использовать замыкающие запятые в JavaScript.</p>\n","type":"js","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2020/12/DglYtvO7Bn0-13.jpg"}}},{"node":{"slug":"react-router-chast-3-redirekty-peredacha-props-komponentu-routa-i-vlozhennie-routy-bonus","content":"\n<p>В этой серии статей вы подробно и доходчиво узнаете о том, как работает Router в React, как его можно использовать и другие интересные фишки этого функционала. Это завершающая часть, в ней будет рассказано о передаче пропсов компоненту роута, редиректах и вложенных роутах. + бонус, стилизация активных элементов навигации.</p>\n\n\n\n<p><a href=\"https://stasonmars.ru/javascript/react-router-chast-1-osnovy-routinga-tipy-dannyh-i-dynamicheskie-stranicy\">Подробно о React Router. Часть 1 —&nbsp;основы&nbsp;роутинга, типы и динамические страницы</a></p>\n\n\n\n<p><a href=\"https://stasonmars.ru/javascript/react-router-chast-2-parametry-zaprosa-404-stranitsa-i-peredacha-propsov\">Подробно о&nbsp;React&nbsp;Router. Часть 2 — параметры запроса, 404 страница и передача пропсов компоненту роута</a></p>\n\n\n\n<p><em>p.s статья описывает&nbsp;самый&nbsp;распространенную версию роутера на данный момент. 6я версия сейчас находится в альфе и имеет&nbsp;</em><a href=\"https://twitter.com/stassonmars/status/1248171321860788225\"><em>кардинально другой синтаксис</em></a><em>.</em></p>\n\n\n\n<p class=\"author\" id=\"0311\"><em>Перевод серии&nbsp;статей&nbsp;</em><a href=\"https://learnwithparam.com/blog/basic-routing-in-react-router/\"><em>Deep dive into React Router</em></a></p>\n\n\n\n<h2 id=\"9761\"><strong>Передаём пропсы компоненту роута</strong></h2>\n\n\n\n<p id=\"1566\">Мы видели несколько примеров и рабочих кейсов в React роутере. Один из них это передача пропсов напрямую компоненту самого роута.</p>\n\n\n\n<p id=\"dded\">В React-router это делается очень легко. Давайте создадим новый роут для передачи props его компоненту.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// App.js\n...\n\nconst PropsPage = () => {  return ( &lt;h3>Props Page&lt;/h3>  );};\nconst App = () => {\n  return (\n    &lt;section className=\"App\">\n      &lt;Router>\n        ...\n        &lt;Link to=\"/404-not-found\">404&lt;/Link>\n        &lt;Link to=\"/props\">Passing Props&lt;/Link>        \n        &lt;Switch>\n          ...\n          &lt;Route exact path=\"/props\" component={PropsPage} />              \n          &lt;Route component={NoMatchPage} />\n        &lt;/Switch>\n      &lt;/Router>\n      &lt;a href=\"/about\">about with browser reload&lt;/a>\n    &lt;/section>\n  );\n};\n\nexport default App;</code></pre>\n\n\n\n<p id=\"c42c\">Прямо сейчас мы добавили компонент и новую страницу. Давайте передарим пропс&nbsp;<code>title</code>&nbsp;уже самой странице.</p>\n\n\n\n<p id=\"f6b1\">Есть два способа это сделать. Первый очень простой.</p>\n\n\n\n<h3><strong>Передаём функцию как пропс компонента в компоненте роута</strong></h3>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>...\n\nconst PropsPage = ({ title }) => {\n  return (\n    &lt;h3>{title}&lt;/h3>\n  );\n};\n\n...\n\n&lt;Route exact path=\"/props-through-component\" component={() => &lt;PropsPage title={`Props through component`} />} /></code></pre>\n\n\n\n<p id=\"8074\">Эта штука сработает, но такой подход не рекомендуется применять с роутером. Почему? Сейчас объясню.</p>\n\n\n\n<p id=\"3f27\">Под капотом React использует&nbsp;<code>React.createElement</code>&nbsp;для рендеринга компонента, переданного пропсу компонента. Если мы передадим ему функцию, то он создаст новый компонент при каждом рендере, вместо того, чтобы просто обновить уже существующий компонент.</p>\n\n\n\n<p id=\"57d9\">В маленьких приложениях с довольно несложными страницами, это не будет влиять на производительность. Но для больших приложений с множественным изменением состояния на странице, это значительно снизит производительность из-за необязательных циклов ре-рендеринга.</p>\n\n\n\n<p id=\"7278\">Роутер даёт нам довольно простое решение в этой ситуации. Вместо простой передачи функции через пропсы&nbsp;<code>component</code>, мы можем передать их через пропсы&nbsp;<code>render</code>. Передавая наши пропсы, нам также надо передать дефолтные пропсы к пропсам рендеринга. Давайте посмотрим пример:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>...\n\n&lt;Link to=\"/props-through-render\">Props through render&lt;/Link>\n...\n\n&lt;Route exact path=\"/props-through-render\" render={(props) => &lt;PropsPage {...props} title={`Props through render`} />} /></code></pre>\n\n\n\n<p id=\"c3ee\">Вот это уже рекомендуемый способ передачи самих пропсов в React роутере.</p>\n\n\n\n<p id=\"683b\">Это очень просто. Если вы хотите увидеть весь пример, то проверьте его <a href=\"https://codesandbox.io/s/props-in-component-react-router-g2im5?from-embed\">тут</a>.</p>\n\n\n\n<h2 id=\"f006\"><strong>Редиректим роуты</strong></h2>\n\n\n\n<p id=\"de44\">В основном редиректы используют при проверке пользователей на авторизацию, если пользователь не авторизован, то его перенаправит на соответствующую страницу.</p>\n\n\n\n<p id=\"f934\">Вообще, всё это очень легко сделать с использованием компонента&nbsp;<code>Redirect</code>.</p>\n\n\n\n<p id=\"d374\">Давайте посмотрим на простой пример того, как он работает. Давайте создадим простую страницу, которая перенаправит на другую страницу основываясь на заданных условиях.</p>\n\n\n\n<p id=\"d383\">Давайте перенаправим с&nbsp;<code>/old-route</code>&nbsp;на&nbsp;<code>/new-route</code></p>\n\n\n\n<h3 id=\"63c3\"><strong>Простой пример редиректа</strong></h3>\n\n\n\n<p id=\"6852\">Добавляем роут редиректа в наш пример.</p>\n\n\n\n<p id=\"dd32\">Сейчас мы создадим два URL.</p>\n\n\n\n<p id=\"1020\"><code>/old-route</code>&nbsp;это старый URL, с которого будет редирект на новый URL&nbsp;<code>/new-route</code>, используя компонент Redirect.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// Импортируем компонент Redirect из react-router\nimport { Route, Redirect } from 'react-router';\n\n// Передаем параметры редиректа этому компоненту\n&lt;Redirect from=\"/old-route\" to=\"/new-route\" />\n// Указываем параметры\n&lt;Route exact path=\"/new-route\" component={RedirectPage} />\n\n&lt;Link to=\"/old-route\">Redirecting to New page&lt;/Link>\n\n// Page component\nconst RedirectPage = () => {\n  return (\n    &lt;h3>Redirect Page&lt;/h3>\n  );\n};</code></pre>\n\n\n\n<p>Теперь проверьте <a href=\"https://codesandbox.io/s/redirect-route-simple-yewt5?from-embed\">пример простого редиректа</a></p>\n\n\n\n<p>Тут вы увидите, что старая ссылка редиректит на новую ссылку и тут же показывает его в браузере.</p>\n\n\n\n<h3 id=\"f0bd\"><strong>Редирект посложнее, основанный на пропсах</strong></h3>\n\n\n\n<p id=\"d8e4\">Тут мы сделаем небольшую страничку, которая будет редиректить на дашборд, если пропс&nbsp;<code>isLoggedin</code>&nbsp;будет&nbsp;<code>true</code>&nbsp;или покажем простое сообщение в случае с&nbsp;<code>false</code>.</p>\n\n\n\n<p id=\"7ac8\">Давайте сначала сделаем страничку.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const AuthPage = ({ isLoggedIn }) => {\n  if (isLoggedIn) {\n    return &lt;Redirect to=\"/dashboard\" />;\n  } else {\n    return &lt;h3>User not loggedin&lt;/h3>;\n  }\n};\n\nconst DashboardPage = () => {\n  return &lt;h3>Dashboard Page&lt;/h3>;\n};</code></pre>\n\n\n\n<p>Давайте укажем роут для страниц&nbsp;<code>Auth</code>&nbsp;и&nbsp;<code>Dashboard</code>:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// Указываем роут для Dashboard\n&lt;Route exact path=\"/dashboard\" component={DashboardPage} />\n// Указываем роут для незалогиненной страницы, передав пропс isLoggedIn как false\n&lt;Route exact path=\"/auth-not-loggedin\" render={(props) => &lt;AuthPage {...props} isLoggedIn={false} />} />\n\n&lt;Route exact path=\"/auth-loggedin\" render={(props) => &lt;AuthPage {...props} isLoggedIn={true} />} />\n\n\n// Lets add the links to navigate to these pages\n&lt;Link to=\"/auth-not-loggedin\">Not Loggedin&lt;/Link>\n&lt;Link to=\"/auth-loggedin\">User Loggedin&lt;/Link></code></pre>\n\n\n\n<p id=\"1d6d\">Теперь можете всё проверить сами. Роут редиректит и меняет URL в браузере на&nbsp;<code>/dashboard</code>, когда мы передаем&nbsp;<code>isLoggedIn</code>&nbsp;как&nbsp;<code>true</code>. И в свою очередь показывает простое сообщение для неавторизованных пользователей.</p>\n\n\n\n<p id=\"7a5b\">Посмотрите <a href=\"https://codesandbox.io/s/redirect-route-complex-x6o6v?from-embed\">этот функционал тут</a></p>\n\n\n\n<h2 id=\"9fe1\"><strong>Вложенные роуты и контент</strong></h2>\n\n\n\n<p id=\"f719\">До этого мы видели простые примеры работы с реакт роутером. А сейчас мы разберемся с тем, как работать с вложенными роутами. Перед тем как углубиться в них давайте поймем, что же это такое?</p>\n\n\n\n<h3 id=\"010f\"><strong>Примеры вложенных роутов</strong></h3>\n\n\n\n<p id=\"2e16\">Простой пример</p>\n\n\n\n<pre class=\"wp-block-preformatted\"></pre>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>www.example.com/users</code></pre>\n\n\n\n<p id=\"d307\">Этот роут показывает всех пользователей.</p>\n\n\n\n<p id=\"e74a\">Вложение первого уровня:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>www.example.com/user/param\nwww.example.com/user/miguel</code></pre>\n\n\n\n<p id=\"2f20\">Эти примеры роутов показывают конкретного пользователя.&nbsp;<code>Param</code>&nbsp;и&nbsp;<code>miguel</code>&nbsp;это&nbsp;<code>userId</code>&nbsp;используемые для получения данных о конкретных пользователях.</p>\n\n\n\n<p id=\"c518\">Вложение второго уровня:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>www.example.com/user/param/details\nwww.example.com/user/param/employer\nwww.example.com/user/miguel/details\nwww.example.com/user/miguel/employer</code></pre>\n\n\n\n<p><code><a href=\"http://www.example.com/user/param/employer\">www.example.com/user/param/employer</a></code>&nbsp;Этот роут получает простую информацию о пользователе и также информацию о его работодателе. Так что можно сказать, что это вложенные роуты. А вложения второго уровня уже зависят от параметров вложения первого уровня (<code>userId: param</code>)</p>\n\n\n\n<p>Давайте начнем с конкретного примера. Мы собираемся показать пользователей и затем вывести детальную информацию о них.</p>\n\n\n\n<h3 id=\"363d\"><strong>Вложенные роуты в React Router</strong></h3>\n\n\n\n<p id=\"9345\">Для примера мы возьмем вот эти данные:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const users = &#91;\n  {\n    name: 'Param',\n    description:\n      'Guy who writes lorem ipsum all the time when he needs content placeholder',\n    tabs: &#91;\n      {\n        name: 'personal',\n        content: {\n          firstname: 'Param',\n          lastname: 'Harrison',\n        },\n      },\n      {\n        name: 'employer',\n        content: {\n          name: 'Jobbatical',\n          city: 'Tallinn, Estonia',\n        },\n      },\n    ],\n  },\n  {\n    name: 'Miguel',\n    description:\n      'the best guy doing deployment in his own clusters of kubernetes world',\n    tabs: &#91;\n      {\n        name: 'personal',\n        content: {\n          firstname: 'Miguel',\n          lastname: 'Medina',\n        },\n      },\n      {\n        name: 'employer',\n        content: {\n          name: 'Skype',\n          city: 'Arizona, US',\n        },\n      },\n      {\n        name: 'other',\n        content: {\n          country: 'Mexico',\n          age: 30,\n        },\n      },\n    ],\n  },\n];</code></pre>\n\n\n\n<p id=\"77f0\">В этом примере есть несколько пользователей и каждый из них имеет разное количество вложенных табов, в каждом из которых есть имя и контент, который мы покажем.</p>\n\n\n\n<p id=\"7e15\">Используя эти данные мы создадим эти роуты:</p>\n\n\n\n<p><strong>Вложение первого уровня:</strong></p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>https:&#47;&#47;y5pt4.csb.app/user/Param\nhttps://y5pt4.csb.app/user/Miguel</code></pre>\n\n\n\n<p><strong>Вложения второго уровня:</strong></p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>https:&#47;&#47;y5pt4.csb.app/user/Param/tab/personal\nhttps://y5pt4.csb.app/user/Param/tab/employer\nhttps://y5pt4.csb.app/user/Miguel/tab/personal\nhttps://y5pt4.csb.app/user/Miguel/tab/employer</code></pre>\n\n\n\n<p><a href=\"https://y5pt4.csb.app/user/Miguel/tab/other\">Примеры</a></p>\n\n\n\n<h3><strong>Показываем вложения первого уровня</strong></h3>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>import { BrowserRouter as Router, Link, Route } from 'react-router-dom';\n\nfunction App() {\n  return (\n    &lt;div className=\"App\">\n      &lt;Router>\n        &lt;h3>Top level routes&lt;/h3>\n        &lt;ul className=\"unlist\">\n          {users.map((user, index) => {\n            return (\n              &lt;li key={index}>\n                &lt;Link to={`/user/${user.name}`}>{user.name}&lt;/Link>\n              &lt;/li>\n            );\n          })}\n        &lt;/ul>\n        &lt;Route path=\"/user/:userName\" component={UserPage} />\n      &lt;/Router>\n    &lt;/div>\n  );\n}</code></pre>\n\n\n\n<p id=\"42db\">Тут мы пробегаемся по всем данным пользователей и показываем ссылку на каждого пользователя с данными о нем.</p>\n\n\n\n<p id=\"7096\">Также мы указываем схему роутов для пользователей.&nbsp;<code>userName</code>&nbsp;это параметр, передающийся компоненту&nbsp;<code>UserPage</code>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const UserPage = ({ match }) => {\n  \n  const {\n    params: { userName },\n  } = match;\n  const user = users.find(({ name }) => name === userName);\n\n  \n  return (\n    &lt;div>\n      User Name: &lt;strong>{user.name}&lt;/strong>\n      &lt;p>{user.description}&lt;/p>\n    &lt;/div>\n  );\n};</code></pre>\n\n\n\n<p id=\"86c3\">Компонент&nbsp;<code>UserPage</code>&nbsp;покажет простую информацию о конкретном пользователе.</p>\n\n\n\n<p id=\"3c6a\">React роутер передаст пропсы&nbsp;<code>match</code>&nbsp;и мы сразу получим информацию о пользователе используя значение&nbsp;<code>userName</code>.</p>\n\n\n\n<h3><strong>Показываем вложенные роуты как табы</strong></h3>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const UserPage = ({ match }) => {\n  ...\n\n  return (\n    &lt;div>\n      ...\n      &lt;p>Dyanmic nested route&lt;/p>\n      &lt;ul className=\"unlist\">\n        {user.tabs.map((tab, index) => {\n          return (\n            &lt;li key={index}>\n              &lt;Link to={`${match.url}/tab/${tab.name}`}>{tab.name}&lt;/Link>\n            &lt;/li>\n          );\n        })}\n      &lt;/ul>\n      \n      &lt;Route path={`${match.path}/tab/:tabName`} component={TabPage} />\n    &lt;/div>\n  );\n};</code></pre>\n\n\n\n<p id=\"766d\">Пропс&nbsp;<code>match</code>&nbsp;отдаёт нам&nbsp;<code>url</code>&nbsp;через&nbsp;<code>match.url</code>, который можно использовать для создания вложенных роутов.</p>\n\n\n\n<p id=\"ef43\">Тут мы создаем вложенные роуты, используя информацию для табов у каждого пользователя.</p>\n\n\n\n<p id=\"7929\"><code>match.path</code>&nbsp;уже выдаёт нам имя пути. Его мы будем использовать для указания вложенной схемы роута.</p>\n\n\n\n<p id=\"cc3c\">Но зачем использовать&nbsp;<code>match.path</code>, а не&nbsp;<code>match.url</code>?</p>\n\n\n\n<p id=\"a52c\">Потому что&nbsp;<code>match.path</code>&nbsp;содержит настоящий путь, то есть&nbsp;<code>user/:userName</code>, где&nbsp;<code>match.url</code>&nbsp;уже готовый url user/Param.</p>\n\n\n\n<p id=\"de9f\">Именно поэтому&nbsp;<code>match.url</code>&nbsp;находится в Link, а&nbsp;<code>match.path</code>&nbsp;используется в определении роута.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&lt;Route path={`${match.path}/tab/:tabName`} component={TabPage} /></code></pre>\n\n\n\n<p><code>tabName</code>&nbsp;это параметр роута, который мы передаём компоненту&nbsp;<code>TabPage</code>. Он использует его для нахождения точного таба и показывает сам контент непосредственно в табе. Давайте глянем на код.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const TabPage = ({ match }) => {\n  const {\n    params: { userName, tabName },\n  } = match;\n\n  const tab = users\n    .find(({ name }) => name === userName)\n    .tabs.find(({ name }) => name === tabName);\n\n  // Show the content for that particular tab\n  return (\n    &lt;div>\n      Tab Name: &lt;strong>{tab.name}&lt;/strong>\n      &lt;h6>Tab content: &lt;/h6>\n      &lt;ul>\n        {Object.keys(tab.content).map((key, index) => {\n          return (\n            &lt;li key={index}>\n              &lt;span>{key} : &lt;/span>\n              &lt;strong>{tab.content&#91;key]}&lt;/strong>\n            &lt;/li>\n          );\n        })}\n      &lt;/ul>\n    &lt;/div>\n  );\n};</code></pre>\n\n\n\n<p id=\"d946\">Пропсы&nbsp;<code>match</code>&nbsp;отдадут нам все params в URL&nbsp;<code>userName</code>,&nbsp;<code>tabName</code></p>\n\n\n\n<p id=\"3d22\">Находим таб в наших данных, используя оба параметра</p>\n\n\n\n<p id=\"0e59\">Показываем информацию таба</p>\n\n\n\n<p id=\"9943\">Следовательно, мы показали вложенные роуты и вложенный контент в этом примере.</p>\n\n\n\n<p id=\"43b6\">Посмотрим пример в действии.</p>\n\n\n\n<p><a href=\"https://codesandbox.io/s/nested-routes-react-router-y5pt4?from-embed\">Пример</a></p>\n\n\n\n<h2 id=\"b6df\">БОНУС:&nbsp;<strong>Используем &lt;NavLink&gt; для указания того, какой элемент активен в панели навигации</strong></h2>\n\n\n\n<p id=\"b6ec\">В React роутере есть&nbsp;<code>&lt;NavLink&gt;</code>&nbsp;и&nbsp;<code>&lt;Link&gt;</code>&nbsp;компоненты. Далее мы рассмотрим разницу между ними и то, как можно было бы использовать&nbsp;<code>&lt;NavLink&gt;</code>&nbsp;для указания того, какая именно ссылка активна в панели навигации приложения.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"1000\" height=\"177\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2020/12/1_5kTlzNFcG5Hu9_QkAZK53g.png\" alt=\"\" class=\"wp-image-64\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2020/12/1_5kTlzNFcG5Hu9_QkAZK53g.png 1000w, https://stasonmars.ru/wp/wp-content/uploads/2020/12/1_5kTlzNFcG5Hu9_QkAZK53g-300x53.png 300w, https://stasonmars.ru/wp/wp-content/uploads/2020/12/1_5kTlzNFcG5Hu9_QkAZK53g-768x136.png 768w\" sizes=\"(max-width: 1000px) 100vw, 1000px\" /></figure>\n\n\n\n<p>Оба компонента&nbsp;<code>&lt;NavLink&gt;</code>&nbsp;и&nbsp;<code>&lt;Link&gt;</code>&nbsp;могут быть использованы для создания удобной навигации в приложении. Внутри обоих компонентов мы можем использовать атрибут&nbsp;<code>to</code>&nbsp;для указания пути ведущему по ссылке. После установки&nbsp;<code>react-router-dom</code>&nbsp;и импорта&nbsp;<code>&lt;Link&gt;</code>, всё связанное с ним будет выглядеть так:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>import { Link } from 'react-router-dom'\n\n&lt;Link to=\"/about\">About&lt;/Link></code></pre>\n\n\n\n<p>Вы можете также импортировать и&nbsp;<code>&lt;NavLink&gt;</code>:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>import { NavLink } from 'react-router-dom'\n&lt;NavLink to=\"/about\">About&lt;/NavLink></code></pre>\n\n\n\n<p>Оба они компилируются в html код, как тут:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"494\" height=\"54\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2020/12/1_qdNP3P8kB9D0V5b3wa2Bbw.png\" alt=\"\" class=\"wp-image-65\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2020/12/1_qdNP3P8kB9D0V5b3wa2Bbw.png 494w, https://stasonmars.ru/wp/wp-content/uploads/2020/12/1_qdNP3P8kB9D0V5b3wa2Bbw-300x33.png 300w\" sizes=\"(max-width: 494px) 100vw, 494px\" /></figure>\n\n\n\n<p>Может показаться, что основной их функционал одинаков. Так зачем же нам тогда оба? А затем, что&nbsp;<code>&lt;NavLink&gt;</code>&nbsp;идёт вместе с дополнительным атрибутом стилизации, который позволяет нам стилизовать по особенному именно активную ссылку.</p>\n\n\n\n<p>Вот пример:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>import React, { Component } from \"react\";\nimport { Link } from \"react-router-dom\";\nclass NavBar extends Component {\n  render() {\n    return (\n      &lt;div className=\"navbar\">\n        &lt;Link to=\"/\" className=\"navbar-logo\">\n          dA\n        &lt;/Link>\n        &lt;div className=\"navbar-list\">\n          &lt;Link to=\"/search\">Collection&lt;/Link>\n          &lt;Link to=\"/map\">Map&lt;/Link>\n          &lt;Link to=\"/login\">Log In&lt;/Link>\n        &lt;/div>\n      &lt;/div>\n    );\n  }\n}\nexport default NavBar;</code></pre>\n\n\n\n<p>Компонент NavBar даёт нам навигацию по четырём роутам — “<code>/</code>”, “<code>/search</code>”, “<code>map</code>” и “<code>login</code>” с использованием старого доброго компонента&nbsp;<code>&lt;Link&gt;</code>.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"812\" height=\"164\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2020/12/1_vvkpTz0fRU7SCZqSWlgSLA.gif\" alt=\"\" class=\"wp-image-66\"/></figure>\n\n\n\n<p id=\"0f17\">Как показано выше, мы можем вполне успешно прыгать по роутам, каждый из которых ассоциирован с компонентом&nbsp;<code>&lt;Link&gt;</code>.</p>\n\n\n\n<p id=\"01b4\">А теперь давайте посмотрим на различия между двумя компонентами.&nbsp;<code>&lt;NavLink&gt;</code>&nbsp;даёт нам дополнительный атрибут&nbsp;<code>activeClassName</code>. В этом атрибуте мы можем указывать класс в CSS, который будет выделять то, что ссылка активна.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>import React, { Component } from \"react\";\nimport { NavLink } from \"react-router-dom\";\nclass NavBar extends Component {\n  render() {\n    return (\n      &lt;div className=\"navbar\">\n        &lt;NavLink to=\"/\" className=\"navbar-logo\">\n          dA\n        &lt;/NavLink>\n        &lt;div className=\"navbar-list\">\n          &lt;NavLink to=\"/search\" activeClassName=\"chosen\">\n            Collection\n          &lt;/NavLink>\n          &lt;NavLink to=\"/map\" activeClassName=\"chosen\">\n            Map\n          &lt;/NavLink>\n          &lt;NavLink to=\"/login\" activeClassName=\"chosen\">\n            Log In\n          &lt;/NavLink>\n        &lt;/div>\n      &lt;/div>\n    );\n  }\n}\nexport default NavBar;</code></pre>\n\n\n\n<p>CSS селекторы описанные ниже, рендерят линию подчеркивания в тех случаях, когда мы наводим на ссылку и когда она открыта и активна.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>.navbar-list a.chosen,\n.navbar-list a:hover {\n  border-bottom: 1px solid #F14B31;\n}</code></pre>\n\n\n\n<p>С помощью&nbsp;<code>&lt;NavLink&gt;</code>, мы можем добавить атрибуты стилизации для активных элементов, чей путь совпадает с URL в браузере.</p>\n","date":"2020-12-14T16:25:30.000Z","title":"Подробно о React Router. Часть 3— редиректы, передача props компоненту роута и вложенные роуты +бонус","id":"3834bdec-c2c4-57cb-b2c6-4c33923e306e","excerpt":"<p>Это завершающая часть, в ней будет рассказано о передаче пропсов компоненту роута, редиректах и вложенных роутах. + бонус, стилизация активных элементов навигации.</p>\n","type":"js","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2020/12/DglYtvO7Bn0-12.jpg"}}},{"node":{"slug":"react-router-chast-2-parametry-zaprosa-404-stranitsa-i-peredacha-propsov","content":"\n<p>В этой серии статей вы подробно и доходчиво узнаете о том, как работает Router в React, как его можно использовать и другие интересные фишки этого функционала. Это вторая часть из 3х, в ней будет рассказано об основе работы с параметрами запросов, 404 страницах и передаче пропсов самому компоненту роута.</p>\n\n\n\n<p>Первая часть &#8212; <a href=\"https://stasonmars.ru/javascript/react-router-chast-1-osnovy-routinga-tipy-dannyh-i-dynamicheskie-stranicy\">Подробно о React Router. Часть 1 — основы роутинга, типы и динамические страницы</a></p>\n\n\n\n<p><em>p.s статья описывает самый распространенную версию роутера на данный момент. 6я&nbsp;версия&nbsp;сейчас находится в альфе и имеет&nbsp;</em><a href=\"https://twitter.com/stassonmars/status/1248171321860788225\"><em>кардинально другой синтаксис</em></a><em>.</em></p>\n\n\n\n<p class=\"author\"><em>Перевод серии статей&nbsp;</em><a href=\"https://learnwithparam.com/blog/basic-routing-in-react-router/\"><em>Deep dive into React Router</em></a></p>\n\n\n\n<h2 id=\"5dcb\"><strong>Работа с параметрами запроса в React Router</strong></h2>\n\n\n\n<p id=\"b0b9\">В третьей части мы узнали о технике создания динамических ссылок в React Router. В этой части, мы узнаем о работе с параметрами запроса в URL.</p>\n\n\n\n<p id=\"fe54\">Давайте создадим новый&nbsp;<code>Route</code>&nbsp;для страницы поиска с параметрами запроса.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// App.js\n...\nconst SearchPage = () => {  return (    &lt;h3>Search Page&lt;/h3>  );}\nconst App = () => {\n  return (\n    &lt;section className=\"App\">\n      &lt;Router>\n        &lt;Link to=\"/\">Home&lt;/Link>\n        &lt;Link to=\"/about\">About&lt;/Link>\n        &lt;Link to=\"/users\">Users&lt;/Link>\n        &lt;Link to=\"/search?q=react\">Search&lt;/Link>        \n        &lt;Route exact path=\"/\" component={IndexPage} />\n        &lt;Route exact path=\"/users\" component={UsersPage} />\n        &lt;Route exact path=\"/user/:userId\" component={UserPage} />\n        &lt;Route exact path=\"/about\" component={AboutPage} />\n        &lt;Route exact path=\"/search\" component={SearchPage} /> \n      &lt;/Router>\n      &lt;a href=\"/about\">about with browser reload&lt;/a>\n    &lt;/section>\n  );\n};\n\n...</code></pre>\n\n\n\n<p id=\"716f\">Это такой визуальный способ создания ссылки, определения роута и компонента. Если вы приглядитесь, то не заметите разницы между простым статичным роутом и роутом с параметрами запроса.</p>\n\n\n\n<p id=\"4e25\">Нам нет нужды в указании параметров запроса в роуте, так как по дефолту они будут обработаны React роутером и отправлены в пропсы компонента.</p>\n\n\n\n<p id=\"15b0\">Если мы укажем вот так&nbsp;<code>/search/?q=:searchValue</code>, то это не сработает в роутере. Вы можете попробовать это в песочнице, роутер этого не поймет.</p>\n\n\n\n<p id=\"58e9\">Теперь нам нужно получить доступ ко всем параметрам запросов, которые мы передаём URL в компоненте. В предыдущей части мы говорили о том как роутер передаёт два параметра&nbsp;<code>match</code>&nbsp;и&nbsp;<code>location</code>.</p>\n\n\n\n<p id=\"26d9\">Для динамических роутов, React роутер передаёт параметры в пропсы&nbsp;<code>match</code>.</p>\n\n\n\n<p id=\"7be7\">Для роутов с параметрами запроса, инфо о них будет отправлено через&nbsp;<code>location</code>&nbsp;пропсы.</p>\n\n\n\n<p id=\"fa8c\">Давайте увидим, какая же информация там отправляется.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>...\n\nconst SearchPage = ({ match, location }) => {\n  return (\n    &lt;p>\n      &lt;strong>Location Props: &lt;/strong>\n      {JSON.stringify(location, null, 2)}\n    &lt;/p>\n  );\n}\n\n...</code></pre>\n\n\n\n<p>Как вы видите на странице&nbsp;поиска:</p>\n\n\n\n<pre class=\"wp-block-code\"><code>Location Props: { \"pathname\": \"/search\", \"search\": \"?q=react\", \"hash\": \"\", \"key\": \"allc40\" }</code></pre>\n\n\n\n<p id=\"1706\">Роутер передаёт параметры запроса в&nbsp;<code>location.search</code>. Если вы добавите больше параметров запросов, то получите все тоже самое в той же строке, например&nbsp;<code>?q=react&amp;limit=3</code>.</p>\n\n\n\n<p id=\"bba3\">Чтобы получить каждое значение отдельно, вы могли бы использовать вашу собственную библиотеку помощник или&nbsp;<em>пакет npm</em>, который умеет работать с параметрами запроса таким образом, чтобы вы получали каждое значение парой ключ-значение, но уже в отдельном объекте.</p>\n\n\n\n<p id=\"7faa\">Например, есть пакет&nbsp;<code>yarn add qs</code>. Но существует огромное количество альтернатив ему. Вы можете смело выбрать тот, который подходит вашему URL.</p>\n\n\n\n<p id=\"cf83\">Давайте покажем значение&nbsp;<code>location.search</code>&nbsp;в компоненте.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const SearchPage = ({ match, location }) => {\n  return (\n    &lt;p>\n      &lt;strong>Query Params: &lt;/strong>\n      {location.search}\n    &lt;/p>\n  );\n};</code></pre>\n\n\n\n<p><a href=\"https://codesandbox.io/s/n7q6kw9n8m?from-embed\">Посмотреть результат</a></p>\n\n\n\n<h2 id=\"be74\"><strong>Создаем страницу 404</strong></h2>\n\n\n\n<p id=\"f6f3\">Мы уже узнали как создавать динамические URL и как работать с параметрами запросов в React роутере, а также как передавать эти значения странице компонента.</p>\n\n\n\n<p id=\"1dc9\">В этой части мы узнаем о том, как показать 404 страницу, в том случае, если нет подходящего роута для URL.</p>\n\n\n\n<p id=\"3f6b\">Запустите приложение и зайдите на любую несуществующую страницу, например&nbsp;<code>/404-not-found</code>.</p>\n\n\n\n<p id=\"3f05\">В данный момент вы не увидите ни один отрендернный компонент. Давайте это исправим и покажем дефолтную страницу для тех случаев, когда нет совпадения ни с одним роутом.</p>\n\n\n\n<p id=\"2b3a\">В React роутере это сделать очень легко. Внутри самого компонента роутера создайте роут без указанного пути. Затем убедитесь в том, что вы поместили этот код после всех роутов так, чтобы роутер сначала проверил все указанные роуты и уже точно принял решение показать 404 страницу.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// App.js\n\n...\n\nconst NoMatchPage = () => {return (&lt;h3>404 - Not found&lt;/h3>);};\nconst App = () => {\n  return (\n    &lt;section className=\"App\">\n      &lt;Router>\n        ...\n        &lt;Link to=\"/users\">Users&lt;/Link>\n        &lt;Link to=\"/search?q=react\">Search&lt;/Link>\n        ...\n        &lt;Route exact path=\"/about\" component={AboutPage} />\n        &lt;Route exact path=\"/search\" component={SearchPage} />\n        &lt;Route component={NoMatchPage} />      \n      &lt;/Router>\n    &lt;/section>\n  );\n};\n\n...</code></pre>\n\n\n\n<p id=\"065e\">Зайдите на любой рандомный URL и вы увидите простую 404ю страницу. Но подождите, давайте проверим будут ли работать другие страницы. А оказывается нет.</p>\n\n\n\n<p id=\"29e5\">Зайдите по ссылке&nbsp;<code>about</code>, вы увидите, что отрендерится и страница&nbsp;<code>about</code>, и 404-я страница. Это произойдёт так как точный роут совпадет с&nbsp;<code>/about</code>&nbsp;и потом он пробежится до конца всех указанных роутов и загрузит&nbsp;<code>404</code>&nbsp;роут, так как у него не указан путь.</p>\n\n\n\n<p id=\"ce53\">В React роутере есть компонент под названием&nbsp;<code>Switch</code>, чтобы остановиться на одном роуте и исключить загрузку любых других роут компонентов после него.</p>\n\n\n\n<p id=\"4eee\">Тут все очень просто. Оберните все роуты в&nbsp;<code>Switch</code>. Давайте это сделаем правильно и сделаем 404-ю страницу без ошибок.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// App.js\n\n...\nimport { Link, BrowserRouter as Router, Route, Switch } from 'react-router-dom';...\n\nconst App = () => {\n  return (\n    &lt;section className=\"App\">\n      &lt;Router>\n        ...\n        &lt;Switch>          \n          &lt;Route exact path=\"/\" component={IndexPage} />\n          ...\n          &lt;Route exact path=\"/search\" component={SearchPage} />\n          &lt;Route component={NoMatchPage} />\n        &lt;/Switch>      \n      &lt;/Router>\n    &lt;/section>\n  );\n};\n\n...</code></pre>\n\n\n\n<p>Тут&nbsp;<code>Switch</code>&nbsp;проверит роуты на совпадение и если найдется совпадающий роут, то дальнейший проверка будет прервана. Таким образом мы избавимся от рендеринга 404 роута для всех страниц.</p>\n\n\n\n<p><a href=\"https://m4n21l3m38.csb.app/\">Пример</a></p>\n\n\n\n<h2 id=\"9ab3\"><strong>Передаём пропсы компоненту роута</strong></h2>\n\n\n\n<p id=\"4976\">Мы видели несколько примеров и рабочих кейсов в React роутере. Один из них это передача пропсов напрямую компоненту роута.</p>\n\n\n\n<p id=\"7515\">В React роутере это очень легко сделать. Давайте создадим новый роут для передачи его компоненту пропсов.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// App.js\n...\n\nconst PropsPage = () => {  return (    &lt;h3>Props Page&lt;/h3>  );};\nconst App = () => {\n  return (\n    &lt;section className=\"App\">\n      &lt;Router>\n        ...\n        &lt;Link to=\"/404-not-found\">404&lt;/Link>\n        &lt;Link to=\"/props\">Passing Props&lt;/Link>        \n        &lt;Switch>\n          ...\n          &lt;Route exact path=\"/props\" component={PropsPage} /> \n          &lt;Route component={NoMatchPage} />\n        &lt;/Switch>\n      &lt;/Router>\n      &lt;a href=\"/about\">about with browser reload&lt;/a>\n    &lt;/section>\n  );\n};\n\nexport default App;</code></pre>\n\n\n\n<p id=\"8304\">Прямо сейчас мы добавили компонент и новую страницу. Давайте передарим пропс&nbsp;<code>title</code>&nbsp;уже самой странице.</p>\n\n\n\n<p id=\"58a7\">Есть два способа это сделать. Первый очень простой.</p>\n\n\n\n<h3><strong>Передаём&nbsp;функцию как пропс компонента в компоненте роута</strong></h3>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>...\n\nconst PropsPage = ({ title }) => {\n  return (\n    &lt;h3>{title}&lt;/h3>\n  );\n};\n\n...\n\n&lt;Route exact path=\"/props-through-component\" component={() => &lt;PropsPage title={`Props through component`} />} /></code></pre>\n\n\n\n<p id=\"e8d7\">Эта штука сработает, но такой подход не рекомендуется применять с роутером. Почему? Сейчас объясню.</p>\n\n\n\n<p id=\"f33e\">Под капотом React использует&nbsp;<code>React.createElement</code>&nbsp;для рендеринга компонента, переданного пропсу компонента. Если мы передадим ему функцию, то он создаст новый компонент при каждом рендеринге вместо того, чтобы просто обновить уже существующий компонент.</p>\n\n\n\n<p id=\"463a\">В маленьких приложениях, с довольно не сложными страницами, это не будет влиять на производительность. Но для больших приложений с множественным измнением состояния на странице, это снизит производительность страницы из-за необязательного ре-рендеринга.</p>\n\n\n\n<p id=\"b3f9\">Роутер даёт нам простое решение в этой ситуации. Вместо простой передачи функции через пропсы&nbsp;<code>component</code>, мы можем передать их через пропсы&nbsp;<code>render</code>. Передавая наши пропсы, нам также надо передать дефолтные пропсы пропсам рендеринга. Давайте посмотрим пример:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>...\n\n&lt;Link to=\"/props-through-render\">Props through render&lt;/Link>\n...\n\n&lt;Route exact path=\"/props-through-render\" render={(props) => &lt;PropsPage {...props} title={`Props through render`} />} /></code></pre>\n\n\n\n<p id=\"8875\">Вот это уже рекомендуемый способ передачи самих пропсов в React роутере.</p>\n\n\n\n<p id=\"7693\">Это очень просто. Если вы хотите увидеть весь пример, то проверьте его <a href=\"https://codesandbox.io/s/props-in-component-react-router-g2im5?from-embed\">тут</a>.</p>\n","date":"2020-12-13T15:15:13.000Z","title":"Подробно о React Router. Часть 2 — параметры запроса, 404 страница и передача пропсов компоненту роута","id":"771b8662-509f-516e-b635-aa2162494388","excerpt":"<p>В этой серии статей вы подробно и доходчиво узнаете о том, как работает Router в React, как его можно использовать и другие интересные фишки этого функционала. Это вторая часть из 3х, в ней будет рассказано об основе работы с параметрами запросов, 404 страницах и передаче пропсов самому компоненту роута.</p>\n","type":"js","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2020/12/DglYtvO7Bn0-11.jpg"}}},{"node":{"slug":"react-router-chast-1-osnovy-routinga-tipy-dannyh-i-dynamicheskie-stranicy","content":"\n<p id=\"1084\">В этой серии статей вы подробно и доходчиво узнаете о том, как работает Router в React, как его можно использовать и другие интересные фишки этого функционала. Это первая часть из 3х, в ней будет рассказано об основах роутинга, типах и созданиях динамических страниц.</p>\n\n\n\n<p id=\"29d7\"><em>p.s статья описывает самый распространенную версию роутера на данный момент. 6я версия сейчас находится в альфе и имеет&nbsp;</em><a href=\"https://twitter.com/stassonmars/status/1248171321860788225\"><em>кардинально другой синтаксис</em></a><em>.</em></p>\n\n\n\n<p class=\"author\"><em>Перевод серии&nbsp;статей&nbsp;</em><a href=\"https://learnwithparam.com/blog/basic-routing-in-react-router/\"><em>Deep dive into React Router</em></a></p>\n\n\n\n<p id=\"82e7\">React это широко используемая&nbsp;библиотека для client-side веб приложений. Сами знаете, в любом веб приложении будет по несколько страниц. Правильный роутинг ссылок и загрузка разных страниц в зависимости от параметров заданных маршрутов это главное требование для буквально любого приложения.</p>\n\n\n\n<p id=\"1d8b\">Существует отличный npm пакет, который берет на себя все сложности роутинга на React. Это&nbsp;<strong>react-router-dom</strong>&nbsp;— одна из самых используемых библиотек в react.</p>\n\n\n\n<h2 id=\"600a\"><strong>Простой роутинг</strong></h2>\n\n\n\n<p id=\"221b\">Давайте создадим две простые страницы.</p>\n\n\n\n<p id=\"0106\">Главную&nbsp;(<code>/</code>)</p>\n\n\n\n<p id=\"17d8\">И страницу About (<code>/about</code>)</p>\n\n\n\n<p id=\"fabf\">Создайте простое react приложение с использованием&nbsp;<code>create-react-app</code>&nbsp;CLI. Это очень просто сделать с помощью npx —&nbsp;<code>npx create-react-app my-react-app</code></p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// App.js\nimport React from 'react';\n\nconst App = () => {\n  return (\n    &lt;section className=\"App\">\n      &lt;h1>React routing Example&lt;/h1>\n    &lt;/section>\n  );\n};\n\nexport default App;</code></pre>\n\n\n\n<p>Давайте создадим две страницы. Ну или просто два функциональных компонента.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// App.js\n...\n\nconst IndexPage = () => {\n  return (\n    &lt;h3>Home Page&lt;/h3>\n  );\n};\n\nconst AboutPage = () => {\n  return (\n    &lt;h3>About Page&lt;/h3>\n  );\n};\n\n...</code></pre>\n\n\n\n<p>Перед тем как углубиться в код роутера. Давайте сначала поймем то, что же нам надо для роутинга страниц в нашем приложении.</p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p>Ссылки для навигации между страницами.</p><p>Нам нужно будет определить пути к страницам. Тут мы укажем путь URL и компонент, который нужно загружать с этим URL.</p><p>Ещё мы определим роутер, который будет проверять наличие запрашиваемого URL в указанных роутах.</p></blockquote>\n\n\n\n<p>Итак, давайте создадим компоненты&nbsp;<code>Link</code>&nbsp;и&nbsp;<code>Route</code>. Для начала установите пакет&nbsp;<code>yarn add react-router-dom</code>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// App.js\n...\nimport { Link, BrowserRouter as Router, Route } from 'react-router-dom';...\n\nconst App = () => {\n  return (\n    &lt;section className=\"App\">\n      &lt;Router>        \n       &lt;Link to=\"/\">Home&lt;/Link>        \n       &lt;Link to=\"/about\">About&lt;/Link>        \n       &lt;Route path=\"/\" component={IndexPage} />        \n       &lt;Route path=\"/about\" component={AboutPage} />      \n      &lt;/Router>    \n    &lt;/section>\n  );\n};</code></pre>\n\n\n\n<p>А теперь дайте пройдем по каждой строчке отдельно.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>import { Link, BrowserRouter as Router, Route } from 'react-router-dom';</code></pre>\n\n\n\n<p id=\"f7c7\">Тут мы импортируем три компонента,</p>\n\n\n\n<p id=\"758f\"><code>Link</code>, который создаст HTML ссылку на страницы.</p>\n\n\n\n<p id=\"149b\"><code>Route</code>, который укажет маршруты.</p>\n\n\n\n<p id=\"c133\">И&nbsp;<code>Router</code>&nbsp;в котором будет храниться вся логика нашего роутинга. Когда пользователь кликает на ссылку, этот компонент проверяет есть ли она в указанных роутах. Если да, то роутер сменит URL в браузере и роут отрендерит заданный компонент.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// Link with URL\n&lt;Router>\n  &lt;Link to=\"/\">Home&lt;/Link>\n  &lt;Link to=\"/about\">About&lt;/Link>\n&lt;/Router></code></pre>\n\n\n\n<p id=\"e99c\">Router должен быть родительским компонентом для&nbsp;<code>Link</code>&nbsp;и&nbsp;<code>Route</code>. Собственно так он и управляет роутингом. Если мы поставим&nbsp;<code>Link</code>&nbsp;или&nbsp;<code>Route</code>&nbsp;за его пределы, то тут мы получим ошибку.</p>\n\n\n\n<h3 id=\"9707\"><strong>Зачем нам нужен Link, а не HTML анкор с href?</strong></h3>\n\n\n\n<p id=\"a35a\">HTML тег&nbsp;<code>a</code>&nbsp;создает ссылку на сервер. Так что каждый раз, как пользователь кликает на роут, он не будет проверять наличие роутера в роуте. Вместо этого он просто редиректнет страницу в браузере на этот роут.</p>\n\n\n\n<p id=\"3d4c\">В то время как&nbsp;<code>Link</code>&nbsp;проверяет роутер и роутер проверяет наличие роута, загружая компонент без перезагрузки страницы. Поэтому это и называется&nbsp;<em>client side роутингом</em>. Он не подгружает страницу с сервера при обращении к компоненту&nbsp;<code>Link</code>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// Route with definition\n&lt;Route path=\"/\" component={IndexPage} /></code></pre>\n\n\n\n<p id=\"30d9\">Тут у Route есть путь и&nbsp;<code>props</code>&nbsp;компоненты.&nbsp;<code>component</code>&nbsp;помогает отрендерить компонент, когда пользователь заходит на этот роут.&nbsp;<code>path</code>&nbsp;props указывает путь&nbsp;<code>url</code>, который должен совпадать при посещении пользователем страницы.</p>\n\n\n\n<p id=\"1b46\">Если вы зайдете немного дальше и проверите работу наших роутов, то они будут работать. Но с небольшими тормозами.</p>\n\n\n\n<p id=\"b1f8\">Кликнув на ссылку&nbsp;<code>about</code>, она отрендерит и&nbsp;<code>IndexPage</code>, и&nbsp;<code>AboutPage</code>. Но почему?</p>\n\n\n\n<p id=\"1145\">Потому что путь указанный для&nbsp;<code>About</code>&nbsp;это&nbsp;<code>/about</code>. Роутер же в свою очередь пробегается по всем определением роутов, сверху вниз. Сначала он проверяет роут с путем&nbsp;<code>/</code>, а у&nbsp;<code>About</code>&nbsp;в URL есть&nbsp;<code>/</code>, так что сначала он рендерит&nbsp;<code>IndexPage</code>. А уже потом проверяет следующий роут&nbsp;<code>/about</code>, который тоже совпадает с заданными параметрами, что приводит к рендерингу компонента&nbsp;<code>AboutPage</code>.</p>\n\n\n\n<h3 id=\"5968\"><strong>Как точно попасть на нужный роут?</strong></h3>\n\n\n\n<p id=\"be88\">Всё очень просто. Используйте props&nbsp;<code>exact</code>&nbsp;в&nbsp;<code>Route</code>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>...\n\nconst App = () => {\n  return (\n    &lt;section className=\"App\">\n      &lt;Router>\n        &lt;Link to=\"/\">Home&lt;/Link>\n        &lt;Link to=\"/about\">About&lt;/Link>\n        &lt;Route exact path=\"/\" component={IndexPage} />        \n        &lt;Route exact path=\"/about\" component={AboutPage} />                         \n&lt;/Router>\n    &lt;/section> \n  );\n};\n\n...</code></pre>\n\n\n\n<p id=\"2e63\">Этот prop поможет попасть на нужный роут только при полном совпадении, а если нет, то он просто не будет рендерить компонент.</p>\n\n\n\n<p id=\"520b\">Теперь оба компонента будут отлично рендериться и&nbsp;<code>Link</code>&nbsp;будет работать правильно.</p>\n\n\n\n<figure class=\"wp-block-embed-wordpress wp-block-embed is-type-wp-embed is-provider-codesandbox\"><div class=\"wp-block-embed__wrapper\">\n<iframe class=\"wp-embedded-content\" sandbox=\"allow-scripts\" security=\"restricted\" title=\"basic-routing-in-react-router\" width=\"500\" height=\"750\" src=\"https://codesandbox.io/embed/9j8l8325qy?fontsize=14&#038;hidenavigation=1&#038;theme=dark#?secret=yUTdyYYfiM\" data-secret=\"yUTdyYYfiM\"></iframe>\n</div></figure>\n\n\n\n<h1 id=\"4b7f\"><strong>Какие бывают роутеры</strong></h1>\n\n\n\n<p id=\"11c3\">В предыдущей&nbsp;секции обсуждали самые основы роутинга в React. Там мы использовали&nbsp;<code>BrowserRouter</code>, как основной роутер.</p>\n\n\n\n<p id=\"f698\">Но есть ещё несколько других типов роутеров в&nbsp;<code>react router</code>. Сейчас мы посмотрим когда их использовать.</p>\n\n\n\n<h3><strong>MemoryRouter</strong></h3>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// https://example.com (Один и тот же url для всех роутов)\nimport { MemoryRouter as Router } from ‘react-router-dom’;</code></pre>\n\n\n\n<p id=\"bf15\">Это роутер, который не меняет URL в браузере, а оставляет изменения в памяти.</p>\n\n\n\n<p id=\"e4b2\">Он очень полезен для тестирования и вне браузерных сред разработки.</p>\n\n\n\n<p id=\"8b1b\">Но в браузере у него нет истории. Так что вы не сможете вернуться назад или вперед при помощи истории.</p>\n\n\n\n<figure class=\"wp-block-embed-wordpress wp-block-embed is-type-wp-embed is-provider-codesandbox\"><div class=\"wp-block-embed__wrapper\">\n<iframe class=\"wp-embedded-content\" sandbox=\"allow-scripts\" security=\"restricted\" title=\"memory-router\" width=\"500\" height=\"750\" src=\"https://codesandbox.io/embed/wnq10opj68?fontsize=14&#038;hidenavigation=1&#038;theme=dark#?secret=bI5OuSAc9Z\" data-secret=\"bI5OuSAc9Z\"></iframe>\n</div></figure>\n\n\n\n<h3><strong>HashRouter</strong></h3>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>/*\nРоуты с хешем, тут вы можете обращаться к истории.\nhttps:&#47;&#47;example.com/#/\nhttps://example.com/#/about\n*/\nimport { HashRouter as Router } from 'react-router-dom';</code></pre>\n\n\n\n<p id=\"0046\">Это роутер, который использует&nbsp;<em>client Side hash роутинг</em>.</p>\n\n\n\n<p id=\"7f2d\">Всякий раз, когда рендерится новый роут, он обновляет URL в браузере с хешированными роутами. (/#/about)</p>\n\n\n\n<p id=\"1664\">Хэш часть ссылки не будет обработана сервером, сервер будет всегда отправлять index.html для каждого запроса и игнорировать хешированное значение, которое будет обработано уже React роутером.</p>\n\n\n\n<p id=\"2868\">Он используется для Legacy браузеров, которые обычно не поддерживают&nbsp;<em>pushState API</em>.</p>\n\n\n\n<p id=\"f727\">Ему не нужна конфигурация на сервере для обработки роутов.</p>\n\n\n\n<p id=\"28e9\">Этот роут не рекомендован командой разработчиков которая создавала сам пакет&nbsp;<strong>react router</strong>. Используйте его только в том случае, если вам нужна поддержка Legacy браузеров или при осутствии серверной логики для обработки&nbsp;<em>client Side роутов</em>.</p>\n\n\n\n<figure class=\"wp-block-embed-wordpress wp-block-embed is-type-wp-embed is-provider-codesandbox\"><div class=\"wp-block-embed__wrapper\">\n<iframe class=\"wp-embedded-content\" sandbox=\"allow-scripts\" security=\"restricted\" title=\"hash-router\" width=\"500\" height=\"750\" src=\"https://codesandbox.io/embed/yq6onnlj4v?fontsize=14&#038;hidenavigation=1&#038;theme=dark#?secret=yOpt211k2I\" data-secret=\"yOpt211k2I\"></iframe>\n</div></figure>\n\n\n\n<h3><strong>BrowserRouter</strong></h3>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>/*\nВы можете использовать историю\nhttps:&#47;&#47;example.com/\nhttps://example.com/about\n*/\nimport { BrowserRouter as Router } from 'react-router-dom';</code></pre>\n\n\n\n<p id=\"705f\">Самый популярный роутер и роутер для современных браузеров, который использует HTML5&nbsp;<code>pushState</code>&nbsp;(<code>pushState</code>,&nbsp;<code>replaceState</code>&nbsp;и&nbsp;<code>popState</code>&nbsp;API)</p>\n\n\n\n<p id=\"1a15\">Он роутится как обычный URL в браузере, так что вы не сможете по ссылке отличить был ли это server Side рендеринг или же client side.</p>\n\n\n\n<p id=\"695d\">Тут подразумевается то, что ваш сервер обрабатывает все URL запросы (<code>/</code>,&nbsp;<code>/about</code>) и указывает на корневой&nbsp;<code>index.html</code>. И уже отсюда,&nbsp;<code>BrowserRouter</code>&nbsp;обрабатывает роутинг релевантной страницы.</p>\n\n\n\n<p id=\"cd2a\">Он принимает&nbsp;<code>forceRefresh</code>&nbsp;пропсы для поддержки Legacy браузеров, которые не тянут HTML5 pushState API.</p>\n\n\n\n<figure class=\"wp-block-embed-wordpress wp-block-embed is-type-wp-embed is-provider-codesandbox\"><div class=\"wp-block-embed__wrapper\">\n<iframe class=\"wp-embedded-content\" sandbox=\"allow-scripts\" security=\"restricted\" title=\"basic-routing-in-react-router\" width=\"500\" height=\"750\" src=\"https://codesandbox.io/embed/9j8l8325qy?fontsize=14&#038;hidenavigation=1&#038;theme=dark#?secret=yUTdyYYfiM\" data-secret=\"yUTdyYYfiM\"></iframe>\n</div></figure>\n\n\n\n<h2 id=\"5b0d\"><strong>Динамические страницы в React Router</strong></h2>\n\n\n\n<p id=\"d03d\">В начале статьи мы изучили то, как создавать простые статические страницы в роутере. Сейчас мы узнаем как создавать динамические ссылки в react роутере.</p>\n\n\n\n<p id=\"37d0\">Мы создадим два роута,</p>\n\n\n\n<p id=\"0d75\">Роут&nbsp;<code>Users</code>&nbsp;— статические роуты для отображения всех ссылок для отдельных пользователей.</p>\n\n\n\n<p id=\"f13d\">Роут&nbsp;<code>User&nbsp;</code>— каждый пользователь будет идентифицирован по своему уникальному&nbsp;<code>ID</code>&nbsp;и ссылка будет передавать этот&nbsp;<code>ID</code>, а компонент будет отображать нужный контент пользователя.</p>\n\n\n\n<p id=\"69c6\">Давайте создадим простой массив&nbsp;<code>users</code>&nbsp;с данными пользователей.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const users = &#91;\n  {\n    name: `Param`,\n  },\n  {\n    name: `Vennila`,\n  },\n  {\n    name: `Afrin`,\n  },\n];</code></pre>\n\n\n\n<p>Давайте создадим новые роуты для всех пользователей и одного пользователя в нашем&nbsp;<code>App.js</code>&nbsp;файле.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// App.js\n...\n\nconst UsersPage = () => {  return (    &lt;h3>Users Page&lt;/h3>  );};\nconst App = () => {\n  return (\n    &lt;section className=\"App\">\n      &lt;Router>\n        &lt;Link to=\"/\">Home&lt;/Link>\n        &lt;Link to=\"/about\">About&lt;/Link>\n        &lt;Link to=\"/users\">Users&lt;/Link>        \n        &lt;Route exact path=\"/\" component={IndexPage} />\n        &lt;Route exact path=\"/users\" component={UsersPage} /> \n        &lt;Route exact path=\"/about\" component={AboutPage} />\n      &lt;/Router>\n      &lt;a href=\"/about\">about with browser reload&lt;/a>\n    &lt;/section>\n  );\n};\n\n...</code></pre>\n\n\n\n<p id=\"af61\">Мы создали ссылку на страницу пользователей и также определили роут для страницы пользователей вместе с ассоциированным компонентом (<code>UsersPage</code>).</p>\n\n\n\n<p id=\"4327\">Давайте создадим ссылки для каждого из них с&nbsp;<code>UsersPage</code>. (<code>/user/1</code>,&nbsp;<code>/user/2</code>,&nbsp;<code>/user/3</code>)</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// userId будет индекс в массиве + 1\nconst UsersPage = () => {\n  return (\n    &lt;>\n      &lt;h3>Users Page&lt;/h3>\n      {users.map((user, index) => (\n        &lt;h5 key={index}>\n          &lt;Link to={`/user/${index + 1}`}>{user.name}'s Page&lt;/Link>\n        &lt;/h5>\n      ))}\n    &lt;/>\n  );\n};</code></pre>\n\n\n\n<p id=\"df0b\">Итак, мы создали страницу пользователей с ссылками на них. Если вы кликните на ссылку, то она приведет вас на несуществующую страницу, потому что мы не создали роут каждому из пользователей.</p>\n\n\n\n<p id=\"dbe1\">Мы можем создать каждый отдельный роут как тут:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&lt;Route exact path=\"/user/1\" component={UserPage1} />\n&lt;Route exact path=\"/user/2\" component={UserPage2} /></code></pre>\n\n\n\n<p>Конечно же нет! Я лгу вам, все мы знаем, что это не подходит для динамических страниц с большим количеством данных. Давайте посмотрим на то, как мы можем создать динамические роуты в React. Это очень и очень легко.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&lt;Route path=\"/user/:userId\" component={UserPage} />\n</code></pre>\n\n\n\n<p>Тут&nbsp;<code>:userId</code>&nbsp;это динамические параметры роута. Он передается компоненту. Вы легко можете получить доступ к пропсам&nbsp;<code>userId</code>&nbsp;в компоненте&nbsp;<code>UserPage</code>.</p>\n\n\n\n<p>Давайте добавим этот код в наш пример.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// App.js\n...\n\nconst UserPage = () => {  return (    &lt;h3>User Page&lt;/h3>  );};\nconst App = () => {\n  return (\n    &lt;section className=\"App\">\n      &lt;Router>\n        &lt;Link to=\"/\">Home&lt;/Link>\n        &lt;Link to=\"/about\">About&lt;/Link>\n        &lt;Link to=\"/users\">Users&lt;/Link>\n        &lt;Route exact path=\"/\" component={IndexPage} />\n        &lt;Route exact path=\"/users\" component={UsersPage} />\n        &lt;Route exact path=\"/user/:userId\" component={UserPage} /> \n        &lt;Route exact path=\"/about\" component={AboutPage} />\n      &lt;/Router>\n      &lt;a href=\"/about\">about with browser reload&lt;/a>\n    &lt;/section>\n  );\n};\n\n...</code></pre>\n\n\n\n<p>Теперь наша страница пользователя работает. Но она не показывает никакую информацию непосредственно о самом пользователе. Давайте с этим разберемся.</p>\n\n\n\n<h2 id=\"5c8c\"><strong>Как получить доступ к параметрам роута в компоненте</strong></h2>\n\n\n\n<p id=\"6a22\">React роутер передаёт два пропса всем компонентам. Это&nbsp;<code>match</code>&nbsp;и&nbsp;<code>location</code>.</p>\n\n\n\n<p id=\"b070\">Давайте посмотрим, какая информация находится в этих пропсах, выведя их через сам компонент.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// App.js\n\nconst UserPage = ({ match, location }) => {  return (\n    &lt;>\n      &lt;p>\n        &lt;strong>Match Props: &lt;/strong>\n        &lt;code>{JSON.stringify(match, null, 2)}&lt;/code>      \n      &lt;/p>\n      &lt;p>\n        &lt;strong>Location Props: &lt;/strong>\n        &lt;code>{JSON.stringify(location, null, 2)}&lt;/code>      \n      &lt;/p>\n    &lt;/>\n  );\n};</code></pre>\n\n\n\n<p>И что же там внутри:</p>\n\n\n\n<pre class=\"wp-block-code\"><code>/*\n  URL: /user/1\n  userId: 1\n*/\n\n// Match Props\n{ \"path\": \"/user/:userId\", \"url\": \"/user/1\", \"isExact\": true, \"params\": { \"userId\": \"1\" } }\n\n// Location Props\n{ \"pathname\": \"/user/1\", \"search\": \"\", \"hash\": \"\", \"key\": \"7e6lx5\" }</code></pre>\n\n\n\n<p id=\"2431\">Если мы взглянем на контент, то интересный нам параметр&nbsp;<code>userId</code>&nbsp;находится в&nbsp;<code>match.params.userId</code>.</p>\n\n\n\n<p id=\"577b\">Давайте применим параметры в&nbsp;<code>UserPage</code>&nbsp;компоненте и покажем информацию о пользователе:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// Получаем userId из пропса match и показываем конкретного пользователя из массива пользователей\nconst UserPage = ({ match, location }) => {\n  const { params: { userId } } = match;\n\n  return (\n    &lt;>\n      &lt;p>\n        &lt;strong>User ID: &lt;/strong>\n        {userId}\n      &lt;/p>\n      &lt;p>\n        &lt;strong>User Name: &lt;/strong>\n        {users&#91;userId - 1].name}\n      &lt;/p>\n    &lt;/>\n  );\n};</code></pre>\n\n\n\n<figure class=\"wp-block-embed-wordpress wp-block-embed is-type-wp-embed is-provider-codesandbox\"><div class=\"wp-block-embed__wrapper\">\n<iframe class=\"wp-embedded-content\" sandbox=\"allow-scripts\" security=\"restricted\" title=\"dynamic-routing-in-react-router\" width=\"500\" height=\"750\" src=\"https://codesandbox.io/embed/p3ozwy018j?fontsize=14&#038;hidenavigation=1&#038;theme=dark#?secret=SaGs3tRNDS\" data-secret=\"SaGs3tRNDS\"></iframe>\n</div></figure>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// Деструктуризация объекта in JavaScript\nconst {\n  params: { userId },\n} = match;</code></pre>\n\n\n\n<p></p>\n","date":"2020-12-10T14:11:39.000Z","title":"Подробно о React Router. Часть 1 — основы роутинга, типы и динамические страницы","id":"911a1691-05bf-55ee-b3c7-65b656dce891","excerpt":"<p>В этой серии статей вы подробно и доходчиво узнаете о том, как работает Router в React, как его можно использовать и другие интересные фишки этого функционала. Это первая часть из 3х, в ней будет рассказано об основах роутинга, типах и созданиях динамических страниц.</p>\n","type":"js","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2020/12/DglYtvO7Bn0-10.jpg"}}},{"node":{"slug":"kak-ispolzovat-nullish-coalescing-v-javascript","content":"\n<p>В этой статье вы узнаете как работать с Nullish Coalsing, а именно оператором нулевого слияния в JavaScript. И чем он отличается от логических операторов. Это первая из цикла статей про ES2020.</p>\n\n\n\n<p class=\"author\"><a href=\"https://medium.com/javascript-in-plain-english/nullish-coalescing-operator-for-javascript-8f502b970ba8\"><em>Перевод статьи How to use the new Nullish Coalescing operator in JavaScript</em></a></p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p><strong>Off topic</strong><em>. Лучше всего оставлять этот термин без перевода, то есть просто Nullish Coalsing. Если использовать русский перевод, то лучше как “оператор нулевого слияния”. Я слышал варианты “нулевой оператор объединения” и “null оператор коалесцирования”. Но это не совсем то, последний вариант вообще ближе к химии, насколько я знаю.</em></p></blockquote>\n\n\n\n<p>Оператор нулевого слияния “<code>??</code>” является нововведением в&nbsp;<strong>ES2020</strong>, которое представляет собой укороченную оценку логического выражения, отдающее правый операнд в случае, если левый операнд является&nbsp;<code>null</code>&nbsp;или&nbsp;<code>undefined</code>, если же нет, то тогда он отдаст левый операнд.</p>\n\n\n\n<p id=\"636d\">Сейчас он находится на 4й стадии рассмотрения, что говорит о том, что он уже готов к внедрению в официальный&nbsp;<a href=\"https://tc39.es/process-document/\">ECMAScript стандарт</a>.</p>\n\n\n\n<p id=\"8202\">Он работает в последних версиях Chrome и Firefox.</p>\n\n\n\n<p id=\"de43\">Вот очень простой пример применения:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const team = null ?? 'A team';\nconsole.log(team);\n//A team</code></pre>\n\n\n\n<h2><strong>Что способствовало созданию Nullish Coalescing оператора</strong></h2>\n\n\n\n<p>Конечно же вы уже знаете другие логические операторы, сокращающие вычисления с обработкой типов данных, такие как “<code>&amp;&amp;</code>” и “<code>||</code>”. Эти операторы используются для обработки&nbsp;<strong>truthy</strong>&nbsp;и&nbsp;<strong>falsy</strong>&nbsp;значений. Но сначала, что есть&nbsp;<code>false</code>, а что есть&nbsp;<code>true</code>&nbsp;в JavaScript?</p>\n\n\n\n<p id=\"a38a\">Falsy:</p>\n\n\n\n<p id=\"fa1d\">boolean false</p>\n\n\n\n<p id=\"ade6\">null value</p>\n\n\n\n<p id=\"fa6a\">undefined</p>\n\n\n\n<p id=\"ac88\">Number 0</p>\n\n\n\n<p id=\"4b2d\">Number NaN</p>\n\n\n\n<p id=\"e4d0\">BigInt 0n</p>\n\n\n\n<p id=\"a1ae\">Пустая строка “”</p>\n\n\n\n<p id=\"f65c\">Truthy:</p>\n\n\n\n<p id=\"2c46\">Все значения, кроме предыдущих.</p>\n\n\n\n<p id=\"e128\">Проблема с&nbsp;<code>&amp;&amp;</code>&nbsp;и&nbsp;<code>||</code>&nbsp;операторами в том, что они ориентируются только на&nbsp;<strong>truthy</strong>&nbsp;и&nbsp;<strong>falsy</strong>, что неизбежно приводит к багам. Эти операторы отлично работают с&nbsp;<code>null</code>&nbsp;и&nbsp;<code>undefined</code>&nbsp;значениями, но многие&nbsp;<code>false</code>&nbsp;значения могут привести к неожиданным результатам.</p>\n\n\n\n<p id=\"c737\">В этом примере я хочу, чтобы мы обработали объект, в котором мы выставим свойству&nbsp;<code>enableAudio</code>&nbsp;значение&nbsp;<code>0</code>. И дальше мы выставим дефолтное значение&nbsp;<code>1</code>, потому что нулевое значение интерпретируется как&nbsp;<strong>falsy</strong>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const response = {\n     enableAudio : 0\n}\nconst enableAudio = response.enableAudio || 1;\nenableAudio\n//1</code></pre>\n\n\n\n<p id=\"9b13\">Nullish coalescing оператор&nbsp;<code>??</code>&nbsp;очень схож с оператором&nbsp;<code>||</code>, кроме того факта, что он не использует&nbsp;<strong>truthy</strong>&nbsp;при принятии решения. Вместо этого он использует nullish, что говорит о том, что значение должно быть либо&nbsp;<code>null</code>, либо&nbsp;<code>undefined</code>.</p>\n\n\n\n<p id=\"5ced\">В следующем примере переменная&nbsp;<code>enableAudio</code>&nbsp;имеет значение&nbsp;<code>0</code>&nbsp;и с оператором нулевого слияния&nbsp;<code>??</code>, оно обрабатывается не как nullish значение. Следовательно, выражение отдаст левый операнд.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const response = {\n     enableAudio : 0\n}\nconst enableAudio = response.enableAudio ?? 1;\nenableAudio\n//0</code></pre>\n\n\n\n<p>С оператором&nbsp;<code>||</code>, если бы первый операнд был бы&nbsp;<strong>truthy</strong>, то он бы отдал первый операнд. В другом случае он перешел бы ко второму. C Nullish Coalsing оператором, если первый оператор&nbsp;<strong>falsy</strong>, но не&nbsp;<strong>nullish</strong>, то отдастся false.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>console.log(false || true);//true\nconsole.log(false ?? true);//false</code></pre>\n\n\n\n<p>В следующем примере&nbsp;<code>0</code>&nbsp;воспринимается как&nbsp;<strong>falsy</strong>. Следовательно выражение отдаст второй операнд с оператором&nbsp;<code>||</code>. Но с оператором Nullish Coalescing, ноль не считается&nbsp;<code>null</code>. Следовательно, выражение отдаст первое значение, то есть&nbsp;<code>0</code>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>console.log(0 || 1); //1\nconsole.log(0 ?? 1); //0</code></pre>\n\n\n\n<p>В следующем примере, если вы попробуете его с оператором&nbsp;<code>||</code>, то результат, полученный вами будет вторым операндом, потому что пустая строка являет собой&nbsp;<strong>falsy</strong>&nbsp;значение. А вот если бы вы использовали Nullish Coalescing оператор, то пустая строка не считалась бы как&nbsp;<code>null</code>&nbsp;и следовательно выражение отдало бы первый операнд.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>console.log('' || 'Hello!');//Hello      \nconsole.log('' ?? 'Hello');//''</code></pre>\n\n\n\n<p>В общем, оператор&nbsp;<code>||</code>&nbsp;обрабатывает значения как&nbsp;<strong>falsy</strong>&nbsp;и&nbsp;<strong>truthy</strong>, а опрератор&nbsp;<code>??</code>&nbsp;обрабатывает их как&nbsp;<strong>nullish</strong>. Это говорит о том, что с оператором&nbsp;<code>||</code>, будет отдан второй операнд, если первый является&nbsp;<code>undefined</code>,&nbsp;<code>null</code>,&nbsp;<code>0</code>,&nbsp;<code>false</code>,&nbsp;<code>NaN</code>&nbsp;или пустой строкой. А вот с оператором&nbsp;<code>??</code>, второй операнд будет отдан только в том случае, если первый является&nbsp;<code>null</code>&nbsp;или&nbsp;<code>undefined</code>.</p>\n\n\n\n<h2 id=\"4227\"><strong>Заключение</strong></h2>\n\n\n\n<p id=\"241d\">Есть очень большое количество багов, которые могут всплыть при использовании&nbsp;<code>||</code>&nbsp;оператора которые вы можете избежать, используя новый оператор nullish coalescing&nbsp;<code>??</code>, а ещё с ним вы вы сможете предотвратить появление большого количества шаблонного кода для подобных проверок.</p>\n","date":"2020-12-07T15:29:23.000Z","title":"Как использовать Nullish Coalescing(оператор нулевого слияния) в JavaScript","id":"3db0e77a-3715-5ed7-86f0-59e0272f5bd3","excerpt":"<p>В этой статье вы узнаете как работать с Nullish Coalsing, а именно оператором нулевого слияния в JavaScript. И чем он отличается от логических операторов. Это первая из цикла статей про ES2020.</p>\n","type":"js","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2020/12/DglYtvO7Bn0-9.jpg"}}},{"node":{"slug":"javascript-pochemu-3true4-i-drugie-hitrye-uravneniya-privedeniya-tipov","content":"\n<p><code>3 + true === 4</code>. Сейчас вы узнаете почему так происходит и ещё узнаете про 8 других интересных JavaScript уравнений.</p>\n\n\n\n<p class=\"author\"><em>Перевод статьи&nbsp;</em><a href=\"https://codeburst.io/javascript-why-does-3-true-4-and-7-other-tricky-equations-9dd13cb2a92a\"><em>JavaScript: Why does 3 + true = 4? (and 7 other tricky equations)</em></a></p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"466\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2020/11/1_5cWyURkYJ3cGngd20lndfA.jpeg\" alt=\"\" class=\"wp-image-52\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2020/11/1_5cWyURkYJ3cGngd20lndfA.jpeg 700w, https://stasonmars.ru/wp/wp-content/uploads/2020/11/1_5cWyURkYJ3cGngd20lndfA-300x200.jpeg 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<h2 id=\"db4d\"><strong>Как лучше читать эту статью</strong></h2>\n\n\n\n<p id=\"2e4e\">Это может вас немного смутить, но вам надо делать&nbsp;так, как я напишу дальше. Вам придется открыть консоль разработчика в Chrome, нажав в Windows:&nbsp;<strong>Ctrl + Shift + J</strong>&nbsp;или в Mac&nbsp;<strong>Cmd + Option + J</strong>. Это даст вам возможность напечатать весь следующий код в браузере и вы сможете увидеть в реальном примере то, что происходит.</p>\n\n\n\n<h3 id=\"5abe\"><strong>3 + true == 4</strong></h3>\n\n\n\n<p id=\"48fe\">Я не шучу. В JavaScript, когда оператор&nbsp;<code>+</code>&nbsp;находится между числом и булевым значением, последний конвертируется в число.</p>\n\n\n\n<p id=\"79c8\">В этих случаях и&nbsp;<code>false == 0</code>. Учитывая это,&nbsp;<code>3 + true</code>&nbsp;конвертируется в&nbsp;<code>3 + 1</code>&nbsp;и следовательно мы получаем ответ&nbsp;<code>4</code>.</p>\n\n\n\n<h3 id=\"96e7\"><strong>True + False</strong></h3>\n\n\n\n<p id=\"759c\">Это следует такой же логике как в примере выше. Когда оператор&nbsp;<code>+</code>&nbsp;размещен между двумя булевыми значениями, они конвертируются в числа. Следовательно,&nbsp;<code>true + false</code>&nbsp;конвертируется в&nbsp;<code>1 + 0</code>&nbsp;и в итоге мы получаем ответ&nbsp;<code>1</code>.</p>\n\n\n\n<h3 id=\"2728\">‘<strong>4’ + 8</strong></h3>\n\n\n\n<p id=\"594f\">Что случается когда мы добавляем число в строке к обычному числу? Когда оператор&nbsp;<code>+</code>&nbsp;находится между этими двумя операндами и один из них является строкой, это сконвертирует другое число или булево значение в строку и свяжет их.</p>\n\n\n\n<p id=\"be64\">Следуя этой логике, &#8216;<code>4' + 8</code>&nbsp;становится&nbsp;<code>'4' + '8'</code>&nbsp;и мы получаем ответ&nbsp;<code>'48'</code>.</p>\n\n\n\n<h3 id=\"feb7\"><strong>true + ‘4’</strong></h3>\n\n\n\n<p id=\"e660\">Так же как и в примере выше, JavaScript сконвертирует&nbsp;<code>boolean</code>&nbsp;в сточное значение и свяжет его. Это станет&nbsp;<code>'true' + '4'</code>&nbsp;и результатом будет&nbsp;<code>'true4'</code>.</p>\n\n\n\n<h3 id=\"54f5\"><strong>1 + 1 + ‘1’</strong></h3>\n\n\n\n<p id=\"2213\">Порядок операций очень важен. В этом примере, JavaScript считает первый&nbsp;<code>+</code>&nbsp;перед чем либо ещё, что ведет к&nbsp;<code>1 + 1 = 2</code>. Далее мы добавляем строчной значение&nbsp;<code>'1'</code>. Происходит связывание и как результат мы получаем&nbsp;<code>'21'</code>.</p>\n\n\n\n<p>Вот цепочка событий:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>1 + 1 + '1'\n  2   + '1'\n       '21'</code></pre>\n\n\n\n<h3 id=\"75b7\">‘<strong>1’ + 1 + 1</strong></h3>\n\n\n\n<p id=\"f3bc\">Что меняется, когда у нас есть строчное значение на первом месте? Помните о порядке операций и работайте слева на право.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>'1' + 1 + 1\n   '11' + 1\n       '111'</code></pre>\n\n\n\n<p><code>string + number = string</code>&nbsp;В этом случае у нас останется только одна длинная строка&nbsp;<code>'111'.</code></p>\n\n\n\n<h3 id=\"1b00\"><strong>-‘69’ + 69</strong></h3>\n\n\n\n<p id=\"4c1c\">Что если мы попытаемся инвертировать в минус строку и затем добавить число? Как вы должны знать к этому моменту, без минуса, наш ответ был бы&nbsp;<code>‘6969’</code>. Тем не менее минус все меняет.</p>\n\n\n\n<p id=\"f5af\">Знак минус перед&nbsp;<code>’69’</code>&nbsp;это унарный оператор минуса, который на самом деле сконвертирует строку в число и сделает его отрицательным. Следовательно, наше уравнение станет&nbsp;<code>-69 + 69</code>, что будет равно&nbsp;<code>0</code>.</p>\n\n\n\n<h3 id=\"47e4\"><strong>-‘giddyup’ + 409</strong></h3>\n\n\n\n<p id=\"8cd2\">Что если наш унарный оператор минуса будет перед строкой, которая не может быть сконвертирована в число? Когда JavaScript не может сделать число, мы остаемся только с&nbsp;<code>NaN</code>, что означает, то что это не число.</p>\n","date":"2020-11-05T16:41:20.000Z","title":"JavaScript. Почему 3 + true = 4? И другие хитрые уравнения приведения типов","id":"99fefe61-69be-5e93-b301-314bd65069ea","excerpt":"<p>3 + true === 4. Сейчас вы узнаете почему так происходит и ещё узнаете про 8 других интересных JavaScript уравнений.</p>\n","type":"js","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2020/11/DglYtvO7Bn0-8.jpg"}}},{"node":{"slug":"15-metodov-raboty-s-elementami-pro-kotorie-vy-ne-slyshaly-vozmozhno","content":"\n<p>В этой статье вы узнаете про 15 методов работы с элементами про которые вы возможно не слышали.</p>\n\n\n\n<p class=\"author\">Перевод статьи —&nbsp;<a href=\"https://hackernoon.com/15-html-element-methods-youve-potentially-never-heard-of-fc6863e41b2a\"><em>15 HTML element methods you’ve potentially never heard of</em></a></p>\n\n\n\n<h2 id=\"6d78\">Для новичков</h2>\n\n\n\n<p id=\"f663\">Давайте обсудим разницу между HTML и DOM.</p>\n\n\n\n<p id=\"b36e\">Старый добрый элемент&nbsp;<code>&lt;table&gt;</code>&nbsp;это HTML, что очевидно. Вы можете использовать его в файле с расширением&nbsp;<code>.html</code>. Он имеет набор атрибутов, которые влияют на вид и поведение страницы.</p>\n\n\n\n<p id=\"6bb3\">И это&nbsp;все, что можно о нем сказать. У него нет ничего общего с JavaScript.</p>\n\n\n\n<p id=\"518d\">DOM это то, что соединяет ваш JavaScript код с HTML элементами в документе, так что вы можете взаимодействовать с этими элементами, как с объектами.</p>\n\n\n\n<p id=\"9812\">Это и есть объектная модель документа, то есть DOM.</p>\n\n\n\n<p id=\"1c32\">Каждый тип элемента в HTML имеет свой собственный ‘интерфейс’, который определяет свойства (который обычно сопоставляются с атрибутами HTML элемента) и методы. Для примера,&nbsp;<code>&lt;table&gt;</code>&nbsp;имеет интерфейс под названием HTMLTableElement.</p>\n\n\n\n<p id=\"aa96\">Вы можете сослаться на конкретный элемент, написав что-то типа того:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const searchBox = document.getElementById('search-box');</code></pre>\n\n\n\n<p id=\"3ad8\">Далее у вас будет доступ ко всем свойствам и методам, которые доступны для этого типа элемента. Для примера, вы можете получить доступ к свойству&nbsp;<code>value</code>&nbsp;с помощью&nbsp;<code>searchBox.value</code>&nbsp;или направить курсор на поле поиска, вызвав&nbsp;<code>searchBox.focus()</code>.</p>\n\n\n\n<p id=\"82c3\"><em>Спасибо за посещение моего 58-ми секундного курса DOM.</em></p>\n\n\n\n<p id=\"affa\">Так вот, тут дело в том, что большинство элементов не имеют каких-либо интересных методов, так что до того как вы отсеете спецификации для вещей, которые вы почти не будете использовать, легко пропустить незаметную важную деталь в поучившемся беспорядке.</p>\n\n\n\n<p id=\"1f03\">Но к счастью для вас, рысканье по спецификациям и написание статей, это два моих любимых способа борьбы со злом. И так поехали.</p>\n\n\n\n<p id=\"e857\">Если вы хотите поиграться с кодом и у вас есть DevTools, то вы можете выбрать элемент в древе элементов, затем напечатать&nbsp;<code>$0</code>&nbsp;в консоле. Это даст вам отсылку к элементу, который вы выбрали. Чтобы увидеть элемент, как объект, введите&nbsp;<code>dir($0)</code>.</p>\n\n\n\n<p id=\"92a6\">Вообще вы можете много&nbsp;<a href=\"https://developers.google.com/web/tools/chrome-devtools/console/command-line-reference\">всего сделать в консоли</a>.</p>\n\n\n\n<h2 id=\"494e\">1. Табличные методы</h2>\n\n\n\n<p id=\"b86d\">Скромная таблица имеет довольно много полезных методов, которые сделают процесс сбора и формирования таблицы настолько же простым, как и сборка стола из Икеи.</p>\n\n\n\n<p id=\"db68\">Вот несколько из них.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const tableEl = document.querySelector('table');\n\nconst headerRow = tableEl.createTHead().insertRow();\nheaderRow.insertCell().textContent = 'Make';\nheaderRow.insertCell().textContent = 'Model';\nheaderRow.insertCell().textContent = 'Color';\n\nconst newRow = tableEl.insertRow();\nnewRow.insertCell().textContent = 'Yes';\nnewRow.insertCell().textContent = 'No';\nnewRow.insertCell().textContent = 'Thank you';</code></pre>\n\n\n\n<p id=\"0149\">Ни единого&nbsp;<code>document.createElement()</code>.</p>\n\n\n\n<p id=\"c186\"><code>.insertRow()</code>&nbsp;метод даже вставит&nbsp;<code>&lt;tbody&gt;</code>&nbsp;для вас, если вы вызовите его прямо на табличном элементе. Не отлично ли это?</p>\n\n\n\n<h2 id=\"9b81\">2. scrollIntoView()</h2>\n\n\n\n<p id=\"aa08\">Вы знаете, что когда у вас есть&nbsp;<code>#something</code>&nbsp;в ссылке и когда страница загружается, браузер проскролит страницу, так что вы сможете увидеть элемент с этим&nbsp;<code>ID</code>?</p>\n\n\n\n<p id=\"6488\">Это всё очень хорошо, но это не работает, если вы рендерите этот элемент после загрузки страницы. Вы можете вручную воспроизвести это поведение, с помощью:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>document.querySelector(document.location.hash).scrollIntoView();\n</code></pre>\n\n\n\n<h2 id=\"b7f8\">3. hidden</h2>\n\n\n\n<p id=\"59b6\">Ок, это не метод, но если вы поспорите, то я возражу в ответ тем, что это между прочим это скорее сеттер и выходит, что это действительно метод, правильно?</p>\n\n\n\n<p id=\"1bf3\">В любом случае, вы когда нибудь делали&nbsp;<code>myElement.style.display = \"none\"</code>, для того, чтобы спрятать элемент? Отлично, прекратите так делать.</p>\n\n\n\n<p id=\"1ca3\">Вы можете просто сделать так&nbsp;<code>myElement.hidden = true</code>.</p>\n\n\n\n<h2 id=\"e8a8\">4. toggle()</h2>\n\n\n\n<p id=\"f291\">Ок, это не совсем метод элемента, а скорее метод для свойства элемента. А точнее, это метод для переключения добавления/удаления класса с элемента с помощью&nbsp;<code>myElement.classList.toggle(\"some-class\")</code></p>\n\n\n\n<p id=\"d43f\">И если вы когда-либо добавляли класс с условным объявлением&nbsp;<code>if</code>, то это преступление — не иначе.</p>\n\n\n\n<p id=\"5cae\">Вам нужно просто передать второй параметр методу&nbsp;<code>toggle</code>. И когда дойдет до дела, ваш класс будет добавлен элементу.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>el.classList.toggle('some-orange-class', theme === 'orange');\n</code></pre>\n\n\n\n<p id=\"85b8\">Я знаю, что вы думаете, то что это не совсем то, что означает понятие “<em>переключать</em>” — и хорошие люди на Internet Explorer согласятся и будут протестовать, не применяя логику второго параметра вообще.</p>\n\n\n\n<p id=\"8081\">В общем, я беру свои слова назад, это не преступление. Выбор за вами.</p>\n\n\n\n<h2 id=\"9665\">5. querySelector()</h2>\n\n\n\n<p id=\"bf9c\">Ок, этот вы точно уже знаете, но я подозреваю, что именно 17% из вас не знали, что вы можете использовать его на любом элементе.</p>\n\n\n\n<p id=\"98d8\">Для примера,&nbsp;<code>myElement.querySelector(\".my-class\")</code>&nbsp;выберет только элементы, которые имеют класс my-class и они являются потомками&nbsp;<code>myElement</code>.</p>\n\n\n\n<h2 id=\"425e\">6. closest</h2>\n\n\n\n<p id=\"b430\">Это метод доступный на всех элементах, которые идут выше в древе элементов. Это как реверс&nbsp;<code>querySelector()</code>. Итак, я бы мог выбрать заголовок данной секции в таком исполнении:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>myElement.closest(\"article\").querySelector(\"h1\");\n</code></pre>\n\n\n\n<p>Вверх до первого&nbsp;<code>&lt;article&gt;</code>&nbsp;и затем назад вниз к первому заголовку&nbsp;<code>&lt;h1&gt;</code>.</p>\n\n\n\n<h2 id=\"5f2c\">7. getBoundingClientRect()</h2>\n\n\n\n<p id=\"b57a\">Этот метод возвращает аккуратный маленький объект с некоторыми деталями, а точнее пространственными деталями элемента, который вы вызываете.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>{\n  x: 604.875,\n  y: 1312,\n  width: 701.625,\n  height: 31,\n  top: 1312,\n  right: 1306.5,\n  bottom: 1343,\n  left: 604.875\n}</code></pre>\n\n\n\n<p id=\"664f\">Будьте аккуратны в двух случаях:</p>\n\n\n\n<p id=\"5b8d\">Его вызов влечет собой перерисовку. В зависимости от устройства и сложности страницы, это может занять несколько миллисекунд. Так что следите за этим, если вы вызываете его повторно, в частности в анимации.</p>\n\n\n\n<p id=\"5416\">Не все браузеры возвращают эти значения. Потому что с чего бы это вдруг?</p>\n\n\n\n<h2 id=\"16b5\">8. matches()</h2>\n\n\n\n<p id=\"7ebb\">Скажем, что я хочу проверить, есть ли у конкретного элемента конкретный класс.</p>\n\n\n\n<p id=\"b932\">Максимум сложности:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>if (myElement.className.indexOf('some-class') > -1) {\n  // do something\n}</code></pre>\n\n\n\n<p>Уже лучше, но ничего пока особо не поменялось:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>if (myElement.className.includes('some-class')) {\n  // do something\n}</code></pre>\n\n\n\n<p>Лучше всего:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>if (myElement.matches('.some-class')) {\n  // do something\n}</code></pre>\n\n\n\n<h2 id=\"6286\">9. insertAdjacentElement()</h2>\n\n\n\n<p id=\"4938\">Этот я выучил только сегодня! Он как&nbsp;<code>appendChild()</code>, но даёт больше контроля, когда вы дополняете элемент потомком.</p>\n\n\n\n<p id=\"b364\"><code>parentEl.insertAdjacentElement(\"beforeend\", newEl)</code>&nbsp;это буквально тоже самое, что и&nbsp;<code>parentEl.appendChild(newEl)</code>, но вы также можете указать&nbsp;<code>beforebegin</code>,&nbsp;<code>afterbegin</code>&nbsp;или&nbsp;<code>afterend</code>, чтобы вставить элемент в место, которое оно предполагает по названию.</p>\n\n\n\n<p id=\"7dc9\">Какой контроль!</p>\n\n\n\n<h2 id=\"c502\">10. contains()</h2>\n\n\n\n<p id=\"b241\">Надо ли вам было знать, есть ли какой элемент внутри другого элемента? Конечно же это всегда очень сильно нужно.</p>\n\n\n\n<p id=\"aad2\">Для примера, если я работаю с кликом мышки и хочу знать, случилось ли это внутри модалки или вне её, то я могу сделать так:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const handleClick = e => {\n  if (!modalEl.contains(e.target)) modalEl.hidden = true;\n};</code></pre>\n\n\n\n<p id=\"1c58\">Где&nbsp;<code>modalEl</code>&nbsp;это сам подал, а e.<code>target</code>&nbsp;будет любым элементом на который кликнули.</p>\n\n\n\n<p id=\"3ab2\">Забавный факт, 100% времени, что я делаю это, у меня получается противоположно неверная логика при первой попытке.</p>\n\n\n\n<p id=\"d5a3\">Даже если я стану умнее и переключусь на другой способ перед кликом на save, я всё равно сделаю это неправильно.</p>\n\n\n\n<h2 id=\"5163\">11. getAttribute()</h2>\n\n\n\n<p id=\"6a66\">Без сомнений это самый бесполезный из всех методов элемента, кроме одного конкретного случая.</p>\n\n\n\n<p id=\"191a\">Помните, когда я упоминал выше, что свойства обычно сопоставляются атрибутам?</p>\n\n\n\n<p id=\"7c3f\">Один из примеров, когда это не так — происходит с атрибутом&nbsp;<code>href</code>, такого элемента как&nbsp;<code>&lt;a href=\"/animals/cat\"&gt;Cat&lt;/a&gt;</code>.</p>\n\n\n\n<p id=\"95ff\"><code>el.href</code>&nbsp;не вернет&nbsp;<code>/animals/cat</code>, как вы уже могли предположить. Так происходит из-за того, что элемент&nbsp;<code>&lt;a&gt;</code>&nbsp;выполняет&nbsp;<code>HTMLHyperlinkElementUtils</code>&nbsp;интерфейс, который имеет группу вспомогательных свойств, таких как&nbsp;<code>protocol</code>&nbsp;и&nbsp;<code>hash</code>, которые говорят вам о том куда ведет ссылка.</p>\n\n\n\n<p id=\"3606\">Одно из таких вспомогательных свойств это&nbsp;<code>href</code>, которое выдаст вам полный URL, со всеми штуками, которые не относятся к атрибуту URL.</p>\n\n\n\n<p id=\"4c15\">Так что вам надо будет использовать&nbsp;<code>el.getAttribute(\"href\")</code>, если вам нужна конкретная строка из атрибута&nbsp;<code>href</code>.</p>\n\n\n\n<h2 id=\"6258\">12. Трио для элемента &lt;dialog&gt;</h2>\n\n\n\n<p id=\"8428\">У сравнительно нового элемента&nbsp;<code>&lt;dialog&gt;</code>&nbsp;есть два нормальных метода и один ну просто восхитительный.&nbsp;<code>show()</code>&nbsp;и&nbsp;<code>close()</code>&nbsp;сделают именно то, что вы ожидаете от них.</p>\n\n\n\n<p id=\"1fd2\">Но&nbsp;<code>showModal()</code>&nbsp;покажет&nbsp;<code>&lt;dialog&gt;</code>&nbsp;выше всего, отцентрованным на странице, как вы и хотите, чтобы показывались ваши формы. Нет нужды в&nbsp;<code>z-index</code>&nbsp;или ручного добавления затемняющего фона, или отслеживания кнопки&nbsp;<code>esc</code>, чтобы его закрыть, браузер знает, как работают формы и сделает это все за вас.</p>\n\n\n\n<p id=\"efb7\">И это просто отлично.</p>\n\n\n\n<h2 id=\"7122\">13. forEach()</h2>\n\n\n\n<p id=\"89e2\">Иногда, когда вы ссылаетесь на список элементов, вы можете пройтись по всем ним с помощью&nbsp;<code>forEach()</code>.</p>\n\n\n\n<p id=\"954e\"><code>for()</code>&nbsp;циклы стали такими винтажными.</p>\n\n\n\n<p id=\"9179\">Скажем так, вам нужно выгрузить URL для всех ссылок на странице. Вы бы могли сделать так, если бы захотели увидеть ошибку.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>document.getElementsByTagName('a').forEach(el => {\n    console.log(el.href);\n});</code></pre>\n\n\n\n<p>Или вы бы могли сделать так:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>document.querySelectorAll('a').forEach(el => {\n    console.log(el.href);\n});</code></pre>\n\n\n\n<p id=\"5ee2\">Так произойдет, потому что&nbsp;<code>getElementsByTagName</code>&nbsp;и другие получают от методов&nbsp;<code>HTMLCollection</code>, а&nbsp;<code>querySelectorAll</code>&nbsp;отдаст&nbsp;<code>NodeList</code>.</p>\n\n\n\n<p id=\"413d\">И это интерфейс&nbsp;<code>NodeList</code>, который дает нам метод&nbsp;<code>forEach()</code>, вместе с&nbsp;<code>keys()</code>,&nbsp;<code>value()</code>&nbsp;и&nbsp;<code>entries()</code>.</p>\n\n\n\n<p id=\"bd65\">На самом деле было бы хорошо, если бы все просто возвращали массивы, вместо того, чтобы вы отдавать что-то фантастическое, не совсем похожее на них. Но не пугайтесь, потому что хороший парень из&nbsp;<code>ECMA</code>&nbsp;дал нам&nbsp;<code>Array.from()</code>, который превращает любой “около массив” в массив. И это работает:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>Array.from(document.getElementsByTagName('a')).forEach(el => {\n    console.log(el.href);\n});</code></pre>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>Array.from(document.querySelectorAll('a'))\n  .map(el => el.origin)\n  .filter(origin => origin !== document.origin)\n  .filter(Boolean);</code></pre>\n\n\n\n<h2 id=\"f796\">14. Формы</h2>\n\n\n\n<p id=\"011f\">У&nbsp;<code>&lt;form&gt;</code>, как вы уже наверное знаете, есть метод&nbsp;<code>submit()</code>. Возможно вы также знаете, что у форм есть метод&nbsp;<code>reset()</code>&nbsp;и они могут&nbsp;<code>reportValidity()</code>, если вы используете валидацию на ваших элементах формы.</p>\n\n\n\n<p id=\"5152\">Вы также можете использовать свойства элементов формы с точечным обозначением для отсылки к элементу по его имени атрибута. Для примера,&nbsp;<code>myFormEl.elements.email</code>&nbsp;вернул бы элемент&nbsp;<code>&lt;input name=\"email\" /&gt;</code>, который принадлежит&nbsp;<code>&lt;form&gt;</code>.</p>\n\n\n\n<p id=\"db96\">Я обманул вас.&nbsp;<code>elements</code>&nbsp;не возвращает список элементов вообще. Он возвращается список контролов и конечно же это не массив, потому что с чего бы это вообще ему им быть.</p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p></p><cite>Пример: если у вас есть три радио кнопки, каждая с одинаковым именем&nbsp;<code>animal</code>, то&nbsp;<code>formEl.elements.animal</code>&nbsp;будет выбирать сбор радио кнопок (1 контрол, 3 элемента).<br></cite></blockquote>\n\n\n\n<p id=\"82b2\">И&nbsp;<code>formEl.elements.animal.value</code>&nbsp;вернет значение любой выбранной кнопки.</p>\n\n\n\n<p id=\"eb86\">Это странный синтаксис, если вы уже подумали об этом. Давайте разберем его:&nbsp;<code>formEl</code>&nbsp;это элемент,&nbsp;<code>elements</code>&nbsp;это&nbsp;<code>HTMLFormControlsCollection</code>, не реальный массив в котором каждый элемент не обязательно является HTML элементом.&nbsp;<code>animal</code>&nbsp;это набор нескольких радио кнопок, совмещенных только потому что у них есть один и тот же атрибут&nbsp;<code>name</code>&nbsp;(есть&nbsp;<code>RadioNodeList</code>&nbsp;интерфейс именно для этой цели) и&nbsp;<code>value</code>, которое смотрит за&nbsp;<code>value</code>&nbsp;атрибутом, какая бы радио кнопка не была выбрана.</p>\n\n\n\n<h2 id=\"13af\">15. select()</h2>\n\n\n\n<p id=\"a31c\">Мне возможно нужно было заранее сказать, так как последний не такой уж и интересный. В любом случае,&nbsp;<code>.select()</code>&nbsp;метод выберет весь текст в любом инпуте, в котором бы вы его не вызвали.</p>\n","date":"2020-10-29T15:20:01.000Z","title":"15 методов работы с элементами про которые вы возможно не слышали","id":"49bee3f0-ecff-557c-b731-6e96ae2d47a0","excerpt":"<p>В этой статье вы узнаете про 15 методов работы с элементами про которые вы возможно не слышали.</p>\n","type":"js","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2020/10/DglYtvO7Bn0-6.jpg"}}},{"node":{"slug":"luchshie-sovety-i-ulovki-javascript","content":"\n<p id=\"3a56\">По факту эти техники сохранят вам кучу времени.</p>\n\n\n\n<p id=\"e9b2\">Возможно большинство из них вам уже знакомо, возможно некоторые нет. Но в любом случае, они будут вам крайне полезны.</p>\n\n\n\n<p id=\"82e8\">Это переводы трех статей, которые действительно помогут вам писать лучше, быстрее и продуктивнее.</p>\n\n\n\n<p class=\"author\"><em>Перевод первой статьи&nbsp;</em><a href=\"https://medium.freecodecamp.org/9-neat-javascript-tricks-e2742f2735c3\"><em>Learn these neat JavaScript tricks in less than 5 minutes</em></a></p>\n\n\n\n<h2 id=\"d45d\"><strong>Очистка и сокращение массива</strong></h2>\n\n\n\n<p id=\"6e55\">Вот простой способ очистки или сокращения массива его переназначения. Вы можете просто поменять его&nbsp;<code>length</code>&nbsp;свойство:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const arr = &#91;11, 22, 33, 44, 55, 66];\n  // Сокращение\narr.length = 3;\nconsole.log(arr); //=> &#91;11, 22, 33]\n  // Очистка\narr.length = 0;\nconsole.log(arr); //=> &#91;]\nconsole.log(arr&#91;2]); //=> undefined</code></pre>\n\n\n\n<h2 id=\"96fc\"><strong>Имитация параметров с помощью деструктуризации</strong></h2>\n\n\n\n<p id=\"16fd\">Велик шанс того, что вы уже используете конфигурацию объектов, когда вам надо передать переменный набор аргументов для функции, например как тут:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>doSomething({ foo: 'Hello', bar: 'Hey!', baz: 42 });\nfunction doSomething(config) {  \n    const foo = config.foo !== undefined ? config.foo : 'Hi';  \n    const bar = config.bar !== undefined ? config.bar : 'Yo!';  \n    const baz = config.baz !== undefined ? config.baz : 13;  // ...}</code></pre>\n\n\n\n<p>Это старый, но эффективный паттерн, который пытается имитировать именованные параметры в JavaScript. Вызов функции выглядит хорошо. С другой стороны,&nbsp;<em>объект конфигурация</em>&nbsp;содержит логику, которая занимает ну уж слишком много писанины. А вот помощью ES2015 деструктуризации, вы можете обойти этот недостаток:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function doSomething({ foo = 'Hi', bar = 'Yo!', baz = 13 }) {  // ...}\nИ если вам нужно сделать конфиг объекта опциональным, но это тоже очень просто:\nfunction doSomething({ foo = 'Hi', bar = 'Yo!', baz = 13 } = {}) {  // ...}</code></pre>\n\n\n\n<h2 id=\"4df6\"><strong>Деструктуризация объекта для элементов массива</strong></h2>\n\n\n\n<p id=\"81aa\">Назначайте элементы массива индивидуальным переменным с помощью деструктуризации объектов:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const csvFileLine = '1997,John Doe,US,john@doe.com,New York';\nconst { 2: country, 4: state } = csvFileLine.split(',');</code></pre>\n\n\n\n<h2 id=\"8877\"><strong>Асинхронные функции с async/await</strong></h2>\n\n\n\n<p id=\"6c04\">Да, есть возможно обождать множественную асинхронную функцию, используя&nbsp;<code>Promise.all</code>:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>await Promise.all(&#91;anAsyncCall(), thisIsAlsoAsync(), oneMore()])\n</code></pre>\n\n\n\n<h2 id=\"a27f\"><strong>Создание пустых объектов</strong></h2>\n\n\n\n<p id=\"eea1\">Вы можете создать 100% пустой объект, который не будет наследовать какие-либо свойства или методы из изначального объекта (например,&nbsp;<code>constructor</code>,&nbsp;<code>toString()</code>&nbsp;и так далее).</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const pureObject = Object.create(null);\nconsole.log(pureObject); //=> {}\nconsole.log(pureObject.constructor); //=> undefined\nconsole.log(pureObject.toString); //=> undefined\nconsole.log(pureObject.hasOwnProperty); //=> undefined\n</code></pre>\n\n\n\n<h2 id=\"331b\"><strong>Форматирование кода JSON</strong></h2>\n\n\n\n<p id=\"bfcf\"><code>JSON.stringify</code>&nbsp;может не просто конвертировать объект в строку. А так же может сделать красивую выдачу JSON:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const obj = {\nfoo: { bar: &#91;11, 22, 33, 44], baz: { bing: true, boom: ‘Hello’ } }\n};\n// Третий параметр это чисто пробелов, используемое для украшения JSON вывода\nJSON.stringify(obj, null, 4);\n// =>”{\n// => “foo”: {\n// => “bar”: &#91;\n// => 11,\n// => 22,\n// => 33,\n// => 44\n// => ],\n// => “baz”: {\n// => “bing”: true,\n// => “boom”: “Hello”\n// => }\n// => }\n// =>}”</code></pre>\n\n\n\n<h2 id=\"f1da\"><strong>Удаление дублирующихся элементов из массива</strong></h2>\n\n\n\n<p id=\"03a2\">Используя сеты ES2015 вместе с оператором расширения, вы легко можете удалить дублирующиеся элементы из массива:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const removeDuplicateItems = arr => &#91;…new Set(arr)];\nremoveDuplicateItems(&#91;42, 'foo', 42, 'foo', true, true]);\n//=> &#91;42, \"foo\", true]</code></pre>\n\n\n\n<h2 id=\"6a52\"><strong>Слияние многоуровневых массивов</strong></h2>\n\n\n\n<p id=\"a4b8\">Вообще слияние многоуровневых массивов довольно тривиально с помощью оператора расширения:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const arr = &#91;11, &#91;22, 33], &#91;44, 55], 66];\nconst flatArr = &#91;].concat(…arr); //=> &#91;11, 22, 33, 44, 55, 66]</code></pre>\n\n\n\n<p>К сожалению, трюк выше сработает только на двухуровневых массивах. Но с рекурсивными запросами, мы можем применить это для массивов с более чем двумя уровнями:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>function flattenArray(arr) {\n  const flattened = &#91;].concat(...arr);\n  return flattened.some(item => Array.isArray(item)) ?      flattenArray(flattened) : flattened\n;}\nconst arr = &#91;11, &#91;22, 33], &#91;44, &#91;55, 66, &#91;77, &#91;88]], 99]]];\nconst flatArr = flattenArray(arr);\n//=> &#91;11, 22, 33, 44, 55, 66, 77, 88, 99]</code></pre>\n\n\n\n<p class=\"author\"><em>Перевод второй статьи&nbsp;</em><a href=\"https://medium.com/dailyjs/7-hacks-for-es6-developers-4e24ff425d0b\"><em>7 Hacks for ES6 Developers</em></a></p>\n\n\n\n<h2 id=\"6d81\"><strong>Перетасовка переменных</strong></h2>\n\n\n\n<p id=\"f496\">Используйте деструктуризацию массивов для перетасовки переменных. Тут все будет понятно из кода:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>let a = 'world', b = 'hello'\n&#91;a, b] = &#91;b, a]\nconsole.log(a) // -> hello\nconsole.log(b) // -> world\n// Да, это магия, детка!</code></pre>\n\n\n\n<h2 id=\"27a0\">Деструктуризация с async/await</h2>\n\n\n\n<p id=\"793f\">И снова, деструктуризация массивов просто шедевральна. Вместе с&nbsp;<code>async/await</code>&nbsp;она делает невообразимые вещи.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const &#91;user, account] = await Promise.all(&#91;\n  fetch('/user'),\n  fetch('/account')\n])</code></pre>\n\n\n\n<h2 id=\"fdde\"><strong>Дебаггинг</strong></h2>\n\n\n\n<p id=\"f76f\">Для всех кто любит дебаггинг с помощью&nbsp;<code>console.log</code>, вот вам крутой пример и да, я слышал про&nbsp;<code>console.table</code>:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const a = 5, b = 6, c = 7\nconsole.log({ a, b, c })\n// выдаёт объект:\n// {\n//    a: 5,\n//    b: 6,\n//    c: 7\n// }</code></pre>\n\n\n\n<h2 id=\"2044\"><strong>Однострочники</strong></h2>\n\n\n\n<p id=\"3dc8\">Синтаксис может быть гораздо компактнее для операций с массивами.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// Найти максимальное значение\nconst max = (arr) => Math.max(…arr);\nmax(&#91;123, 321, 32]) // вывод: 321\n// Сумма массива\nconst sum = (arr) => arr.reduce((a, b) => (a + b), 0)\nsum(&#91;1, 2, 3, 4]) // вывод: 10</code></pre>\n\n\n\n<h2 id=\"df0b\"><strong>Конкатенация(слияние) массивов</strong></h2>\n\n\n\n<p id=\"2419\">Вообще оператор расширения может использоваться вместо <code>concat</code>:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const one = &#91;'a', 'b', 'c']\nconst two = &#91;'d', 'e', 'f']\nconst three = &#91;'g', 'h', 'i']\n// старый способ #1\nconst result = one.concat(two, three)\n// старый способ #2\nconst result = &#91;].concat(one, two, three)\n// новый\nconst result = &#91;...one, ...two, ...three]</code></pre>\n\n\n\n<h2 id=\"8f3c\"><strong>Клонирование</strong></h2>\n\n\n\n<p id=\"c4d0\">Клонирование массивов и объектов с легкостью:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const obj = { …oldObj }\nconst arr = &#91; …oldArr ]</code></pre>\n\n\n\n<h2 id=\"9789\"><strong>Именованные параметры</strong></h2>\n\n\n\n<p id=\"ad26\">Создание функции и ее вызов можно сделать более читабельным с помощью деструктуризации:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const getStuffNotBad = (id, force, verbose) => {\n  ...do stuff\n}\nconst getStuffAwesome = ({ id, name, force, verbose }) => {\n  ...do stuff\n}\n// Где то там в коде, что такое вообще true, true и к чему оно?\ngetStuffNotBad(150, true, true)\n// А вот уже по другому... I ❤ JS!!!\ngetStuffAwesome({ id: 150, force: true, verbose: true })</code></pre>\n\n\n\n<p>И третья, бонусная статья аж 2013-го года. Все эти практики уже давно знакомы, но все же самые интересные из них не помешает закрепить.</p>\n\n\n\n<p class=\"author\"><em>Перевод статьи&nbsp;</em><a href=\"https://hackernoon.com/javascript-hacks-for-hipsters-624d50c76e8e\"><em>Javascript Hacks for Hipsters</em></a></p>\n\n\n\n<h2 id=\"d5fa\"><strong>Вызов метода</strong></h2>\n\n\n\n<p id=\"55e2\">Я реально не люблю блоки&nbsp;<code>if</code>/<code>else</code>&nbsp;и это довольно полезный трюк для вызова нужной функции, основываясь на булиных значениях.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// Скукота\nif (success) {\n  obj.start();\n} else {\n  obj.stop();\n}\n\n// По-хипстерски\nvar method = (success ? 'start' : 'stop');\nobj&#91;method]();</code></pre>\n\n\n\n<h2 id=\"c36f\"><strong>Совмещаем строки</strong></h2>\n\n\n\n<p id=\"7993\">Известный факт, что строки подобны другим строкам. И рано или поздно вы бы захотели связать две или более из них. Мне действительно не нравится работа с плюсом, по-этому&nbsp;<code>join()</code>&nbsp;приходит на помощь.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>&#91;'first', 'name'].join(' '); // = 'first name';\n\n&#91;'milk', 'coffee', 'sugar'].join(', '); // = 'milk, coffee, sugar'</code></pre>\n\n\n\n<h2 id=\"8796\"><strong>Дефолтный оператор</strong></h2>\n\n\n\n<p id=\"307b\">JavaScript сам по себе не знает, что содержит объект. Иногда вы получаете его как аргумент функции, в другой раз вы можете прочесть его из сети или из файла конфигурации. В любом случае, вы можете использовать&nbsp;<code>||</code>&nbsp;оператор, чтобы использовать второй аргумент, если первый выдает&nbsp;<code>false</code>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// Ставим по дефолту 'No name' когда myName пуст (или null, или undefined)\nvar name = myName || 'No name';\n\n\n// Убеждаемся, есть ли у нас объект options\nvar doStuff = function(options) {\n  options = options || {};\n  // ...\n};</code></pre>\n\n\n\n<h2 id=\"010c\"><strong>Оператор на страже точности &amp;&amp;</strong></h2>\n\n\n\n<p id=\"73f2\">Схожий с дефолтным оператором, этот оператор супер полезен. Он исключает буквально все&nbsp;<code>if</code>&nbsp;запросы и делает код куда лучше.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// Скучно\nif (isThisAwesome) {\n  alert('yes'); // нет\n}\n\n// Отлично\nisThisAwesome &amp;&amp; alert('yes');\n\n// Ещё один крутой подход\nvar aCoolFunction = undefined;\naCoolFunction &amp;&amp; aCoolFunction(); // не запустится и не закрэшится</code></pre>\n\n\n\n<p></p>\n","date":"2020-10-28T12:52:30.000Z","title":"Лучшие советы и уловки JavaScript","id":"8a6751b2-7989-53d0-a5c0-5170ecbcf456","excerpt":"<p>По факту эти техники сохранят вам кучуко времени. Возможно большинство из них вам уже знакомо, возможно некоторые нет. Но в любом случае, они будут вам крайне полезны.</p>\n","type":"js","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2020/10/DglYtvO7Bn0-5.jpg"}}},{"node":{"slug":"interesnie-novovvedeniya-v-javascript-es2021","content":"\n<p>В этой статье вы узнаете про интересные нововведения в JavaScript, которые ожидают нас в 2021 году. Не все конечно, но тут собраны и описаны самые интересные из них.</p>\n\n\n\n<p class=\"author\"><em><a href=\"https://codeburst.io/exciting-features-of-javascript-es2021-es12-1de8adf6550b\" data-type=\"URL\" data-id=\"https://codeburst.io/exciting-features-of-javascript-es2021-es12-1de8adf6550b\">Перевод JavaScript ES2021 Exciting Features</a></em></p>\n\n\n\n<p>Каждый год в JavaScript добавляется новый функционал. В этом году был зарелизен ES2020 или ES11, теперь мы ожидаем релиза ES2021(ES12), который намечается на середину 2021-го года.</p>\n\n\n\n<p>Новый функционал, каждый год добавляемый в JS, проходит через четыре стадии рассмотрения. В этой статье мы обсудим тот функционал, который уже находится на 4-й стадии, то есть на последней и который уже был успешно добавлен в Google Chrome V8.</p>\n\n\n\n<p>Функционал, который мы будем обсуждать в этой статье:</p>\n\n\n\n<p><code>String.prototype.replaceAll</code></p>\n\n\n\n<p><code>Promise.any</code></p>\n\n\n\n<p>Логические операторы и выражения присваивания</p>\n\n\n\n<p>Числовые разделители</p>\n\n\n\n<p><code>Intl.ListFormat</code></p>\n\n\n\n<p><code>dateStyle</code> и <code>timeStyle</code> для <code>Intl.DateTimeFormat</code></p>\n\n\n\n<h2>String.prototype.replaceAll</h2>\n\n\n\n<p>В JavaScript метод <code>replace()</code> заменяет только первый совпадающий элемент в строке. Если нам понадобится заменить все совпадения, то мы сможем сделать только только с помощью регулярных выражений.</p>\n\n\n\n<p>Предложенный в ES2020 метод <code>replaceAll()</code> отдаёт новую строку, где все подходящие символы будут заменены на другие. Это могут быть строки или регулярные выражения, а заменять можно будет на строку или функцию, которая будет отрабатывать при каждом совпадении.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>let str = 'I use linux, I love linux'\nstr = str.replaceAll('linux', 'windows');\n\nconsole.log(str)\n\n/****  Output  ****/\n// I use windows, I love windows</code></pre>\n\n\n\n<h2>Promise.any</h2>\n\n\n\n<p>В ES2020 нам представят метод <code>Promise.any()</code>, который резко останавливается и сразу отдаёт значение, как только выполнится первый промис из списка выполняемых промисов. Если выполнение всех промисов закончится неудачей, то будет выдана ошибка.</p>\n\n\n\n<p>Этот метод конечно же отличается от <code>Promise.race()</code> тем, что последний останавливается и выдает промис вне зависимости от результата его выполнения.</p>\n\n\n\n<p><strong>Пример 1а:</strong> Несмотря на то, что неудачно завершившийся промис заканчивает работу раньше, чем успешно завершившийся. <code>Promise.any()</code> отдаст первый из успешно завершившихся.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>Promise.any(&#91;\n  new Promise((resolve, reject) => setTimeout(reject, 200, 'Third')),\n  new Promise((resolve, reject) => setTimeout(resolve, 1000, 'Second')),\n  new Promise((resolve, reject) => setTimeout(resolve, 2000, 'First')),\n])\n.then(value => console.log(`Result: ${value}`))\n.catch (err => console.log(err))\n\n/****  Output  ****/\n// Result: Second</code></pre>\n\n\n\n<p><strong>Пример 1б:</strong> Когда все промисы неудачно завершаются, то выдает AggregatorError.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>Promise.any(&#91;\n  Promise.reject('Error 1'),\n  Promise.reject('Error 2'),\n  Promise.reject('Error 3')\n])\n.then(value => console.log(`Result: ${value}`))\n.catch (err => console.log(err))\n\n/****  Output  ****/\n// AggregateError: All promises were rejected\n</code></pre>\n\n\n\n<h2><strong>Логические операторы и выражения присваивания</strong></h2>\n\n\n\n<p>В JavaScript существует много выражений присваивания и логических операторов, например как тут:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// Выражение присвивания\nlet num = 5\nnum+=10\nconsole.log(num) // 15\n\n// Логический оператор\nlet num1 = 6\nlet num2 = 3\nconsole.log(num1 === 6 &amp;&amp; num2 === 2) // false\nconsole.log(num1 === 6 || num2 === 2) // true</code></pre>\n\n\n\n<p>С помощью нового функционала мы сможем комбинировать логические операторы и выражения присваивания. Ниже вы увидите несколько примеров с <code>&amp;&amp;</code>, <code>||</code> и <code>??</code>:</p>\n\n\n\n<h3>Логический оператор назначения с &amp;&amp;</h3>\n\n\n\n<p>Тут мы выставляем значение левосторонней переменной только в том случае, если правая имеет значение <code>true</code>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>let num1 = 5\nlet num2 = 10\n\nnum1 &amp;&amp;= num2\n\nconsole.log(num1) // 10\n\n// можно записать как\n// 1. num1 &amp;&amp; (num1 = num2)\n// 2. if (num1) num1 = num2</code></pre>\n\n\n\n<h3>Логический оператор назначения с ||</h3>\n\n\n\n<p>Тут мы выставляем значение <code>num1</code> на левую переменную только в том случае, если последняя будет <code>false</code>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>let num1\nlet num2 = 10\n\nnum1 ||= num2\n\nconsole.log(num1) // 10\n\n// можно записать как\n// 1. num1 || (num1 = num2)\n// 2. if (!num1) num1 = num2</code></pre>\n\n\n\n<h3>Логический оператор назначения с ??</h3>\n\n\n\n<p>В ES2020 был представлен Nullish Coalescing оператор, который можно совмещать с оператором назначения. Он назначает правую переменную левой переменной только в случае, если последняя имеет значение <code>undefined</code> или <code>null</code>.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>let num1\nlet num2 = 10\n\nnum1 ??= num2\nconsole.log(num1) // 10\n\nnum1 = false\nnum1 ??= num2\nconsole.log(num1) // false\n\n// можно записать как\n// num1 ?? (num1 = num2)</code></pre>\n\n\n\n<h2><strong>Числовые разделители</strong></h2>\n\n\n\n<p>С приходом числовых разделителей станет куда проще читать и воспринимать числовые значения, применяя <code>_</code>(нижнее подчеркивание), раздавая разделители группам цифр. Для примера:</p>\n\n\n\n<pre class=\"wp-block-code\"><code>let number = 100_000 \n\nconsole.log(number)\n\n/****  Output  ****/\n// 100000</code></pre>\n\n\n\n<h2><strong>Intl.ListFormat</strong></h2>\n\n\n\n<p>Этот объект принимает два параметра, каждый из которых является опциональным. Первый это заданный язык(локаль), а второй это объект с параметрами у которых есть два свойства &#8212; стиль и тип.</p>\n\n\n\n<p><code>new Intl.ListFormat([locales[, options]])</code></p>\n\n\n\n<p>В <code>Intl.ListFormat</code> есть метод под названием <code>format()</code>, который получает массив как аргумент и форматирует его разными способами в зависимости от языка.</p>\n\n\n\n<p>Ниже есть несколько примеров в которых показаны различные комбинации для локалей.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>const arr = &#91;'Pen', 'Pencil', 'Paper']\n\nlet obj = new Intl.ListFormat('en', { style: 'short', type: 'conjunction' })\nconsole.log(obj.format(arr)) \n\n/****  Output  ****/\n// Pen, Pencil, &amp; Paper\n\n\nobj = new Intl.ListFormat('en', { style: 'long', type: 'conjunction' })\nconsole.log(obj.format(arr)) \n\n/****  Output  ****/\n// Pen, Pencil, and Paper\n\n\nobj = new Intl.ListFormat('en', { style: 'narrow', type: 'conjunction' })\nconsole.log(obj.format(arr)) \n\n/****  Output  ****/\n// Pen, Pencil, Paper\n\n\n// Итальянский\nobj = new Intl.ListFormat('it', { style: 'short', type: 'conjunction' })\nconsole.log(obj.format(arr)) \n\n/****  Output  ****/\n// Pen, Pencil e Paper\n\n\n// Немецкий\nobj = new Intl.ListFormat('de', { style: 'long', type: 'conjunction' })\nconsole.log(obj.format(arr)) \n\n/****  Output  ****/\n// Pen, Pencil und Paper</code></pre>\n\n\n\n<h2><strong>dataStyle и timeStyle опции для Intl.DateTimeFormat</strong></h2>\n\n\n\n<p><code>Intl.DateTimeFormat</code> это объект конструктор для объектов, которые включают в себя формат даты и отображения времени зависимые от используемого языка. &nbsp;<code>dateStyle</code>&nbsp;и&nbsp;<code>timeStyle</code> опции могут быть использованы для запроса специфического отображения даты или времени в заданной длине.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// Только время в коротком формате\nlet o = new Intl.DateTimeFormat('en' , { timeStyle: 'short' })\nconsole.log(o.format(Date.now()))\n// 11:27 PM\n\n\n// Только время в обычном формате\no = new Intl.DateTimeFormat('en' , { timeStyle: 'medium'})\nconsole.log(o.format(Date.now()))\n// 11:27:57 PM\n\n\n// Время в расширенном формате\no = new Intl.DateTimeFormat('en' , { timeStyle: 'long' })\nconsole.log(o.format(Date.now()))\n// 11:27:57 PM GMT+11\n\n\n// Только дата в сокращенном формате\no = new Intl.DateTimeFormat('en' , { dateStyle: 'short'})\nconsole.log(o.format(Date.now()))\n// 10/6/20\n\n\n// Только дата в обычном формате\no = new Intl.DateTimeFormat('en' , { dateStyle: 'medium'})\nconsole.log(o.format(Date.now()))\n// Oct 6, 2020\n\n\n// Только дата в расширенном формате\no = new Intl.DateTimeFormat('en' , { dateStyle: 'long'})\nconsole.log(o.format(Date.now()))\n// October 6, 2020</code></pre>\n\n\n\n<p><code>dateStyle</code> и <code>timeStyle</code> используются вместе с разными лингвистическими тегами, как показано на примере ниже:</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>let abc\n\n// Английский\nabc = new Intl.DateTimeFormat('en' , { timeStyle: 'short', dateStyle: 'long'})\nconsole.log(abc.format(Date.now()))\n// October 6, 2020 at 11:40 PM\n\n\n// Итальянский\nabc = new Intl.DateTimeFormat('it' , { timeStyle: 'short', dateStyle: 'long'})\nconsole.log(abc.format(Date.now()))\n// 6 ottobre 2020 23:40\n\n\n// Немецкий\nabc = new Intl.DateTimeFormat('de' , { timeStyle: 'short', dateStyle: 'long'})\nconsole.log(abc.format(Date.now()))\n// 6. Oktober 2020 um 23:40</code></pre>\n","date":"2020-10-23T15:22:12.000Z","title":"Интересные нововведения в JavaScript ES2021","id":"0e8c7ec4-a6d1-5af6-9cd0-692be5438131","excerpt":"<p>В этой статье вы узнаете про интересные нововведения в JavaScript, которые ожидают нас в 2021 году. Не все конечно, но в этой тут собраны и описаны самые интересные из них.</p>\n","type":"js","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2020/10/DglYtvO7Bn0-2.jpg"}}},{"node":{"slug":"13-interesnih-momentov-po-stilizacii-koda-ot-google","content":"\n<p>Для тех кто еще не в курсе, Google выложил&nbsp;<a rel=\"noreferrer noopener\" href=\"https://google.github.io/styleguide/jsguide.html\" target=\"_blank\">стилевое руководство по написанию JavaScript</a>, которое излагает лучшие стилистические практики по написанию ясного и понимаемого кода.</p>\n\n\n\n<p class=\"author\"><a rel=\"noreferrer noopener\" href=\"https://medium.freecodecamp.org/google-publishes-a-javascript-style-guide-here-are-some-key-lessons-1810b8ad050b\" target=\"_blank\"><em>Перевод статьи 13 Noteworthy Points from Google’s JavaScript Style Guide</em></a></p>\n\n\n\n<p id=\"c250\">Там нет строгих правил для написания валидного JavaScript, а есть только советы для написания последовательного и привлекательного кода для всех ваших проектов. Особенно это интересно для JavaScript, который сам по себе гибкий и довольно многообразный язык, позволяющий использовать широкий выбор стилизации кода.</p>\n\n\n\n<p id=\"0e26\">У Google и Airbnb есть два самых популярных стилевых руководства по этой теме. Я определенно советую вам ознакомится с обоими, если вы проводите много времени с JavaScript.</p>\n\n\n\n<p id=\"dc28\">Далее в статье будут тринадцать самых интересных замечаний и релевантных правил из <strong>Google JS Style Guide</strong>.</p>\n\n\n\n<p id=\"b251\">Они покрывают весь спектр работы с кодом, от спорных вопросов до неясных спецификакций, которые удивили даже меня. Конечно же, они изменят суть того, как я буду писать JavaScript в будущем.</p>\n\n\n\n<p id=\"6ead\">Для каждого правила я дам краткое изложение по спецификации, подкрепленное цитатой из стилевого руководства, которое описывает правило в деталях. Где это будет возможно, я покажу пример стиля на практике и сопоставлю его с кодом, который не подходит этому правилу.</p>\n\n\n\n<h2>Используйте пробелы, а не табы (табуляцию)</h2>\n\n\n\n<blockquote class=\"wp-block-quote\"><p><em>Кроме символа разграничителя строки, ASCII символ горизонтального пробела (0х20) — единственный символ пробела/разграничителя, который появляется где-либо в исходном файле. Это подразумевает то, что Tab символы не используются для отступов.</em></p></blockquote>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// плохо\nfunction foo() {\n∙∙∙∙let name;\n}\n\n// плохо\nfunction bar() {\n∙let name;\n}\n\n// хорошо\nfunction baz() {\n∙∙let name;\n}</code></pre>\n\n\n\n<h2><strong>Точки с запятыми необходимы</strong></h2>\n\n\n\n<blockquote class=\"wp-block-quote\"><p>Каждое объявление должно заканчиваться на точку с запятой.</p><p>Запрещается полагаться на автоматическую вставку этих символов.</p></blockquote>\n\n\n\n<p id=\"f677\">Хоть я и не могу представить, почему кто-то против этой идеи, но  использование точек с запятыми в JS становится новыми дебатами масштаба ‘spaces versus tabs’.</p>\n\n\n\n<p id=\"6cac\">Google твердо обозначил свою позицию в защиту использования точки с запятой.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// плохо\nlet luke = {}\nlet leia = {}\n&#91;luke, leia].forEach(jedi => jedi.father = 'vader')\n\n// хорошо\nlet luke = {};\nlet leia = {};\n&#91;luke, leia].forEach((jedi) => {\n  jedi.father = 'vader';\n});</code></pre>\n\n\n\n<h2><strong>Пока что не используйте модули ES6</strong></h2>\n\n\n\n<blockquote class=\"wp-block-quote\"><p>Не применяйте модули из ES6, пока что (т.е. слова export и import), так как их семантика пока не не финализирована. Обратите внимание, что это правило будет пересмотрено, после того, как семантика станет полным стандартом.</p></blockquote>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// Не делайте пока что такие вещи:\n// — — — lib.js — — —\nexport function square(x) {\n    return x * x\n}\nexport function diag(x, y) {\nreturn sqrt(square(x) + square(y));\n}\n//------ main.js ------\nimport { square, diag } from 'lib';</code></pre>\n\n\n\n<h2><strong>Горизонтальное выравнивание это конечно плохо, но не запрещено</strong></h2>\n\n\n\n<blockquote class=\"wp-block-quote\"><p><em>Эта практика допустима, но в основном это считается дурным тоном следуя стилю от Google. Не нужно даже продолжать использовать горизонтальные выравнивания в местах, где это уже использовалось.</em></p></blockquote>\n\n\n\n<p>Горизонтальное выравнивание это практика добавления большого количества пробелов в ваш код, чтобы определенные символы появлялись прямо под другими символами на предыдущей строке.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// плохо\n{\n    tiny:   42,  \n    longer: 435, \n  };\n  // хорошо\n  {\n    tiny: 42, \n    longer: 435,\n  };</code></pre>\n\n\n\n<h2><strong>Больше не используйте var</strong></h2>\n\n\n\n<blockquote class=\"wp-block-quote\"><p>Объявляйте все локальные переменные с помощью const или let. Используйте const по дефолту, пока переменную не надо будет переназначить. Слово var не должно использоваться.</p></blockquote>\n\n\n\n<p>Я до сих пор вижу людей, которые используют слово <code>var</code> в примерах кода. Не могу сказать, есть ли для этого веские причины или это просто дело долгоумерающей привычки.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// плохо\nvar example = 42;\n// хорошо\nlet example = 42;</code></pre>\n\n\n\n<h2><strong>Стрелочные функции предпочтительнее</strong></h2>\n\n\n\n<blockquote class=\"wp-block-quote\"><p><em>Стрелочные функции дают краткий синтаксис и решают много сложностей с ним. Предпочитайте стрелочные функции вместо слова function, особенно во вложенных функциях.</em></p></blockquote>\n\n\n\n<p>Буду честен, я просто думал, что стрелочные функции это отлично, потому что они короче и вообще лучше выглядят. Но оказывается, что у них довольно важное предназначение в плане упрощения написания кода.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// плохо\n&#91;1, 2, 3].map(function (x) {\n  const y = x + 1;\n  return x * y;\n});\n\n// хорошо\n&#91;1, 2, 3].map((x) => {\n  const y = x + 1;\n  return x * y;\n});</code></pre>\n\n\n\n<h2><strong>Используйте шаблонные строки вместо их объединения</strong></h2>\n\n\n\n<blockquote class=\"wp-block-quote\"><p>Используйте шаблонные строки, обозначемые с помощью `, вместо сложного объединнения строк, особенно если есть несколько строчных литералов. К тому же, они могут быть в несколько строк.</p></blockquote>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// плохо\nfunction sayHi(name) {\n  return 'How are you, ' + name + '?';\n}\n\n// плохо\nfunction sayHi(name) {\n  return &#91;'How are you, ', name, '?'].join();\n}\n\n// плохо\nfunction sayHi(name) {\n  return `How are you, ${ name }?`;\n}\n\n// хорошо\nfunction sayHi(name) {\n  return `How are you, ${name}?`;\n}</code></pre>\n\n\n\n<h2><strong>Не используйте <strong>line continuations</strong> для длинных строк</strong></h2>\n\n\n\n<blockquote class=\"wp-block-quote\"><p>Не применяйте line continuations как в обычных строках, так и в шаблонных строках. Пусть даже ES5 позволяет делать это, такой подход может привести с неловким ошибкам, если какой-нибудь пробел будет после слеша и это менее очевидно для читателей.</p></blockquote>\n\n\n\n<p id=\"130e\">Интересен тот момент, что это правило по которому мнения Google и Airbnb расходятся.&nbsp;<a href=\"https://github.com/airbnb/javascript#strings--line-length\" target=\"_blank\" rel=\"noreferrer noopener\">Вот пример Airbnb</a>.</p>\n\n\n\n<p id=\"63fd\">В то время, как Google рекомендует связывать длинные строки, как показано ниже, руководство от Airbnb советует буквально ничего не делать и допускать длинным строкам тянуться сколько хотят.</p>\n\n\n\n<pre class=\"wp-block-code\"><code>// Плохо (Извините, это не показывается как надо на мобильных)\nconst longString = 'This is a very long string that \\\n    far exceeds the 80 column limit. It unfortunately \\\n    contains long stretches of spaces due to how the \\\n    continued lines are indented.';\n// Хорошо\nconst longString = 'This is a very long string that ' + \n    'far exceeds the 80 column limit. It does not contain ' + \n    'long stretches of spaces since the concatenated ' +\n    'strings are cleaner.';</code></pre>\n\n\n\n<h2>“<strong>for… of” предпочтительный тип цикла for</strong></h2>\n\n\n\n<blockquote class=\"wp-block-quote\"><p><em>В ES6, у языка теперь три разных типа циклов for. Их все можно использовать, хотя for-of циклы должны быть предпочтительнее, если возможно.</em></p></blockquote>\n\n\n\n<p id=\"5e48\">Это странно, если вы спросите меня, но я думаю это надо упомянуть, так как довольно интересно, что Google объявил предпочтительный тип цикла loop.</p>\n\n\n\n<p id=\"aee0\">Я был всегда впечатлен тем, что <code>for…in</code> циклы были лучше для объектов, в то время как <code>for…of </code>были лучше для массивов. В общем правильный инструмент для подходящей ситуации.</p>\n\n\n\n<p id=\"a678\">Пока спецификация Google не противоречит этой идее, до сих пор интересно узнать, почему они сделали предпочтение в сторону этого цикла.</p>\n\n\n\n<h2><strong>Не используйте eval()</strong></h2>\n\n\n\n<blockquote class=\"wp-block-quote\"><p>Не используйте eval или Function(…string) конструктор, кроме кодлоадеров. Этот функционал потенциально опасен и просто не работает в CSP среде.</p></blockquote>\n\n\n\n<p>На страничке <code>eval()</code> в MDN, даже есть секция под названием <strong>“Не используйте eval!”</strong></p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// плохо\nlet obj = { a: 20, b: 30 };\nlet propName = getPropName();  // returns \"a\" or \"b\"\neval( 'var result = obj.' + propName );\n\n// хорошо\nlet obj = { a: 20, b: 30 };\nlet propName = getPropName();  // returns \"a\" or \"b\"\nlet result = obj&#91; propName ];  //  obj&#91; \"a\" ] is the same as obj.a</code></pre>\n\n\n\n<h2><strong>Константы должны именоваться ЗАГЛАВНЫМИ_БУКВАМИ разделенные нижними подчеркиваниями</strong></h2>\n\n\n\n<blockquote class=\"wp-block-quote\"><p>Если вы уверены в том, что какие-либо переменные не должны меняться, вы можете указать это написав имя переменной с большой буквы. Это сделает неизменность константы очевидной, как только она начнет использоваться по всему коду.</p></blockquote>\n\n\n\n<p><strong>НО</strong> есть примечательное исключение для этого случая, это константы в функциях. Тут они должны писаться камелКейсом или по-русски горбатым регистром.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// Плохо\nconst number = 5;\n// Хорошо\nconst NUMBER = 5;</code></pre>\n\n\n\n<h2><strong>По переменной на объявление</strong></h2>\n\n\n\n<blockquote class=\"wp-block-quote\"><p><em>Каждая локальная переменная объявляет только одну переменную: такие объявления как let a = 1, b =2 не используются.</em></p></blockquote>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// bad\nlet a = 1, b = 2, c = 3;\n// good\nlet a = 1;\nlet b = 2;\nlet c = 3;</code></pre>\n\n\n\n<h2><strong>Используйте одинарные кавычки, а не двойные</strong></h2>\n\n\n\n<blockquote class=\"wp-block-quote\"><p>Обычные строчные литералы заключаются в одинарные кавычки, а не в двойные.</p></blockquote>\n\n\n\n<p>Совет: если строка содержит один символ цитирования, то рассмотрите использование шаблонных строк во избежании выхода из области цитаты.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>// плохо\nlet directive = \"No identification of self or mission.\"\n// плохо\nlet saying = \n'Say it ain\\u0027t so.';\n// хорошо\nlet directive = 'No identification of self or mission.';\n// хорошо\nlet saying = `Say it ain't so`;</code></pre>\n\n\n\n<h2 id=\"14e7\"><strong>И напоследок</strong></h2>\n\n\n\n<p id=\"1b21\">Как я и сказал вначале, это не строгие правила. Google это просто один из технологических гигантов и это просто рекомендации.</p>\n\n\n\n<p id=\"6938\">Интересно посмотреть на стиль рекомендаций, которые выкладывают компании, такие как Google, которые нанимают множество блестящих людей, которые тратят непомерно много времени на написание отличного кода.</p>\n\n\n\n<p id=\"b69f\">Вы можете следовать этим правилам, если хотите. Но всегда будут недовольные и вы спокойно можете пренебречь некоторыми или вообще всеми из этих правил.</p>\n\n\n\n<p id=\"4d4d\">Я лично считаю, что есть несколько случаев, в которых спецификации Airbnb более подходящи, чем от Google. Не важно какую позицию вы занимаете по этим конкретным правилам, все ещё важно соблюдать стилистическую последовательность при написании любого кода.</p>\n","date":"2020-08-17T14:14:10.000Z","title":"13 интересных моментов по стилизации JavaScript кода от Google","id":"9624dab4-aa17-5129-835c-f320b0ba8e95","excerpt":"<p>Для тех кто еще не в курсе, Google выложил стилевое руководство по написанию JavaScript, которое излагает лучшие стилистические практики по написанию ясного и понимаего кода.</p>\n","type":"js","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2020/08/DglYtvO7Bn0.jpg"}}}]},"allWordpressWpHtmlCss":{"edges":[{"node":{"slug":"standarty-napisaniya-gibkogo-nadezhnogo-i-zhiznesposobnogo-html-s-css","content":"\n<p id=\"f89b\">Вообще, эта статья является неким руководством по написанию грамотного HTML и CSS. Но явно не полноценным руководством сводом правил или БЭМ, который, кстати, является очень спорным моментом в мире фронт-энда. Но об этом потом.</p>\n\n\n\n<p id=\"4c29\">То, что вы прочитаете, скорее является сводом правил хорошего тона при вёрстке, которые сведут на минимум проблемы с пониманием и рендерингом вашей работы.</p>\n\n\n\n<p class=\"author\" id=\"7e07\">Перевод статьи&nbsp;<a href=\"http://codeguide.co/#html-practicality\"><em>Standards for developing flexible, durable, and sustainable HTML and CSS.</em></a></p>\n\n\n\n<h2 id=\"7336\">HTML</h2>\n\n\n\n<h3 id=\"8818\">Синтаксис</h3>\n\n\n\n<p id=\"0739\">Используйте двойные пробелы — это единственный способ, который будет гарантировать то, что ваш код покажется и отрендерится одинаковым образом в любой среде разработки.</p>\n\n\n\n<p id=\"4fe5\">Вложенные элементы должны иметь только одинарный отступ,&nbsp;<strong>то есть двойным пробелом.</strong></p>\n\n\n\n<p id=\"9dc4\">На&nbsp;атрибутах всегда используйте двойные кавычки, а не одинарные.</p>\n\n\n\n<p id=\"1e38\">Не включайте закрывающий слеш в самозкрывающиеся элементы — HTML5&nbsp;<a href=\"http://dev.w3.org/html5/spec-author-view/syntax.html#syntax-start-tag\">спецификация указывает на то, что они вообще опциональны, но мы то знаем.</a></p>\n\n\n\n<p id=\"0451\">Ни в коем случае не пропускайте закрывающие теги (такие как&nbsp;<code>&lt;/li&gt;</code>&nbsp;или&nbsp;<code>&lt;/body&gt;</code>).</p>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;!DOCTYPE html>\n&lt;html>\n  &lt;head>\n    &lt;title>Заголовок страницы&lt;/title>\n  &lt;/head>\n  &lt;body>\n    &lt;img src=\"images/company-logo.png\" alt=\"Company\">\n    &lt;h1 class=\"hello-world\">Привет, братиш!&lt;/h1>\n  &lt;/body>\n&lt;/html></code></pre>\n\n\n\n<h3 id=\"bf53\">HTML5 doctype</h3>\n\n\n\n<p id=\"50cd\">Чтобы работать в режиме стандартов и последовательного рендеринга элементов в каждом доступном браузере — добавляйте этот простой доктайп в начале каждой HTML страницы. Вообще, всегда старайтесь помнить про стандарты.</p>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;!DOCTYPE html>\n&lt;html>\n  &lt;head>\n  &lt;/head>\n&lt;/html></code></pre>\n\n\n\n<h3 id=\"de68\">Атрибуты языка</h3>\n\n\n\n<p id=\"0954\">Вырезка из спецификации HTML5:</p>\n\n\n\n<p id=\"a989\"><em>Разработчикам рекомендуется указывать атрибут языка в начале html файла, тем самым указывая на принадлежность языка документа. Это способствует&nbsp;</em><strong><em>инструментам генерации голоса</em></strong><em>&nbsp;определить то, какое произношение использовать, а инструментам перевода определить каким правилам придерживаться и так далее.</em></p>\n\n\n\n<p id=\"6e52\"><a href=\"http://www.w3.org/html/wg/drafts/html/master/semantics.html#the-html-element\">Вообще, прочитайте побольше об атрибуте lang в этой спецификации.</a></p>\n\n\n\n<p id=\"b765\">А вот, ссылка на&nbsp;<a href=\"http://reference.sitepoint.com/html/lang-codes\">Sitepoint со списком языковых кодов</a></p>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;html lang=\"ru\">\n  &lt;!-- ... -->\n&lt;/html></code></pre>\n\n\n\n<h3 id=\"e66a\">Режим совместимости IE</h3>\n\n\n\n<p id=\"60f2\">Internet Explorer поддерживает тег использования совместимости&nbsp;<code>&lt;meta&gt;</code>, чтобы указывать то, под какую версию IE должна быть отрендерена страница. Да, пока что обстоятельства этого требуют и самый подходящий способ — это указать IE использовать последний поддерживаемый мод с&nbsp;<strong>edge mode</strong>.</p>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;meta http-equiv=\"X-UA-Compatible\" content=\"IE=Edge\"></code></pre>\n\n\n\n<h3 id=\"b6f3\">Кодировки</h3>\n\n\n\n<p id=\"eaab\">Легко и быстро делайте правильный рендеринг вашего контента, указывая точную кодировку вашим страницам. Так вы можете избежать использования мнемоников в HTML (&nbsp;<em>Это &amp;nbsp; и т.п. В общем, дальше вы поняли</em>), указывая их точную кодировку документу. В основном, самая ходовая кодировка это&nbsp;<code>UTF-8</code>.</p>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;head>\n  &lt;meta charset=\"UTF-8\">\n&lt;/head></code></pre>\n\n\n\n<h3 id=\"0ce4\">Указание пути к CSS и JavaScript</h3>\n\n\n\n<p id=\"3b56\">По спецификации HTML5, нет нужды в конкретном указании type при вставке CSS и JavaScript файлов, добавля как&nbsp;<code>text/css</code>&nbsp;так и&nbsp;<code>text/javascript</code>&nbsp;как страндартные указатели на типы подключаемых файлов. Теперь это лишнее.</p>\n\n\n\n<p id=\"4a93\">Просто сделайте так:</p>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;!-- Внешний CSS -->\n&lt;link rel=\"stylesheet\" href=\"code-guide.css\">\n\n&lt;!-- Внутренний CSS -->\n&lt;style>\n  /* ... */\n&lt;/style>\n\n&lt;!-- JavaScript -->\n&lt;script src=\"code-guide.js\">&lt;/script></code></pre>\n\n\n\n<h3 id=\"e7aa\">Практичность прежде всего</h3>\n\n\n\n<p id=\"5719\">Старайтесь поддерживать HTML стандарты и семантику,&nbsp;<strong>но не ценой практичности</strong>. Используйте как можно меньше разметки с наименее возможным количеством запутанных моментов и спорных вложений.</p>\n\n\n\n<h3 id=\"3cd8\">Порядок атрибутов</h3>\n\n\n\n<p id=\"a75c\">HTML атрибуты должны располагаться именно в таком порядке для облегчения чтения кода:</p>\n\n\n\n<pre class=\"wp-block-code\"><code>class\nid, name\ndata-*\nsrc, for, type, href, value\ntitle, alt\nrole, aria-*</code></pre>\n\n\n\n<p>Классы сделаны для удобного переиспользования компонентов, так что они идут первыми.&nbsp;<code>ID</code>&nbsp;это уже более специфичные вещи и относится к ним нужно довольно бережно, так что они идут вторыми.</p>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;a class=\"...\" id=\"...\" data-toggle=\"modal\" href=\"#\">\n  Example link\n&lt;/a>\n\n&lt;input class=\"form-control\" type=\"text\">\n\n&lt;img src=\"...\" alt=\"...\"></code></pre>\n\n\n\n<h3 id=\"1ad7\">Булиные атрибуты (Логические атрибуты)</h3>\n\n\n\n<p id=\"6f47\"><em>p.s. тут используется слово булиные для простоты упоминания в тексте, который и так не очень простой. В общем, как в простом сленге разработки.</em></p>\n\n\n\n<p id=\"ae7d\">Это атрибуты, которые нуждаются в необъявленном значении. Да,&nbsp;<code>XHTML</code>&nbsp;требует, чтобы вы объявляли их значение, но в HTML5 нет такого требования.</p>\n\n\n\n<p id=\"e865\">Для дальнейшего чтения, примите во внимание следующую&nbsp;<a href=\"http://www.whatwg.org/specs/web-apps/current-work/multipage/common-microsyntaxes.html#boolean-attributes\">WhatWG секцию по булиным атрибутам.</a></p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p>Присутствие булиных атрибутов на элементе указывает на значение&nbsp;<code>true</code>, а отсутствие атрибута указывает на значение&nbsp;<code>false</code>.</p></blockquote>\n\n\n\n<p id=\"827a\">Если вам&nbsp;<em>необходимо</em>&nbsp;присутствие атрибута, НО наличие его значения вам ненужно, то следуйте этому наставлению WhatWG:</p>\n\n\n\n<p id=\"5780\"><em>Если атрибут есть, его значение должно быть либо пустой строкой, либо каноничным именем атрибута, без заглавного или замыкающего пробела.</em></p>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;input type=\"text\" disabled>\n\n&lt;input type=\"checkbox\" value=\"1\" checked>\n\n&lt;select>\n  &lt;option value=\"1\" selected>1&lt;/option>\n&lt;/select></code></pre>\n\n\n\n<h3 id=\"fb6c\">Сокращение разметки</h3>\n\n\n\n<p id=\"e493\">Где только возможно, избегайте излишних родительских элементов при написании HTML. Во многих случаях это приводит к повторениям и рефакторингу, но в итоге вы получаете меньше HTML. Вот хороший пример:</p>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;!-- Отстой -->\n&lt;span class=\"avatar\">\n  &lt;img src=\"...\">\n&lt;/span>\n\n&lt;!-- Уже получше -->\n&lt;img class=\"avatar\" src=\"...\"></code></pre>\n\n\n\n<h3 id=\"8d20\">Разметка созданная в JavaScript</h3>\n\n\n\n<p id=\"14aa\">Создание разметки в JavaScript файле усложняет поиск контента, усложняет его редактирование и уменьшает скорость его рендеринга.&nbsp;<strong>Избегайте такого подхода всегда, когда это только возможно.</strong></p>\n\n\n\n<h2 id=\"6130\">CSS</h2>\n\n\n\n<h3 id=\"28a0\">Синтаксис</h3>\n\n\n\n<p id=\"e7d7\">Используйте двойные пробелы, это единственный способ гарантировать то, что ваш код везде одинаково отрендерится и будет легко прочитан.</p>\n\n\n\n<p id=\"4e4d\">Группируя селекторы, дайте каждому по строке.</p>\n\n\n\n<p id=\"de30\">Включайте один пробел перед открывающей скобкой блока, чтобы было понятнее.</p>\n\n\n\n<p id=\"bd9b\">Ставьте закрывающие скобки на новой строке.</p>\n\n\n\n<p id=\"b062\">Делайте один пробел после каждого&nbsp;<code>:</code></p>\n\n\n\n<p id=\"f4c0\">Каждое объявление должно появляться на своей собственной строке для получения точного отчета об ошибках. В общем, чтобы видеть на какой строке был сбой.</p>\n\n\n\n<p id=\"12eb\">Заканчивайте каждое объявление точкой с запятой. В последнем объявлении это опционально, но в таком случае ваш код будет более склонен выдать ошибку в самых странных моментах при рендеринге.</p>\n\n\n\n<p id=\"d81f\">Свойства, разделенные запятой, должны включать в себя пробел после каждой запятой. Например как в случае с&nbsp;<code>box-shadow</code>.</p>\n\n\n\n<p id=\"9918\">Не ставьте пробелы после запятых в значениях&nbsp;<code>rgb()</code>,&nbsp;<code>rgba()</code>,&nbsp;<code>hsl()</code>,&nbsp;<code>hsla()</code>, or&nbsp;<code>rect()</code>. Это поможет различать разные значения цвета(запятая, без пробела) от разных значений свойств (запятая с пробелом).</p>\n\n\n\n<p id=\"25b0\">Не добавляйте ноль к свойствам значений или цветовым параметрам, то есть&nbsp;<code>.5</code>&nbsp;вместо&nbsp;<code>0.5</code>&nbsp;и&nbsp;<code>-.5px</code>&nbsp;вместо&nbsp;<code>-0.5px</code>.</p>\n\n\n\n<p id=\"9df2\">Все хекс значения пишите в нижнем регистре, то есть&nbsp;<code>#fff</code>. Буквы в нижнем регистре легче отличить, когда читаешь документ, так как у них больше уникальных очертаний.</p>\n\n\n\n<p id=\"8d1f\">Используйте сокращенные хекс значения, где это только возможно. Например,&nbsp;<code>#fff&nbsp;</code>вместо&nbsp;<code>#ffffff</code>.</p>\n\n\n\n<p id=\"b168\">Заключайте в скобки значения атрибутов в селекторах. Например,&nbsp;<code>input[type=”text”]</code>. Хоть это и опционально, но это хорошая практика в плане логичности.</p>\n\n\n\n<p id=\"e0b0\">Избегайте указывания единиц измерения для нулевых значений. Например,&nbsp;<code>margin: 0</code>, вместо&nbsp;<code>margin: 0px</code>.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>/* Плохой CSS */\n.selector, .selector-secondary, .selector&#91;type=text] {\n  padding:15px;\n  margin:0px 0px 15px;\n  background-color:rgba(0, 0, 0, 0.5);\n  box-shadow:0px 1px 2px #CCC,inset 0 1px 0 #FFFFFF\n}\n\n/* Хороший CSS */\n.selector,\n.selector-secondary,\n.selector&#91;type=\"text\"] {\n  padding: 15px;\n  margin-bottom: 15px;\n  background-color: rgba(0,0,0,.5);\n  box-shadow: 0 1px 2px #ccc, inset 0 1px 0 #fff;\n}</code></pre>\n\n\n\n<h3 id=\"613f\">Порядок объявления</h3>\n\n\n\n<p id=\"ddee\">Следующие объявления, должны группироваться в таком порядке:</p>\n\n\n\n<p id=\"8d15\"><em>Позиционирование</em></p>\n\n\n\n<p id=\"172b\"><em>Box model</em></p>\n\n\n\n<p id=\"ae44\"><em>Типография</em></p>\n\n\n\n<p id=\"ae5c\"><em>Визуализация</em></p>\n\n\n\n<p id=\"0123\">Главное — позиционирование идет первым, так как оно может удалить элемент с потока документа и переопределить относительные стили для box-модели, которая идет следующей, так как указывает размещение и размеры элемента.</p>\n\n\n\n<p id=\"cc80\">Всё остальное, что внутри компонента или не влияет на предыдущие две секции, идет последним:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.declaration-order {\n  /* Позиционирование */\n  position: absolute;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 100;\n\n  /* Box-model */\n  display: block;\n  float: right;\n  width: 100px;\n  height: 100px;\n\n  /* Типография */\n  font: normal 13px \"Helvetica Neue\", sans-serif;\n  line-height: 1.5;\n  color: #333;\n  text-align: center;\n\n  /* Визаулизация */\n  background-color: #f5f5f5;\n  border: 1px solid #e5e5e5;\n  border-radius: 3px;\n\n  /* Всякое */\n  opacity: 1;\n}</code></pre>\n\n\n\n<h3 id=\"03b5\">Не используйте @import</h3>\n\n\n\n<p id=\"d735\">В сравнении с&nbsp;<code>&lt;link&gt;</code>,&nbsp;<code>@import</code>&nbsp;медленнее, добавляет несколько дополнительных запросов странице и может вызывать другие непредвиденные проблемы. Избегайте его применение и делайте уклон на другие решения:</p>\n\n\n\n<p id=\"b6d3\">Используйте несколько&nbsp;<code>&lt;link&gt;</code>&nbsp;элементов</p>\n\n\n\n<p id=\"47ec\">Компилируйте свой CSS с препроцессором, таким как Sass, в один файл.</p>\n\n\n\n<p id=\"8774\">Сливайте вместе ваши CSS файлы с функционалом, предоставленным в Rails, Jekyll и других.</p>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;!-- Используйте link -->\n&lt;link rel=\"stylesheet\" href=\"core.css\">\n\n&lt;!-- Избегайте @imports -->\n&lt;style>\n  @import url(\"more.css\");\n&lt;/style></code></pre>\n\n\n\n<h3>Размещение медиа запросов </h3>\n\n\n\n<p>Размещайте медиа запросы как можно ближе к своим релевантным наборам правил. Не связывайте их через разные таблицы стилей или под конец документа. Делая так, вы только усложните работу с ними в будущем, не говоря уже о том треше, с которым придется столкнуться тому, кто потом будет работать с вашим кодом. Вот обычная хорошая разметка с медиа-запросами:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.element { ... }\n.element-avatar { ... }\n.element-selected { ... }\n\n@media (min-width: 480px) {\n  .element { ...}\n  .element-avatar { ... }\n  .element-selected { ... }\n}</code></pre>\n\n\n\n<h3 id=\"43ef\">Свойства с префиксом</h3>\n\n\n\n<p id=\"9dfa\">Используя вендорные свойства префиксов, делайте отступ каждому свойству так, будто это объявление нового свойства, то есть в линию, для того, чтобы облегчить мультистрочное редактирование.</p>\n\n\n\n<p id=\"68d4\">В Textmate, используйте Text → Edit Each Line in Selection (⌃⌘A). В Sublime Text 2, используйте Selection → Add Previous Line (⌃⇧↑) и Selection → Add Next Line (⌃⇧↓).</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>/* Свойства с префиксами */\n.selector {\n  -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.15);\n          box-shadow: 0 1px 2px rgba(0,0,0,.15);\n}</code></pre>\n\n\n\n<h3 id=\"a668\">Одиночные объявления стилей</h3>\n\n\n\n<p id=\"1f70\">В примерах, где набор правил включает только одно указание стиля, рассмотрите вариант с удалением переноса строк, для улучшения читабельности и быстроты редактирования. Каждый набор правил с несколькими декларациями должен разделяться на разные строки.</p>\n\n\n\n<p id=\"b4cc\">Ключевой фактор тут, это обнаружение ошибок — то есть CSS валидатор подмечает то, что у вас есть синтаксическая ошибка на 183 строке. С одиночной декларацией,&nbsp;<em>вы её не пропустите</em>. В множественном объявлении стилей, разные строки обязательны для сохранения здравого смысла.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>/* Одиночное объявление стиля */\n.span1 { width: 60px; }\n.span2 { width: 140px; }\n.span3 { width: 220px; }\n\n/* Множественное объявление, по стилю на строку */\n.sprite {\n  display: inline-block;\n  width: 16px;\n  height: 15px;\n  background-image: url(../img/sprite.png);\n}\n.icon           { background-position: 0 0; }\n.icon-home      { background-position: 0 -20px; }\n.icon-account   { background-position: 0 -40px; }</code></pre>\n\n\n\n<h3 id=\"8cb6\">Условные сокращения</h3>\n\n\n\n<p id=\"630b\">Ограничивайте себя в использовании условных сокращений, в тех примерах, где вам надо выставлять все доступные значения. По обыкновению, злоупотребляют сокращениями следующих свойств:</p>\n\n\n\n<p id=\"e0f3\"><em>padding</em></p>\n\n\n\n<p id=\"7ca7\"><em>margin</em></p>\n\n\n\n<p id=\"97d9\"><em>font</em></p>\n\n\n\n<p id=\"2bba\"><em>background</em></p>\n\n\n\n<p id=\"bf14\"><em>border</em></p>\n\n\n\n<p id=\"2f59\"><em>border-radius</em></p>\n\n\n\n<p id=\"358a\">Зачастую, нам просто не нужно выставлять все значения в условных сокращениях. Для примера, HTML заголовки выставляют только верхний и нижний margin, так что когда необходимо, переписывайте только два этих значения. Чрезмерное использование сокращений зачастую ведет к медленному рендеренгу кода, с ненужными перезаписями и непреднамеренными побочными эффектами.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>/* Плохой пример */\n.element {\n  margin: 0 0 10px;\n  background: red;\n  background: url(\"image.jpg\");\n  border-radius: 3px 3px 0 0;\n}\n\n/* Хороший пример */\n.element {\n  margin-bottom: 10px;\n  background-color: red;\n  background-image: url(\"image.jpg\");\n  border-top-left-radius: 3px;\n  border-top-right-radius: 3px;\n}</code></pre>\n\n\n\n<h3 id=\"1ce5\">Вложения в Less и Sass</h3>\n\n\n\n<p id=\"ed9a\">Под страхом расстрела избегайте ненужных вложений в препроцессорах. Просто если вы можете это делать, то это не означает того, что вам всегда надо это делать. Рассматривайте использование вложений только в тех случаях, если вам надо масштабировать стили по родителю и если есть несколько элементов для вложения.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>// Без вложения\n.table > thead > tr > th { … }\n.table > thead > tr > td { … }\n\n// С вложением\n.table > thead > tr {\n  > th { … }\n  > td { … }\n}</code></pre>\n\n\n\n<h3 id=\"02e2\">Операторы в Less и Sass</h3>\n\n\n\n<p id=\"1dc2\">Для улучшения читабельности, заключайте математические операции в скобки с пробелом между значениями, переменными и операторами.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>// Плохой пример\n.element {\n  margin: 10px 0 @variable*2 10px;\n}\n\n// Хороший пример\n.element {\n  margin: 10px 0 (@variable * 2) 10px;\n}</code></pre>\n\n\n\n<h3 id=\"a894\">Комментарии</h3>\n\n\n\n<p id=\"32be\">Помните, что код пишется и поддерживается людьми. Убедитесь, что ваш код достаточно описателен, хорошо прокомментирован и доступен для понимания другими. Создавайте комменты в коде, передающие контекст и своё конкретное предназначение. А не просто повторяющие компонент или имя класса.</p>\n\n\n\n<p id=\"195e\">Убеждайтесь в том, что вы пишите полные предложения для больших комментариев и сжатые фразы для заглавных записей.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>/* Плохой пример */\n/* Modal header */\n.modal-header {\n  ...\n}\n\n/* Good example */\n/* Wrapping element for .modal-title and .modal-close */\n.modal-header {\n  ...\n}</code></pre>\n\n\n\n<h3 id=\"052f\">Именование классов</h3>\n\n\n\n<p id=\"7d69\">Пишите классы в нижнем регистре и используйте тире, а не нижние подчеркивания или горбатый регистр. Тире служит как естественный пробел в связанных классах. (<code>.btn</code>&nbsp;и&nbsp;<code>.btn-danger</code>).</p>\n\n\n\n<p id=\"d106\">Избегайте чрезмерных или слишком коротких, спорных определений названий.&nbsp;<code>.btn</code>&nbsp;очень полезно для кнопок, но&nbsp;<code>.s</code>&nbsp;не означает ровным счетом ничего.</p>\n\n\n\n<p id=\"5a7c\">Классы должны быть как можно короче и более сжатыми, на сколько это возможно.</p>\n\n\n\n<p id=\"7b8d\">Используйте имена со смыслом, предпочитайте структурные или целесообразные имена, взамен презентативных.</p>\n\n\n\n<p id=\"44a1\">Добавляйте классам префикс, основываясь на их ближайшем родителе или основном классе.</p>\n\n\n\n<p id=\"a0c6\">Используйте&nbsp;<code>.js-*</code>&nbsp;классы для обозначения поведения, но держите эти классы подальше от вашего CSS.</p>\n\n\n\n<p id=\"f520\">Также, очень полезно применять эти правила при раздаче имен переменным в Sass и Less.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>/* Плохой пример */\n.t { ... }\n.red { ... }\n.header { ... }\n\n/* Хороший пример */\n.tweet { ... }\n.important { ... }\n.tweet-header { ... }</code></pre>\n\n\n\n<h3 id=\"edab\">Селекторы</h3>\n\n\n\n<p id=\"0d62\"><strong>Обязательно обратите внимание на эту статью —&nbsp;<a href=\"https://stasonmars.ru/html-css/prokachivaem-naviki-raboty-s-css-selectorami/\">Прокачиваем навыки работы с CSS селекторами</a></strong></p>\n\n\n\n<p id=\"9cd3\">Используйте классы вместо обычных тегов элементов для оптимального рендеринга.</p>\n\n\n\n<p id=\"cada\">Избегайте исползования нескольких селекторов атрибутов, например&nbsp;<code>[class^=\"…\"]</code>, на часто встречающихся компонентах. Известно, что производительность браузера страдает из-за этого.</p>\n\n\n\n<p id=\"5e34\">Сохраняйте селекторы краткими и ограничивайте количество элементов в каждом селекторе до трех.</p>\n\n\n\n<p id=\"6d30\">Масштабируйте классы до ближайшего родителя, только тогда, когда нужно. Когда не используются префиксные классы.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>/* Плохой пример */\nspan { ... }\n.page-container #stream .stream-item .tweet .tweet-header .username { ... }\n.avatar { ... }\n\n/* Хороший пример */\n.avatar { ... }\n.tweet-header .username { ... }\n.tweet .avatar { ... }</code></pre>\n\n\n\n<h3 id=\"b08d\">Организация кода</h3>\n\n\n\n<p id=\"288a\">Организуйте секции кода по компонентам.</p>\n\n\n\n<p id=\"a96e\">Создавайте последовательную иерархию комментирования.</p>\n\n\n\n<p id=\"eea6\">Используйте последовательные пробелы при разделении секций кода, чтобы потом вам было легче читать большие документы.</p>\n\n\n\n<p>Используя несколько CSS файлов, разделяйте их по компонентам, а не по страницам. Страницы могут быть перераспределены, а компоненты смещены.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>/*\n * Начало секции компонента\n */\n\n.element { ... }\n\n\n/*\n * Начало секции компонента\n *\n * Иногда вам надо добавлять дополнительный контекст для целого компонента. Делайте это как описано ниже, при необходимости.\n */\n\n.element { ... }\n\n/* Связанный саб-компонент или модификатор стиля */\n.element-heading { ... }</code></pre>\n\n\n\n<h3 id=\"9ea2\">Предпочтения при редактировании</h3>\n\n\n\n<p id=\"293f\">Выставите вашему редактору следующие настройки, чтобы избежать распространенные несоответствия в коде и странные различия:</p>\n\n\n\n<p id=\"4aa4\">Используйте двойной пробел.</p>\n\n\n\n<p id=\"ffaf\">Обрезайте&nbsp;<em>болтающиеся(лишние)</em>&nbsp;пробелы при сохранении.</p>\n\n\n\n<p id=\"b84a\">Выставляйте кодировку на&nbsp;<code>UTF-8</code>.</p>\n\n\n\n<p id=\"cb7c\">Добавляйте новые строки с конца.</p>\n\n\n\n<p id=\"59b7\">Рассмотрите документирование и применение этих свойств в вашем проекте в&nbsp;<code>.editorconfig</code>&nbsp;файле. Для примера, вот один&nbsp;<a href=\"https://github.com/twbs/bootstrap/blob/master/.editorconfig\">для Bootstrap</a>. Вот больше про&nbsp;<a href=\"http://editorconfig.org/\">EditorConfig</a>.</p>\n","date":"2021-02-14T15:53:49.000Z","title":"Стандарты написания гибкого, надежного и жизнеспособного HTML c CSS","id":"5d29a53f-ec56-5b98-8117-d0f03d17e0f8","excerpt":"<p>Вообще, эта статья является неким руководством по написанию грамотного HTML и CSS. Но явно не полноценным руководством сводом правил или БЭМ, который, кстати, является очень спорным моментом в мире фронт-энда.</p>\n","type":"html-css","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2021/02/standartynaposankjnfk.jpg"}}},{"node":{"slug":"css-svoistvo-background-image-kak-antipattern","content":"\n<p>CSS свойство&nbsp;<code>background-image</code>&nbsp;позволяет нам делать крутые вещи, но в большинстве случаев наступило время оставить его позади. На всякий случай —&nbsp;<a href=\"https://ru.wikipedia.org/wiki/%D0%90%D0%BD%D1%82%D0%B8%D0%BF%D0%B0%D1%82%D1%82%D0%B5%D1%80%D0%BD\">что такое антипаттерн</a>.</p>\n\n\n\n<p class=\"author\"><em>Перевод статьи&nbsp;</em><a href=\"https://nystudio107.com/blog/the-css-background-image-property-as-an-anti-pattern\"><em>The CSS background-image property as an anti-pattern</em></a></p>\n\n\n\n<p id=\"0d7d\">Многие из нас набили руку, используя такое свойство CSS как&nbsp;<code>background-image</code>, делая c ним всё, что только можно. Для многих оно стало просто старым хорошим товарищем, но уже видимо тем, с которым пора распрощаться.</p>\n\n\n\n<p id=\"196b\">Сама проблема заключается не в свойстве&nbsp;<code>background-image</code>&nbsp;как таковом. Зачастую оно используется там, где ему совсем не место, например в CTA изображениях или для графики, имеющей отношение к элементам UI.</p>\n\n\n\n<p id=\"6638\">Если использовать его неправильно, то оно вполне может стать&nbsp;<strong>антипаттерном</strong>. Но есть ли подходящие кейсы для использования&nbsp;<code>background-image</code>? Несомненно есть.</p>\n\n\n\n<p id=\"0059\">Однако, есть несколько серьёзных недостатков при использовании&nbsp;<code>background-image</code>&nbsp;и что куда важнее, уже сейчас у нас есть способы действительно лучше подходящие для работы с изображениями.</p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p>Давайте не будем вспоминать дни танцующих хомячков на фоне.</p></blockquote>\n\n\n\n<p id=\"6dc0\">Перейдем к делу и поговорим о конкретных недостатках использования&nbsp;<code>background-image</code>&nbsp;и затем о том, что мы можем использовать вместо него.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"525\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_yuYUrkMTpxxiYAPXtUPfsA.jpeg\" alt=\"\" class=\"wp-image-223\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_yuYUrkMTpxxiYAPXtUPfsA.jpeg 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_yuYUrkMTpxxiYAPXtUPfsA-300x225.jpeg 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p id=\"75d0\">Вот несколько причин почему использованием&nbsp;<code>background-image</code>&nbsp;может быть плохой практикой в вёрстке:</p>\n\n\n\n<h2 id=\"d18f\"><strong>Это плохо для SEO</strong></h2>\n\n\n\n<p id=\"2b9f\">Изображения, которые лежат в&nbsp;<code>background-image</code>&nbsp;не краулятся или не индексируются Google. Не велика проблема, да? Тогда посмотрите эту цитату из статьи&nbsp;<a href=\"https://moz.com/blog/seo-photos-visuals-graphics-whiteboard-friday\">How to Rank in Google Image Search</a>&nbsp;на&nbsp;<a href=\"http://moz.com/\">moz.com</a>:</p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p><strong>Треть всех поисковых запросов в Google</strong>&nbsp;выходит на изображения и&nbsp;<strong>12.5%</strong>&nbsp;страниц с результатами поиска показывают блоки(карточки) с результатами для изображений.</p></blockquote>\n\n\n\n<p id=\"24dd\">Давайте призадумаемся. Одна треть или 33% всех запросов в Google выходит на изображения. Если картинка релевантна теме страницы или бизнес направлению вашего клиента (а если и нет, то возможно должно быть), вам&nbsp;<em>точно</em>&nbsp;нужно быть проиндексированным.</p>\n\n\n\n<p id=\"3b08\">Если вы используете&nbsp;<code>background-image</code>, то тут вы в пролёте и у вас не может быть тега&nbsp;<code>alt=</code>&#171;&#187;, чтобы отдать Google описание и контекст изображения.</p>\n\n\n\n<h2 id=\"e25c\">Это плохо для доступности (Accessibility)</h2>\n\n\n\n<p id=\"0d5e\">Свойство&nbsp;<code>background-image</code>&nbsp;не очень хорошо сказывается на доступности. Скринридеры будут полностью его игнорировать.</p>\n\n\n\n<p id=\"0f01\">Посмотрите на ограничения с доступностью в этом случае:</p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p>Браузеры не отдают никакой конкретной информации о фоновых изображениях для вспомогательных технологий. Это важно в первую очередь для скринридеров, так как они не будут обозначать присутствие фоновых изображений и следовательно, пользователь не получит никакой полезной информации о них.</p></blockquote>\n\n\n\n<p id=\"0cba\">Даже если скринридеры не полностью игнорируют изображения, в фонах которых нет текста&nbsp;<code>alt=\"\"</code>, который может дать полезное описание об изображении или передать его контекст.</p>\n\n\n\n<p id=\"7351\"><strong>Совет:</strong>&nbsp;Если вы хотите, чтобы скринридер пропустил изображение (ну вдруг это просто элемент дизайна), просто оставьте&nbsp;<code>alt=\"\"</code>&nbsp;пустым (использование&nbsp;<code>role=\"presentation\"</code>&nbsp;тут не самый оптимальный вариант, так как оно нарушает&nbsp;<a href=\"https://www.w3.org/TR/using-aria/#rule1\">первое правило ARIA</a>).</p>\n\n\n\n<h2 id=\"52b8\">Плохо для производительности</h2>\n\n\n\n<p id=\"ee64\">Как свойство&nbsp;<code>background-image</code>&nbsp;может негативно влиять на производительность?</p>\n\n\n\n<p id=\"69bc\">Так как обычно только одно изображение используется для&nbsp;<code>background-image</code>, вне зависимости от ширины экрана устройства или разрешения.</p>\n\n\n\n<p id=\"e730\">Что нам в идеале надо, так это иметь возможность использовать адаптивные изображения таким образом, чтобы браузер мог загрузить разные размеры изображений в зависимости от ширины экрана устройства или разрешения экрана.</p>\n\n\n\n<p id=\"68f6\">Тут ощутимая разница будет заметна на мобильных устройствах или при медленных интернет соединениях, так же как и на вычислительной мощности, требуемой для масштабирования изображений. Посмотрите статью&nbsp;<a href=\"https://nystudio107.com/blog/image-optimization-project-results\">Post-Mortem: Applied Image Optimization</a>.</p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p>На обычном сайте изображения будут&nbsp;<strong>самым тяжелым куском</strong>&nbsp;из отправляемых данных. Мы просто обязаны оптимизировать их.</p></blockquote>\n\n\n\n<p id=\"dc3b\">Пока вы можете это сделать через&nbsp;<code>@media</code>&nbsp;запросы с помощью CSS&nbsp;<code>background-image</code>, но в итоге, это будет довольно обременительным подходом, если вам понадобится изменить изображение или переименовать его, ну или поменять его версию.</p>\n\n\n\n<p id=\"bd89\">Причина по которой это становится таким обременительным в том, что изображение вставлено в ваш CSS, который обычно формируется на стадии сборки страницы, которая в свою очередь не находится под клиентским контролем.</p>\n\n\n\n<p id=\"dfc4\">Так как это всё слишком замудрено, люди просто забивают на этот момент и в итоге имеют одну версию изображения для всех размеров экранов и разрешений.</p>\n\n\n\n<p id=\"6ac4\">Хотя и есть всякие JavaScript библиотеки как&nbsp;<a href=\"https://github.com/aFarkas/lazysizes/tree/gh-pages/plugins/bgset\">bgset</a>, но зачем добавлять ещё больше JavaScript для решения проблемы у которой и так много недостатков?</p>\n\n\n\n<p id=\"5ca1\">Добавьте к этому желание использовать фишки следующего поколения, такие как WebP, как прогрессивное улучшение и всё станет реально плохо с подходом на&nbsp;<code>background-image</code>.</p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p>Ваш браузер просто не может начать скачивать изображение до того, как он не скачает и не запарсит CSS.</p></blockquote>\n\n\n\n<p id=\"f299\">Ещё одна польза в том, что если ваши изображения вставлены в CSS через&nbsp;<code>background-image</code>, браузеру нужно скачать и запарсить ваш CSS, перед тем, как он сможет запросить изображения.</p>\n\n\n\n<p id=\"69c8\">Это говорит о том, что ваше “<strong>основное</strong>” изображение будет понижено в очереди загрузок и довольно медленно загрузится, имея низкий приоритет. Если вы используете изображения через HTML элементы, то браузер может запросить их куда быстрее, иногда даже перед началом загрузки стилей страницы.</p>\n\n\n\n<h2 id=\"67b7\">Плохо для CMS и CDN</h2>\n\n\n\n<p id=\"bbee\">Свойство&nbsp;<code>background-image</code>&nbsp;также не очень хорошо, если дело касается CMS’ок и CDN’ов.</p>\n\n\n\n<p id=\"72d4\">Давайте представим, что у нас есть главное изображение на сайте, которое я показываю с помощью&nbsp;<code>background-image</code>&nbsp;в&nbsp;<code>div</code>.</p>\n\n\n\n<p id=\"fd6d\">Люди со всего мира заходят на этот сайт и мне нужно, чтобы CDN доставлял им эти ресурсы оптимально быстрым способом.</p>\n\n\n\n<p id=\"5467\">Если у меня есть ссылка на изображение, вставленная в CSS, то я сделаю глобальный поиск в редакторе и заменю все свои изображения, а вернее ссылки на них с локальных на CDN’овские.</p>\n\n\n\n<p id=\"7c08\">Если вы предварительно выставили ссылки на изображения, как переменные с помощью CSS Variables, то вам повезло! Но большинство людей так не делает и необходимость в создании и деплое CSS с обновленными ресурсами, всякий раз как вы хотите обновить ваши изображения кажется ну уж слишком избыточной для работы с таким таском. Но придется делать либо так, либо генерить инлайновый CSS, но давайте уже обойдемся без этого.</p>\n\n\n\n<p id=\"7802\">Куда проще просто дать вашей CMS добавить URL префикс, но это может стать грубоватым подходом, если вы делаете это через CSS&nbsp;<code>background-image</code>, требующим генерацию инлайновых стилей или же если вы прибегаете к другим махинациям с вёрсткой.</p>\n\n\n\n<p id=\"3f99\">Вообще, вставка ссылок на изображения в CSS сейчас мне кажется каким-то&nbsp;<em>хардкодингом</em>.</p>\n\n\n\n<h2 id=\"34cd\">Ну так, а когда это выходит хорошим подходом?</h2>\n\n\n\n<p id=\"f547\">Итак, мы только что обсуждали недостатки, но когда же выходит было бы хорошо воспользоваться&nbsp;<code>background-image</code>?</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"525\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_sKlmyvnuxzCcrYlAG8XKxw.jpeg\" alt=\"\" class=\"wp-image-224\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_sKlmyvnuxzCcrYlAG8XKxw.jpeg 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_sKlmyvnuxzCcrYlAG8XKxw-300x225.jpeg 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p id=\"5810\">Это покажется слишком очевидным, но если вам надо просто добавить декоративное изображение как фон, то это именно тот кейс, в котором нужно использовать&nbsp;<code>background-image</code>!</p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p>Хорошо использовать&nbsp;<code>background-image</code>&nbsp;тогда, когда вам нужно просто фоновое изображение и ничего более.</p></blockquote>\n\n\n\n<p id=\"cfb5\">Если вы так делаете, то рассмотрите использование image-set() вместе с&nbsp;<code>background-image()</code>, чтобы уменьшить проблемы с производительностью, упомянутые выше.</p>\n\n\n\n<p id=\"3cdf\">Не то, чтобы свойство само по себе плохое, просто его впихивали куда ни попадя, для задач в которых оно является далеко не лучшим решением.</p>\n\n\n\n<h2 id=\"aa92\">Используйте &lt;picture&gt;!</h2>\n\n\n\n<p id=\"9ceb\">Я полагаю, что весьма весомой причиной широкого использования&nbsp;<code>background-image</code>&nbsp;является сопутствующее свойство —&nbsp;<code>background-size: cover;</code>, которое точно даст вам знать, что заданное изображение покрывает всю положенную область, к которой оно прикреплено.</p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p>Свойство object-fit уже спешит на помощь!</p></blockquote>\n\n\n\n<p>Если вы используете семантически верный элемент в купе со свойством object-fit, то вы получите тот же самый эффект, что и в случае с background-size: cover;, но также вы получите ещё и такие плюшки: SEO-friendly изображения.</p>\n\n\n\n<p id=\"a03d\">Изображения, которые будут читаемы скринридерами. Тут нужно просто использовать свойство&nbsp;<code>alt=\"\"</code>.</p>\n\n\n\n<p id=\"a316\">Отличную работу с CMS сгенерированными ссылками на изображения и CDN’ами.</p>\n\n\n\n<p id=\"41cd\">Этот подход будет отлично работать с&nbsp;<code>srcset</code>&nbsp;для оптимизированных изображений</p>\n\n\n\n<p id=\"8a04\">Вы сможете использовать&nbsp;<code>&lt;source&gt;</code>&nbsp;для передовых форматов изображений, таких как&nbsp;<code>.webp</code>.</p>\n\n\n\n<p id=\"fde8\">Это вообще не сложно сделать, а профитов немерено! Свойство&nbsp;<code>object-fit</code>&nbsp;указывает изображению или видео то, как оно должно умещаться в родительский контейнер. Вам нужно просто поменять это:</p>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;div style=\"background-image: url('/some/man-with-a-dog.jpg');\n            background-size: cover;\">\n&lt;/div></code></pre>\n\n\n\n<p>На это:</p>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;picture>\n  &lt;img src=\"/some/man-with-a-dog.jpg\"\n       alt=\"Man with a dog\"\n       style=\"object-fit: cover;\"\n  />\n&lt;/picture></code></pre>\n\n\n\n<p id=\"8315\">Очевидно, что в обоих случаях вы бы не стали использовать инлайновые стили, но к нашей радости вы можете видеть то, какой гибкий подход у нас есть под рукой, если бы мы оставили&nbsp;<code>background-image</code>&nbsp;свойство и использовали бы действительно семантические HTML элементы, такие как&nbsp;<code>&lt;picture&gt;</code>&nbsp;и&nbsp;<code>&lt;img&gt;</code>.</p>\n\n\n\n<p id=\"68ec\">Затем мы можем в лёгкую добавить адаптированные по размерам изображения через&nbsp;<code>srcset</code>. Мы также можем легко использовать передовые форматы, такие как .webp на выбор браузера из&nbsp;<code>&lt;source&gt;</code>.</p>\n\n\n\n<p id=\"a60d\">Более того, мы можем воспользоваться преимуществом таких плюшек, как&nbsp;<a href=\"https://addyosmani.com/blog/lazy-loading/\">нативная ленивая загрузка в Chrome</a>, ну и в других бразуерах тоже, как только они её внедрят.</p>\n\n\n\n<p id=\"3e2e\">Вот как бы выглядел код, который делает все эти вещи:</p>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;picture>\n    &lt;source\n        srcset=\"/some/_1170x658_crop_center-center/man-with-a-dog.webp 1170w,\n                /some/_970x545_crop_center-center/man-with-a-dog.webp 970w,\n                /some/_750x562_crop_center-center/man-with-a-dog.webp 750w,\n                /some/_320x240_crop_center-center/man-with-a-dog.webp 320w\"\n        sizes=\"100vw\"\n        type=\"image/webp\"\n    />\n    &lt;source\n        srcset=\"/some/_1170x658_crop_center-center/man-with-a-dog.jpg 1170w,\n                /some/_970x545_crop_center-center/man-with-a-dog.jpg 970w,\n                /some/_750x562_crop_center-center/man-with-a-dog.jpg 750w,\n                /some/_320x240_crop_center-center/man-with-a-dog.jpg 320w\"\n        sizes=\"100vw\"\n    />\n    &lt;img\n        src=\"/some/man-with-a-dog-placeholder.jpg\"\n        alt=\"Man with a dog\"\n        style=\"object-fit: cover;\"\n        loading=\"lazy\"\n    />\n&lt;/picture></code></pre>\n\n\n\n<p id=\"3b37\"><em>Так мы получаем:</em></p>\n\n\n\n<p id=\"e4c7\">Ленивую загрузку, если браузер её поддерживает (в противном случае они не происходит, всё нормально)</p>\n\n\n\n<p id=\"84cf\">webp, если браузер его поддерживает.</p>\n\n\n\n<p id=\"f685\"><code>srcset</code>&nbsp;из оптимизированных адаптивных изображений на выбор браузера.</p>\n\n\n\n<p id=\"6f89\">SEO-friendly, прогрессивное улучшение, доступность и производительность — всё это обернуто в одной, хорошо сделанной компактной вундервафле.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"525\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_vYspc0OoBfjiz52Typht9Q.jpeg\" alt=\"\" class=\"wp-image-225\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_vYspc0OoBfjiz52Typht9Q.jpeg 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_vYspc0OoBfjiz52Typht9Q-300x225.jpeg 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p id=\"0edd\"><strong><em>Boom!</em></strong></p>\n\n\n\n<p id=\"f5f9\">И все эти изображения могут быть автоматически заресайзены прямо из CMS, с помощью таких инструментов, как ImageOptimize, упрощая ссылаемость на CDN или Amazon S3. И в конце концов, вы же можете делать&nbsp;<a href=\"https://alligator.io/css/cropping-images-object-fit/\">обрезку изображений с помощью&nbsp;</a><code><a href=\"https://alligator.io/css/cropping-images-object-fit/\">object-fit</a></code>.</p>\n\n\n\n<h2 id=\"855c\">Со старым в новое!</h2>\n\n\n\n<p id=\"c6a0\"><a href=\"https://caniuse.com/#search=picture\">Поддержка бразуерами&nbsp;</a><code><a href=\"https://caniuse.com/#search=picture\">&lt;picture&gt;</a></code>&nbsp;и&nbsp;<code>scrset</code>&nbsp;фантастически хороша! (есть даже&nbsp;<a href=\"https://scottjehl.github.io/picturefill\">полифилл</a>ы,&nbsp;<a href=\"https://github.com/bfred-it/object-fit-images\">если они</a>&nbsp;вам нужны.<a href=\"https://github.com/bfred-it/object-fit-images)\">)</a>&nbsp;и такая же хорошая поддержка для&nbsp;<code>object-fit</code>&nbsp;(<a href=\"https://github.com/bfred-it/object-fit-images\">тоже есть полифилл</a>). Ещё один хороший паттерн для использования через&nbsp;<a href=\"http://polyfill.io/\">polyfill.io</a>.</p>\n\n\n\n<p id=\"1d27\">В общем, настало время избавиться от&nbsp;<code>background-image</code>&nbsp;в вашем наборе инструментов, кроме тех редких случаев, когда оно вам реально будет нужно по назначению.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"525\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_UbvQz5_BW-rP0WREgCpE1Q.jpeg\" alt=\"\" class=\"wp-image-226\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_UbvQz5_BW-rP0WREgCpE1Q.jpeg 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_UbvQz5_BW-rP0WREgCpE1Q-300x225.jpeg 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p id=\"fbd6\">Пишите код, используя лучшие практики для подавляющего большинства, затем используйте прогрессивное улучшение и при нужде полифиллы. Не будьте закованы в узы прошлого из-за очень маленького процента ваших посетителей, у которых не будет работать это свойство.</p>\n\n\n\n<p id=\"a45f\">Не используйте изображения, как просто картинки; используйте соответствующие семантические HTML элементы.</p>\n\n\n\n<p id=\"f2b8\">Я думаю, что в конечном итоге вы поймете то, что ваши сайты станут более SEO-friendly, более доступны и куда более производительнее… а еще у вас будет ощущение удовлетворенности от написания на семантически грамотном HTML.</p>\n\n\n\n<p id=\"d938\">Свойство CSS&nbsp;<code>background-image</code>&nbsp;никогда не подразумевалось для использования основных изображений или UI элементов. Но сейчас для этого уже есть способы получше, так что давайте их просто использовать.</p>\n\n\n\n<p id=\"aa46\">Если все это заинтересовало вас в плане оптимизации изображений, обратите внимание на отличную книгу&nbsp;<a href=\"http://images.guide/\">images.guide</a>, чтобы узнать об этом ещё больше!</p>\n\n\n\n<p id=\"7729\">Enjoy your&nbsp;<code>object-fit</code>!</p>\n","date":"2021-02-12T13:20:36.000Z","title":"CSS свойство background-image как антипаттерн","id":"b6cd9842-3352-5496-802b-8f2cc9b39eea","excerpt":"<p>CSS свойство background-image позволяет нам делать крутые вещи, но в большинстве случаев наступило время оставить его позади. В этой статье вы узнаете почему это свойство является антипаттерном и чем его заменить</p>\n","type":"html-css","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2021/02/bgimgantipatternfdnsf.jpg"}}},{"node":{"slug":"kak-ya-perestal-ispolzovat-bootstrap-v-ugodu-css-grid","content":"\n<p>Лично я считаю, что в плане веба, Bootstrap ещё рано полностью заменять на CSS Grid. Но перевел эту статью с точки зрения перспективы на будущее, которое уже далеко не за горами.</p>\n\n\n\n<p class=\"author\"><em>Перевод статьи&nbsp;</em><a href=\"https://blog.theodo.fr/2018/03/stop-using-bootstrap-layout-thanks-to-css-grid/?ct=t(hamail_20180515)\"><em>How I stopped using Bootstrap’s layout thanks to CSS Grid</em></a></p>\n\n\n\n<h2 id=\"59ff\">Почему я перестал использовать Bootstrap?</h2>\n\n\n\n<p id=\"97aa\">Bootstrap требует слишком много писанины: вам нужно наплодить много <code>div</code>’ов, даже если вам нужно сделать в макете всего два блока.</p>\n\n\n\n<p id=\"45f1\">Дела становятся еще хуже, когда вы добавляете адаптивность</p>\n\n\n\n<p id=\"f444\">Или когда вы хотите переместить блоки</p>\n\n\n\n<p id=\"c653\">Сетка Bootstrap ограничена 12-ю колонками</p>\n\n\n\n<p id=\"1bf6\">По дефолту, у Boostrap&nbsp;<code>10px</code>&nbsp;внутренние отступы, которые довольно сложно переписать.</p>\n\n\n\n<p id=\"7018\">Bootstrap должен скачиваться со стороны пользователя, что тормозит ваш сайт.</p>\n\n\n\n<h2 id=\"de96\">Как создать разметку для сайта без Bootstrap?</h2>\n\n\n\n<p id=\"3561\">Предположим, что у вас есть следующий шаблон, который вам нужно интегрировать:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"295\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_GExAbQYr_tSQ5-HlmtG4lw.png\" alt=\"\" class=\"wp-image-205\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_GExAbQYr_tSQ5-HlmtG4lw.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_GExAbQYr_tSQ5-HlmtG4lw-300x126.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<h3><strong>Как бы это выглядело с Bootstrap:</strong></h3>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;body>\n  &lt;div class=\"container\">\n    &lt;div class=\"row\">\n      &lt;div class=\"col-12 header\">...&lt;/div>\n    &lt;/div>\n    &lt;div class=\"row\">\n      &lt;div class=\"col-4 navigation-menu\">...&lt;/div>\n      &lt;div class=\"col-8 main-content\">...&lt;/div>\n    &lt;/div>\n    &lt;div class=\"row\">\n      &lt;div class=\"col-12 footer\">...&lt;/div>\n    &lt;/div>\n  &lt;/div>\n&lt;/body></code></pre>\n\n\n\n<p>Хоть у вас всего четыре блока, вам понадобилось аж 9&nbsp;<code>div</code>’ов, чтобы закодить ваш шаблон.</p>\n\n\n\n<h3 id=\"f99b\">Как бы просто это выглядело с CSS Grid</h3>\n\n\n\n<p id=\"d68a\">Спасибо гридам, вы можете получить тот же результат с помощью всего четырёх&nbsp;<code>div</code>’ов.</p>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;body>\n  &lt;div class=\"container\">\n    &lt;div class=\"header\">...&lt;/div>\n    &lt;div class=\"navigation-menu\">...&lt;/div>\n    &lt;div class=\"main-content\">...&lt;/div>\n    &lt;div class=\"footer\">...&lt;/div>\n  &lt;/div>\n&lt;/body></code></pre>\n\n\n\n<p>Хоть это не так просто как с импортом в Bootstrap, но вам надо будет добавить некоторые дополнительные CSS стили.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.container {\n  display: grid;\n  grid-template-columns: repeat(12, 1fr);\n}\n.header {\n  grid-column: span 12;\n}\n.navigation-menu {\n  grid-column: span 4;\n}\n.main-content {\n  grid-column: span 8;\n}\n.footer {\n  grid-column: span 12;\n}</code></pre>\n\n\n\n<p>На примере выше, вы сначала определили 12-ти колоночный контейнер в гридах. А затем выставили количество строк, через которые будет проходить элемент.</p>\n\n\n\n<h2 id=\"d8a8\"><strong>Что там у нас с адаптивностью?</strong></h2>\n\n\n\n<p id=\"6661\">Более того, помимо простой версии, скорее всего вам понадобится адаптивность шаблона не только под смартфоны, но и под планшеты.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"478\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_GyKr6Hd8wKnQC_ACgq5IXQ.png\" alt=\"\" class=\"wp-image-206\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_GyKr6Hd8wKnQC_ACgq5IXQ.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_GyKr6Hd8wKnQC_ACgq5IXQ-300x205.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<h3 id=\"7b1a\"><strong>С Bootstrap это будет выглядеть так</strong></h3>\n\n\n\n<p id=\"6854\">Чем сложнее становится дизайн, тем сложнее и запутанней становится ваш HTML c всё большим и большим количеством классов:</p>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;body>\n  &lt;div class=\"container\">\n    &lt;div class=\"row\">\n      &lt;div class=\"col-xs-12 header\">...&lt;/div>\n    &lt;/div>\n    &lt;div class=\"row\">\n      &lt;div class=\"col-xs-12 col-md-6 col-lg-4 navigation-menu\">...&lt;/div>\n      &lt;div class=\"col-xs-12 col-md-6 col-lg-8 main-content\">...&lt;/div>\n    &lt;/div>\n    &lt;div class=\"row\">\n      &lt;div class=\"col-xs-12 footer\">...&lt;/div>\n    &lt;/div>\n  &lt;/div>\n&lt;/body></code></pre>\n\n\n\n<h3 id=\"6fcf\"><strong>На CSS Grid</strong></h3>\n\n\n\n<p id=\"0866\">Если вы хотите добавить адаптивность вашему шаблону, то впринципе нет нужды в замене HTML.</p>\n\n\n\n<p id=\"7415\">Вам только лишь надо добавить некоторые медиа запросы в ваш CSS:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>...\n@media screen and (max-width: 768px) {\n  .navigation-menu {\n    grid-column: span 6;\n  }\n  .main-content {\n    grid-column: span 6;\n  }\n}\n@media screen and (max-width: 480px) {\n  .navigation-menu {\n    grid-column: span 12;\n  }\n  .main-content {\n    grid-column: span 12;\n  }\n}</code></pre>\n\n\n\n<h1 id=\"6ffc\"><strong>А как насчет подвигать блоки?</strong></h1>\n\n\n\n<p id=\"c3fa\">Скажем, к примеру, что вместо на мобильных устройствах вы хотите навигационную панель над шапкой:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"478\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_ndnFvkhKgfhMqrOY9YdE7A.png\" alt=\"\" class=\"wp-image-207\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_ndnFvkhKgfhMqrOY9YdE7A.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/1_ndnFvkhKgfhMqrOY9YdE7A-300x205.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p>На Bootstrap это бы выглядело так. Вам надо было бы продублировать ваше меню, спрятать одно и показывать другое на мобильных телефонах, а другое на десктопах соответственно.</p>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;body>\n  &lt;div class=\"container\">\n    &lt;div class=\"row\">\n      &lt;div class=\"col-xs-12 hidden-sm-up navigation-menu-mobile\">...&lt;/div>\n      &lt;div class=\"col-xs-12 header\">...&lt;/div>\n    &lt;/div>\n    &lt;div class=\"row\">\n      &lt;div class=\"col-md-6 col-lg-4 hidden-xs-down navigation-menu\">...&lt;/div>\n      &lt;div class=\"col-xs-12 col-md-6 col-lg-8 main-content\">...&lt;/div>\n    &lt;/div>\n    &lt;div class=\"row\">\n      &lt;div class=\"col-xs-12 footer\">...&lt;/div>\n    &lt;/div>\n  &lt;/div>\n&lt;/body></code></pre>\n\n\n\n<p>И само собой, HTML станет все больше и сложнее с ростом шаблона.</p>\n\n\n\n<h3 id=\"7b33\">С CSS Grid</h3>\n\n\n\n<p id=\"99b3\">Вам нужна только одна строчка CSS, чтобы передвинуть меню навигации наверх и вот как:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>...\n@media screen and (max-width: 480px) {\n  .navigation-menu {\n    grid-row: 1;\n    grid-column: span 12;\n  }\n  ...\n}</code></pre>\n\n\n\n<h2 id=\"ac95\">Настраиваем ваш грид шаблон!</h2>\n\n\n\n<p id=\"8b6d\">Имейте столько колонок, сколько хотите.</p>\n\n\n\n<p id=\"22fa\">По-дефолту, Bootstrap идет с 12-ти колоночной системой сеток. Это значение может быть переписано, но если вы так сделаете, это будет переписано везде в приложении.</p>\n\n\n\n<p id=\"e9ef\">С другой стороны, с CSS Grid, вы можете указать количество колонок на строку для каждого вашего грида.</p>\n\n\n\n<p id=\"1efb\">В&nbsp;<code>grid-template-columns: repeat(12, 1fr);</code>&nbsp;вы можете просто указать число колонок, которые вы хотите вместо 12ти.</p>\n\n\n\n<h3 id=\"6baa\"><strong>Нежелательные 10px внутренние отступы</strong></h3>\n\n\n\n<p id=\"515c\">Колонки в Bootstrap имеют&nbsp;<code>10px</code>&nbsp;внутренние отступы слева и справа. Самое лучшее решение тут, это переписать их используя&nbsp;<code>padding-right: 0 !important;</code>&nbsp;и&nbsp;<code>padding-left: 0 !important;</code></p>\n\n\n\n<p id=\"3e2f\">С CSS Grid шаблоном, вам надо контролировать все CSS классы, вы можете выставлять внутренние отступы везде где вам надо.</p>\n\n\n\n<h2 id=\"8a2d\">Больше нет нужды скачивать библиотеку</h2>\n\n\n\n<p id=\"f437\">Даже если таблица стилей Bootstrap весит всего несколько килобайт, она затормозит загрузку вашей страницы.</p>\n\n\n\n<p id=\"6cd3\">Все основные браузеры поставляются с поддержкой CSS Grid, начиная с 2017, так что нет нужды скачивать какие-либо дополнительные CSS, чтобы использовать гриды.</p>\n\n\n\n<p id=\"a407\">На время обновления статьи, уже&nbsp;<strong>95.47% браузеров</strong>&nbsp;поддерживали CSS Grid.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"1024\" height=\"403\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/Screenshot-2021-02-09-at-17.43.08-1024x403.png\" alt=\"\" class=\"wp-image-208\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/02/Screenshot-2021-02-09-at-17.43.08-1024x403.png 1024w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/Screenshot-2021-02-09-at-17.43.08-300x118.png 300w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/Screenshot-2021-02-09-at-17.43.08-768x303.png 768w, https://stasonmars.ru/wp/wp-content/uploads/2021/02/Screenshot-2021-02-09-at-17.43.08.png 1282w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" /></figure>\n","date":"2021-02-09T15:47:23.000Z","title":"Как я перестал использовать Bootstrap в угоду CSS Grid","id":"44017478-841a-56f8-a8b6-7fafa871a426","excerpt":"<p>В этой статье вы узнаете как можно заменить сетку на Bootstrap, сделав её на CSS Grid</p>\n","type":"html-css","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2021/02/gridbootstrpafnksdnf.jpg"}}},{"node":{"slug":"css-selectory-4-urovnya","content":"\n<p>В этой статье рассказывается про селекторы 4 уровня в CSS, которые уже можно&nbsp;<em>частично</em>&nbsp;применять в разработке, про которые ещё мало кто знает и про те, которые только ожидают часа своего всеобщего признания. Но в любом случае знание и понимание этого материала значительно упростит ваш процесс работы как в настоящем, так и в будущем.</p>\n\n\n\n<p class=\"author\"><em>Перевод статьи&nbsp;</em><a href=\"https://blog.logrocket.com/css-selectors-level-4-b5da36bcd54c\"><em>CSS selectors level 4</em></a></p>\n\n\n\n<p>Селекторы это основная часть CSS. Они дают вам возможность делать такие вещи, как например, выборка всех элементов определенного типа:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>div {\n  /* some styles to apply to all div elements */\n}</code></pre>\n\n\n\n<p>Или&nbsp;вы можете выбрать элемент, который является замыкающим дочерним элементом своего родителя:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>ul li:last-child {\n  /* some styles to apply to only the last child of a list */\n}</code></pre>\n\n\n\n<p id=\"2d72\">Конечно же они дают вам возможность делать куда более сложные вещи, например выбор всех дочерних элементов списка, кроме последнего.</p>\n\n\n\n<p id=\"271e\">По факту, есть куда больше одного способа сделать это и куда более запутанные и сложные.</p>\n\n\n\n<p id=\"f571\">Для примера, сравним этот:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>ul li {\n  /* Styles to apply to all children */\n}\nul li:last-child {\n  /* Styles to reset the previous styles because they don’t apply to the last child */\n}</code></pre>\n\n\n\n<p>С этим:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>ul li:nth-last-child(n+2) { \n  /* Styles to apply to all children except the last one */\n}</code></pre>\n\n\n\n<p><code>ul li</code>&nbsp;это примеры селекторов первого уровня.</p>\n\n\n\n<p><code>last-child</code>&nbsp;и&nbsp;<code>nth-last-child</code>&nbsp;это примеры селекторов 3-го уровня.</p>\n\n\n\n<p>Вы можете рассматривать уровни, как версии спецификаций CSS селекторов, в которых каждый уровень добавляет селекторы&nbsp;<em>“помощнее”</em>.</p>\n\n\n\n<p>В этой статье я предоставлю вам обзор последнего поколения селекторов, а именно 4 уровня, в соответствии со спецификацией Editors’s Draft на январь 2019 года, по следующим категориям:</p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p></p><cite>Логические комбинации<br>Селекторы атрибутов<br>Лингвистические псевдоклассы<br>Псевдоклассы положения<br>Пользовательские псевдоклассы<br>Псевдоклассы форм ввода<br>Древовидные псевдоклассы<br>Табличные селекторы</cite></blockquote>\n\n\n\n<p id=\"ace7\">Во время написания, спецификация для селекторов 4 уровня находится в драфте. Ситуация может измениться, если они достигнут статуса официальной рекомендации и к своему сожалению, вы в итоге обнаружите, что многие селекторы либо не поддерживаются некоторыми браузерами или им нужен префикс с&nbsp;<code>:-moz-</code>&nbsp;или&nbsp;<code>:-webkit-</code>.</p>\n\n\n\n<p id=\"af49\">Для каждого селектора я дам ссылку на его&nbsp;<strong>Can I Use</strong>&nbsp;страничку, так что вы увидите какие браузеры его поддерживают (если это возможно), также дам краткое описание, пример и ссылку на Codepen, так что вы сможете попробовать его в действии (даже если он сейчас не работает, всё равно это может измениться в будущем).</p>\n\n\n\n<p id=\"25e8\">Учитывая всё вышесказанное, давайте начнем с селекторов из категории логических комбинаций.</p>\n\n\n\n<h2 id=\"2680\"><strong>Логические комбинации</strong></h2>\n\n\n\n<p id=\"9f8b\">Эта категория включает в себя селекторы, которые комбинируют другие селекторы.</p>\n\n\n\n<h3 id=\"2eb3\"><strong>:not(selector1, selector2, …)</strong></h3>\n\n\n\n<p id=\"ca0a\"><a href=\"https://caniuse.com/#feat=css-not-sel-list\">Поддержка браузерами</a></p>\n\n\n\n<p id=\"2e6d\">Этот селектор выделяет все элементы, кроме тех, которые не подходят по селекторам из списка, который представлен в виде аргумента. К примеру:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>p:not(.beginning, .middle) {\n  color: red;\n}</code></pre>\n\n\n\n<p id=\"4cf1\">Сделает все p элементы у которых нет классов beginning и middle красного цвета.</p>\n\n\n\n<p id=\"1490\">Версия 3 уровня для этого селектора позволяет включить только один селектор, вместо списка из нескольких. Для примера, вышеупомянутый селектор может быть записан как:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>p:not(.beginning):not(.middle) {\n  color: red;\n}</code></pre>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\":not pseudo-class\" src=\"https://codepen.io/eh3rrera/embed/xMGxvY?height=265&amp;theme-id=light&amp;default-tab=css,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/eh3rrera/pen/xMGxvY'>:not pseudo-class</a> by Esteban Herrera\n  (<a href='https://codepen.io/eh3rrera'>@eh3rrera</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<h3 id=\"99a8\"><strong>:is(selector1, selector2, …)</strong></h3>\n\n\n\n<p id=\"9a8d\"><a href=\"https://caniuse.com/#feat=css-matches-pseudo\">Поддержка браузерами</a></p>\n\n\n\n<p id=\"ad75\">Он выбирает элементы, которые подходят по выборке селекторов из списка аргументов. Для примера:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>p:is(.beginning, .middle) {\n  color: blue;\n}</code></pre>\n\n\n\n<p id=\"5a7c\">Сделает все элементы&nbsp;<code>p</code>&nbsp;у которых есть классы&nbsp;<code>beginning</code>&nbsp;и&nbsp;<code>middle</code>&nbsp;синим цветом.</p>\n\n\n\n<p id=\"37db\">Одним из самых примечательных изменений с последнего рабочего драфта является то, что селектор&nbsp;<code>:matches()</code>&nbsp;был переименован в&nbsp;<code>:is()</code>&nbsp;и убран из Safari (который был единственным браузером с его полной поддержкой), так что теперь он куда более совместимый со своей противоположностью, такой как&nbsp;<code>:not()</code>.</p>\n\n\n\n<p id=\"c929\"><code>:matches</code>&nbsp;можно применять как алиас для&nbsp;<code>:is()</code>, если нужно для обратной совместимости. Хотя,&nbsp;<code>:matches()</code>&nbsp;ранее назывался&nbsp;<code>:any()</code>, так что многие браузеры поддерживают этот псевдокласс с префиксом:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>p:-webkit-any(.beginning, .middle) {\n  color: blue;\n}\n\np:-moz-any(.beginning, .middle) {\n  color: blue;\n}</code></pre>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\":is pseudo-class\" src=\"https://codepen.io/eh3rrera/embed/daYRLJ?height=265&amp;theme-id=light&amp;default-tab=css,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/eh3rrera/pen/daYRLJ'>:is pseudo-class</a> by Esteban Herrera\n  (<a href='https://codepen.io/eh3rrera'>@eh3rrera</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<h3 id=\"c4d3\"><strong>:where(selector1, selector2, …)</strong></h3>\n\n\n\n<p id=\"1840\">На время написания, этот селектор не поддерживался ни одним браузером.</p>\n\n\n\n<p id=\"1a8a\">У него такой же синтаксис и функционал, как и у&nbsp;<code>:is()</code>, но ни сам селектор и ни какой из его аргументов влияют на его специфичность, которая всегда равна нулю.</p>\n\n\n\n<p id=\"4623\">Специфичность это&nbsp;<em>“вес”</em>&nbsp;CSS правила. Если два селектора применены к одному и тому же элементу, то выигрывает тот у которого наивысшая специфичность. Всё понятно. А если у нескольких правил одинаковая специфичность, то последнее правило в CSS будет применено к элементу.</p>\n\n\n\n<p id=\"0a98\">Этот селектор можно использовать как фильтр или для перезаписи стилей связанных с элементом.</p>\n\n\n\n<p id=\"8164\">В спецификации приводится следующий пример:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>a:not(:hover) {\n  text-decoration: none;\n}\n\nnav a {\n  /* Has no effect */\n  text-decoration: underline;\n}\n\n/* With the new :where Level 4 selector */\na:where(:not(:hover)) {\n  text-decoration: none;\n}\n\nnav a {\n  /* Should work */\n  text-decoration: underline;\n}</code></pre>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\":where pseudo-class\" src=\"https://codepen.io/eh3rrera/embed/daYzZg?height=265&amp;theme-id=light&amp;default-tab=css,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/eh3rrera/pen/daYzZg'>:where pseudo-class</a> by Esteban Herrera\n  (<a href='https://codepen.io/eh3rrera'>@eh3rrera</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<h3 id=\"dcee\"><strong>:has(relativeSelector1, relativeSelector2, …)</strong></h3>\n\n\n\n<p id=\"2b2c\"><a href=\"https://caniuse.com/#feat=css-has\">Поддержка браузерами</a>. На время написания, этот селектор не поддерживался ни одним браузером.</p>\n\n\n\n<p id=\"be9c\">Этот селектор берет список родственных селекторов как список аргументов. Он выделяет элемент, если любой из его родственных селекторов (в его области видимости) подходит по критерию. Для примера:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>p:has(strong, em) {\n  color: red;\n}</code></pre>\n\n\n\n<p>Тут всем элементам p, в которых есть&nbsp;<code>&lt;strong&gt;</code>&nbsp;или&nbsp;<code>&lt;em&gt;</code>&nbsp;теги, выставится красный свет.</p>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\":has pseudo-class\" src=\"https://codepen.io/eh3rrera/embed/QYjmYX?height=265&amp;theme-id=light&amp;default-tab=html,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/eh3rrera/pen/QYjmYX'>:has pseudo-class</a> by Esteban Herrera\n  (<a href='https://codepen.io/eh3rrera'>@eh3rrera</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<h2 id=\"999b\"><strong>Селекторы атрибутов</strong></h2>\n\n\n\n<p id=\"42e8\">Эта категория включает в себя селекторы, которые работают с селекторами атрибутов.</p>\n\n\n\n<h3 id=\"08a7\"><strong>[foo=”bar” i]</strong></h3>\n\n\n\n<p id=\"4dda\"><a href=\"https://caniuse.com/#feat=css-case-insensitive\">Поддержка браузерами</a></p>\n\n\n\n<p id=\"644c\">Этот селектор выберет тот элемент, чьё значение атрибута&nbsp;<code>foo</code>&nbsp;равно&nbsp;<code>bar</code>, вне зависимости от регистра.</p>\n\n\n\n<p id=\"e8bd\">Для примера:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>p&#91;class=\"text\" i] {\n  color: green;\n}</code></pre>\n\n\n\n<p>Сделает зеленым всем элементы p, чей атрибут class имеет значения text, TEXT, text или другую комбинацию.</p>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\"Case-insensitive selector\" src=\"https://codepen.io/eh3rrera/embed/pGjVEg?height=265&amp;theme-id=light&amp;default-tab=html,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/eh3rrera/pen/pGjVEg'>Case-insensitive selector</a> by Esteban Herrera\n  (<a href='https://codepen.io/eh3rrera'>@eh3rrera</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<h3 id=\"eb2c\"><strong>[foo=“bar” s]</strong></h3>\n\n\n\n<p id=\"eddf\">На время написания, этот селектор пока не поддерживался ни одним браузером.</p>\n\n\n\n<p id=\"0d4c\">Выбирает элемент, чью имя атрибута foo, точно соответствует&nbsp;<code>bar</code>, в соответствии с регистром.</p>\n\n\n\n<p id=\"8629\">Для примера:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>p&#91;class=\"text\" s] {\n  color: green;\n}</code></pre>\n\n\n\n<p>Сделает зеленым все элементы&nbsp;<code>p</code>, у которых атрибут&nbsp;<code>class</code>&nbsp;имеет значение&nbsp;<code>text</code>&nbsp;(и не&nbsp;<code>Text</code>&nbsp;или тп).</p>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\"Case-sensitive selector\" src=\"https://codepen.io/eh3rrera/embed/yZYjbJ?height=265&amp;theme-id=light&amp;default-tab=html,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/eh3rrera/pen/yZYjbJ'>Case-sensitive selector</a> by Esteban Herrera\n  (<a href='https://codepen.io/eh3rrera'>@eh3rrera</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<h2 id=\"a24f\"><strong>Лингвистические псевдоклассы</strong></h2>\n\n\n\n<p id=\"a519\">Эта категория включает в себя селекторы, которые работают с лингвистическими установками, основанными на тонкостях каждого языка или правописания.</p>\n\n\n\n<h3 id=\"18fd\"><strong>:dir(ltr)</strong></h3>\n\n\n\n<p id=\"e323\"><a href=\"https://caniuse.com/#search=dir\">Поддержка браузерами</a></p>\n\n\n\n<p id=\"ca34\">Выбирает элементы написанные слева направо, там где указана направленность написания. И напротив,&nbsp;<code>:dir(rtl)</code>&nbsp;выбирает элементы, которые написаны справа налево.</p>\n\n\n\n<p id=\"8b2b\">Для примера:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>p:dir(ltr) {\n  background-color: red;\n}</code></pre>\n\n\n\n<p>Тут фоновый цвет выставится на красный всем элементам p, написанным слева направо.</p>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\":dir(ltr) pseudo-class\" src=\"https://codepen.io/eh3rrera/embed/GzpdwV?height=265&amp;theme-id=light&amp;default-tab=css,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/eh3rrera/pen/GzpdwV'>:dir(ltr) pseudo-class</a> by Esteban Herrera\n  (<a href='https://codepen.io/eh3rrera'>@eh3rrera</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<h3 id=\"2670\"><strong>:lang(zh, “*-hant”)</strong></h3>\n\n\n\n<p id=\"445d\"><a href=\"https://caniuse.com/#search=%3Alang\">Поддержка браузерами</a>. На время написания, версия 4-го уровня для этого селектора не поддерживалась ни одним браузером.</p>\n\n\n\n<p id=\"2bb5\">Выбирает элемент, отмеченный как китайский (или другой язык, просто поменяйте&nbsp;<code>zh</code>&nbsp;на нужный) или написанный традиционными китайскими символами (или любой другой системой символов, просто поменяйте&nbsp;<code>*-hant</code>&nbsp;на любой другой код символов)</p>\n\n\n\n<p id=\"1747\">На самом деле, этот селектор можно использовать с CSS2, однако, структуризация поиска по языку и разделение запятой в аргументах, являются нововведениями в селекторах 4-го уровня.</p>\n\n\n\n<p id=\"22f6\">Этот селектор может принимать список из одного языка или диапазон языков, как аргумент. Если диапазон языков содержит звездочки, то они должны быть либо экранированы&nbsp;<code>(:lang(es-\\*))</code>, либо указаны как строка&nbsp;<code>(:lang(\"es-*\"))</code>.</p>\n\n\n\n<p id=\"6450\">Для примера:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>p:lang(\"*-CH\") {\n  background-color: red;\n}</code></pre>\n\n\n\n<p>Выставит фоновый цвет красным, всем элементам&nbsp;<code>p</code>, в которых есть текст, написанный на одном из языков Швейцарии (<code>CH</code>&nbsp;указывает Швейцарию).</p>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\":lang pseudo-class\" src=\"https://codepen.io/eh3rrera/embed/YByjzp?height=265&amp;theme-id=light&amp;default-tab=html,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/eh3rrera/pen/YByjzp'>:lang pseudo-class</a> by Esteban Herrera\n  (<a href='https://codepen.io/eh3rrera'>@eh3rrera</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<h2 id=\"9a49\"><strong>Псевдоклассы положения</strong></h2>\n\n\n\n<p id=\"dee8\">Эта категория включает в себя селекторы, относящиеся к ссылкам.</p>\n\n\n\n<h3 id=\"f5de\"><strong>:any-link</strong></h3>\n\n\n\n<p id=\"2b92\">Пока что нет странички на&nbsp;<strong>Can I Use</strong>, но он поддерживается большинством основных браузеров.</p>\n\n\n\n<p id=\"0018\">Этот селектор выделяет все элементы, у которых есть атрибут&nbsp;<code>href</code>&nbsp;(такие как&nbsp;<code>&lt;a&gt;</code>&nbsp;или&nbsp;<code>&lt;link&gt;</code>). Другими словами, все элементы, которые подходят псевдоклассам&nbsp;<code>:link</code>&nbsp;и&nbsp;<code>:visited</code>.</p>\n\n\n\n<p id=\"3100\">Для примера:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>a:any-link {\n  color: red;\n}</code></pre>\n\n\n\n<p>Выдаст всем элементам a c атрибутом href, красный цвет.</p>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\":any-link pseudo-class\" src=\"https://codepen.io/eh3rrera/embed/vbNaeJ?height=265&amp;theme-id=light&amp;default-tab=html,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/eh3rrera/pen/vbNaeJ'>:any-link pseudo-class</a> by Esteban Herrera\n  (<a href='https://codepen.io/eh3rrera'>@eh3rrera</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<h3 id=\"8e93\"><strong>:local-link</strong></h3>\n\n\n\n<p id=\"abe5\">На момент написания, этот селектор не поддерживается ни одним из браузеров.</p>\n\n\n\n<p id=\"7082\">Этот элемент выбирает элементы, которые ссылаются на эту же страницу. Если ссылка включает в себя фрагмент настоящей ссылки, то она тоже подпадает под селектор. Если же нет, то фрагмент части ссылки настоящего URL не рассматривается.</p>\n\n\n\n<p id=\"ad6a\">Для примера:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>a:local-link {\n  text-decoration: none;\n}</code></pre>\n\n\n\n<p>Этот селектор сделает все ссылки с атрибутом&nbsp;<code>href</code>, которые ссылаются на эту же страницу, без подчеркнутыми.</p>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\":local-link pseudo-class\" src=\"https://codepen.io/eh3rrera/embed/GzpBwG?height=265&amp;theme-id=light&amp;default-tab=html,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/eh3rrera/pen/GzpBwG'>:local-link pseudo-class</a> by Esteban Herrera\n  (<a href='https://codepen.io/eh3rrera'>@eh3rrera</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<h2 id=\"8225\"><strong>Пользовательские псевдоклассы (или user-action псевдоклассы)</strong></h2>\n\n\n\n<p id=\"ec5c\">Это категория включает в себя селекторы для тех элементов, с которыми взаимодействует пользователь.</p>\n\n\n\n<h3 id=\"1bff\"><strong>:focus-within</strong></h3>\n\n\n\n<p id=\"1c47\"><a href=\"https://caniuse.com/#feat=css-focus-within\">Поддержка браузерами</a></p>\n\n\n\n<p id=\"db6d\">Выбирает элементы, который либо подходят под псевдокласс&nbsp;<code>:focus</code>&nbsp;(когда элемент в фокусе), либо когда у них есть потомки, которые подходят под&nbsp;<code>:focus</code>.</p>\n\n\n\n<p id=\"4686\">Для примера, рассмотрим следующую форму:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>&lt;form>\n&lt;input type=\"text\" id=\"name\" placeholder=\"Enter your name\" />\n&lt;/form></code></pre>\n\n\n\n<p>Она добавит рамку вокруг поля ввода при фокусе.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>form:focus-within {\n  border: 2px solid;\n}</code></pre>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\":focus-within pseudo-class\" src=\"https://codepen.io/eh3rrera/embed/BMoGWx?height=265&amp;theme-id=light&amp;default-tab=html,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/eh3rrera/pen/BMoGWx'>:focus-within pseudo-class</a> by Esteban Herrera\n  (<a href='https://codepen.io/eh3rrera'>@eh3rrera</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<h3 id=\"ed34\"><strong>:focus-visible</strong></h3>\n\n\n\n<p id=\"1e44\"><a href=\"https://caniuse.com/#feat=css-focus-visible\">Поддержка браузерами</a></p>\n\n\n\n<p id=\"4635\">Выбирает элемент, если он в фокусе (как псевдокласс&nbsp;<code>:focus</code>) и браузер определяет, что фокус сделан прямо явным образом, обычно это делается с помощью кольца фокусировки (в браузерах такая штука в настройках есть).</p>\n\n\n\n<p id=\"b167\">Однако, разница с&nbsp;<code>:focus</code>&nbsp;довольно тонкая, но всё же есть.</p>\n\n\n\n<p id=\"e74b\">Если&nbsp;<code>:focus-visible</code>&nbsp;что-то выбирает, то&nbsp;<code>:focus</code>&nbsp;делает это тоже, но на самом деле это не всегда так и зависит от браузера (включена ли у него отрисовка кольца фокуса) и того, как элемент попал в фокус (мышкой или клавиатурой).</p>\n\n\n\n<p id=\"c32b\">У Firefox есть свой такой селектор, как псевдокласс&nbsp;<code>:-moz-focusring</code>.</p>\n\n\n\n<p id=\"fcce\">Для примера, в некоторых случаях, следующая стилизация:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>/* Standard Level 4 selector */\n:focus-visible {\n  background-color: lightgray;\n}\n\n/* Level 4 selector for Firefox*/\n:-moz-focusring  {\n  background-color: lightgray;\n}</code></pre>\n\n\n\n<p>Применится только к элементу, если на нем сфокусировались через клавиатурную навигацию (<em>tabbing navigation</em>).</p>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\":focus-visible pseudo-class\" src=\"https://codepen.io/eh3rrera/embed/KJdbMp?height=265&amp;theme-id=light&amp;default-tab=css,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/eh3rrera/pen/KJdbMp'>:focus-visible pseudo-class</a> by Esteban Herrera\n  (<a href='https://codepen.io/eh3rrera'>@eh3rrera</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<h2 id=\"1487\"><strong>Псевдоклассы форм ввода</strong></h2>\n\n\n\n<p id=\"4a21\">Эта категория включает в себя селекторы, которые применяются к элементам имеющем отношение к формам ввода.</p>\n\n\n\n<h3 id=\"a44d\"><strong>:read-write и :read-only</strong></h3>\n\n\n\n<p id=\"ef3d\"><a href=\"https://caniuse.com/#feat=css-read-only-write\">Поддержка браузерами</a></p>\n\n\n\n<p id=\"c542\"><code>:read-write</code>&nbsp;выбирает элементы, чьё значение можно изменить, такие каr&nbsp;<code>&lt;input&gt;</code>&nbsp;без атрибута&nbsp;<code>readonly</code>.</p>\n\n\n\n<p id=\"c4a8\"><code>:read-only</code>&nbsp;выбирает элементы, которые в свою очередь уже нельзя изменить, например тот же&nbsp;<code>&lt;input&gt;</code>, но с атрибутом&nbsp;<code>readonly</code>.</p>\n\n\n\n<p id=\"4851\">Однако, эти селекторы не просто выбирают элементы&nbsp;<code>&lt;input&gt;</code>&nbsp;или&nbsp;<code>&lt;textarea&gt;</code>, они выбирают любой элемент, который может быть отредактирован пользователем, например как&nbsp;<code>&lt;p&gt;</code>&nbsp;с атрибутом&nbsp;<code>contenteditable&nbsp;</code>со значением&nbsp;<code>true</code>.</p>\n\n\n\n<p id=\"b9c8\">К примеру:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>:read-write {\n  background-color: lightyellow;\n}\n\n:read-only {\n  background-color: lightgray;\n}\n\n/* For Firefox */\n:-moz-read-write {\n  background-color: lightyellow;\n}\n\n:-moz-read-only {\n  background-color: lightgray;\n}</code></pre>\n\n\n\n<p>Тут фоновый цвет измениться для всех элементов, которые можно изменить и которые нельзя. На&nbsp;<code>lightyellow</code>&nbsp;и&nbsp;<code>lightgrey</code>, соответственно.</p>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\":read-write and :read-only pseudo-classes\" src=\"https://codepen.io/eh3rrera/embed/JxGXWw?height=265&amp;theme-id=light&amp;default-tab=html,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/eh3rrera/pen/JxGXWw'>:read-write and :read-only pseudo-classes</a> by Esteban Herrera\n  (<a href='https://codepen.io/eh3rrera'>@eh3rrera</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<h3 id=\"d14a\"><strong>:placeholder-shown</strong></h3>\n\n\n\n<p id=\"017b\"><a href=\"https://caniuse.com/#feat=css-placeholder-shown\">Поддержка браузерами</a></p>\n\n\n\n<p id=\"91a9\">Этот селектор выбирает элемент ввода, который в данный момент показывает текст плейсхолдера.</p>\n\n\n\n<p id=\"5efe\">Для примера:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>input:placeholder-shown {\n  color: red;\n}</code></pre>\n\n\n\n<p>Выставит красный текст плейсхолдеру элемента&nbsp;<code>&lt;input&gt;</code>&nbsp;(только для самого плейсхолдера).</p>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\":placeholder-shown pseudo-class\" src=\"https://codepen.io/eh3rrera/embed/jdWrbp?height=265&amp;theme-id=light&amp;default-tab=html,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/eh3rrera/pen/jdWrbp'>:placeholder-shown pseudo-class</a> by Esteban Herrera\n  (<a href='https://codepen.io/eh3rrera'>@eh3rrera</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<h3 id=\"e697\"><strong>:default</strong></h3>\n\n\n\n<p id=\"ff5c\"><a href=\"https://caniuse.com/#feat=css-default-pseudo\">Поддержка браузерами</a></p>\n\n\n\n<p id=\"3d1a\">Выбирает элемент, который является дефолтной опцией в группе связанных элементов. Обычно он применяется к кнопкам и выбранным спискам/меню.</p>\n\n\n\n<p id=\"ba47\">Для примера:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>input:default {\n  box-shadow: 0 0 2px 2px green;\n}\n\ninput:default + label {\n  color: green;\n}</code></pre>\n\n\n\n<p>Задаст зеленую тень дефолтному&nbsp;<code>&lt;input&gt;</code>&nbsp;элементу и зеленый цвет его лейблу.</p>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\":default pseudo-class\" src=\"https://codepen.io/eh3rrera/embed/wNMWjx?height=265&amp;theme-id=light&amp;default-tab=html,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/eh3rrera/pen/wNMWjx'>:default pseudo-class</a> by Esteban Herrera\n  (<a href='https://codepen.io/eh3rrera'>@eh3rrera</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<h3 id=\"be59\"><strong>:indeterminate</strong></h3>\n\n\n\n<p id=\"2baf\"><a href=\"https://caniuse.com/#feat=css-indeterminate-pseudo\">Поддержка браузерами</a></p>\n\n\n\n<p id=\"3e02\">Тут выберутся элементы, чьё значение имеет промежуточное состояние. Для примера, радио и чекбокс группы состоящие из не выбранных элементов или прогресс-бары, процент завершения которых неизвестен.</p>\n\n\n\n<p id=\"2641\">Для примера:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>input&#91;type=\"radio\"]:indeterminate + label {\n  color: red;\n}</code></pre>\n\n\n\n<p>Этот пример выдаст лейблам радио элементов в группе, красный цвет, в том случае, если в этой группе нет выбранных элементов.</p>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\":indeterminate pseudo-class\" src=\"https://codepen.io/eh3rrera/embed/yZeaBL?height=265&amp;theme-id=light&amp;default-tab=html,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/eh3rrera/pen/yZeaBL'>:indeterminate pseudo-class</a> by Esteban Herrera\n  (<a href='https://codepen.io/eh3rrera'>@eh3rrera</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<h3 id=\"ab39\"><strong>:valid и :invalid</strong></h3>\n\n\n\n<p id=\"e574\"><a href=\"https://caniuse.com/#feat=form-validation\">Поддержка браузерами</a></p>\n\n\n\n<p id=\"1f94\">Они выделят элементы, чьё содержимое или значение, соответственно, валидное или наоборот, в соответствии с семантикой их валидности. Если семантика не определена (или не может быть определена), то элемент и не&nbsp;<code>:valid</code>, и не&nbsp;<code>:invalid</code>.</p>\n\n\n\n<p id=\"2b07\">Пример для элемента ввода типа email:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>input:invalid {\n  color: red;\n}\n\ninput:valid {\n  color: green;\n}</code></pre>\n\n\n\n<h3 id=\"e4c3\"><strong>:in-range and :out-of-range</strong></h3>\n\n\n\n<p id=\"ccb0\"><a href=\"https://caniuse.com/#feat=css-in-out-of-range\">Поддержка браузерами</a></p>\n\n\n\n<p id=\"42b9\">Эти селекторы применяются только к элементам, которые имеют диапазон ограничений, для примера, если у них может быть указанные минимум и максимум. Если же нигде нет таких ограничений, то элемент не является и не&nbsp;<code>:in-range</code>, и не&nbsp;<code>:out-of-range</code>.</p>\n\n\n\n<p id=\"ee08\">К примеру, для&nbsp;<code>&lt;input&gt;</code>&nbsp;элемента с минимальным значением&nbsp;<code>1</code>&nbsp;и максимальным&nbsp;<code>5</code>:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>input:out-of-range {\n  color: red;\n}\n\ninput:in-range {\n  color: green;\n}</code></pre>\n\n\n\n<p>В некоторых случаях, эти селекторы будут иметь тот же эффект, что и&nbsp;<code>:valid</code>&nbsp;и&nbsp;<code>:invalid</code>.</p>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\":in-range and :out-of-range pseudo-class\" src=\"https://codepen.io/eh3rrera/embed/RvroLN?height=265&amp;theme-id=light&amp;default-tab=css,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/eh3rrera/pen/RvroLN'>:in-range and :out-of-range pseudo-class</a> by Esteban Herrera\n  (<a href='https://codepen.io/eh3rrera'>@eh3rrera</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<h3 id=\"4fa4\"><strong>:required and :optional</strong></h3>\n\n\n\n<p id=\"9382\"><a href=\"https://caniuse.com/#feat=form-validation\">Поддержка браузерами для :required</a></p>\n\n\n\n<p id=\"97c5\"><a href=\"https://caniuse.com/#feat=css-optional-pseudo\">Поддержка браузерами для :optional</a></p>\n\n\n\n<p id=\"c716\">Эти селекторы применяются к элементам формы, которые соответственно, required или optional, перед отправкой формы. Элементы, которые не являются элементами форм, являются ни чем иным, как ни тем и не другим.</p>\n\n\n\n<p id=\"be66\">Для примера:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>input:optional {\n  color: gray;\n}\n\ninput:required {\n  color: red;\n}</code></pre>\n\n\n\n<p>Даст элементам с&nbsp;<code>required</code>&nbsp;красный цвет и опциональным элементам выдаст серый цвет.</p>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\":required and :optional pseudo-class\" src=\"https://codepen.io/eh3rrera/embed/QYyGRQ?height=265&amp;theme-id=light&amp;default-tab=html,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/eh3rrera/pen/QYyGRQ'>:required and :optional pseudo-class</a> by Esteban Herrera\n  (<a href='https://codepen.io/eh3rrera'>@eh3rrera</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<h2 id=\"4b17\"><strong>Древовидные псевдоклассы</strong></h2>\n\n\n\n<p id=\"4973\">Эта категория включает в себя селекторы, которые основаны на информации, лежащей в древовидной структуре документа, но не может быть представлена другими селекторами, например как позиция элемента относительно его родителя.</p>\n\n\n\n<p id=\"c68e\"><a href=\"https://caniuse.com/#feat=css-nth-child-of\">Поддержка браузерами</a>&nbsp;(на момент написания, версия 4 уровня для этого селектора ничем не поддерживается).</p>\n\n\n\n<p id=\"4413\"><code>:nth-child</code>&nbsp;выбирает каждый элемент, который является N-ным дочерним элементом своего родителя.&nbsp;<code>:nth-last-child</code>&nbsp;делает то же самое, но ведёт счет с конца. Вы можете поиграться с&nbsp;<a href=\"https://css-tricks.com/examples/nth-child-tester/\">:nth тестером</a>, чтобы понять разницу и узнать больше&nbsp;<a href=\"https://drafts.csswg.org/css-syntax-3/#anb-microsyntax\">об An+B обозначениях</a>.</p>\n\n\n\n<p id=\"fcb6\">В самом начале этой статьи, я показал вам пример&nbsp;<code>:nth-last-child</code>&nbsp;и сказал, что это был селектор 3-го уровня. Однако, для 4-го уровня, этот селектор принимает опциональный&nbsp;<code>of</code>&nbsp;селектор, который отфильтровывает потомков по признаку, который подходит под этот селектор.</p>\n\n\n\n<p id=\"ad7a\">Вообще тут могут быть различия в том, как объявлен селектор. Для примера:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>li.item:nth-child(-n+2)</code></pre>\n\n\n\n<p id=\"745b\">Выберет первые два элемента&nbsp;<code>li</code>, но только если у них есть класс&nbsp;<code>item</code>.</p>\n\n\n\n<p id=\"2d6c\">Это не то же самое, что:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>:nth-child(-n+2 of li.item)</code></pre>\n\n\n\n<p id=\"70e4\">Тут выберутся первые два&nbsp;<code>&lt;li&gt;</code>&nbsp;элемента, которые имеют класс&nbsp;<code>item</code>, даже если они не первые два потомка в списке.</p>\n\n\n\n<p id=\"8388\">Попробуйте (в браузере, который поддерживает этот селектор, таком как Safari):</p>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\":nth-child 1/2\" src=\"https://codepen.io/eh3rrera/embed/NoxgEE?height=265&amp;theme-id=light&amp;default-tab=html,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/eh3rrera/pen/NoxgEE'>:nth-child 1/2</a> by Esteban Herrera\n  (<a href='https://codepen.io/eh3rrera'>@eh3rrera</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\":nth-child 2/2\" src=\"https://codepen.io/eh3rrera/embed/pGgwpG?height=265&amp;theme-id=light&amp;default-tab=html,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/eh3rrera/pen/pGgwpG'>:nth-child 2/2</a> by Esteban Herrera\n  (<a href='https://codepen.io/eh3rrera'>@eh3rrera</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<h2 id=\"68c0\"><strong>Табличные селекторы</strong></h2>\n\n\n\n<p id=\"1c53\">Эта категория включает селекторы, которые работают с колонками таблицы.</p>\n\n\n\n<h3 id=\"7fb9\"><strong>F | | E</strong></h3>\n\n\n\n<p id=\"dea4\">На время написания, этот селектор вообще никем и ничем не поддерживался.</p>\n\n\n\n<p id=\"51b1\">Селектор комбинирования колонок (<code>||</code>), выбирает элемент типа E, который представляет ячейку в таблице и принадлежит колонке, представленной элементом с типом F.</p>\n\n\n\n<p id=\"8954\">Для примера, рассмотрим следующую таблицу:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>&lt;table>\n  &lt;colgroup>\n    &lt;col span=\"2\">\n    &lt;col class=\"selected\">\n  &lt;/colgroup>\n  &lt;tr>\n    &lt;th>ID&lt;/th>\n    &lt;th>Description&lt;/th>\n    &lt;th>Price&lt;/th>\n  &lt;/tr>\n  &lt;tr>\n    &lt;td>1&lt;/td>\n    &lt;td>Computer&lt;/td>\n    &lt;td>$999&lt;/td>\n  &lt;/tr>\n  &lt;tr>\n    &lt;td>2&lt;/td>\n    &lt;td>Tablet&lt;/td>\n    &lt;td>$499&lt;/td>\n  &lt;/tr>\n&lt;/table></code></pre>\n\n\n\n<p>Выдаст ярко-желтый цвет ячейкам (<code>&lt;td&gt;</code>&nbsp;элементам), которые относятся к&nbsp;<code>selected</code>&nbsp;колонке (<em>price</em>).</p>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\"Column combinator selector\" src=\"https://codepen.io/eh3rrera/embed/xMZLQY?height=265&amp;theme-id=light&amp;default-tab=html,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/eh3rrera/pen/xMZLQY'>Column combinator selector</a> by Esteban Herrera\n  (<a href='https://codepen.io/eh3rrera'>@eh3rrera</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<h3 id=\"5064\"><strong>:nth-col(An+B) and :nth-last-col(An+B)</strong></h3>\n\n\n\n<p id=\"2b74\">На время написания, этот селектор не поддерживается никем и ничем.</p>\n\n\n\n<p id=\"5032\">Вы можете рассматривать эти селекторы, как колоночную версию&nbsp;<code>:nth-child</code>&nbsp;и&nbsp;<code>:nth-last-child</code>.</p>\n\n\n\n<p id=\"006c\"><code>:nth-col(An+B)</code>&nbsp;выбирает элемент в гриде или таблице, который представляет собой ячейку колонки, у которой&nbsp;<em>An+B-1</em>&nbsp;колонок перед ней, с любым положительным целым числом или нулевым значением n.</p>\n\n\n\n<p id=\"333d\"><code>:nth-last-col(An+B)</code>&nbsp;выберет элемент сетки или таблицы, который представляет собой ячейку колонки, у которой&nbsp;<em>An+B-1</em>&nbsp;колонок после неё, с любым положительным или нулевым значением n.</p>\n\n\n\n<p id=\"6a14\">Для примера:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>col.nth-col(1) {\n  background-color: lightyellow;\n}\n\ncol.nth-last-col(1) {\n  background-color: lightgreen;\n}</code></pre>\n\n\n\n<p id=\"9273\">Выдаст первой колонке таблицы светло-желтый фон, а также последней колонке выдаст светло-зеленый фон.</p>\n\n\n\n<h2 id=\"d3a2\"><strong>Заключение</strong></h2>\n\n\n\n<p id=\"48f4\">Селекторы 4 уровня позволяют вам делать сложную выборку селекторами, довольно простым способом.</p>\n\n\n\n<p id=\"b5b8\">Мы сейчас покрыли большинство селекторов указанных в Editor’s Draft спецификации на январь 2019 года, однако, я оставил в покое некоторые селекторы, которые скорее всего исчезнут или изменятся, ну или если по ним вообще нет никакой информации, в том числе и о поддержки другими браузерами:</p>\n\n\n\n<p id=\"cf61\"><a href=\"https://drafts.csswg.org/selectors-4/#target-within-pseudo\">:target-within</a></p>\n\n\n\n<p id=\"0ddc\"><a href=\"https://drafts.csswg.org/selectors-4/#the-scope-pseudo\">:scope</a></p>\n\n\n\n<p id=\"fdbd\"><a href=\"https://drafts.csswg.org/selectors-4/#time-pseudos\">Временные псевдоклассы</a></p>\n\n\n\n<p id=\"f656\"><a href=\"https://drafts.csswg.org/selectors-4/#blank\">:blank</a></p>\n\n\n\n<p id=\"cd27\"><a href=\"https://drafts.csswg.org/selectors-4/#user-pseudos\">:user-invalid</a></p>\n\n\n\n<p id=\"ca3b\">Но вам определенно нужно за ними следить, так же как и за другими селекторами 4-го уровня.</p>\n","date":"2021-02-02T16:49:13.000Z","title":"CSS селекторы 4-го уровня","id":"24790ac6-bf80-560b-b036-68445e7a41b3","excerpt":"<p>В этой статье рассказывается про селекторы 4 уровня в CSS, которые уже можно частично применять в разработке, про которые ещё мало кто знает и про те, которые только ожидают часа своего всеобщего признания. </p>\n","type":"html-css","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2021/02/cssselectorzdfnks.jpg"}}},{"node":{"slug":"razmery-shriftov-css-pikseli-vs-em-vs-rem-procenti-vs-viewport-edinitsy","content":"\n<p>В этой статье вы узнаете про выставление размера шрифта в пикселях, em, rem, процентах и viewport единицах.</p>\n\n\n\n<p class=\"author\"><em>Эта статья перевод —&nbsp;</em><a href=\"https://medium.com/@madhum86/css-font-sizing-pixels-vs-em-vs-rem-vs-percent-vs-viewport-units-b1485716afe7\"><em>CSS Font Sizing: Pixels vs Em vs Rem vs Percent vs Viewport Units</em></a></p>\n\n\n\n<p id=\"cc6c\">Очень много обсуждений велось по поводу пикселей, <code>em</code>, процентов, <code>rem</code> и какое свойство шрифтов когда использовать. Не смотря на более сотни статей в сети, эта тема может быть довольно запутанной, учитывая то, как использование этих свойств шрифтов разнится в зависимости от нужд наших проектов. Для примера, некоторые советуют не использовать фиксированные пиксели на базовом уровне (html и body элементы), так как пользователь не будет иметь возможности сбросить размер шрифтов под свои параметры. Но для людей типа меня, которые зависимы от bootstrap, это не совсем благоразумно. Мы заканчиваем с фиксированными основными значениями в пикселях и начинаем создавать свойства шрифтов для всего проекта, отталкиваясь от основных пиксельных значений.</p>\n\n\n\n<p id=\"beae\">Эта статья объясняет разницу между свойствами шрифтов и как лучше их использовать. Естественно нет конкретного пути того, как это делать и большая часть того какой шрифт использовать и насколько будет определяющим этот момент, основываясь на понимании единиц размерности шрифтов и тип проекта — всё это определяющие моменты, от которых зависит выборка в вариативности инструментов.</p>\n\n\n\n<h2 id=\"e026\"><strong>Пиксели</strong></h2>\n\n\n\n<p id=\"8e6c\">Перед наступлением эпохи адаптивного дизайна, пиксели широко использовались как единица размерности шрифтов для всего от типографики до ширины, отступов и высоты. Тем не менее, пиксели это единицы с фиксированным размером и они не меняются, основываясь на размере viewport или масштабности. Если вы хотите сделать адаптивный сайт, используя пиксели, то это может стать довольно сложным занятием, так как вам придется отслеживать все значения основанные на пикселях в CSS, включая значения в медиа запросах. Так какое же свойство шрифта мы можем использовать, чтобы делать минимальные изменения в нашем CSS, но оставаться масштабируемыми? И тут нам на помощь приходят em, rem, проценты и единицы viewport.</p>\n\n\n\n<h2 id=\"3cd0\"><strong>Em</strong></h2>\n\n\n\n<p id=\"a17a\"><code>Em</code>&nbsp;— гибкая масштабируемая единица, которая конвертируется браузером в пиксели. Если стандартный размер шрифта в Chrome равен 16px, то&nbsp;<code>1 em</code>&nbsp;=&nbsp;<code>16px</code>. Главное заблуждение по поводу em в том, что оно зависит от размера шрифта родительского элемента. Следуя спецификации W3, em относителен размеру шрифта элемента на котором их используют.&nbsp;<code>Em</code>&nbsp;широко используются для типографии, такой как заголовки, текста, параграфы и с элементами ассоциированными с ней, такими как внешние отступы и внутренние. Если вы выставите базовый размер шрифта для для&nbsp;<code>html</code>&nbsp;и&nbsp;<code>body</code>&nbsp;элементов в пикселях и свойства ваших типографических элементов будут определяться в с помощью em, для адаптивного дизайна все что вам нужно будет сделать это изменить стандартный размер шрифта на базовом уровне, например.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>@media (max-width: 400px) {\n html, body { font-size: 15px; }\n}</code></pre>\n\n\n\n<p id=\"65c9\">и все&nbsp;<code>em</code>&nbsp;значения будут автоматически пересчитаны.</p>\n\n\n\n<p id=\"6774\">Тем не менее, у em есть большое предостережение! Наследование! </p>\n\n\n\n<p id=\"6774\">Для примера,&nbsp;<code>&lt;div&gt;</code>&nbsp;с размером шрифта в&nbsp;<code>16px</code>&nbsp;содержит&nbsp;<code>&lt;p&gt;</code>&nbsp;размером шрифта в&nbsp;<code>2em</code>, что пересчитывается как&nbsp;<code>32px</code>&nbsp;для&nbsp;<code>&lt;p&gt;</code>. Теперь добавьте&nbsp;<code>&lt;div&gt;</code>&nbsp;в&nbsp;<code>&lt;p&gt;</code>&nbsp;с размером шрифта в&nbsp;<code>0.5em</code>, как результат у дива будет размер&nbsp;<code>16px</code>, как у половины от&nbsp;<code>32px</code>, а не&nbsp;<code>8px</code>. И тут нам на помощь приходят rem.</p>\n\n\n\n<h2 id=\"3ead\"><strong>Rem</strong></h2>\n\n\n\n<p id=\"ea09\"><code>rem</code> относителен размеру шрифта корневого элемента(<code>html</code>&nbsp;элемент). Если размер шрифта&nbsp;<code>html</code>&nbsp;элемента равен&nbsp;<code>16px</code>, то&nbsp;<code>1rem</code>&nbsp;=&nbsp;<code>16px</code>.&nbsp;<code>Rem</code>&nbsp;будет ВСЕГДА относителен корневому элементу, не полагаясь на вложенные элементы. Тем не менее, использование исключительно rem без em может вызвать своеобразные проблемы в плане типографики, так как она может стать слишком большой или маленькой, что приведет к проблемам в масштабируемости.</p>\n\n\n\n<h2 id=\"efad\"><strong>Проценты</strong></h2>\n\n\n\n<p id=\"deec\">Значения в процента всегда относительны от другого значения, будь это родительское значение элемента или другое свойство элемента. Проценты широко используются в адаптивном дизайне. Отличный тому пример Bootstrap. Двенадцати колоночный макет бутстрапа имеет значения ширины выставленные в процентах, таким образом они всегда гибкие и подстраиваются относительно родительского элемента.</p>\n\n\n\n<p id=\"634b\">Проценты широко используются для выставления ширины и высоты контейнеров, дивов и для адаптивной графики.</p>\n\n\n\n<h2 id=\"7f23\"><strong>Единицы viewport</strong></h2>\n\n\n\n<p id=\"6386\">Ширина и высота viewport свойств относительна ширине/высоте заданного размера viewport.</p>\n\n\n\n<p><a href=\"https://stasonmars.ru/html-css/viewport-edinitsy-v-css/\">Подробно про viewport единицы вы можете почитать в этой статье.</a></p>\n\n\n\n<p id=\"ebdb\"><code>1vw</code>&nbsp;= 1% ширины viewport</p>\n\n\n\n<p id=\"2490\"><code>1vh</code>&nbsp;= 1% высоты viewport</p>\n\n\n\n<p id=\"23df\">Viewport в данному случае означает размер окна браузера. Если вы хотите выставить размер элемента, основываясь на ширине viewport, а не на родительском/корневом элементе, то viewport единицы это то, что вам нужно.&nbsp;<code>vw</code>/<code>vh</code>&nbsp;единицы отлично работают с типографикой и широко используются там же.</p>\n\n\n\n<h2 id=\"6d6b\"><strong>Финальный вердикт</strong></h2>\n\n\n\n<p id=\"ed70\">С тех пор как я часто начал использовать Bootstrap, мой стандартный размер базового шрифта стал в пикселях. Я использую проценты, чтобы выставить ширину и высоту для изображений, контейнеров и дивов, а em и rem для типографики и элементов относящихся к типографике, таким как&nbsp;<code>margin</code>&nbsp;и&nbsp;<code>padding</code>&nbsp;и т. п. Сейчас я играюсь с единицами viewport для адаптивной типографики и нахожу это очень крутым. Экспериментируйте с этими свойствами как можно больше и вы вскоре найдете стиль подогнанный именно для вас.</p>\n","date":"2021-01-29T15:01:00.000Z","title":"Размеры шрифтов CSS. Пиксели vs Em vs Rem vs Проценты vs Viewport единицы","id":"3a14e27f-c4e7-57c4-9655-efcd4015cf53","excerpt":"<p>В этой статье вы узнаете про выставление размера шрифта в пикселях, em, rem, процентах и viewport единицах.</p>\n","type":"html-css","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2021/01/rememviewportjndksfn.jpg"}}},{"node":{"slug":"viewport-edinitsy-v-css","content":"\n<p>В этой статье вы узнаете про единицы вьюпорта в CSS и варианты их применения.</p>\n\n\n\n<p class=\"author\"><em>Перевод&nbsp;</em><a rel=\"noreferrer noopener\" href=\"https://ishadeed.com/article/viewport-units/\" target=\"_blank\"><em>CSS Viewport Units</em></a></p>\n\n\n\n<p>Viewport единицы уже существуют несколько лет и со временем я вижу рост их применения другими разработчиками. Их полезность заключается в том, что они дают нам возможность выставлять размеры гибким и динамическим образом, без прямого использования JavaScript. Также, для них легко сделать фоллбэк в случае отсутствия поддержки браузером.</p>\n\n\n\n<h2 id=\"84d4\"><strong>Интро</strong></h2>\n\n\n\n<p id=\"32cd\">В соответствии со спецификацией CSS, процентные вьюпорт единицы относительны размеру изначального блок контейнера, который сам по себе является корневым элементом страницы.</p>\n\n\n\n<p id=\"f029\">Viewport единицы это&nbsp;<code>vw</code>,&nbsp;<code>vh</code>,&nbsp;<code>vmin</code>&nbsp;и&nbsp;<code>vmax</code>.</p>\n\n\n\n<h3 id=\"d6cb\"><strong>Viewport ширина</strong></h3>\n\n\n\n<p id=\"6247\">Единица&nbsp;<code>vw</code>&nbsp;представляет собой процентное измерение ширины корневого элемента. Один&nbsp;<code>vw</code>&nbsp;равен 1% ширины вьюпорта.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"312\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_L2AVtkxRhUB7zoiajq2NAg.png\" alt=\"\" class=\"wp-image-132\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_L2AVtkxRhUB7zoiajq2NAg.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_L2AVtkxRhUB7zoiajq2NAg-300x134.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p>Тут у нас есть элемент с таким CSS:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.element {\n    width: 50vw;\n}</code></pre>\n\n\n\n<p>Когда ширина вьюпорта равна&nbsp;<code>500px</code>, то&nbsp;<code>50vw</code>&nbsp;будут высчитаны таким образом:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>width = 500*50% = 250px</code></pre>\n\n\n\n<h3 id=\"eb6a\"><strong>Viewport высота</strong></h3>\n\n\n\n<p id=\"332a\">Единица&nbsp;<code>vh</code>&nbsp;представляет собой процентное измерение высоты корневого элемента. Один&nbsp;<code>vh</code>&nbsp;равен 1% высоты вьюпорта.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"312\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_kc2g2fzTx3SAkcph9NBt-A.png\" alt=\"\" class=\"wp-image-133\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_kc2g2fzTx3SAkcph9NBt-A.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_kc2g2fzTx3SAkcph9NBt-A-300x134.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p>У нас есть элемент с таким CSS:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.element {\n    height: 50vh;\n}</code></pre>\n\n\n\n<p>Если высота вьюпорта равна&nbsp;<code>290px</code>, то&nbsp;<code>70vh</code>&nbsp;будет высчитано следующим образом:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>height = 290*70% = 202px</code></pre>\n\n\n\n<p>Вот и всё! Теперь давайте взглянем на другие единицы.</p>\n\n\n\n<h3 id=\"0e5e\"><strong>Vmin</strong></h3>\n\n\n\n<p id=\"9294\">Эта единица является минимумом ширины или высоты вьюпорта. Если ширина вьюпорта больше его высоты, то значение единицы будет высчитано, основываясь на высоте.</p>\n\n\n\n<p id=\"4a7a\">Давайте посмотрим на пример ниже.</p>\n\n\n\n<p id=\"1579\">У нас есть мобильный телефон в лэндскейп режиме и у элемента на странице есть такая единица как&nbsp;<code>vmin</code>. В этом случае, значение будет высчитано по высоте вьюпорта, так как оно меньше ширины.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"1024\" height=\"552\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_DDoJrXcoVX5loBUkMc17FQ-1024x552.png\" alt=\"\" class=\"wp-image-134\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_DDoJrXcoVX5loBUkMc17FQ-1024x552.png 1024w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_DDoJrXcoVX5loBUkMc17FQ-300x162.png 300w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_DDoJrXcoVX5loBUkMc17FQ-768x414.png 768w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_DDoJrXcoVX5loBUkMc17FQ.png 1368w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" /></figure>\n\n\n\n<pre class=\"wp-block-code css\"><code>.element {\n    padding-top: 10vmin;\n    padding-bottom: 10vmin;\n}</code></pre>\n\n\n\n<p>Вот как она будет считаться:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"376\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_J_Wol0-88jy5cRj7211gKQ.png\" alt=\"\" class=\"wp-image-135\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_J_Wol0-88jy5cRj7211gKQ.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_J_Wol0-88jy5cRj7211gKQ-300x161.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p>Как вы уже могли предположить, результат будет считаться таким образом:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>padding-top = (10% of height) = 10% * 164 = 16.4px \npadding-bottom = (10% of height) = 10% * 164 = 16.4px</code></pre>\n\n\n\n<h3 id=\"1c49\"><strong>Vmax</strong></h3>\n\n\n\n<p id=\"f9f2\">Это прямая противоположность&nbsp;<code>vmin</code>. Значение считается основываясь на максимальной ширине и высоте.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"601\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_v-p6MyuVPBKae9ZiIZXufA.png\" alt=\"\" class=\"wp-image-136\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_v-p6MyuVPBKae9ZiIZXufA.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_v-p6MyuVPBKae9ZiIZXufA-300x258.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p>Давайте посмотрим на пример:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.element {\n    padding-top: 10vmax;\n    padding-bottom: 10vmax;\n}</code></pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"376\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_INb5s2nv253EyecbEkCBxQ.png\" alt=\"\" class=\"wp-image-137\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_INb5s2nv253EyecbEkCBxQ.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_INb5s2nv253EyecbEkCBxQ-300x161.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p>Результат бы был высчитан таким образом:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>padding-top = (10% of width) = 10% * 350 = 35px\npadding-bottom = (10% of width) = 10% * 350 = px</code></pre>\n\n\n\n<h2 id=\"e9a0\"><strong>Как viewport единицы отличаются от процентов?</strong></h2>\n\n\n\n<p id=\"efe7\">Они берут за основу корневой элемент страницы, в то время как проценты основаны на размере своего контейнера. Поэтому они и отличаются друг от друга и каждый имеет свойственные себе примеры использования.</p>\n\n\n\n<h2 id=\"f662\"><strong>Примеры использования viewport единиц</strong></h2>\n\n\n\n<p id=\"2abb\">В следующих секциях мы посмотрим на некоторые примеры использования единиц viewport и на то, как их применять в ваших рабочих проектах.</p>\n\n\n\n<h3><strong>Размер шрифта</strong></h3>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"265\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_5itbhe1WrKZly_Ju2zXPbw.png\" alt=\"\" class=\"wp-image-138\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_5itbhe1WrKZly_Ju2zXPbw.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_5itbhe1WrKZly_Ju2zXPbw-300x114.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p>Единицы вьюпорта идеальны для адаптивной типографики. Для примера, мы можем использовать следующий код для заголовка статьи:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.title {\n    font-size: 5vw;\n}</code></pre>\n\n\n\n<p id=\"d0d1\">Размер заголовка будет увеличиваться или уменьшаться в зависимости от ширины вьюпорта. Это как будто бы мы выдали размеру шрифта 5% ширины страницы. Однако, как бы не хотелось, а надо протестировать и смотрим,&nbsp;<a href=\"https://ishadeed.com/assets/viewport-units/font-size-issue.mp4\" target=\"_blank\" rel=\"noreferrer noopener\">что получается</a>.</p>\n\n\n\n<p id=\"12f0\">Обратите внимание, что шрифт стал очень мелким при мобильных размерах, это очень плохо в плане доступности и UX. Насколько я знаю, минимальный размер шрифта на мобильных устройствах не должен быть ниже&nbsp;<code>14px</code>. А там у нас выходит уже ниже&nbsp;<code>10px</code>.</p>\n\n\n\n<p id=\"a05a\">Чтобы решить эту проблему, нам надо дать заголовку минимальный размер шрифта, который не может быть меньше положенной нормы. И тут CSS&nbsp;<code>calc()</code>&nbsp;спешит на помощь!</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.title {\n    font-size: calc(14px + 2vw);\n}</code></pre>\n\n\n\n<p id=\"a957\">У функции&nbsp;<code>calc()</code>&nbsp;будет основное значение и оно добавит к нему&nbsp;<code>2vw</code>. Учитывая это, размер шрифта точно не будет слишком маленьким.</p>\n\n\n\n<p id=\"40aa\">Ещё стоит рассмотреть то, как себя будет вести размер шрифта на больших экранах, к примеру на 27” аймаках. Что будет? Ну вы уже наверное предположили. Размер шрифта бахнет аж в&nbsp;<code>95px</code>, что само по себе уже кошмар. Чтобы предохраниться от этой ситуации мы можем использовать медиа запросы на определённых брейкпоинтах и менять размеры шрифтов.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>@media (min-width: 1800px) {\n    .title {\n        font-size: 40px;\n    }\n}</code></pre>\n\n\n\n<p>Сбрасывая&nbsp;<code>font-size</code>&nbsp;мы можем быть уверены в том, что размер шрифта не будет слишком большим. Тут возможно вам понадобится несколько медиа запросов, но это сугубо ваше личное дело когда и как их использовать в контексте проекта.</p>\n\n\n\n<h3 id=\"f459\"><strong>Полноэкранные секции</strong></h3>\n\n\n\n<p id=\"33d4\">Иногда нам надо, чтобы секция забирала 100% высоты виюпорта. Это так называемые полноэкранные секции. Для их создания мы можем использовать вьюпорт единицу высоты.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.section {\n    height: 100vh;\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n}</code></pre>\n\n\n\n<p>Добавив&nbsp;<code>height: 100vh</code>, мы можем точно убедиться в том, высота секции будет в 100% высоту вьюпорта. Также, тут я добавил немного флексбокса, чтобы отцентровать контент вертикально и горизонтально.</p>\n\n\n\n<h3 id=\"b414\"><strong>Прилипающий футер</strong></h3>\n\n\n\n<p id=\"0dc6\">На больших экранах вы могли уже обратить внимание на то, что футер не прилипает к концу страницы. Ну и это нормально. Это даже не рассматривается как плохая практика. Однако, тут у нас есть пространство для улучшений. Давайте рассмотрим следующий кейс, в котором и происходит эта ошибка.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"405\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_S-PyPpXWDVK0_Cx9h9mEZQ.png\" alt=\"\" class=\"wp-image-139\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_S-PyPpXWDVK0_Cx9h9mEZQ.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_S-PyPpXWDVK0_Cx9h9mEZQ-300x174.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p>Чтобы её решить, нам нужно отдать основному контенту высоту, равную разнице между высотой вьюпорта и суммой хедера и футера. Динамически это довольно хитрая операция, но с помощью единиц вьюпорта всё становится довольно быстро и понятно.</p>\n\n\n\n<h3 id=\"eefd\"><strong>Первое решение: calc и единицы вьюпорта</strong></h3>\n\n\n\n<p id=\"74f4\">Если высота хедера и футера фиксированны, то их можно совместить с помощью функции&nbsp;<code>calc()</code>:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>header,\nfooter {\n    height: 70px;\n}\n\nmain {\n    height: calc(100vh - 70px - 70px);\n}</code></pre>\n\n\n\n<p id=\"138c\">Это решение не гарантирует того, что оно будет всегда работать, особенно для футера. За всю свою карьеру я никогда не использовал футер с фиксированной высотой, потому что это просто непрактично, особенно на разных размерах экранов.</p>\n\n\n\n<h3 id=\"29f7\"><strong>Второе решение: Flexbox и вьюпорт единицы (рекомендуемое)</strong></h3>\n\n\n\n<p id=\"1f4c\">Добавляя&nbsp;<code>100vh</code>&nbsp;как высоту для&nbsp;<code>body</code>&nbsp;элемента, мы можем использовать флексы для того, чтобы основной контент занимал всё оставшееся место.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>body {\n    min-height: 100vh;\n    display: flex\n    flex-direction: column;\n{\n\nmain {\n    flex-grow: 1;\n}</code></pre>\n\n\n\n<p>С учетом этого, наша проблема решена и у нас есть прилипающий футер вне зависимости от длины контента.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"405\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_GZPj18NGgpdOsrwiY7TP2w.png\" alt=\"\" class=\"wp-image-140\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_GZPj18NGgpdOsrwiY7TP2w.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_GZPj18NGgpdOsrwiY7TP2w-300x174.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<h3 id=\"0eff\"><strong>Адаптивные элементы</strong></h3>\n\n\n\n<p id=\"6ec4\">Занимаясь подготовкой материала я наткнулся на&nbsp;<a href=\"https://properdesign.co.uk/grid-viewport-units-site-previews/\" target=\"_blank\" rel=\"noreferrer noopener\">эту статью</a>&nbsp;и она мне реально понравилась. Так что я возьму пример использования оттуда и объясню его своим способом.</p>\n\n\n\n<p id=\"5e73\">Предположим, что у нас есть портфолио для того, чтобы показать свои адаптивные работы и у нас имеется три типа устройства (мобильные, планшеты и ноутбук). В каждом устройстве есть по изображению. Суть в том, чтобы сделать этот контент 100% отзывчивым на CSS.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"365\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_1v5lqmbFRzLL_OJ6rLRnhQ.png\" alt=\"\" class=\"wp-image-141\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_1v5lqmbFRzLL_OJ6rLRnhQ.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_1v5lqmbFRzLL_OJ6rLRnhQ-300x156.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p>Используя гриды и единицы вьюпорта, мы можем сделать это адаптивным и динамическим.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>&lt;div class=\"wrapper\">\n  &lt;div class=\"device laptop\">&lt;/div>\n  &lt;div class=\"device mobile\">&lt;/div>\n  &lt;div class=\"device tablet\">&lt;/div>\n&lt;/div></code></pre>\n\n\n\n<p>Обратите внимание, что вьюпорт единицы используются в grid-* свойствах. Они также используются для&nbsp;<code>border</code>,&nbsp;<code>border-radius</code>&nbsp;и других свойств. Всё это приведет к флюидному дизайну.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.wrapper {\n  display: grid;\n  grid-template-columns: repeat(20, 5vw); \n  grid-auto-rows: 6vw;\n}\n\n.mobile { \n  position: relative;\n  z-index: 1;\n  grid-column: 2 / span 3;\n  grid-row: 3 / span 5;\n}\n \n.tablet {\n  position: relative;\n  z-index: 1;\n  grid-column: 13 / span 7; \n  grid-row: 4 / span 4;\n  border-bottom: 1vw solid #a9B9dd;\n  border-right: solid 3vw #a9B9dd;\n}\n \n.laptop {\n  position: relative;\n  grid-column: 3/span 13;\n  grid-row: 2 / span 8;\n}\n\n.laptop:after {\n    content:\"\";\n    position:absolute;\n    bottom: -3vw;\n    left: -5.5vw;\n    right: -5.5vw;\n    height: 3vw;\n    background-color: #a9B9dd;\n    border-radius: 0 0 1vw 1vw;\n}</code></pre>\n\n\n\n<p><a rel=\"noreferrer noopener\" href=\"https://ishadeed.com/assets/viewport-units/devices.mp4\" target=\"_blank\">Видео пример</a></p>\n\n\n\n<h3 id=\"437a\"><strong>Выходим за пределы контейнера</strong></h3>\n\n\n\n<p id=\"4f10\">Я обратил внимание на случай, который больше всего подходит для редакторских шаблонов. А именно когда дочерний элемент забирает 100% ширины вьюпорта, хотя его родитель ограничен в ней. Давайте рассмотрим пример ниже:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"359\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_DjtxL4aIngGA5J05fH7HbQ.png\" alt=\"\" class=\"wp-image-142\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_DjtxL4aIngGA5J05fH7HbQ.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_DjtxL4aIngGA5J05fH7HbQ-300x154.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p>Чтобы достигнуть такого же эффекта, мы можем использовать вьюпорт единицы и свойства позиционирования. Вот наш CSS:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.break-out {\n    width: 100vw;\n    position: relative;\n    left: 50%;\n    right: 50%;\n    margin-left: -50vw;\n    margin-right: -50vw;\n}</code></pre>\n\n\n\n<p>Давайте разберем всё по полочкам и поймём как это работает.</p>\n\n\n\n<p><strong>Добавляем&nbsp;</strong><code><strong>width: 100vw</strong></code></p>\n\n\n\n<p>Самый важный шаг, который даст изображению ширину равную 100% вьюпорта.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"359\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_vTFWpH84uKolcHE5MhO8sw.jpeg\" alt=\"\" class=\"wp-image-143\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_vTFWpH84uKolcHE5MhO8sw.jpeg 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_vTFWpH84uKolcHE5MhO8sw-300x154.jpeg 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p><strong>Добавляем&nbsp;</strong><code><strong>margin-left: -50vw</strong></code></p>\n\n\n\n<p>Чтобы отцентровать изображение, нам понадобится выдать отрицательный маргин с половиной ширины вьюпорта.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"359\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_7m757QtQai0rfpEoDHRT6A.jpeg\" alt=\"\" class=\"wp-image-144\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_7m757QtQai0rfpEoDHRT6A.jpeg 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_7m757QtQai0rfpEoDHRT6A-300x154.jpeg 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p><strong>Добавляем&nbsp;</strong><code><strong>left: 50%</strong></code></p>\n\n\n\n<p>И наконец, мы отодвинем изображение в правую сторону со значением 50% от ширины его родителя.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"333\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_10qY852nZN2HUDjBOf_eNQ.jpeg\" alt=\"\" class=\"wp-image-145\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_10qY852nZN2HUDjBOf_eNQ.jpeg 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_10qY852nZN2HUDjBOf_eNQ-300x143.jpeg 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<h2 id=\"2366\"><strong>Вертикальный и горизонтальный спейсинг</strong></h2>\n\n\n\n<p id=\"8141\">Ещё один интересный пример, а именно использование вьюпорт единиц для спейсинга между элементами. Его можно использовать с таким значениями как&nbsp;<code>margin</code>,&nbsp;<code>top</code>,&nbsp;<code>bottom</code>&nbsp;и&nbsp;<code>grid-gap</code>. Применяя его, спейсинг будет основываться на ширине вьюпорта и его высоте, что может быть крайне полезным для создания динамических шаблонов.</p>\n\n\n\n<h3 id=\"3efb\"><strong>Модалка</strong></h3>\n\n\n\n<p id=\"632b\">В случае с модалками нам надо отталкивать их с самого верха вьюпорта. Зачастую я делал это с помощью свойства&nbsp;<code>top</code>&nbsp;и процентов с пикселями. Однако, с единицами вьюпорта, мы можем добавить спейсинг, который может меняться, основываясь на высоте самого вьюпорта.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"444\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_p23BlRWcD1yDxCF46-hnJg.png\" alt=\"\" class=\"wp-image-146\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_p23BlRWcD1yDxCF46-hnJg.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_p23BlRWcD1yDxCF46-hnJg-300x190.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<pre class=\"wp-block-code css\"><code>.modal-body {\n    top: 20vh;\n}</code></pre>\n\n\n\n<p>Посмотрите&nbsp;<a rel=\"noreferrer noopener\" href=\"https://ishadeed.com/assets/viewport-units/spacing-modal-final.mp4\" target=\"_blank\">это видео</a>, чтобы посмотреть на результат.</p>\n\n\n\n<h3 id=\"c259\"><strong>Шапка</strong></h3>\n\n\n\n<p id=\"d9f5\">Шапка это секция, которая показывает нам общую картину на странице или сайте. Часто там есть заголовок и описание, и среди этого всего есть фиксированная высота и падинги для верха и подвала страницы. Тут нам интересны падинги.</p>\n\n\n\n<p id=\"f242\">Для примера, вот как выглядит CSS:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.page-header {\n    padding-top: 1rem;\n    padding-bottom: 1rem;\n}\n\n@media (min-width: 800px) {\n    .page-header {\n        padding-top: 4rem;\n        padding-bottom: 4rem;\n    }\n}</code></pre>\n\n\n\n<p>Вертикальный паддинг довольно мал на мобильных устройствах и он становится больше на больших вьюпортах. Как насчет использования единиц вьюпорта? Давайте посмотрим на это.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.page-header {\n    padding-top: 10vh;\n    padding-bottom: 10vh;\n}\n\n.page-header h2 {\n    margin-bottom: 1.5vh;\n}</code></pre>\n\n\n\n<p>Я использовал&nbsp;<code>vh</code>&nbsp;для паддинга в шапке и маргина под заголовком. Обратите внимание&nbsp;<a rel=\"noreferrer noopener\" href=\"https://ishadeed.com/assets/viewport-units/spacing-page-header.mp4\" target=\"_blank\">как меняется спейсинг</a>!</p>\n\n\n\n<h3 id=\"879e\"><strong>Сетка из нескольких элементов</strong></h3>\n\n\n\n<p id=\"5307\">Ещё один пример динамического спейсинга можно применить в сетке из нескольких элементов. Тут может быть всё: статьи, секции контента, услуги и тп. В нашем примере мы посмотрим на то, как можно использовать вьюпорт единицы для сетки из статей.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"428\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_n4PxGmabRTUM_ZQAtZICNA.png\" alt=\"\" class=\"wp-image-147\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_n4PxGmabRTUM_ZQAtZICNA.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_n4PxGmabRTUM_ZQAtZICNA-300x183.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p>Используя их в&nbsp;<code>grid-gap</code>, мы можем получить желаемый результат. Обратите внимание, что я применял функцию&nbsp;<code>calc()</code>. Суть использования&nbsp;<code>calc()</code>&nbsp;в том, чтобы у нас уже был базис для вертикального и горизонтального промежутков.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.wrapper {\n    display: grid;\n    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));\n    grid-gap: calc(14px + 1vh) calc(14px + 0.5vw);\n}</code></pre>\n\n\n\n<h3 id=\"1654\"><strong>Vmin и Vmax — примеры использования</strong></h3>\n\n\n\n<p id=\"8479\">Изучая примеры использования для этих двух единиц, я не нашёл ничего, только этот пример из&nbsp;<a href=\"https://css-tricks.com/simple-little-use-case-vmin/\" target=\"_blank\" rel=\"noreferrer noopener\">CSS-tricks</a>.</p>\n\n\n\n<p id=\"ac67\">Этот пример показывает возможность работы с верхним и нижним паддингом в шапке элемента. Паддинг зачастую слишком сокращен, когда вьюпорт довольно мал. Используя&nbsp;<code>vmin</code>, мы можем иметь флюидные верхние и нижние паддинги, которые основываются на вьюпорте с маленькими размерами.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.page-header {\n    padding: 10vmin 1rem;\n}</code></pre>\n\n\n\n<p><a rel=\"noreferrer noopener\" href=\"https://ishadeed.com/assets/viewport-units/vmin-use.mp4\" target=\"_blank\">Пример</a></p>\n\n\n\n<h2 id=\"d6e3\"><strong>Вертикальные медиа запросы и единицы вьюпорта</strong></h2>\n\n\n\n<p id=\"1645\">Несколько лет назад я написал статью о&nbsp;<a href=\"https://ishadeed.com/article/vertical-media-queries/\" target=\"_blank\" rel=\"noreferrer noopener\">вертикальных медиа запросах</a>.</p>\n\n\n\n<p id=\"d796\">Сейчас я хочу пролить свет на эту тему, так как она имеет прямое отношение к статье, которую вы сейчас читаете.</p>\n\n\n\n<h3 id=\"824b\"><strong>Секции на всю высоту экрана в Landscape режиме</strong></h3>\n\n\n\n<p id=\"9201\">Используя вертикальные медиа запросы мы можем проверять находится ли девайс пользователя в лэндскэйп режиме. Если так, то тогда не будет смысла иметь секцию, занимающую всю высоту вьюпорта, применяя&nbsp;<code>height: 100vh</code>.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"337\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_qgPdQB23xvXBNy4YBtWKAw.png\" alt=\"\" class=\"wp-image-148\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_qgPdQB23xvXBNy4YBtWKAw.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_qgPdQB23xvXBNy4YBtWKAw-300x144.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p>Чтобы решить эту проблему, мы можем сделать следующее.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>@media (min-height: 400px) {\n    .section {\n        height: 100vh;\n    }\n}</code></pre>\n\n\n\n<p>Или мы можем использовать&nbsp;<code>orientation</code>&nbsp;в медиа запросах:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>@media (orientation: landscape) {\n    .section {\n        height: 100vh;\n    }\n}</code></pre>\n\n\n\n<h3 id=\"bfcd\"><strong>Соотношение сторон</strong></h3>\n\n\n\n<p id=\"b3e3\">Мы можем использовать&nbsp;<code>vh</code>&nbsp;для создания адаптивных элементов, которые поддерживают актуальное состояние соотношения сторон вне зависимости от размера вьюпорта. Давайте на это посмотрим.</p>\n\n\n\n<p id=\"68e1\">Нам нужно решить, какое соотношение сторон нам нужно. Для примера,&nbsp;<em>9/16</em>.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>section {\n    /* 9/16 * 100 */\n    height: 56.25vw;\n}</code></pre>\n\n\n\n<p><a href=\"https://codepen.io/shadeed/pen/dc4e82f3c873cc64ae5c5bc4a3f4ef9f\">Пример</a></p>\n\n\n\n<h3 id=\"e4ab\"><strong>Используем единицы вьюпорта для графических элементов</strong></h3>\n\n\n\n<p id=\"5dbc\">Я не уверен правильно ли я назвал это, но надеюсь, что вы поймете суть следующих графических примеров.</p>\n\n\n\n<p id=\"50d7\">Довольно популярный подход с верхним бордером</p>\n\n\n\n<p id=\"05b4\">Вы знали, что верхний бордер один из самых используемых элементов на веб сайтах к сегодняшнему дню? В основном его цвет, это такой же как и основной цвет страницы.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"327\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_4x1A2_WWsg8UKpz3_OTUeA.png\" alt=\"\" class=\"wp-image-149\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_4x1A2_WWsg8UKpz3_OTUeA.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_4x1A2_WWsg8UKpz3_OTUeA-300x140.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p>Давайте сделаем изначальным значением бордера&nbsp;<code>3px</code>. Как конвертировать это фиксированное значение в вьюпорт единицу? Вот как можно это посчитать:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>vw = (Pixel Value / Viewport width) * 100</code></pre>\n\n\n\n<p id=\"5e20\">Ширина вьюпорта используется для расчета отношения между пикселями и vw единицей.</p>\n\n\n\n<p id=\"2d36\">Для примера, вот как добавлен верхний бордер:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.header {\n    border-top: 4px solid #8f7ebc;  \n}</code></pre>\n\n\n\n<p>В моём случае ширина вьюпорта равна&nbsp;<em>1440</em>.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>vw = (4 / 1440) * 100 = 0.277\n</code></pre>\n\n\n\n<p>И вот такой CSS мы получим:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.header {\n    border-top: 0.277vw solid #8f7ebc;  \n}</code></pre>\n\n\n\n<p>Даже лучше, мы можем использовать основное значение в пикселях и единицу вьюпорта.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.header {\n    border-top: calc(2px + 0.138vw) solid $color-main;\n}</code></pre>\n\n\n\n<h3 id=\"12a6\"><strong>Нумерация секций</strong></h3>\n\n\n\n<p id=\"b3ca\">Для элементов секций с каунтером или иконкой, мы можем тоже применить единицы вьюпорта. Посмотрите на макет ниже:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"127\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_1VR3NGEF5a-xfJkS0mJUOA.png\" alt=\"\" class=\"wp-image-150\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_1VR3NGEF5a-xfJkS0mJUOA.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_1VR3NGEF5a-xfJkS0mJUOA-300x54.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<pre class=\"wp-block-code css\"><code>/**\n1. Используем гибкое значение для flex, width и height свойств.\n2. line-height используется для центровки текста вертикально.\n3. Размер шрифта.\n4. Расстояние между кругом и текстом\n**/\n.point:before {\n    flex: 0 0 calc(24px + 4vw); /* &#91;1] */\n    width: calc(24px + 4vw); /* &#91;1] */\n    height: calc(24px + 4vw); /* &#91;1] */\n    line-height: calc(24px + 4vw); /* &#91;2] */\n    font-size: calc(14px + 1vw); /* &#91;3] */\n    margin-right: calc(10px + 0.5vw); /* &#91;4] */\n}</code></pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"328\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_6KQUVxezgQKBjuObN8yf5g.png\" alt=\"\" class=\"wp-image-151\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_6KQUVxezgQKBjuObN8yf5g.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_6KQUVxezgQKBjuObN8yf5g-300x141.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p><a href=\"https://codepen.io/shadeed/pen/ca6ffb8b39c03ef7683eb15a7d53e195\">Пример</a></p>\n\n\n\n<h3 id=\"207e\"><strong>Viewport Units Watcher</strong></h3>\n\n\n\n<p id=\"d1c8\">Я сделал инструмент, которые помогает мне в проверке высчитанного значения элементов у единиц вьюпорта. Посмотрите ниже:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"395\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_DmeKMXjoSmVPcmJ-uOu3zQ.png\" alt=\"\" class=\"wp-image-152\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_DmeKMXjoSmVPcmJ-uOu3zQ.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_DmeKMXjoSmVPcmJ-uOu3zQ-300x169.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p>Я добавил имя класса и свойство для каждого элемента и при смене размеров вьюпорта, значение будут динамически обновляться. Это куда лучше, чем использование DevTools и высчитывание каждого отдельного элемента.</p>\n\n\n\n<p><a href=\"https://codepen.io/shadeed/pen/a531488bfdb9056b27f92f5dd190d257\">Пример</a></p>\n\n\n\n<h3 id=\"f4cf\"><strong>Проблема со скроллом на мобильных устройствах</strong></h3>\n\n\n\n<p id=\"41ce\">Есть распространенная проблема на мобильных устройствах, которая касается скролла, даже если используется&nbsp;<code>100vh</code>. Проблема тут в том, что адресная строка находится во вьюхе. Луис Хобрегс написал статью об этом и показал простое и легкое её решение.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.my-element {\n  height: 100vh;\n  height: calc(var(--vh, 1vh) * 100);\n}</code></pre>\n\n\n\n<p>А теперь js:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>let vh = window.innerHeight * 0.01;\ndocument.documentElement.style.setProperty('--vh', `${vh}px`);</code></pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"577\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_u3KmHDsW72H43eSr3-9row.png\" alt=\"\" class=\"wp-image-153\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_u3KmHDsW72H43eSr3-9row.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_u3KmHDsW72H43eSr3-9row-300x247.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<h3 id=\"1656\"><strong>Использование 100vw как антипаттерн</strong></h3>\n\n\n\n<p id=\"a856\">Применяя&nbsp;<code>100vw</code>&nbsp;для того, чтобы выдать элементу полную ширину вьюпорта, всё у вас будет отлично работать на Mac OS, так как вертикальный скроллбар там спрятан по-дефолту. Как результат, ширина скроллбара добавлена полной ширине.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"497\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_PQ2GypNHM9GOKCRbYDR-fQ.png\" alt=\"\" class=\"wp-image-154\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_PQ2GypNHM9GOKCRbYDR-fQ.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_PQ2GypNHM9GOKCRbYDR-fQ-300x213.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p>Однако, пользователи Windows обратят внимание на то, что появился горизонтальный скроллинг. Почему? Потому что ширина скроллбара была добавлена ширине экрана. Скажем, что вы добавили такой CSS:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.element {\n    width: 100vw;\n}</code></pre>\n\n\n\n<p>На Windows, высчитанная ширина&nbsp;<code>.element</code>&nbsp;будет равна&nbsp;<code>100vw + 8.5px</code>, где&nbsp;<code>8.5px</code>&nbsp;это ширина вертикального скроллбара.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"497\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_nVyFuQ04gY-d8HTc62L3Zg.png\" alt=\"\" class=\"wp-image-155\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_nVyFuQ04gY-d8HTc62L3Zg.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_nVyFuQ04gY-d8HTc62L3Zg-300x213.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p id=\"a386\">Насколько я знаю, то пока что нет конкретного решения этой проблемы без использования JavaScript, применение которого тут я не советую. Лучше избегать&nbsp;<code>100vw</code>&nbsp;и использовать альтернативу. Для примера, мы можем применить CSS Grid, чтобы элемент вышел за пределы контейнера, посмотрите на решение&nbsp;<a href=\"https://cloudfour.com/thinks/breaking-out-with-css-grid-layout/\" target=\"_blank\" rel=\"noreferrer noopener\">в этой статье</a>.</p>\n\n\n\n<p id=\"630e\">Спасибо Крису Моргану и Килиану Валкхофу за то, что предупредили меня об этой проблеме.</p>\n\n\n\n<h2 id=\"3a36\"><strong>Доступность это важно</strong></h2>\n\n\n\n<p id=\"f883\">Используя единицы вьюпорта довольно часто на вашем проекте, например для создание всего макета, доступность становится очень важной. Когда шаблон зумится ближе или отдаляется, элементы с единицами вьюпорат не будут увеличиваться или уменьшаться как вы ожидали. Это станет проблемой для пользователей, которые полагались на зум в браузере.</p>\n\n\n\n<p id=\"7e30\">По словам Сары Суейдан, использование единиц вьюпорта для размеров шрифтов это плохая практика в плане доступности. Лучше комбинировать их с фиксированными значениями, как описано ниже:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.title {\n    font-size: calc(16px + .3vw);\n}</code></pre>\n\n\n\n<p>Даже лучше, мы можем использовать CSS единицы&nbsp;<code>em</code>&nbsp;и&nbsp;<code>rem</code>, вместо&nbsp;<code>px</code>. Таким образом у нас будет больше контроля при изменении размера шрифта.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.title {\n    font-size: calc(1rem + .3vw);\n}</code></pre>\n\n\n\n<p>И это будет хорошо. Пожалуйста, убедитесь в том, что использование единиц вьюпорта подходит для того, что вы делаете и не забывайте хорошо тестировать.</p>\n\n\n\n<h2 id=\"9627\"><strong>Полезные инструменты</strong></h2>\n\n\n\n<p id=\"4eb0\">Я нашёл этот&nbsp;<a href=\"https://pxtovw.dev-calc.space/\" target=\"_blank\" rel=\"noreferrer noopener\">полезный конвертер</a>&nbsp;из&nbsp;<code>px</code>&nbsp;в&nbsp;<code>vw</code>, который может помочь вам в вашем проекте.</p>\n\n\n\n<p id=\"006b\">У вас есть какие-нибудь полезные инструменты?&nbsp;<a href=\"https://twitter.com/shadeed9\" target=\"_blank\" rel=\"noreferrer noopener\">Дайте мне знать</a>.</p>\n\n\n\n<h2 id=\"689e\"><strong>Ресурсы и связанные статьи</strong></h2>\n\n\n\n<figure class=\"wp-block-embed-wordpress wp-block-embed is-type-wp-embed is-provider-css-tricks\"><div class=\"wp-block-embed__wrapper\">\n<blockquote class=\"wp-embedded-content\" data-secret=\"eoiGe0U9AQ\"><a href=\"https://css-tricks.com/full-width-containers-limited-width-parents/\">Full Width Containers in Limited Width Parents</a></blockquote><iframe class=\"wp-embedded-content\" sandbox=\"allow-scripts\" security=\"restricted\" style=\"position: absolute; clip: rect(1px, 1px, 1px, 1px);\" title=\"&#8220;Full Width Containers in Limited Width Parents&#8221; &#8212; CSS-Tricks\" src=\"https://css-tricks.com/full-width-containers-limited-width-parents/embed/#?secret=eoiGe0U9AQ\" data-secret=\"eoiGe0U9AQ\" width=\"500\" height=\"282\" frameborder=\"0\" marginwidth=\"0\" marginheight=\"0\" scrolling=\"no\"></iframe>\n</div></figure>\n\n\n\n<figure class=\"wp-block-embed-wordpress wp-block-embed is-type-wp-embed is-provider-css-tricks\"><div class=\"wp-block-embed__wrapper\">\n<blockquote class=\"wp-embedded-content\" data-secret=\"oB8GE8ZKsE\"><a href=\"https://css-tricks.com/fun-viewport-units/\">Fun with Viewport Units</a></blockquote><iframe class=\"wp-embedded-content\" sandbox=\"allow-scripts\" security=\"restricted\" style=\"position: absolute; clip: rect(1px, 1px, 1px, 1px);\" title=\"&#8220;Fun with Viewport Units&#8221; &#8212; CSS-Tricks\" src=\"https://css-tricks.com/fun-viewport-units/embed/#?secret=oB8GE8ZKsE\" data-secret=\"oB8GE8ZKsE\" width=\"500\" height=\"282\" frameborder=\"0\" marginwidth=\"0\" marginheight=\"0\" scrolling=\"no\"></iframe>\n</div></figure>\n\n\n\n<figure class=\"wp-block-embed-wordpress wp-block-embed is-type-wp-embed is-provider-css-tricks\"><div class=\"wp-block-embed__wrapper\">\n<blockquote class=\"wp-embedded-content\" data-secret=\"WyoDXQ1KXI\"><a href=\"https://css-tricks.com/simple-little-use-case-vmin/\">Simple Little Use Case for `vmin`</a></blockquote><iframe class=\"wp-embedded-content\" sandbox=\"allow-scripts\" security=\"restricted\" style=\"position: absolute; clip: rect(1px, 1px, 1px, 1px);\" title=\"&#8220;Simple Little Use Case for `vmin`&#8221; &#8212; CSS-Tricks\" src=\"https://css-tricks.com/simple-little-use-case-vmin/embed/#?secret=WyoDXQ1KXI\" data-secret=\"WyoDXQ1KXI\" width=\"500\" height=\"282\" frameborder=\"0\" marginwidth=\"0\" marginheight=\"0\" scrolling=\"no\"></iframe>\n</div></figure>\n\n\n\n<h2 id=\"d589\"><strong>Заключение</strong></h2>\n\n\n\n<p id=\"669b\">Это всё. У вас есть какие-нибудь комментарии и предложения? Пишите автору на&nbsp;<a href=\"https://twitter.com/shadeed9\" target=\"_blank\" rel=\"noreferrer noopener\">shadeed9</a>.</p>\n","date":"2021-01-27T17:38:57.000Z","title":"Viewport единицы в CSS","id":"b8a232fa-254e-5bfa-8f47-687718f3808a","excerpt":"<p>В этой статье вы узнаете про единицы вьюпорта в CSS и варианты их применения.</p>\n","type":"html-css","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2021/01/viewportcssjnkjn.jpg"}}},{"node":{"slug":"kak-dovesti-raboty-s-form-do-ideala","content":"\n<p>У всех у нас были моменты, когда при использовании автозаполнения мы попадали в полный беспорядок. Одни поля остаются пустыми, другие заполняются неверными значениями, а еще одни полагаются на placeholder’ы, которые должны нам сказать то, чем же должна быть заполнена форма. Правильно ли вы в таком случае введете содержимое формы?</p>\n\n\n\n<p>Возможно единственным способом убедиться в верности заполненного значения будет удаление значения, выставленного автозаполнением, чтобы увидеть заново <code>placeholder</code>. Это расстраивает и вообще так не должно быть, в принципе.</p>\n\n\n\n<h2 id=\"22e6\">Делаем разметку правильно</h2>\n\n\n\n<p id=\"1a20\">Хорошая форма начинается с правильной разметки.</p>\n\n\n\n<h3 id=\"6f5f\">Выключаем автокоррекцию</h3>\n\n\n\n<p id=\"5346\">Выключайте&nbsp;<code>autocorrect</code>, когда он вам не нужен. Очень надоедает, когда система пытается что-то исправить, особенно если она не знает что. Это могут быть имена, названия улиц, компаний и городов. Всякий раз, когда вы пишете&nbsp;<code>&lt;input&gt;</code>, спросите себя: является ли потенциальное значение чем-то из общепринятого словаря? Если ответ — нет, то выключайте автокоррекцию. Вам это не нужно и пользователю уж темболее.</p>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;input autocorrect=\"off\" ...></code></pre>\n\n\n\n<h2 id=\"8386\">2. Выключайте autocapitalise</h2>\n\n\n\n<p id=\"76e7\">Выключайте его когда он вам не нужен. Похоже, что этот подход можно применить только к полям email, но поверьте, это очень удобно, избегать того, чтобы первый символ email был написан с большой буквы.</p>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;input autocapitalize=\"off\" …></code></pre>\n\n\n\n<h2 id=\"0be1\">3. Используйте autocomplete</h2>\n\n\n\n<p id=\"e662\">Этот атрибут позволяет вам контролировать то, как браузер должен заполнять заданные поля формы. Это ключ к правильно работающему автозаполнению. Популярными значениями для атрибута являются:&nbsp;<code>name</code>,&nbsp;<code>email</code>,&nbsp;<code>username</code>,&nbsp;<code>new-password</code>&nbsp;и&nbsp;<code>current-password</code>, но лист значений которые вы можете использовать&nbsp;<a rel=\"noreferrer noopener\" href=\"https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fe-autocomplete-name\" target=\"_blank\">может быть буквально бесконечным.</a></p>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;input autocomplete=\"tel\" …>\n&lt;input autocomplete=\"email\" …></code></pre>\n\n\n\n<h2 id=\"bc21\">4. Используйте required</h2>\n\n\n\n<p id=\"2c93\">Этот атрибут указывает на то, что поле ввода должно быть обязательно заполнено перед отправкой. Старайтесь использовать его, вместо валидации на JS, тогда, когда это возможно. Лучше дать браузеру сделать эту работу, вместо изобретения колеса с кастомной валидацией.</p>\n\n\n\n<p id=\"2445\">Браузеры по дефолту делают очень много: например, появляется подсказка и <code>input</code> попадает под видимость, когда пользователь пытается засабмитить пустое, требующее заполнение поле.</p>\n\n\n\n<p id=\"3d54\">Так же рекомендуется указывать на обязательность заполнения поля, добавляя подсказку для пользователя рядом с&nbsp;<code>input&nbsp;</code>или&nbsp;<code>label</code>. И даже тогда, когда все поля требуют заполнения.</p>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;input required ...></code></pre>\n\n\n\n<h2 id=\"ee21\">5. Используйте&nbsp;<code>type</code>&nbsp;и pattern</h2>\n\n\n\n<p id=\"eaa6\">Сенсорные устройства могут показывать разные, оптимизированные клавиатуры для каждой формы ввода, сразу же, как вы укажете им это сделать. Для примера: цифровая клавиатура на iPhone 6S имеет область-клика на 521% больше, чем дефолтная клавиатура. И это просто идеально для инпутов, которые принимаются только числовые значения.</p>\n\n\n\n<p id=\"5970\">Оптимизированные шаблоны клавиатуры могут быть вызваны при использовании type и pattern атрибутов. Есть также новый атрибут <code>inputmode</code>, но пока что он не может использоваться во многих браузерах.</p>\n\n\n\n<p id=\"f4a5\">Используйте&nbsp;<code>pattern=\"[0–9]*\"</code>&nbsp;или&nbsp;<code>inputmode=\"numeric\"</code>&nbsp;для вызова числовой клавиатуры.</p>\n\n\n\n<p id=\"6639\">Используйте&nbsp;<code>type=\"email\"</code>, чтобы вызвать email клавиатуру.</p>\n\n\n\n<p id=\"e928\">Используйте&nbsp;<code>type=\"url\"</code>, чтобы вызвать url клавиатуру.</p>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;input pattern=\"\\d*\" ...>\n&lt;input type=\"email\" ...>\n&lt;input type=\"url\" ...></code></pre>\n\n\n\n<h2 id=\"e165\">5. Используйте лейблы</h2>\n\n\n\n<p id=\"8bcd\">Дизайнеры и разработчики любят пропускать&nbsp;<code>&lt;label&gt;</code>, так как это делает форму чище, а код и стилизацию проще, но он играет важную роль для пользователей. Контроль формы, который полагается только на placeholder, является неидентифицируемым при заполнении. Это является особенной проблемой, тогда когда форма была заполнена с использованием автозаполнения: пользователи не могут сказать, заполнен ли <code>input</code> правильно, пока они не удалят введенное значение.</p>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;label for=\"email\">E-Mail&lt;/label>\n&lt;input id=\"email\" …></code></pre>\n\n\n\n<h2 id=\"cd77\">6. Используйте placeholder</h2>\n\n\n\n<p id=\"18fa\">Placeholder это подсказка для пользователя. Они всегда должны показывать потенциальное значение в ожидаемом формате. Такие&nbsp;<code>placeholder&nbsp;</code>как&nbsp;<code>+49</code>&nbsp;или&nbsp;<code>https://</code>&nbsp;идеальны для того, чтобы сказать пользователям, что они должны начать вводить номера телефонов с кода страны, а ссылки с протокола.</p>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;input placeholder=\"Jane Doe\" …></code></pre>\n\n\n\n<h2 id=\"25c8\">7. Используйте disabled</h2>\n\n\n\n<p id=\"9d34\">Используйте этот атрибут, чтобы деактивировать поля ввода. Не класс. Я повторяю: не класс.&nbsp;<code>disabled</code>&nbsp;может быть применен ко всем контроллерам форм и говорить браузеру, чтобы пользователь не использовал этот элемент. Добавление дополнительного класса в плане стилизации это ок, но помните, что вы можете также выбрать элемент с использованием&nbsp;<code>input[disabled]</code>&nbsp;в CSS.</p>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;select disabled>\n\t&lt;option value=\"a\">A&lt;/option>\n\t&lt;option value=\"b\">B&lt;/option>\n&lt;/select>\n\n&lt;select>\n\t&lt;option disabled>Choose A or B&lt;/option>\n\t&lt;option value=\"a\">A&lt;/option>\n\t&lt;option value=\"b\">B&lt;/option>\n&lt;/select>\n\n&lt;input disabled ...>\n&lt;textarea disabled ...>&lt;/textarea></code></pre>\n\n\n\n<h2 id=\"5b9f\">Получаем правильное юзабилити</h2>\n\n\n\n<p id=\"5bf1\">Правильная разметка это уже хорошая база для хорошего юзабилити.&nbsp;<code>autocorrect</code>,&nbsp;<code>autocapitalize</code>&nbsp;и autocomplete упрощают заполнение формы, используя&nbsp;<code>type</code>&nbsp;и&nbsp;<code>pattern</code>, вы точно будете знать, что сенсорные устройства показывают оптимизированную клавиатуру и placeholder дает пользователям знать, что им нужно ввести. Но этого недостаточно. Все еще есть множество моментов, в которых вы можете ошибиться, когда дело доходит до стилизации и общей структуры. Вот три отличных ресурса, чтобы улучшить UX ваших форм.</p>\n\n\n\n<p id=\"9ef7\"><a href=\"https://uxdesign.cc/design-better-forms-96fadca0f49c\" target=\"_blank\" rel=\"noreferrer noopener\">Делаем формы лучше</a>.</p>\n\n\n\n<p id=\"887d\"><a href=\"http://uxmovement.com/category/forms/\" target=\"_blank\" rel=\"noreferrer noopener\">UX Movement</a>. Это блог, который вам поможет улучшить ваши интерфейсы, показывая то, как хороший и плохой дизайн практически влияют на поведение пользователя.</p>\n\n\n\n<p id=\"7204\"><a href=\"https://baymard.com/blog\" target=\"_blank\" rel=\"noreferrer noopener\">Baymard Institute</a></p>\n\n\n\n<p id=\"06a5\">E-commerce UX исследование — раскрывает то, какие дизайн-проекты вызывают проблемы с юзабилити и как создать опыт взаимодействия в e-commerce по последнему слову техники. Бесплатные статье также содержат некоторые отличные посты, относящиеся к формам и инпутам.</p>\n\n\n\n<h2 id=\"416c\">Делаем стилизацию правильно</h2>\n\n\n\n<p id=\"eab8\">Стилизация формы это кошмар. Элементы даются со своим собственным стилем, который варьируется от системы к системе и от браузера к браузеру. Есть даже многостраничное руководство на MDN, объясняющее то, почему так тяжело стилизовать виджеты с CSS?</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"1000\" height=\"630\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_yy6jDGA2Pga_Kpg6bZA7zQ.png\" alt=\"\" class=\"wp-image-121\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_yy6jDGA2Pga_Kpg6bZA7zQ.png 1000w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_yy6jDGA2Pga_Kpg6bZA7zQ-300x189.png 300w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_yy6jDGA2Pga_Kpg6bZA7zQ-768x484.png 768w\" sizes=\"(max-width: 1000px) 100vw, 1000px\" /></figure>\n\n\n\n<p id=\"81aa\">Я провел очень много времени за стилизацией форм, так что принял решение сделать базу дефолтных стилей для распространенных input элементов:&nbsp;<a rel=\"noreferrer noopener\" href=\"https://github.com/electerious/formbase\" target=\"_blank\">formbase</a>&nbsp;устраняет кроссбраузерные баги, несоответствия между системами и применяет красивую дефолтную стилизацию для нескольких элементов input. Ноль зависимостей, без JavaScript, только CSS.</p>\n\n\n\n<p id=\"07e1\">Альтернатива formbase это Boilerform: маленький бойлерплэйт из HTML и CSS, который начался с подачи Chris Coyier (<a rel=\"noreferrer noopener\" href=\"https://css-tricks.com/boilerform/\" target=\"_blank\">A Boilerform Idea</a>) Она уже превратилась в проект, который пытается сделать работу с формами безболезненной.</p>\n\n\n\n<h2 id=\"9a7c\">Примеры разметки</h2>\n\n\n\n<p id=\"9e21\">Я бы хотел завершить этот пост несколькими примерами, показывающими распространенные поля ввода и их правильные атрибуты. Заходите в эту секцию всякий раз, когда вы пишите форму, чтобы убедиться в том, что ваша разметка соответствует лучшим практикам в этом деле.</p>\n\n\n\n<h3 id=\"fa68\">Имя</h3>\n\n\n\n<p id=\"d2c7\">Совет: всегда используйте одно имя, вместо разделения одного целого инпута.</p>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;label for=\"name\">Name&lt;/label>\n&lt;input id=\"name\" name=\"name\" type=\"text\" autocorrect=\"off\" autocomplete=\"name\" placeholder=\"Jane Doe\"></code></pre>\n\n\n\n<h3>Компания</h3>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;label for=\"company\">Company&lt;/label>\n&lt;input id=\"company\" name=\"company\" type=\"text\" autocorrect=\"off\" autocomplete=\"organization\" placeholder=\"World Wide Web Consortium\"></code></pre>\n\n\n\n<h2 id=\"227d\">Почтовый код</h2>\n\n\n\n<p id=\"e81f\">Совет: некоторые страны используют буквы в своих почтовых кодах. Убедитесь, что вы удалили pattern, когда пользователю нужно будет ввести почтовый код одной из таких стран.</p>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;label for=\"postalcode\">Postal code&lt;/label>\n&lt;input id=\"postalcode\" name=\"postalcode\" type=\"text\" pattern=\"\\d*\" novalidate autocorrect=\"off\" autocomplete=\"postal-code\" placeholder=\"02139\"></code></pre>\n\n\n\n<h3>Город</h3>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;label for=\"city\">City&lt;/label>\n&lt;input id=\"city\" name=\"city\" type=\"text\" autocorrect=\"off\" autocomplete=\"address-level2\" placeholder=\"Cambridge\"></code></pre>\n\n\n\n<h3>Улица</h3>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;label for=\"country\">Country name&lt;/label>\n&lt;input id=\"country\" name=\"countryname\" type=\"text\" autocomplete=\"country\" placeholder=\"Germany\"></code></pre>\n\n\n\n<h3>Телефон</h3>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;label for=\"tel\">Phone&lt;/label>\n&lt;input id=\"tel\" name=\"tel\" type=\"tel\" autocorrect=\"off\" autocomplete=\"tel\" placeholder=\"+1 617 253 5702\"></code></pre>\n\n\n\n<h3>E-mail</h3>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;label for=\"email\">E-Mail&lt;/label>\n&lt;input id=\"email\" name=\"email\" type=\"email\" autocapitalize=\"off\" autocorrect=\"off\" autocomplete=\"email\" placeholder=\"janedoe@example.com\"></code></pre>\n\n\n\n<h3>Дата рождения</h3>\n\n\n\n<pre class=\"wp-block-code html\"><code>&lt;label for=\"birthday\">Birthday&lt;/label>\n&lt;input id=\"birthday\" name=\"birthday\" type=\"date\" autocorrect=\"off\" autocomplete=\"bday\" placeholder=\"YYYY-MM-DD\" disabled></code></pre>\n\n\n\n<p></p>\n","date":"2021-01-20T14:58:50.000Z","title":"Как довести работу с <form> до идеала","id":"c6a3e197-bfc6-545b-928c-48c436f865e3","excerpt":"<p>Давйате посмотри на то, как можно довести работу с тегом form до идела и сделать жизнь пользователей проще</p>\n","type":"html-css","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2021/01/fjhbdhjsfbjshdbfjhsbdjkfsbk.jpg"}}},{"node":{"slug":"prokachivaem-naviki-raboty-s-css-selectorami","content":"\n<p>Работа с CSS селекторами это важный момент любой части Front-end разработки. Чем лучше вы их знаете, тем больше времени вы экономите себе и своим коллегам.</p>\n\n\n\n<p class=\"author\"><a rel=\"noreferrer noopener\" href=\"https://blog.logrocket.com/level-up-your-css-selector-skills-5d7bb45ddd37\" target=\"_blank\"><em>Перевод статьи Level up your CSS selector skills</em></a></p>\n\n\n\n<p id=\"cdbc\">Я использую уже CSS много лет, но есть одна вещь, которую я детально не рассматривал до недавнего момента — это тема CSS селекторов.</p>\n\n\n\n<p id=\"4d27\">Зачем нам глубоко это знать? Мы уже все хорошо знаем селекторы, верно? Но проблема тут в том(в моём случае), что со временем можно привязаться к использованию одного и того же проверенного набора CSS селекторов на каждом проекте, чтобы достигнуть того, что нам нужно сделать.</p>\n\n\n\n<p id=\"ce8c\">По-этому я взял на себя смелость провести детальное ревью этих самых селекторов и пройтись по некоторым самым интересным из них, которые были новыми для меня или с которыми я просто напросто не сталкивался прежде.</p>\n\n\n\n<p id=\"4acd\">Я так же открыл несколько новых, крутых селекторов, которые будут доступны в будущем, но пока что они не совсем широко поддерживаются.</p>\n\n\n\n<p id=\"1c1d\">Я приглашаю вас присоединиться ко мне, чтобы посмотреть на различные типы селекторов. Сколько из них вы уже используете в вашей ежедневной работе? Посмотрите и по возможности поделитесь.</p>\n\n\n\n<p id=\"a5fe\">Готовы прокачаться в плане CSS селекторов? Ок, поехали.</p>\n\n\n\n<h2 id=\"688b\">Комбинированные селекторы</h2>\n\n\n\n<p id=\"da5b\">Давайте начнем со знакомой территории. Комбинированные селекторы используются для выбора элементов потомков, так и сестринских. Впрочем мы с ними уже довольно хорошо знакомы.</p>\n\n\n\n<p id=\"d781\">Селектор потомка&nbsp;<code>A B</code></p>\n\n\n\n<p id=\"a238\">Селектор прямого потомка&nbsp;<code>A &gt; B</code></p>\n\n\n\n<p id=\"ba6a\">Смежный селектор&nbsp;<code>A + B</code></p>\n\n\n\n<p id=\"0d8b\">Родственный селектор&nbsp;<code>A ~ B</code></p>\n\n\n\n<p id=\"6d12\">Смежный селектор&nbsp;<code>A + B</code>&nbsp;должен уже быть вам знаком, он выбирает элемент B, который идет сразу после A. Но что по поводу родственного селектора&nbsp;<code>A ~ B</code>? Он выбирает все родственные элементы, которые идут после A. Вот их пример:</p>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\"Combinator Selectors\" src=\"https://codepen.io/dgwyer/embed/RyvYXd?height=265&amp;theme-id=light&amp;default-tab=html,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/dgwyer/pen/RyvYXd'>Combinator Selectors</a> by David Gwyer\n  (<a href='https://codepen.io/dgwyer'>@dgwyer</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<p>Строка New York выбрана, потому что она идет сразу же за первой строкой, а последние два города подсвечены синим, как основные родственные селекторы, подходящие под все города после четвертого.</p>\n\n\n\n<h2 id=\"90fa\">Селекторы атрибутов</h2>\n\n\n\n<p id=\"43f9\">Мне очень нравятся селекторы атрибутов. Они довольно гибки, когда вам надо выбрать элементы, включающие в себя атрибуты с конкретными значениями.</p>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\"Attribute Selectors #1\" src=\"https://codepen.io/dgwyer/embed/MGLZEK?height=265&amp;theme-id=light&amp;default-tab=html,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/dgwyer/pen/MGLZEK'>Attribute Selectors #1</a> by David Gwyer\n  (<a href='https://codepen.io/dgwyer'>@dgwyer</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<p id=\"f528\">Этот пример демонстрирует выборку всех чекбоксов в инпуте и применение стилей к их ассоциированным лейблам, сделав их жирными и синими.</p>\n\n\n\n<p id=\"6b1d\">Затем мы переписываем стиль для чекбокса с именем&nbsp;<code>chk2</code>&nbsp;и цвет его лейбла становится красным. Обратите внимание как другие лейблы не подвергаются стилизации.</p>\n\n\n\n<p id=\"df05\">Селекторы атрибутов, а не только вообще для форм, могут выбирать любые атрибуты на любом элементе. И вы можете выбрать любой атрибут, а не только те которые официально поддерживаются. Более того, вы можете просто проверить наличие атрибута, как написано дальше:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>button&#91;icon]</code></pre>\n\n\n\n<p>Он выбирает элементы&nbsp;<code>&lt;button&gt;</code>, которые содержат атрибут icon. Он выберет атрибут в не зависимости пустой или и имеет какие-то значения. Вот несколько примеров:</p>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\"Attribute Selectors #2\" src=\"https://codepen.io/dgwyer/embed/pVGGye?height=265&amp;theme-id=light&amp;default-tab=css,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/dgwyer/pen/pVGGye'>Attribute Selectors #2</a> by David Gwyer\n  (<a href='https://codepen.io/dgwyer'>@dgwyer</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<p id=\"df26\">Первая ссылка не имеет атрибута <code>target</code>, так что её не выбираем. Следующие две ссылки выбираются, так как у них есть пустой атрибут target или один со значением, это не важно. И под конец, последняя ссылка становится розовой, так как выбирается из-за наличия атрибута <code>fluffy</code>. Её значение нерелевантно и просто должно быть само по себе, чтобы селектор&nbsp;<code>a[fluffy]</code>&nbsp;его выбрал.</p>\n\n\n\n<p id=\"1dba\">Практический пример этого мог бы быть в подсвечивании изображений, которые не имеют атрибута <code>alt</code>. Этот атрибут требуется для доступности, так что он важен в целях SEO, так что вам нужно убедиться в том, что все изображения его имеют. Мы можем использовать следующее правило, чтобы это сделать:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>img:not(&#91;alt]) {\n border: 2px red dashed;\n}</code></pre>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\"Attribute Selectors #3\" src=\"https://codepen.io/dgwyer/embed/OZdqLp?height=265&amp;theme-id=light&amp;default-tab=html,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/dgwyer/pen/OZdqLp'>Attribute Selectors #3</a> by David Gwyer\n  (<a href='https://codepen.io/dgwyer'>@dgwyer</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<p id=\"91df\">Если вы хотите выбрать конкретную группу атрибутов, то для вас на этот случай есть группа очень полезных селекторов:</p>\n\n\n\n<p id=\"0b7c\"><code>A[attr^=val]</code>&nbsp;Атрибуты, которые начинаются со значения val.</p>\n\n\n\n<p id=\"c7f7\"><code>A[attr|=val]</code>Атрибуты, которые начинаются со значения val или он первый в списке, разделенном тире.</p>\n\n\n\n<p id=\"89e2\"><code>A[attr*=val]</code>&nbsp;— Значение появляется везде в атрибуте.</p>\n\n\n\n<p id=\"072b\"><code>A[attr~=val]</code>&nbsp;— Значение является одним из разделенным пробелом.</p>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\"Attribute Selectors #4\" src=\"https://codepen.io/dgwyer/embed/MGLdvE?height=265&amp;theme-id=light&amp;default-tab=html,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/dgwyer/pen/MGLdvE'>Attribute Selectors #4</a> by David Gwyer\n  (<a href='https://codepen.io/dgwyer'>@dgwyer</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<p id=\"96ac\">Первые два примера очень схожи, кроме&nbsp;<code>A[attr|=val]</code>, который также выбирает значения разделенные тире. Именно это может быть полезно для выбора языковых атрибутов. Как пример&nbsp;<code>&lt;p lang=“en-us”&gt;</code>.</p>\n\n\n\n<p id=\"5cae\">Выбор расширений файлов становится очень простым с&nbsp;<code>A[attr$=\"val\"]</code>, а в купе с&nbsp;<code>::after</code>&nbsp;вы можете легко показать совпавшие файлы. Не используя&nbsp;<code>attr()</code>&nbsp;и конкатенацию для совмещения их со строкой.</p>\n\n\n\n<p id=\"a5e0\">Со значением&nbsp;<code>A[attr*val]</code>&nbsp;вы можете показать любой домен, не зависимо от того, какой протокол он использует или какой субдомен у него.</p>\n\n\n\n<p id=\"4818\">И на последок, у нас есть&nbsp;<code>A[attr~=val]</code>, который отлично подходит для выбора значений в атрибутах, состоящих их списка значений, разделенных пробелами. Он выбирает только целое слово, а не фрагмент, как&nbsp;<code>*=</code>&nbsp;оператор, так что много множества слов выбраны не будут.</p>\n\n\n\n<p id=\"0a3a\">Все примеры селекторов атрибутов выше являются чувствительными к регистру. Но у нас у всех есть трюк в рукаве. Если мы добавим i, перед закрывающей скобкой, то мы сможем выключить чувствительность к реестру при выборке.</p>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\"Attribute Selectors #5\" src=\"https://codepen.io/dgwyer/embed/LmaYzp?height=265&amp;theme-id=light&amp;default-tab=html,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/dgwyer/pen/LmaYzp'>Attribute Selectors #5</a> by David Gwyer\n  (<a href='https://codepen.io/dgwyer'>@dgwyer</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<p>Большинство основных браузеров поддерживает выборку чувствительную к регистру, кроме Internet Explorer и Microsoft Edge.</p>\n\n\n\n<h1 id=\"7f14\">Селекторы пользовательского интерфейса</h1>\n\n\n\n<p id=\"1e35\">Если вы работали над стилизацией форм, то вы без сомнений встречали эти типы псевдо-классов:</p>\n\n\n\n<p id=\"8f42\"><code>:enabled</code></p>\n\n\n\n<p id=\"ec62\"><code>:disabled</code></p>\n\n\n\n<p id=\"4fa2\"><code>:checked</code></p>\n\n\n\n<p id=\"1683\">Для примера, мы можем использовать&nbsp;<code>:checked</code>&nbsp;для стилизации простого to-do списка.</p>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\"User Interface Selectors #1\" src=\"https://codepen.io/dgwyer/embed/BxbjoO?height=265&amp;theme-id=light&amp;default-tab=html,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/dgwyer/pen/BxbjoO'>User Interface Selectors #1</a> by David Gwyer\n  (<a href='https://codepen.io/dgwyer'>@dgwyer</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<p id=\"3f6a\">Это довольно стандартно, но к нашему распоряжению есть другие интересные псевдо классы.</p>\n\n\n\n<p id=\"fb46\"><code>:default</code> выбирает один или более элементов, которые дефолтны в группе связанных элементов. Это может быть удачно скомбинировано с кнопкой reset:</p>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\"User Interface Selectors #2\" src=\"https://codepen.io/dgwyer/embed/ELMoNK?height=265&amp;theme-id=light&amp;default-tab=html,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/dgwyer/pen/ELMoNK'>User Interface Selectors #2</a> by David Gwyer\n  (<a href='https://codepen.io/dgwyer'>@dgwyer</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<p id=\"6618\">Мы можем использовать псевдо классы для выбора значений ввода, верны они или нет. А так же не напрямую для CSS, в таких случаях как выбор любых требуемых элементов, перед тем как форма будет отправлена.</p>\n\n\n\n<p id=\"f7ee\"><code>:valid</code></p>\n\n\n\n<p id=\"c5d6\"><code>:invalid</code></p>\n\n\n\n<p id=\"aba7\"><code>:required</code></p>\n\n\n\n<p id=\"af2d\"><code>:optional (не обязательно)</code></p>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\"User Interface Selectors #3\" src=\"https://codepen.io/dgwyer/embed/qYvpMP?height=265&amp;theme-id=light&amp;default-tab=css,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/dgwyer/pen/qYvpMP'>User Interface Selectors #3</a> by David Gwyer\n  (<a href='https://codepen.io/dgwyer'>@dgwyer</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<p id=\"5945\">Если вы начнете писать в форму ввода адреса электронной почты, то потом оно должно стать валидным. Однако, форма ввода рабочего адреса всегда нужна и должна быть валидной, так что мы не можем оставить её пустой. Обратите внимание на то, как мы можем связывать псевдо-классы (<code>:required:invalid</code>), чтобы достигнуть того, что нам нужно.</p>\n\n\n\n<p id=\"05a4\">Далее у нас есть два псевдо класса, которые могут подходить, если элемент формы (который поддерживает атрибуты min и max) находится в нужном диапазоне или нет.</p>\n\n\n\n<p id=\"88eb\"><code>:in-range</code></p>\n\n\n\n<p id=\"308d\"><code>:out-of-range</code></p>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\"User Interface Selectors #4\" src=\"https://codepen.io/dgwyer/embed/Jvzpgz?height=265&amp;theme-id=light&amp;default-tab=css,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/dgwyer/pen/Jvzpgz'>User Interface Selectors #4</a> by David Gwyer\n  (<a href='https://codepen.io/dgwyer'>@dgwyer</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<p id=\"7661\">И снова, мы можем использовать кнопку с типом <code>reset</code>, чтобы сбросить все до дефолтных значений чисел элемента ввода.</p>\n\n\n\n<p id=\"2d81\">Завершая эту секцию, давайте взглянем на&nbsp;<code>:ready-only</code>,&nbsp;<code>:read-write</code>&nbsp;и&nbsp;<code>:placeholder-shown</code>.</p>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\"User Interface Selectors #5\" src=\"https://codepen.io/dgwyer/embed/ZoPREB?height=265&amp;theme-id=light&amp;default-tab=css,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/dgwyer/pen/ZoPREB'>User Interface Selectors #5</a> by David Gwyer\n  (<a href='https://codepen.io/dgwyer'>@dgwyer</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<p id=\"6d9a\">Используя их вы сможете легко выбрать элементы, которые только для чтения или редактируемые. Таким элементам не обязательно быть только полями формы ввода, как и продемонстрировано на примере выше.</p>\n\n\n\n<p id=\"c8c6\">И под конец,&nbsp;<code>:placeholder-shown</code>, который выберет элементы с которыми не взаимодействовали и будет до сих пор показываться текст дефолтного плейсхолдера. Этот селектор должен использоваться очень аккуратно, так как он пока широко не распространен.</p>\n\n\n\n<h2 id=\"63d1\">Структурные селекторы</h2>\n\n\n\n<p id=\"232f\">Это очень мощные селекторы и они могут выделять элементы, основываясь на их позиции в&nbsp;<code>DOM</code>. Они дают вам гибкости в выборе элементов на чистом CSS, что могло бы с другой стороны потребовать работы с JavaScript.</p>\n\n\n\n<p id=\"c19f\">Этот тип селекторов отличается от тех которые мы видели до этого тем, что они позволяют вам передать параметр, чтобы изменить работу селектора.</p>\n\n\n\n<p id=\"bea8\">Для примера&nbsp;<code>:nth-child()</code>&nbsp;получает значение, которое будет соответствовать конкретному дочернему элементу, относительно его родительского контейнера.</p>\n\n\n\n<p id=\"c963\">И так, если бы у нас был бы список элементов, то следующий селектор выбрал бы третий по списку.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>ul:nth-child(3)</code></pre>\n\n\n\n<p id=\"3bf8\">Однако, параметр не обязательно должен быть простым числом, он может быть простым выражением, что в свою очередь делает этот псевдокласс более мощным.</p>\n\n\n\n<p id=\"da58\"><code>ul:nth-child(2)</code>&nbsp;— Выберет второй дочерний элемент</p>\n\n\n\n<p id=\"5495\"><code>ul:nth-child(4n)</code>&nbsp;— Выберет каждый четвертый дочерний элемент (4, 8, 12, …)</p>\n\n\n\n<p id=\"9baa\"><code>ul:nth-child(2n + 1)</code>&nbsp;— Выберет каждый второй дочерний элемент, начиная с первого (1, 3, 5, …)</p>\n\n\n\n<p id=\"4afe\"><code>ul:nth-child(3n — 1)</code>&nbsp;— Выберет каждый третий дочерний элемент, начиная с минус первого (2, 5, 8, …)</p>\n\n\n\n<p id=\"7d87\"><code>ul:nth-child(odd)</code>&nbsp;— Выберет нечетные элементы (1, 3, 5, …)</p>\n\n\n\n<p id=\"52b4\"><code>ul:nth-child(even)</code>&nbsp;— Выберет четные элементы (2, 4, 6, …)</p>\n\n\n\n<p id=\"acbc\">Выражение переменной n всегда начинается с нуля, так что, чтобы разобраться какие элементы выберутся, начните с n, как нуля, затем n как 1 и так далее, чтобы составить список элементов.</p>\n\n\n\n<p id=\"885c\">Вы можете использовать простые выражения со следующими структурными селекторами:</p>\n\n\n\n<p id=\"a0c1\"><code>:nth-child()</code></p>\n\n\n\n<p id=\"fd7a\"><code>:nth-last-child()</code></p>\n\n\n\n<p id=\"c59f\"><code>:nth-of-type()</code></p>\n\n\n\n<p id=\"4e34\"><code>:nth-last-of-type()</code></p>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\"Structural Selectors #1\" src=\"https://codepen.io/dgwyer/embed/MGxzEq?height=265&amp;theme-id=light&amp;default-tab=css,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/dgwyer/pen/MGxzEq'>Structural Selectors #1</a> by David Gwyer\n  (<a href='https://codepen.io/dgwyer'>@dgwyer</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<p id=\"ab4a\"><code>:nth-last-child()</code>&nbsp;и&nbsp;<code>:nth-last-of-type()</code>&nbsp;очень схожи с :<code>nth-child()</code>&nbsp;и&nbsp;<code>:nth-of-type()</code>, кроме того, что они выбирают последний элемент, а не первый.</p>\n\n\n\n<p id=\"223d\">Вы можете покреативить с селекторами, играясь с различными комбинациями. Для примера, предидущий пример Pen содержал селектор:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>ul:last-of-type li:nth-last-of-type(2)::after {\n  content: “ (2nd from end)”;\n  /* Other styles… */\n}</code></pre>\n\n\n\n<p id=\"3c3e\">Он выберет псевдо элемент, который идёт после второго с конца списка внутри второго неупорядоченного списка. Если вы когда-нибудь пытались расшифровать сложный селектор, то лучше читать их справа на лево, так они могут быть разобраны логически.</p>\n\n\n\n<p id=\"78f2\">Следующий набор селекторов это специализированные структурные селекторы, так как они выбирают конкретного потомка и только. Вы не можете передать им выражение, чтобы изменить их поведение.</p>\n\n\n\n<p id=\"b350\"><code>:first-child</code></p>\n\n\n\n<p id=\"001f\"><code>:last-child</code></p>\n\n\n\n<p id=\"d8a8\"><code>:only-child</code></p>\n\n\n\n<p id=\"c611\"><code>:first-of-type</code></p>\n\n\n\n<p id=\"65af\"><code>:last-of-type</code></p>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\"Structural Selectors #2\" src=\"https://codepen.io/dgwyer/embed/JvzwJE?height=265&amp;theme-id=light&amp;default-tab=html,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/dgwyer/pen/JvzwJE'>Structural Selectors #2</a> by David Gwyer\n  (<a href='https://codepen.io/dgwyer'>@dgwyer</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<p id=\"d438\">На первый взгляд, тут много всего и вам надо быть осторожным при использовании таких типов селекторов, так как вы можете получить результаты которые вы не ожидали.</p>\n\n\n\n<p id=\"d853\">Для примера, вы можете удивиться почему And so on… текст синий внутри тега&nbsp;<code>&lt;section&gt;</code>. На самом деле весь контент секции синий, как последний потомок главного дива — контейнера. Другие элементы секции имеют свои собственные цвета, переписанные другими селекторами, оставляя только один параграф разукрашенным в синий цвет.</p>\n\n\n\n<h2 id=\"4236\">Селекторы контента</h2>\n\n\n\n<p id=\"fb35\">Эта секция о специальном наборе селекторов для выбора контента. Для нас доступны следующие из них:</p>\n\n\n\n<p id=\"109e\"><code>::first-line</code></p>\n\n\n\n<p id=\"7fcc\"><code>::first-letter</code></p>\n\n\n\n<p id=\"7066\"><code>::selection</code></p>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\"Content Selectors #1\" src=\"https://codepen.io/dgwyer/embed/xjBBqN?height=265&amp;theme-id=light&amp;default-tab=html,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/dgwyer/pen/xjBBqN'>Content Selectors #1</a> by David Gwyer\n  (<a href='https://codepen.io/dgwyer'>@dgwyer</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<p id=\"05bf\"><code>::first-line</code>&nbsp;и&nbsp;<code>::first-letter</code>&nbsp;работают только для блочных элементов. Так же аккуратно используйте&nbsp;<code>::first-letter</code>&nbsp;только на конкретных элементах, иначе каждый параграф будет буквицу, что возможно не то, чего вы хотели бы.</p>\n\n\n\n<p id=\"b959\">Есть довольно интересные селекторы в разработке, которые пока что не доступны, но когда они будут поддерживаться, то они откроют невероятное количество возможностей.</p>\n\n\n\n<p id=\"48bf\">Вот список контент селекторов, за которыми стоит следить:</p>\n\n\n\n<p id=\"2e97\"><code>::inactive-selection</code>&nbsp;— Выбирает контент внутри негативного окна.</p>\n\n\n\n<p id=\"3f26\"><code>::spelling-error&nbsp;</code>— Проверяет грамматику и правописание для редактируемых элементов.</p>\n\n\n\n<p id=\"27d3\"><code>::grammar-error</code>&nbsp;— Выбирает грамматические ошибки.</p>\n\n\n\n<p id=\"8589\"><code>::marker&nbsp;</code>— Выбирает маркеры списков.</p>\n\n\n\n<p id=\"af2a\"><code>::placeholder</code>&nbsp;— Выбирает текст плейсхолдеров элементов формы.</p>\n\n\n\n<h1 id=\"2dee\">Всякие другие селекторы</h1>\n\n\n\n<p id=\"5d2d\">И так, у нас есть немного времени упомянуть несколько других селекторов, которые не подходят ни под одну из предидущих категорий. Не переживайте, это почти уже всё. К сожалению, большинство из них экспериментальные, так что вам нужно подождать немного перед их использованием в деле.</p>\n\n\n\n<p id=\"45b2\"><code>:target</code>&nbsp;выбирает элемент с&nbsp;<code>id</code>, который соответствует части данного URL. Так что если бы у нас был элемент с&nbsp;<code>id</code>&nbsp;<code>part1&nbsp;</code>и ссылка:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>https:&#47;&#47;mysite.com#part1</code></pre>\n\n\n\n<p>Мы бы могли выбрать этот элемент:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>:target { border: 1px red solid; }</code></pre>\n\n\n\n<p>Если у вас большой селектор, тогда&nbsp;<code>:matches()</code>&nbsp;сможет его упростить. Для примера, если у вас такая выборка:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>nav p.content,\nheader p.content,\nmain p.content,\nsidebar p.content,\nfooter p.content {\n  margin: 15px;\n  padding: 10px;\n}</code></pre>\n\n\n\n<p>То он может быть упрощен с&nbsp;<code>:matches()</code>&nbsp;и быть эквивалентным:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>:matches(nav, header, main, sidebar, footer) p:content {\n  margin: 15px;\n  padding: 10px;\n}</code></pre>\n\n\n\n<p id=\"3d40\">Отлично, это поможет сделать таблицы стилей более читаемыми. Далее у нас есть&nbsp;<code>:any-link</code>, очень удобный селектор и делает тоже самое, что и&nbsp;<code>:link</code>&nbsp;и&nbsp;<code>:visited</code>&nbsp;вместе.</p>\n\n\n\n<p id=\"6949\">Так что эти два селектора были бы фактически тем же самым:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>:any-link {\n  color: red;\n}\n:link, :visited {\n  color: red;\n}</code></pre>\n\n\n\n<p id=\"ebb6\">И мы подходим к последним селекторам в этой статье:</p>\n\n\n\n<p id=\"6062\"><code>:dir()</code></p>\n\n\n\n<p id=\"0ba5\"><code>:lang()</code></p>\n\n\n\n<p id=\"8640\">Оба они относятся к языку сайта.</p>\n\n\n\n<p id=\"47e8\"><code>:dir()</code>&nbsp;берёт параметр&nbsp;<code>ltr</code>&nbsp;или&nbsp;<code>rtl</code>, в зависимости от направления текста, который вы хотите выбрать и сейчас поддерживается Firefox.</p>\n\n\n\n<p id=\"75cf\">Так что&nbsp;<code>:dir(rtl)</code>&nbsp;выбрал бы все элементы с контентом в направлении справа на лево.</p>\n\n\n\n<p id=\"8baa\">Каждый элемент в HTML документе может выставлять свой индивидуальный язык, используя атрибут lang.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>&lt;div lang=\"en\">The language of this element is set to English.&lt;/div>\n&lt;div lang=\"el\">Η γλώσσα αυτού του στοιχείου έχει οριστεί στα ελληνικά.&lt;/div>\n&lt;div lang=\"is\">Tungumál þessa þáttar er sett á íslensku.&lt;/div></code></pre>\n\n\n\n<p id=\"40e3\">Один и тот же простой текст введен в три дива, но с указанием страны, добавленным в конец контента. Также, коды стран используются атрибуте Lang представляя соответствующую страну.</p>\n\n\n\n<p id=\"d3cc\"><code>en</code>&nbsp;— Английский язык</p>\n\n\n\n<p id=\"a510\"><code>el&nbsp;</code>— Греческий язык</p>\n\n\n\n<p id=\"8d8b\"><code>is&nbsp;</code>— Исландский язык</p>\n\n\n\n<p id=\"2db1\">Дивы могут быть выбраны по&nbsp;<code>:lang</code>&nbsp;селектору:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>:lang(en) { color: red; }\n:lang(el) { color: green; }\n:lang(is) { color: blue; }</code></pre>\n\n\n\n<p>Вот демонстрация:</p>\n\n\n\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\"Misc Selectors\" src=\"https://codepen.io/dgwyer/embed/xjBoNG?height=265&amp;theme-id=light&amp;default-tab=html,result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\n  See the Pen <a href='https://codepen.io/dgwyer/pen/xjBoNG'>Misc Selectors</a> by David Gwyer\n  (<a href='https://codepen.io/dgwyer'>@dgwyer</a>) on <a href='https://codepen.io'>CodePen</a>.\n</iframe>\n\n\n\n<p>И хорошие новости в том, что&nbsp;<code>:lang</code>&nbsp;селектор уже поддерживается всеми главными браузерами.</p>\n\n\n\n<h2 id=\"6d20\">И под конец</h2>\n\n\n\n<p id=\"b521\">Я надеюсь, что вы нашли эту статью полезной. Я определенно хорошо провожу время, улучшая свои навыки работы с селекторами и играясь с разными возможностями.</p>\n\n\n\n<p id=\"592d\">Есть много крутых вещей, которые вы можете сделать с чистым CSS, что не было возможным хотя бы несколько лет назад.</p>\n\n\n\n<p id=\"2cc7\">Это очень интересно для дизайнеров, которые могут красивую продвинутую стилизацию и анимацию на чистом CSS и всё это без единой строчки кода на JavaScript.</p>\n\n\n\n<p id=\"53ef\">Веселой стилизации!</p>\n","date":"2021-01-15T14:36:08.000Z","title":"Прокачиваем навыки работы с CSS селекторами","id":"c3a920d9-2073-52cd-955e-de683316bbdd","excerpt":"<p>Работа с CSS селекторами это важный момент любой части Front-end разработки. Чем лучше вы их знаете, тем больше времени вы экономите себе и своим коллегам.</p>\n","type":"html-css","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2021/01/kjdnskjfndkjslfnkjdlnfksjndfklsnfks.jpg"}}},{"node":{"slug":"css-important-i-chto-my-mozhem-s-nim-podelat","content":"\n<p>Используя&nbsp;<code>!important</code>&nbsp;вы даете максимально больше важности CSS правилу на котором его применяете. Вы можете применять его не только в таблице сталей, но и в инлайновых стилях. И кстати, если вы так делаете, то вы совершаете большую ошибку. Сейчас узнаем почему.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"303\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_JVgiKsV02qczV8MG2gu7Ug.png\" alt=\"\" class=\"wp-image-90\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_JVgiKsV02qczV8MG2gu7Ug.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_JVgiKsV02qczV8MG2gu7Ug-300x130.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p>Правило&nbsp;<code>!important</code>&nbsp;представлено в спецификации CSS1 с целью перезаписи буквально любых стилевых значений. Для разработчиков это куда более важный элемент, нежели для простых пользователей. Как вы уже наверное догадались, этот подход был мало связан с доступностью и поэтому пришлось его переосмыслить, но уже в CSS2.</p>\n\n\n\n<p class=\"author\"><a rel=\"noreferrer noopener\" href=\"https://pineco.de/css-important-and-what-we-can-use-for-it/?ct=t(hamail_20180615)\" target=\"_blank\"><em>Перевод статьи CSS !important and What We Can Use for It</em></a></p>\n\n\n\n<p id=\"7532\">Правило с&nbsp;<code>!important</code>&nbsp;само по себе не обращает внимания на специфику или каскадирование. Поведение зависит от контекста, но практически всё в CSS может быть перезаписано с&nbsp;<code>!important</code>.</p>\n\n\n\n<p id=\"4195\">Если вы почитаете о CSS архитектуре, то вы увидите, что никто не советует использование&nbsp;<code>!important</code>. Применяя его, по факту, вы делаете код только хуже. По большому счету это правда, так как вы полностью убиваете каскадирование и специфичность перезаписываемого стиля элемента. Если вы используете его, чтобы перезаписать правило в коде посложнее, то тут каждый человек заверит вас, что это обернется для вас кошмаром.</p>\n\n\n\n<p id=\"97d0\">И так, зная это, зачем тогда нам использовать&nbsp;<code>!important</code>? Как вы уже предположили, это удобный инструмент, но мы должны использовать его с осторожностью. Давайте посмотрим несколько возможных примеров использования, но сначала немного простого CSS.</p>\n\n\n\n<h2 id=\"3fa3\"><strong>Специфичность CSS и каскадирование</strong></h2>\n\n\n\n<p id=\"62d1\">Говоря о специфичности, мы имеем ввиду более точный селектор, как в следующем примере:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.entry-content {\n    color: red;\n}\n\n.entry-content p {\n    color: black;\n}</code></pre>\n\n\n\n<p id=\"f3bc\">Последнее правило более точное, так как мы выбрали&nbsp;<code>&lt;p&gt;</code>&nbsp;элементы внутри&nbsp;<code>.entry-content</code>, следовательно&nbsp;<code>&lt;p&gt;</code>&nbsp;теги будут черного цвета.</p>\n\n\n\n<p id=\"e3ce\">Менее специфичные селекторы это типовые селекторы (<code>h1</code>,&nbsp;<code>p</code>,&nbsp;<code>span</code>,&nbsp;<code>div</code>), следующие за классовыми селекторами (<code>.entry-content</code>), селекторами атрибутов (<code>type='radio'</code>) и псевдоклассами(<code>:hover</code>,&nbsp;<code>:focus</code>). Самые весомые в этом случае это ID селекторы (<code>#main</code>).</p>\n\n\n\n<p id=\"76f8\">Под каскадированием мы подразумеваем естественный каскадный поток CSS. Где по важности находится правило? Чем оно ближе к концу в цепочке правил, тем больше важности оно имеет. Порядок таков: объявления из браузера, затем от пользователя, затем от автора, затем от автора с&nbsp;<code>!important</code>, затем от пользователя с&nbsp;<code>!important</code>. Если у браузера есть дефолтный стиль для тегов заголовков, то вы как автор легко можете перезаписать его с селекторами меньшей специфичности. И мы еще не упоминали наследование, которое случается довольно часто.</p>\n\n\n\n<p id=\"4b00\">Конечно же, такое каскадирование тоже работает в таблице стилей: более позднее правило с той же специфичностью побьёт предыдущее.</p>\n\n\n\n<p id=\"69f7\">Вообще понимание&nbsp;<a rel=\"noreferrer noopener\" href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity\" target=\"_blank\"><em>специфичности</em></a>&nbsp;и&nbsp;<a rel=\"noreferrer noopener\" href=\"https://developer.mozilla.org/en-US/docs/Learn/CSS/Introduction_to_CSS/Cascade_and_inheritance\" target=\"_blank\"><em>каскадирования</em></a>&nbsp;могло бы быть посложнее. Для большей информации проверьте ссылки.</p>\n\n\n\n<h2 id=\"92eb\"><strong>И так, для чего мы можем его использовать?</strong></h2>\n\n\n\n<p id=\"585a\">Безусловно&nbsp;<code>!important</code>&nbsp;имеет плохую репутацию, так как иногда для ленивых разработчиков — особенно для меня — гораздо удобнее перезаписать всё с помощью этого не совсем элегантного способа, вместо того, чтобы копаться в коде и решать реальную проблему, которая обычно кроется в плохой архитектуре.</p>\n\n\n\n<h3 id=\"a063\">Дебажиим код</h3>\n\n\n\n<p id=\"dda3\">Самый очевидный способ использовать это слово — это дебаггинг вашего кода, обычно в браузере. Временно используя !important в вашем коде, вы можете устранить некоторые конфликты и можете изолировать проблему. В Chrome, вы можете также добавить инлайновые стили, которые также переписывают необходимые авторские значения.</p>\n\n\n\n<p id=\"ca38\">Это удобно для быстрых правок и целей исследования. Если вам всё таки понадобилось это правило, то возможно вам пора заняться  рефакторингом кода.</p>\n\n\n\n<h2 id=\"0872\">Скрытие элементов</h2>\n\n\n\n<p id=\"b81f\">Есть разные способы что-нибудь спрятать от обычных пользователей, но если вы хотите точно убедиться в результате, то !important может быть полезным. Конечно, если вы работаете над своим проектом, вы знаете точно — так ли это вам нужно.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.visually-hidden {\n    position: absolute !important;\n    height: 1px; width: 1px; \n    overflow: hidden;\n    clip: rect(1px 1px 1px 1px); \n    clip: rect(1px, 1px, 1px, 1px);\n}</code></pre>\n\n\n\n<p>В этом примере, вы заставляете элемент выставить позиционирование на абсолютное, несмотря на каскадирование и специфичность. Обратите внимание, что тут может быть несколько случаев, где этого не совсем достаточно, но это несомненно паршивый подход в плане долгосрочной перспективы.</p>\n\n\n\n<h2 id=\"3244\">Защитный CSS</h2>\n\n\n\n<p id=\"5f5c\">Это концепция в которой вы, как разработчик пытаетесь убедиться в том, что пользователь может сделать наименьшее количество ошибок во время редактирования контента. Вот например как тут, где конкретно указывается, что все изображения будут блочными элементами.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.entry-content img {\n    display: block !important;\n}</code></pre>\n\n\n\n<p id=\"8d21\">Используя этот коды вы убедитесь в том, что пользователь по ошибке не сможет сделать изображение строчным или строчно-блочным , даже если теоретически может.</p>\n\n\n\n<h3 id=\"f1fd\">Хакнуть восхитительный WYSIWYG редактор</h3>\n\n\n\n<p id=\"8ce0\">В WordPress стандартным WYSIWYG редактором является TinyMCE, который по моему мнению не самый худший. Один из его вспомогательным атрибутов не использует инлайновые стили как CKEditor.</p>\n\n\n\n<p id=\"262e\">Когда вы редактируете контент в CKEditor, тут будут инлайновые стили, которые имеют больший вес в приоритезации, чем авторские. Что нам делать? Использовать !important и контролировать необходимое поведение.</p>\n\n\n\n<h2 id=\"6180\">Вспомогательные классы</h2>\n\n\n\n<p id=\"7fc3\">Большинство вспомогательных классов имеют низкую специфичность, особенно с всего одним классом. Этот момент может быть довольно коварным, если вы используете класы внутри контейнера, как например тут.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.btn{\n    display: inline-block;\n    background: #3590f1;\n    padding: 0.7em 1.6em;\n    border-radius: 2px;\n    font-size: 1rem;\n    font-weight: 700;\n    color: #fff;\n    text-transform: uppercase;\n    text-decoration: none;\n\n    &amp;:hover,\n    &amp;:focus {\n        background: #5adba0;\n    }\n}\n\n.entry-content a {\n    text-decoration: underline;\n    color: #3590f1;\n}</code></pre>\n\n\n\n<p>Хотя с нашим классом&nbsp;<code>.btn</code>&nbsp;всё ок, его специфичность низка, так что простое второе правило, которое идет дальше — перепишет его свойства, в данном случае это <code>color</code> и&nbsp;<code>text-decoration</code>. Вам нужно написать простой селектор, но проблема всё же останется.</p>\n\n\n\n<p>Вы можете решить ее, использовав&nbsp;<code>!important</code>, как в этом примере:</p>\n\n\n\n<p class=\"codepen\" data-height=\"265\" data-theme-id=\"light\" data-default-tab=\"css,result\" data-user=\"adamlaki\" data-slug-hash=\"wjxbrQ\" style=\"height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;\" data-pen-title=\"CSS !important with Utility Classes\">\n  <span>See the Pen <a href=\"https://codepen.io/adamlaki/pen/wjxbrQ\">\n  CSS !important with Utility Classes</a> by Adam Laki (<a href=\"https://codepen.io/adamlaki\">@adamlaki</a>)\n  on <a href=\"https://codepen.io\">CodePen</a>.</span>\n</p>\n<script async=\"\" src=\"https://cpwebassets.codepen.io/assets/embed/ei.js\"></script>\n\n\n\n<p>После этого, вам также придется применять эту технику в модификаторах и всяких псевдо объявлениях стилей.</p>\n\n\n\n<h2 id=\"f826\">БЭМ метод</h2>\n\n\n\n<p id=\"fa5e\">БЭМ это тот метод, который основывается низкой специфичности и иногда из-за этого может вызывать некоторые неприятности со стилями. Почти все селекторы имеют один класс. Я даже не знаю сколько раз мне надо было рефакторить код, созданный по этой технике. Конечно, у вас есть и свои решения описанных проблем, но в следующий раз может вы тоже будете использовать&nbsp;<code>!important</code>.</p>\n","date":"2021-01-13T15:06:02.000Z","title":"CSS !important и что мы можем с ним поделать","id":"6c8548b2-30da-5cae-83cc-5bc5692ea681","excerpt":"<p>Используя !important вы даете максимально больше важности CSS правилу на котором его применяете. Вы можете применять его не только в таблице сталей, но и в инлайновых стилях. И кстати, если вы так делаете, то вы совершаете большую ошибку. Сейчас узнаем почему.</p>\n","type":"html-css","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2021/01/fkdjsbjfkhbdsjhdbsjkf.jpg"}}},{"node":{"slug":"velikolepnyi-hover-effect-s-css-peremennimy","content":"\n<p id=\"21a3\">Для того, чтобы понять, что такое CSS переменные то советую прочитать статью — <a href=\"https://stasonmars.ru/html-css/rukovodstvo-po-rabote-s-peremennimy-v-css/\">Руководство по работе с переменными в CSS</a>.</p>\n\n\n\n<p id=\"ed79\">Там вы поймете, что с ними делать и как с ними быть. Ничего сложного на самом деле, только нужно немного захотеть разобраться.</p>\n\n\n\n<p id=\"3165\">А в этой статье вы узнаете как применять эти самые переменные в реальном и очень полезном кейсе. Создавая великолепный hover эффект.</p>\n\n\n\n<p class=\"author\"><em>Перевод статьи&nbsp;</em><a href=\"https://blog.prototypr.io/stunning-hover-effects-with-css-variables-f855e7b95330\"><em>Stunning hover effects with CSS variables</em></a></p>\n\n\n\n<p> Недавно я был воодушевлён забавной hover анимацией&nbsp;<a href=\"https://getgrover.com/de-en/products/iphone-x-64gb\">на сайте Grover</a>. Двигая мышкой над кнопкой подписки появляется цветной градиент, который следует за курсором во время его движения. Идея простая, но как результат мы получаем кнопку, которая выделяется на фоне других и прямо напрашивается на то, чтобы по ней кликнули.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"696\" height=\"316\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_h6jWPeAzIatzjLmRr9JAvg.gif\" alt=\"\" class=\"wp-image-82\"/></figure>\n\n\n\n<p>Как мы можем достигнуть такого же эффекта, чтобы наш сайт тоже выделялся? Ну, это не так сложно, как вы уже могли подумать.</p>\n\n\n\n<h2 id=\"02f0\">Отслеживание позиции</h2>\n\n\n\n<p id=\"56e9\">Первое, что нам нужно это позиция мышки.</p>\n\n\n\n<pre class=\"wp-block-code javascript\"><code>document.querySelector('.button').onmousemove = (e) => {\n  const x = e.pageX - e.target.offsetLeft\n  const y = e.pageY - e.target.offsetTop\n  e.target.style.setProperty('--x', `${ x }px`)\n  e.target.style.setProperty('--y', `${ y }px`)\n \n}</code></pre>\n\n\n\n<p id=\"1b0a\">Выберите элемент и ждите пока пользователь не двинет мышкой вдоль него.</p>\n\n\n\n<p id=\"a923\">Высчитайте позицию относительно элемента.</p>\n\n\n\n<p id=\"d3b9\">Сохраните координаты в CSS переменную.</p>\n\n\n\n<p id=\"3d8a\">Да, всего 9 строчек кода, чтобы указать CSS где пользователь позиционирует мышку. Вообще количество эффектов, которое вы можете сделать с помощью этой информации просто бесчисленно. Но давайте завершим наш CSS, для начала.</p>\n\n\n\n<h2 id=\"e816\">Анимируем градиент</h2>\n\n\n\n<p id=\"9dc7\">Теперь у нас есть координаты записанные в CSS переменные и мы можем использовать их по всему нашему CSS.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.button {\n  position: relative;\n  appearance: none;\n  background: #f72359;\n  padding: 1em 2em;\n  border: none;\n  color: white;\n  font-size: 1.2em;\n  cursor: pointer;\n  outline: none;\n  overflow: hidden;\n  border-radius: 100px;\n  span {\n    position: relative;\n  }\n  &amp;::before {\n    --size: 0;\n    content: '';\n    position: absolute;\n    left: var(--x);\n    top: var(--y);\n    width: var(--size);\n    height: var(--size);\n    background: radial-gradient(circle closest-side, #4405f7, transparent);\n    transform: translate(-50%, -50%);\n    transition: width .2s ease, height .2s ease;\n  }\n  &amp;:hover::before {\n    --size: 400px;\n  }\n}</code></pre>\n\n\n\n<p id=\"e4ba\">Оберните текст в <code>span</code>, чтобы избежать того, что градиент появится над ним.</p>\n\n\n\n<p id=\"914e\">Начните с&nbsp;<code>width</code>&nbsp;и&nbsp;<code>height</code>&nbsp;<code>0px</code>&nbsp;и поднимайте до&nbsp;<code>400px</code>, когда пользователь наведет на кнопку. И не забудьте выставить переход (<code>transition</code>), чтобы бы все это происходило плавно, быстро и красиво.</p>\n\n\n\n<p id=\"96db\">Используйте координаты, чтобы следовать за мышкой.</p>\n\n\n\n<p id=\"1d73\">Примените&nbsp;<code>radial-gradient</code>&nbsp;для&nbsp;<code>background</code>&nbsp;и используйте closest-side circle. Closest-side заполнит весь before, не выходя за него.</p>\n\n\n\n<h2 id=\"0e65\">Результат</h2>\n\n\n\n<p id=\"0fdf\">И всё! Добавьте недостающий HTML и наслаждайтесь кнопкой.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>&lt;button class=\"button\">\n  &lt;span>Hover me I'm awesome&lt;/span>\n&lt;/button></code></pre>\n\n\n\n<p><a href=\"https://codepen.io/electerious/pen/MQrRxX\">codepen пример</a></p>\n\n\n\n<h2 id=\"8a1f\">Огромные возможности</h2>\n\n\n\n<p id=\"522f\">Вы можете сделать огромное количество эффектов, реагируя на позицию мышки. Это прекрасно и с этим забавно поиграться.</p>\n\n\n\n<p id=\"5a18\">Вот схожая анимация, которую я использовал:</p>\n\n\n\n<blockquote class=\"twitter-tweet\"><p lang=\"en\" dir=\"ltr\">May the hover be with you <a href=\"https://t.co/2jrmVorLRW\">pic.twitter.com/2jrmVorLRW</a></p>— Tobias Reich (@electerious) <a href=\"https://twitter.com/electerious/status/957688130269786112?ref_src=twsrc%5Etfw\">January 28, 2018</a></blockquote> <script async=\"\" src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"></script>\n\n\n\n<p>Или включите фантазию и сделайте 3D параллакс кнопку:</p>\n\n\n\n<blockquote class=\"twitter-tweet\"><p lang=\"en\" dir=\"ltr\">3D parallax button with JS controlled CSS variables <a href=\"https://twitter.com/CodePen?ref_src=twsrc%5Etfw\">@CodePen</a> 🎉 <a href=\"https://t.co/qE0woiNip8\">https://t.co/qE0woiNip8</a> <a href=\"https://t.co/Wyi0xjRzPq\">pic.twitter.com/Wyi0xjRzPq</a></p>— Tobias Reich (@electerious) <a href=\"https://twitter.com/electerious/status/789582380889669632?ref_src=twsrc%5Etfw\">October 21, 2016</a></blockquote> <script async=\"\" src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"></script>\n\n\n\n<p>Возможности безграничным. Только попробуйте сами.</p>\n\n\n\n<h2 id=\"58aa\">Вопросы и ответы</h2>\n\n\n\n<p id=\"92ca\">Почему анимация&nbsp;<code>width</code>&nbsp;и&nbsp;<code>height</code>&nbsp;вместо использования&nbsp;<code>transform: scale()</code>?</p>\n\n\n\n<p id=\"8c4b\">Производительность довольно плоха при анимации width и height, и вам надо всегда стараться использовать transform при доступной возможности. Так почему я так не делал? Проблема в том, что браузер рендерит элементы (которые трансформируются) в ускоренном слое. Этот слой может вызывать проблемы в случае, когда кнопка имеет не прямоугольные края.</p>\n\n\n\n<p id=\"a613\">Конечно же есть способы для применения transform, но некоторые браузеры этого не любят. Отказ от применения transition до transform это одно потенциальное решение. Есть также обходное решение для Safari, которое может исправить эту&nbsp;<a href=\"https://gist.github.com/ayamflow/b602ab436ac9f05660d9c15190f4fd7b\">проблему с обрезкой</a>.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"701\" height=\"289\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_YmW0jcdl0EVE3dVO63dW9g.png\" alt=\"\" class=\"wp-image-84\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_YmW0jcdl0EVE3dVO63dW9g.png 701w, https://stasonmars.ru/wp/wp-content/uploads/2021/01/1_YmW0jcdl0EVE3dVO63dW9g-300x124.png 300w\" sizes=\"(max-width: 701px) 100vw, 701px\" /></figure>\n","date":"2021-01-09T15:15:51.000Z","title":"Великолепный hover эффект с CSS переменными","id":"a39712dc-6c4f-5705-b310-d3cd25bc0b5c","excerpt":"<p>А в этой статье вы узнаете как применять эти самые переменные в реальном и очень полезном кейсе. Создавая великолепный hover эффект</p>\n","type":"html-css","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2021/01/DglYtvO7Bn0-16.jpg"}}},{"node":{"slug":"7-primerov-ispolzovaniya-css-peremennyh","content":"\n<p>В этой статье вы узнаете о 7-ми полезных примерах из реальной жизни, в которых CSS переменные будут лучшими помощниками для того, чтобы  сохранить ваше время и силы.</p>\n\n\n\n<p class=\"author\"><a href=\"https://css-irl.info/7-uses-for-css-custom-properties/\"><em>Перевод статьи 7 Uses for CSS Custom Properties</em></a></p>\n\n\n\n<p>Кастомные свойства (также известные как CSS переменные) позволяют нам хранить значения различных CSS свойств для их дальнейшего переиспользования. Если вы сравнительно недавно про них узнали, то возможно вы удивитесь тому, насколько они круче переменных в известных CSS препроцессорах. <a href=\"https://stasonmars.ru/html-css/rukovodstvo-po-rabote-s-peremennimy-v-css\">Почитайте руководство по работе с переменными в CSS, если вы еще не знаете, что это такое.</a> В своей работе я часто использую кастомные свойства и думаю, что могу собрать несколько примеров использования в этой статье.</p>\n\n\n\n<h2 id=\"a7dc\"><strong>Применение в цветовых функциях</strong></h2>\n\n\n\n<p id=\"95f9\">CSS переменные не просто представляют собой значения свойств — их можно ещё использовать для хранения отдельных значений. Тут часто упоминают цветовые функции в CSS.&nbsp;<em>HSLA</em>&nbsp;отлично подходит для этого примера, давая нам небывалый уровень контроля, когда дело касается смешивания цветов.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.some-element {\n  background-color: hsla(\n    var(--h, 120),\n    var(--s, 50),\n    var(--l, 50),\n    var(--a, 1)\n  );\n}\n\n.some-element.darker {\n  --l: 20;\n}</code></pre>\n\n\n\n<p>Ещё мы можем делать всякие крутые штуки, например высчитывать добавочные цвета. В&nbsp;<a href=\"https://blog.logrocket.com/how-to-create-better-themes-with-css-variables-5a3744105c74/\">этой статье</a>&nbsp;вы можете более детально узнать о манипуляциях с цветами при помощи кастомных свойств. Также у&nbsp;<a href=\"https://www.sarasoueidan.com/blog/hex-rgb-to-hsl/\">Sara Soueidan</a>&nbsp;есть отличная статья по этой теме.</p>\n\n\n\n<h2 id=\"0552\"><strong>Сокращенные свойства</strong></h2>\n\n\n\n<p id=\"0cae\">Если вы используете сокращения в таких свойствах, как&nbsp;<code>animation</code>&nbsp;и нужно поменять одно значение только для другого элемента, то написание всех свойств заново может привести к ошибках и прибавить лишней тягомотины при последующей работе с кодом. Используя кастомные свойства мы можем очень легко изменить одно значение в сокращённом варианте нужного CSS свойства:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.some-element {\n  animation: var(--animationName, pulse) var(--duration, 2000ms) ease-in-out\n    infinite;\n}\n\n.some-element.faster {\n  --duration: 500ms;\n}\n\n.some-element.shaking {\n  --animationName: shake;\n}</code></pre>\n\n\n\n<h2 id=\"892d\"><strong>Повторяющиеся значения</strong></h2>\n\n\n\n<p id=\"40c8\">Предположим, что у нас есть элемент у которого имеется какое-нибудь постоянное значение только для его верхнего внутреннего отступа и другое значение для всех остальных сторон. Написание такого кода, как показано ниже, может быть очень утомительным, особенно если вы хотите внести изменения в значения свойств, отвечающих за внутренние отступы:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.some-element {\n  padding: 150px 20px 20px 20px;\n}\n\n@media (min-width: 50em) {\n  padding: 150px 60px 60px 60px;\n}</code></pre>\n\n\n\n<p>Использование кастомных свойств говорит о том, что нам нужно сделать изменение только в одном месте, чтобы скорректировать размеры отступов. И даже лучше, если это стандартное значение, используемое по всему сайту, то мы можем указать его в секции с переменными (<em>руте CSS</em>), конфиге или дизайн-токинах.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>:root {\n  --pad: 20px;\n}\n\n@media (min-width: 50em) {\n  :root {\n    --pad: 60px;\n  }\n}\n\n.some-element {\n  padding: 150px var(--pad) var(--pad) var(--pad);\n}</code></pre>\n\n\n\n<h2 id=\"fe07\"><strong>Комплексные вычисления</strong></h2>\n\n\n\n<p id=\"df79\">Кастомные свойства могут быть довольно удобным инструментов для хранения значений, посчитанных при помощи&nbsp;<code>calc()</code>&nbsp;функции, которые, кстати, могут быть посчитаны из других кастомных свойств. Один такой пример это вычисление дополнительных цветов, как упоминалось выше. Ещё один это то, когда вам надо посчитать инверсию свойства. Я написал статью на CSS Tricks, там объясняется то, как посчитать реверс плавности в анимации при помощи&nbsp;<a href=\"https://css-tricks.com/reversing-an-easing-curve/\">кастомных свойств</a>.</p>\n\n\n\n<p id=\"e293\">Я часто использую CSS переменные в&nbsp;<code>clip-path</code>, если мне надо посчитать один path относительно другого или относительно других известных переменных. В следующем коде мы посчитаем clip path для двух псевдо-элементов таким образом, чтобы сам элемент был рассечен пополам.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.element {\n  --top: 20%;\n  --bottom: 80%;\n  --gap: 1rem;\n  --offset: calc(var(--gap) / 2);\n}\n\n.element::before {\n  clip-path: polygon(\n    calc(var(--top) + var(--offset)) 0,\n    100% 0,\n    100% 100%,\n    calc(var(--bottom) + var(--offset)) 100%\n  );\n}\n\n.element::after {\n  clip-path: polygon(\n    calc(var(--top) - var(--offset)) 0,\n    calc(var(--bottom) - var(--offset)) 100%,\n    0 100%,\n    0 0\n  );\n}</code></pre>\n\n\n\n<p><a href=\"https://codepen.io/michellebarker/pen/yLLGVMQ\">Пример</a></p>\n\n\n\n<h2 id=\"356f\"><strong>Поочередная анимация</strong></h2>\n\n\n\n<p id=\"5b92\">Если нам нужно добавить отдельные стили для поочереденой анимации нескольких элементов потомков, то мы можем элегантно выставить&nbsp;<code>animation-delay</code>&nbsp;каждому из них, просто указав кастомные свойство как индекс элемента:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.element {\n  --delay: calc(var(--i, 0) * 500ms);\n  animation: fadeIn 1000ms var(--delay, 0ms);\n}\n\n.element:nth-child(2) {\n  --i: 2;\n}\n\n.element:nth-child(3) {\n  --i: 3;\n}</code></pre>\n\n\n\n<p><a href=\"https://codepen.io/michellebarker/pen/VwYYpqw\">Пример</a></p>\n\n\n\n<p id=\"4561\">К сожалению, тут нам пока что надо назначать переменные конкретно каждому потомку, что может привести к проблемам, в случае, если у нас не определено их точное количество. Splitting JS это отличная библиотека, которая позаботится об этом, назначив индекс элемента, как переменную, да и она вообще довольно полезна для такого рода поочередных анимаций. Но конечно же, все было бы круче без привлечения JS.</p>\n\n\n\n<p id=\"8f54\">Adam Argyle недавно предложил&nbsp;<a href=\"https://github.com/w3c/csswg-drafts/issues/4559\">две новых CSS функции</a>,&nbsp;<code>sibling-count()</code>&nbsp;и&nbsp;<code>sibling-index()</code>, которые бы значительно поменяли ситуацию, сделав возможными много новых вещей на чистом CSS. Они еще не применяются ни одним из браузеров, но это будет чрезвычайно сильным пополнением в инструментарии CSS, так что надо следить за их возможным релизом.</p>\n\n\n\n<h2 id=\"6d60\"><strong>Адаптивные гриды</strong></h2>\n\n\n\n<p id=\"fed2\">До этого, я уже&nbsp;<a href=\"https://css-irl.info/super-powered-layouts/\">об этом писал</a>, но кастомные свойства помочь в создании сложных шаблонов на гридах, упростив управление их поведением. Предположим, что у нас есть грид в 8 колонок, который мы хотим сделать 12-ти колоночным на каком-либо разрешении экрана:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>:root {\n  --noOfColumns: 8;\n}\n\n@media (min-width: 60em) {\n  :root {\n    --noOfColumns: 12;\n  }\n}\n\n.grid {\n  display: grid;\n  grid-template-columns: repeat(var(--noOfColumns), 1fr);\n}</code></pre>\n\n\n\n<p>Нам совершенно необязательно прописывать всё значение свойства целиком всякий раз, когда нам надо обновить количество колонок — тут мы можем спокойной применить кастомные свойства. Вообще, это сравнительно простой пример, но он может быть очень полезным, если у нас под рукой куда более сложный грид. Также этот подход применим к таким вещам, как размер трека или расположение элемента.</p>\n\n\n\n<h2 id=\"9852\"><strong>Вендорные префиксы</strong></h2>\n\n\n\n<p id=\"342d\">Некоторые свойства (такие как&nbsp;<code>clip-path</code>) всё ещё требуют наличия вендорных префиксов, хотя эта проблема уже быстро решается. Если вам надо написать вендорный префикс и затем вам надо изменить значение свойства, то вам надо убедиться в том, что вы меняете его также и на запрефиксенном свойстве. С помощью кастомных свойств, мы можем просто делать так:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.some-element {\n  --clip: polygon(0 0, 100% 0, 50% 100%, 0 100%);\n\n  -webkit-clip-path: var(--clip);\n  clip-path: var(--clip);\n}</code></pre>\n\n\n\n<p>Теперь&nbsp;у нас есть только одно место, где нужно делать изменения.</p>\n\n\n\n<h2 id=\"7336\"><strong>Заключение</strong></h2>\n\n\n\n<p id=\"9a1f\">Это далеко не все возможности применения CSS переменных, но это те, которые я обычно нахожу полезными в процессе своей работы и те, которые делают мой код более эффективным и поддерживаемым. Без сомнений, вы откроете для себя куда больше примеров их использования!</p>\n","date":"2020-12-18T13:32:31.000Z","title":"7 примеров использования CSS переменных","id":"09509d8f-efee-5fcf-9697-57e903cfd1e5","excerpt":"<p>В этой статье вы узнаете о 7-ми полезных примерах из реальной жизни, в которых CSS переменные будут лучшими помощниками для того, чтобы  сохранить ваше время и силы.</p>\n","type":"html-css","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2020/12/DglYtvO7Bn0-15.jpg"}}},{"node":{"slug":"rukovodstvo-po-rabote-s-peremennimy-v-css","content":"\n<p>В этой статье вы узнаете основы применения переменных в CSS, их области использования, ограничения и нюансы взаимодействия с JavaScript, включая интерактивные примеры.</p>\n\n\n\n<p class=\"author\"><em>Эта статья является переводом —&nbsp;</em><a href=\"https://nearsoft.com/blog/css-variables-guide/\"><em>CSS Variables Guide</em></a></p>\n\n\n\n<p id=\"91d5\">Итак, откройте свой Codepen с нового проекта, чтобы быть готовым всё лично протестировать и пощупать.</p>\n\n\n\n<p id=\"5b83\">Практически все языки программирования поддерживают переменные, но не CSS. Изначально он их и не поддерживал, нууу, до этого момента.</p>\n\n\n\n<p id=\"0e71\">На самом деле, это скорее кастомные CSS свойства, чем “переменные”. Да, название технически неверное, но цепляет и даёт понимание.</p>\n\n\n\n<h2 id=\"0201\"><strong>CSS — это кромешный беспорядок</strong></h2>\n\n\n\n<p id=\"c32d\">Любой, кто когда-либо работал с CSS, знает то, как тяжело держать код в порядке.</p>\n\n\n\n<p id=\"aa5b\">Для примера, использовать одни и те же значения в разных правилах это боль в плане поддержки и к тому же высока вероятность вызвать ошибку, например такую как опечатку и т.п. Множество раз мы предпочитали верить на слово нашему текстовому редактору и его замечательной функции “найти и заменить,” и это работало, правда одно время. Но чем больше проект, тем проще сделать изменение которое приведет к беспорядку, особенно в каком-нибудь ну уж самом неожиданном месте.</p>\n\n\n\n<h2 id=\"e160\"><strong>Но о чем всё это?</strong></h2>\n\n\n\n<p id=\"7065\">Вы уже наверное подумали о переменных в CSS? Но зачем они, если они уже есть в моем любимом препроцессоре?</p>\n\n\n\n<p id=\"7ab8\">Да, есть инструменты которые могут нам помочь в неких повторяющихся задачах. Препроцессоры такие как SASS и Stylus поддерживают переменные. Это делает нас более эффективными во время разработки и поддержки широкомасштабных приложений. Тем не менее, их недостаток в том, что довольно сложно произвести изменения во время выполнения кода.</p>\n\n\n\n<p id=\"df8b\">Препроцессоры компилируют всё в стандартный CSS код. Альтернативой могла бы быть генерация кода динамически, как требуется. Но это было бы в конечном итоге довольно затруднительным процессом и к тому же очень медленным.</p>\n\n\n\n<h2><strong>Причины для использования CSS переменных</strong></h2>\n\n\n\n<blockquote class=\"wp-block-quote\"><p>Понятный код</p><p>Возможность делать изменения в больших проектах максимально просто</p><p>Избежание опечаток</p><p>Возможность делать изменения во время работы</p></blockquote>\n\n\n\n<h2 id=\"cfc7\"><strong>Что это за кастомные CSS свойства?</strong></h2>\n\n\n\n<p id=\"9647\">По своей сути было добавлено две функции. Первая это возможность выставлять произвольные значения свойствам с полностью костомизируемыми именами. И функция var(), чтобы получать значения этих свойств.</p>\n\n\n\n<p>Вот простой пример:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>:root {\n    --brand-color: #666;\n}\n\n#main {\n    color: var(--brand-color);\n}\n\n:root {\n    --brand-color: #666;\n}\n \n#main {\n    color: var(--brand-color);\n}</code></pre>\n\n\n\n<p>В котором&nbsp;<code>–-brand-color</code>&nbsp;это свойство, которое определяется значением&nbsp;<code>#666</code>. А&nbsp;<code>var()</code>&nbsp;это функция, которая позволяет нам получать доступ к значению, которое было предварительно определено, выдавая в результате&nbsp;<code>color: #666;</code>.</p>\n\n\n\n<h2 id=\"ca00\"><strong>Синтаксис</strong></h2>\n\n\n\n<p id=\"0a43\">Синтаксис довольно простой. Все свойства должны начинаться с двойного тире <code>( — — )</code></p>\n\n\n\n<p id=\"ff05\">Свойства чувствительны к реестру, таким образом&nbsp;<code>—-brand-color&nbsp;</code>является уже отличным от&nbsp;<code>—-Brand-color</code>, который в свою очередь отличается от&nbsp;<code>--Brand-Color</code>.</p>\n\n\n\n<p id=\"29ee\">Я знаю, возможно вы сейчас думаете, что синтаксис довольно непривлекателен и вы будете правы. Но двойное тире нужно для того, чтобы была некая <em>ретро-совместимость</em> с браузерами, которые до сих пор не поддерживают эти функции.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"232\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2020/12/1_zA90sS8-TQX_u_di19oTYQ.jpeg\" alt=\"\" class=\"wp-image-72\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2020/12/1_zA90sS8-TQX_u_di19oTYQ.jpeg 700w, https://stasonmars.ru/wp/wp-content/uploads/2020/12/1_zA90sS8-TQX_u_di19oTYQ-300x99.jpeg 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<h2 id=\"5332\"><strong>Каскадирование/Область видимости</strong></h2>\n\n\n\n<p id=\"c95b\">Мы можем определять свойства, как «локальные» так и  «глобальные». Переменные доступны в области видимости элементов, где они определены. Все элементы потомки имеют доступ к родительским свойствам, но не наоборот.</p>\n\n\n\n<p id=\"26a2\">Кастомные свойства следуют тем же правилам, что и каскадные стили. Мы можем определить тоже свойство на разных уровнях, например:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>:root { --text-color: green; }\n\ndiv { --text-color: blue; }\n\n.error { --text-color: red; }\n\n* {\n  color: var(--text-color);\n}\n\n&lt;p>I'm green because got my color from root&lt;/p>\n\n&lt;div>I got blue from div selector&lt;/div>\n\n&lt;div class=\"error\">\n    I'm red because the .error.\n    &lt;p>Another red here because inheritance!&lt;/p>\n&lt;/div></code></pre>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" width=\"369\" height=\"126\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2020/12/Screenshot-2020-12-17-at-18.23.09.png\" alt=\"\" class=\"wp-image-73\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2020/12/Screenshot-2020-12-17-at-18.23.09.png 369w, https://stasonmars.ru/wp/wp-content/uploads/2020/12/Screenshot-2020-12-17-at-18.23.09-300x102.png 300w\" sizes=\"(max-width: 369px) 100vw, 369px\" /></figure></div>\n\n\n\n<p id=\"05fe\">Обратите внимание, что&nbsp;<code>:root</code>&nbsp;самый верхний элемент, эквивалентен глобальной области видимости. Тоже самое имя свойства может быть назначено с другим значением элементу потомку. Интересно, не так-ли?</p>\n\n\n\n<p id=\"f5ca\">Мы также можем изменять значения с помощью медиа запросов:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>:root {\n  --gutter: 10px 0;\n}\n\nmain {\n  padding: var(--gutter);\n  display: flex;\n  flex-flow: wrap;\n  background-color: green;\n}\n\n@media (min-width: 600px) {\n  :root {\n    --gutter: 16px;\n  }\n}\n\narticle {\n  padding: var(--gutter);\n  background-color: yellow;\n  height: 1rem;\n  margin-bottom: 1rem;\n  width: 100%;\n}\n\narticle:last-of-type {\n  margin-bottom: 0;\n}\n\n&lt;main>\n  &lt;article>&lt;/article>\n  &lt;article>&lt;/article>\n  &lt;article>&lt;/article>\n&lt;/main></code></pre>\n\n\n\n<p><a href=\"https://codepen.io/tonymtz/pen/jZaBov\">Пример</a></p>\n\n\n\n<p id=\"00a7\">Самые известные CSS препроцессоры не дадут вам определять переменные в медиа запросах. Внезапненько, да?</p>\n\n\n\n<p id=\"c8fb\">Тут даже можно определять свойства из уже существующих.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>:root {\n    --brand-color: red;\n    --header-text-color: var(--brand-color);\n}\n\n:root {\n    --brand-color: red;\n    --header-text-color: var(--brand-color);\n}</code></pre>\n\n\n\n<p id=\"60a4\">Примите во внимание, что это не работает с Microsoft Edge 15 из-за неизвестного бага.</p>\n\n\n\n<p id=\"91d4\">Хоть это и мягко говоря не рекомендуется, но вы можете определять свойства в тэгах стилей,&nbsp;<code>&lt;html style = \" --color: red;\"&gt;</code>.</p>\n\n\n\n<h2 id=\"1a7b\"><strong>Var()</strong></h2>\n\n\n\n<p id=\"cdfc\">Как написано на&nbsp;<a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/var\">MDN</a>, функция&nbsp;<code>var()</code>&nbsp;имеет такой синтаксис,</p>\n\n\n\n<p id=\"4fc4\"><code>var( &lt;custom-property-name&gt;[, &lt;declaration-value&gt;]? )</code></p>\n\n\n\n<p id=\"8a4e\">Где&nbsp;<code>custom-property-name</code>&nbsp;это название свойства, которое вы определяете. Если оно неверное или не существует,&nbsp;<code>declaration-value</code>&nbsp;будет использовано вместо него.</p>\n\n\n\n<p id=\"ed92\">Мы может объявлять больше одного разделенных запятой свойств, как в случае с&nbsp;<code>font-family</code>.</p>\n\n\n\n<p id=\"5b23\">Будьте осторожны с запятыми. Для примера, чтобы указать более двух свойств для padding, сделайте это как тут:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.foo {\n  padding: var(--gutter, 10px 0 0 5px);\n}</code></pre>\n\n\n\n<p><code>--gutter</code>&nbsp;это основное значение, а «<code>10px 0 0 5px</code>» используется если&nbsp;<code>-- gutter</code>&nbsp;имеет неверное значение или вообще не существует.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"232\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2020/12/1_CRU_h7Uecl6aIV-CQ-FtDg.jpeg\" alt=\"\" class=\"wp-image-74\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2020/12/1_CRU_h7Uecl6aIV-CQ-FtDg.jpeg 700w, https://stasonmars.ru/wp/wp-content/uploads/2020/12/1_CRU_h7Uecl6aIV-CQ-FtDg-300x99.jpeg 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<h2 id=\"9bc2\"><strong>Ограничения</strong></h2>\n\n\n\n<p id=\"caa7\">Само&nbsp;<code>var()</code>&nbsp;не поддерживает вставление в строки или их связывание.</p>\n\n\n\n<p id=\"ea41\">В отличие от препроцессоров,&nbsp;<code>var()</code>&nbsp;не может быть использована, чтобы определять имена свойств.</p>\n\n\n\n<p id=\"68f9\">Если вы хотите пойти немного глубже, вы можете детально обратить внимание на CSS синтаксис.</p>\n\n\n\n<h2 id=\"3313\"><strong>Циклические зависимости</strong></h2>\n\n\n\n<p id=\"366b\">Допустимо реализовывать зависимости между свойствами, как в примере ниже.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>:root {\n  --main-color: #c06;\n  --accent-background: linear-gradient(to top, var(--main-     color), white);\n}</code></pre>\n\n\n\n<p>Но циклические зависимости недопустимы. Вот пример:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>:root {\n  --one: #c06;\n  --two: #ccc;\n  --one: calc(var(--two) + 20px);\n  --two: calc(var(--one) — 20px);\n}</code></pre>\n\n\n\n<p>В этом случае, как&nbsp;<code>-one</code>, так и&nbsp;<code>-two</code>&nbsp;рассматривались бы как неверные. Их изначальные значения не переписаны и остаются такими же, таким образом они бы имели свои изначальные значения вместо указанных.</p>\n\n\n\n<h2 id=\"beeb\"><strong>Указываем значения с помощью calc()</strong></h2>\n\n\n\n<p id=\"7639\">Функция&nbsp;<code>calc()</code>&nbsp;используется для выполнения вычислений и определения CSS значений. На данный момент она поддерживается всеми современными браузерами.</p>\n\n\n\n<p id=\"2235\">Вы можете комбинировать её с&nbsp;<code>var()</code>, чтобы указывать значения на лету.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>header {\n  --gutter: 20;\n  padding: calc(var(--gutter) * 1px);\n}</code></pre>\n\n\n\n<p>В этом случае,&nbsp;<code>--gutter</code>&nbsp;указан, как единичный знак с цифровым значением&nbsp;<code>20</code>. Но padding нужна единица измерения (такая как&nbsp;<code>px</code>). Так как вы не можете связывать строки, вы можете вместо этого умножить на «<code>1px</code>», для того, чтобы искусственно подправить значение.</p>\n\n\n\n<h2 id=\"0f42\"><strong>Работа с JavaScript</strong></h2>\n\n\n\n<p id=\"55e7\">Чтобы получить значение кастомного свойства в JavaScript, используйте&nbsp;<code>getPropertyValue()</code>&nbsp;метод из&nbsp;<a href=\"https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleDeclaration\">CSSSTyleDeclaration</a>.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>&lt;style>\n    :root {--brand-color: cyan; }\n    p { color: var(--brand-color); \n&lt;/style>\n\n&lt;p>This text is cyan&lt;/p>\n\n&lt;script>\n    const styles = getComputedStyle(document.documentElement);\n    const colorValue = styles.getPropertyValue('--brand-color');\n    // colorValue = 'cyan';\n&lt;/script>\n\n&lt;style>\n    :root {--brand-color: cyan; }\n    p { color: var(--brand-color); }\n&lt;/style>\n \n&lt;p>This text is cyan&lt;/p>\n \n&lt;script>\n    const styles = getComputedStyle(document.documentElement);\n    const colorValue = styles.getPropertyValue('--brand-color');\n    // colorValue = 'cyan';\n&lt;/script>\n</code></pre>\n\n\n\n<p>С другой стороны, чтобы определить свойство, мы используем&nbsp;<code>setProperty()</code>&nbsp;метод:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>&lt;style>\n    :root {--brand-color: cyan; }\n    p { color: var(--brand-color); }\n&lt;/style>\n\n&lt;p>This text is red&lt;/ p>\n\n&lt;script>\n    document.documentElement.style.setProperty ('--brand-color', 'red');\n&lt;/script>\n\n&lt;style>\n    :root {--brand-color: cyan; }\n    p { color: var(--brand-color); }\n&lt;/style>\n \n&lt;p>This text is red&lt;/ p>\n \n&lt;script>\n    document.documentElement.style.setProperty ('--brand-color', 'red');\n&lt;/script>\n</code></pre>\n\n\n\n<p>Вы также можете определять значения свойств из значений других, используя старого друга&nbsp;<code>var()</code>&nbsp;с&nbsp;<code>setProperty()</code>:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>&lt;style>\n    :root {\n        --brand-color: cyan;\n        --secondary-color: yellow;\n    }\n&lt;/style>\n\np { color: var (--brand-color); }\n\n&lt;p>I'm yellow!&lt;/p>\n\n&lt;script>\n    document.documentElement.style.setProperty ('--brand-color', 'var (--secondary-color)');\n&lt;/script>\n\n&lt;style>\n    :root {\n        --brand-color: cyan;\n        --secondary-color: yellow;\n    }\n&lt;/style>\n \np { color: var (--brand-color); }\n \n&lt;p>I'm yellow!&lt;/p>\n \n&lt;script>\n    document.documentElement.style.setProperty ('--brand-color', 'var (--secondary-color)');\n&lt;/script>\n</code></pre>\n\n\n\n<h2><strong>Поддержка на данный момент</strong></h2>\n\n\n\n<p>Кастомные свойства на данный момент поддерживаются&nbsp;<a href=\"https://caniuse.com/#feat=css-variables\">большинством браузеров</a>.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"1024\" height=\"332\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2020/12/Screenshot-2020-12-17-at-18.49.52-1024x332.png\" alt=\"\" class=\"wp-image-75\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2020/12/Screenshot-2020-12-17-at-18.49.52-1024x332.png 1024w, https://stasonmars.ru/wp/wp-content/uploads/2020/12/Screenshot-2020-12-17-at-18.49.52-300x97.png 300w, https://stasonmars.ru/wp/wp-content/uploads/2020/12/Screenshot-2020-12-17-at-18.49.52-768x249.png 768w, https://stasonmars.ru/wp/wp-content/uploads/2020/12/Screenshot-2020-12-17-at-18.49.52.png 1301w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" /></figure>\n\n\n\n<p>У Microsoft Edge 15 есть проблемы. Следующие баги выявлены:</p>\n\n\n\n<p id=\"b728\"><a href=\"https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/12143022/\">Игнорирование вложенных расчетов</a></p>\n\n\n\n<p id=\"50ea\"><a href=\"https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/11676012/\">Анимации с кастомными свойствами могут покрашить браузер</a></p>\n\n\n\n<p id=\"1d9b\"><a href=\"https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/11495448/\">Вы не можете использовать эти свойства с псевдо-элементами</a></p>\n\n\n\n<p></p>\n","date":"2020-12-17T16:55:34.000Z","title":"Руководство по работе с переменными в CSS","id":"29bf9c41-b5de-52ac-8f7c-c4675ee65e5a","excerpt":"<p>В этой статье вы узнаете основы применения переменных в CSS, их области использования, ограничения и нюансы взаимодействия с JavaScript, включая интерактивные примеры.</p>\n","type":"html-css","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2020/12/DglYtvO7Bn0-14.jpg"}}},{"node":{"slug":"uluchshaem-proizvoditelnost-web-shriftov-na-realnom-primere","content":"\n<p>Тема веб-шрифтов довольно расплывчатая и периодически порождает больше вопросов, чем ответов. Однако, в этой статье, а вернее наглядном примере, описывается как ускорить производительность этих самых шрифтов, скорость их загрузки и вместе с этим, скорость загрузки страницы, с её отрисовкой.</p>\n\n\n\n<p class=\"author\">Перевод статьи&nbsp;<a href=\"https://www.netcentric.biz/insights/2019/01/web-font-performance.html\"><em>Improving web font performance: a case study</em></a></p>\n\n\n\n<h2 id=\"4c13\"><strong>Всё, что нужно знать для оптимизации работы веб-шрифтов</strong></h2>\n\n\n\n<h3 id=\"2096\">Железо и софт</h3>\n\n\n\n<p id=\"9065\">В основном я использовал macOS 10 с Chrome 70 для анализа и всегда понижал параметры сети до быстрого 3G и понижал CPU в 4 раза.</p>\n\n\n\n<h3 id=\"b280\">Схожие шрифты</h3>\n\n\n\n<p id=\"fb85\">Давайте начнем с простой загрузки домашней страницы сайта, чтобы посмотреть на то, какие же файлы загружаются:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"126\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_tHV8mDPpiFy48nRM_iGVhA.png\" alt=\"\" class=\"wp-image-36\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_tHV8mDPpiFy48nRM_iGVhA.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_tHV8mDPpiFy48nRM_iGVhA-300x54.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p id=\"6c37\">Мы загружаем 5 шрифтовых файлов, .ttf и CAC-Regular останутся нетронутыми в силу своей специфичности, но я обратил внимание на то, что у нас есть 3 шрифта с довольно-таки одинаковыми именами:</p>\n\n\n\n<p id=\"fbd8\">CS-Light.woff2</p>\n\n\n\n<p id=\"7e9a\">CS-Regular.woff2</p>\n\n\n\n<p id=\"afa8\">CS-Demi.woff2</p>\n\n\n\n<p id=\"e2f7\">Мне стало интересно насколько они разные и все ли из них нам так сильно будут нужны? Поэтому, я решил сравнить их визуально, наложив один шрифт на другой. Я выбрал использование CS-light, как основного, так как мне показалось, что его проще сравнить с другими шрифтами. В нашем случае, выставление более низкого font-weight свойства для CS-Regular не дало никаких изменений, так что я мог сделать его только жирнее.</p>\n\n\n\n<p id=\"07aa\">В общем, у меня CS-Regular в зелёном цвете, тот который я хочу заменить и CS-Light в красном цвете, и как видно, они вообще не совпадают.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"327\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_5iJqTM10AyyfqUN2H7ytEg.png\" alt=\"\" class=\"wp-image-37\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_5iJqTM10AyyfqUN2H7ytEg.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_5iJqTM10AyyfqUN2H7ytEg-300x140.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p id=\"d531\"><strong>Очевидно, что у нас 2 разных шрифта.</strong></p>\n\n\n\n<p id=\"6bf9\">Первое слово при наложении ещё можно прочитать, но потом всё выглядит как-то диковато и разбросано. В общем, вы сами видите. Однако, я смог увидеть некоторые сходства, так что я попробовал сравнить их как можно ближе, применив немного CSS:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>@font-face {\n  font-family: \"CS-Light\";\n  src: url(\"CS-Light.woff2\") format(\"woff2\");\n}\n\n@font-face {\n  font-family: \"CS-Regular\";\n  src: url(\"CS-Regular.woff2\") format(\"woff2\");\n}\n\n.cs-light, .cs-regular {\n  font-size: 2em;\n}\n\n.cs-regular {\n  color: green;\n  font-family: CS-Regular;\n}\n\n.cs-light {\n  color: red;\n  font-family: CS-Light;\n  letter-spacing: 0.012em;\n  line-height: 1.345em;\n}</code></pre>\n\n\n\n<p id=\"dc85\">Добавляем&nbsp;<code>letter-spacing</code>&nbsp;и&nbsp;<code>line-height</code>&nbsp;к&nbsp;<code>.cs-light</code></p>\n\n\n\n<p id=\"f312\">Играясь с этими двумя свойствами,&nbsp;<code>letter-spacing</code>&nbsp;и&nbsp;<code>line-height</code>, кстати, оба отлично всеми поддерживаются, у меня получилось сделать наложение получше:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"330\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_lTwnEIwK2IMKV7_5Spaz4g.png\" alt=\"\" class=\"wp-image-38\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_lTwnEIwK2IMKV7_5Spaz4g.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_lTwnEIwK2IMKV7_5Spaz4g-300x141.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p id=\"f478\">Это не идеально, но я был удивлён тем, как близко я мог подойти и как схожи два эти шрифта.</p>\n\n\n\n<p id=\"1310\">Я также хотел убедиться в том, что они будут похожи, при смене <code>font-size</code>:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"91\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_puz98ueVbykSNn2G0emEiA.png\" alt=\"\" class=\"wp-image-39\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_puz98ueVbykSNn2G0emEiA.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_puz98ueVbykSNn2G0emEiA-300x39.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p id=\"6a79\"><strong>font-size: 1em</strong></p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"294\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_UOpa6TjJqrNl-YnTSVbaPA.png\" alt=\"\" class=\"wp-image-40\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_UOpa6TjJqrNl-YnTSVbaPA.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_UOpa6TjJqrNl-YnTSVbaPA-300x126.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p id=\"a6b7\"><strong>font-size: 3em</strong></p>\n\n\n\n<p id=\"c5eb\">Мне реально понравился результат. Я видел небольшую разницу, особенно тогда, когда текст становился немного больше, но в целом всё выглядело схоже.</p>\n\n\n\n<p id=\"231c\">Далее, я хотел также проверить другой шрифт, который у нас был, под названием CS-Demi, чтобы посмотреть на то, смогу ли я получить схожие результаты:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"361\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_H9_twsLo1f9-AqcHRRbtUQ.png\" alt=\"\" class=\"wp-image-41\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_H9_twsLo1f9-AqcHRRbtUQ.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_H9_twsLo1f9-AqcHRRbtUQ-300x155.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<h2 id=\"dccf\">CS-Light cs CS-Demi</h2>\n\n\n\n<p id=\"ed11\">И снова, по началу это не совсем совпадало. Таким образом, мне пришлось пройти через тот же процесс и поиграться с некоторыми CSS свойствами, также было добавление свойства&nbsp;<code>font-weight</code>, так как этот шрифт был жирнее чем другой:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>@font-face {\n  font-family: \"CS-Light\";\n  src: url(\"CS-Light.woff2\") format(\"woff2\");\n}\n\n@font-face {\n  font-family: \"CS-Demi\";\n  src: url(\"CS-Demi.woff2\") format(\"woff2\");\n}\n\n.cs-light, .cs-demi {\n  font-size: 2em;\n}\n\n.cs-demi {\n  color: green;\n  font-family: CS-Demi;\n}\n\n.cs-light {\n  color: red;\n  font-family: CS-Light;\n  font-weight: 600;\n  letter-spacing: 0.031em;\n  line-height: 1.37em;\n}</code></pre>\n\n\n\n<p id=\"fd23\"><strong>Также, добавление свойства&nbsp;</strong><code><strong>font-weight</strong></code></p>\n\n\n\n<p id=\"ea2f\">Под конец у меня был довольно приличный результат. Он конечно не так хорош, как предыдущие, но всё же сложно сказать то, что разница между этими двумя шрифтами существует, если вы заранее не знаете того, какой из них какого цвета:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"365\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_ADLgAL_ppt66nCdLAOjjkA.png\" alt=\"\" class=\"wp-image-42\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_ADLgAL_ppt66nCdLAOjjkA.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_ADLgAL_ppt66nCdLAOjjkA-300x156.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p id=\"f248\"><strong>Font-size: 2em</strong></p>\n\n\n\n<p id=\"c14f\">Итак, теперь у нас довольно схожий результат при загрузке только одного файла вместо трёх. Давайте посмотрим на то, как именно всё улучшится:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"126\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_63zOqx3Ra7IEKG1dtwE3xA.png\" alt=\"\" class=\"wp-image-43\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_63zOqx3Ra7IEKG1dtwE3xA.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_63zOqx3Ra7IEKG1dtwE3xA-300x54.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p id=\"64e7\"><strong>344.7 KB of web fonts</strong></p>\n\n\n\n<p id=\"8b15\">Мы загружаем&nbsp;<strong>344.7кб</strong>&nbsp;веб-шрифтов, разделенных на 5 файловых запросов.</p>\n\n\n\n<p id=\"e575\">После избавления от CS-Regular и CS-Demi, у нас получается&nbsp;<strong>197.7кб</strong>&nbsp;всего на 3 файловых запроса, что говорит о сокращении на&nbsp;<strong>147кб</strong>, представляя собой примерно&nbsp;<strong>42.6%</strong>&nbsp;общего веса шрифтов на странице. Очень неплохо.</p>\n\n\n\n<h2 id=\"ddf7\"><strong>FOIT и FOUT</strong></h2>\n\n\n\n<p id=\"f98f\">Ещё одной проблемой с которой мы столкнулись с веб сайтами являются FOIT&nbsp;<em>(Тот момент, когда при загрузке шрифта текст не виден на самой странице)&nbsp;</em>и FOUT&nbsp;<em>(Тот момент, когда текст при загрузке отображается дефолтным или системным шрифтом)</em>. Вы можете визуально наблюдать эти моменты в тех случаях, когда ваше интернет соединение немного медленнее, чем обычно. В общем, при проверке пожаловались на это:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"219\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_naJtrldxL9UjqMbJysrPeQ.png\" alt=\"\" class=\"wp-image-44\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_naJtrldxL9UjqMbJysrPeQ.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_naJtrldxL9UjqMbJysrPeQ-300x94.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p id=\"5e6f\"><strong>Время загрузки шрифтов довольно долгое (3.000ms)</strong></p>\n\n\n\n<p id=\"6c2d\">Но спасибо свойству&nbsp;<code>font-display</code>, с его помощью мы можем избежать FOIT очень просто, выставив ему значение&nbsp;<code>fallback</code>:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>@font-face {\n  font-family: \"CS-Light\";\n  src: url(\"CS-Light.woff2\") format(\"woff2\");\n  font-display: fallback;\n}</code></pre>\n\n\n\n<p id=\"2660\"><strong>font-display: fallback</strong></p>\n\n\n\n<p><strong>Как объясняется на Google Developers:</strong></p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p><em>fallback даёт&nbsp;</em><code>font-face</code><em>&nbsp;очень маленький период времени (100ms или даже меньше, как рекомендуется в некоторых случаях) и короткий период смены шрифта (3 секунды, как рекомендуется в некоторых случаях). Другими словами, font-face рендерится сначала с fallback, если основной шрифт не загружен, но затем шрифт меняется на основной как только тот загрузится. Однако, если проходит слишком много времени, то&nbsp;</em><code>fallback</code><em>&nbsp;будет использоваться для всего протяжения времени взаимодействия со страницей.&nbsp;</em><code>fallback</code><em>&nbsp;хорош в тех случаях, когда вы хотите, чтобы пользователь начал читать как можно быстрее и не отвлекался на смещение текста, при загрузке основного шрифта.</em></p></blockquote>\n\n\n\n<p>Но будьте осторожны:&nbsp;<code>font-display</code>&nbsp;пока что не полностью поддерживается!</p>\n\n\n\n<p id=\"0ff1\">И наконец, после добавления этого свойства, мы можем пофиксить FOIT, ну правда только на тех браузерах, которые его поддерживают.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"53\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_pCEcC4sZjvzCuhEgYQFGGg.png\" alt=\"\" class=\"wp-image-45\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_pCEcC4sZjvzCuhEgYQFGGg.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_pCEcC4sZjvzCuhEgYQFGGg-300x23.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p id=\"cfb7\"><strong>FOIT больше не проблема.</strong></p>\n\n\n\n<p id=\"59fc\">Однако, у нас осталась проблема с FOUT, чтобы пофиксить её, я посмотрел на прелоад.</p>\n\n\n\n<h2><strong>Preload</strong></h2>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"126\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_63zOqx3Ra7IEKG1dtwE3xA-1.png\" alt=\"\" class=\"wp-image-46\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_63zOqx3Ra7IEKG1dtwE3xA-1.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_63zOqx3Ra7IEKG1dtwE3xA-1-300x54.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p id=\"486c\">Нам нужно приоритизировать запрос на CS-Light</p>\n\n\n\n<p id=\"d394\">Проверяя тайминг запроса нашего CS-Light шрифта, я мог наблюдать то, что мне надо было почти 5 секунд на загрузку и он также загружался в тоже время, что и другие шрифты:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"439\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_3n40a3V0ioNcfRlt11nxXA.png\" alt=\"\" class=\"wp-image-47\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_3n40a3V0ioNcfRlt11nxXA.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_3n40a3V0ioNcfRlt11nxXA-300x188.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p id=\"8cac\"><strong>Это перед preload</strong></p>\n\n\n\n<p id=\"ce0e\">В общем, я принял решение загружать самый важный веб-шрифт, просто добавив одну строчку кода в&nbsp;<code>&lt;head&gt;</code>,&nbsp;<a href=\"https://w3c.github.io/preload/\">сейчас обязательно посмотрите спецификации preload</a>:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>&lt;head>\n  &lt;link rel=\"preload\" href=\"CS-Light.woff2\" as=\"font\" type=\"font/woff2\" crossorigin=\"anonymous\">\n&lt;/head></code></pre>\n\n\n\n<p>В общем, тут мы прелоадим главный файл шрифта.</p>\n\n\n\n<p>Я сразу же заметил, что Chrome начал загружать главный файл шрифта перед другими и само собой быстрее:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"133\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_Uz9sAr6328JNAMcezsL3lg.png\" alt=\"\" class=\"wp-image-48\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_Uz9sAr6328JNAMcezsL3lg.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_Uz9sAr6328JNAMcezsL3lg-300x57.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p id=\"ccd3\">Теперь у нашего файла со шрифтами высокий приоритет при загрузке</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"420\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_oKGKWifyyfLddzPPJ5-LNQ.png\" alt=\"\" class=\"wp-image-49\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_oKGKWifyyfLddzPPJ5-LNQ.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_oKGKWifyyfLddzPPJ5-LNQ-300x180.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p id=\"5598\"><strong>Время на загрузку ресурсов теперь делится на 2 этапа.</strong></p>\n\n\n\n<p id=\"7f7c\">Следовательно, мы начали загружать наш наиболее важный шрифт за&nbsp;<strong>1.45s</strong>, вместо&nbsp;<strong>5.33s</strong>, что говорит о росте производительности в&nbsp;<strong>72.8%</strong>. Это означает то, что теперь требуется&nbsp;<strong>2.14s</strong>&nbsp;вместо&nbsp;<strong>4.29s</strong>&nbsp;на загрузку, указывая на рост в&nbsp;<strong>50%</strong>, относительно длительности времени, требуемого на загрузку контента.</p>\n\n\n\n<p id=\"901d\">После всех этих оптимизаций, мы наконец-то можем всё поставить вместе и получить вот такой код:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>&lt;!DOCTYPE html>\n&lt;html lang=\"en\">\n  &lt;head>\n    &lt;meta charset=\"utf-8\">\n    &lt;title>Improving Web Font Performance: A Case Study&lt;/title>\n    &lt;link rel=\"preload\" href=\"CS-Light.woff2\" as=\"font\" type=\"font/woff2\" crossorigin=\"anonymous\">\n    &lt;style>\n      @font-face {\n        font-family: \"CS-Light\";\n        src: url(\"CS-Light.woff2\") format(\"woff2\");\n        font-display: fallback;\n      }\n      .cs-demi, .cs-light, .cs-regular {\n        font-family: CS-Light;\n        font-size: 2em;\n      }\n      .cs-demi {\n        font-weight: 600;\n        letter-spacing: 0.031em;\n        line-height: 1.37em;\n      }\n      .cs-regular {\n        letter-spacing: 0.012em;\n        line-height: 1.345em;\n      }\n    &lt;/style>\n  &lt;/head>\n  &lt;body>\n    &lt;p class=\"cs-light\">CS-Light&lt;/p>\n    &lt;p class=\"cs-demi\">CS-Demi&lt;/p>\n    &lt;p class=\"cs-regular\">CS-Regular&lt;/p>\n  &lt;/body>\n&lt;/html></code></pre>\n","date":"2020-10-29T15:50:56.000Z","title":"Улучшаем производительность веб-шрифтов на реальном примере","id":"dea75c80-9b20-51c1-9361-5c96d4cdb3cc","excerpt":"<p>в этой статье, а вернее наглядном примере, описывается как ускорить производительность этих самых шрифтов, скорость их загрузки и вместе с этим, скорость загрузки страницы, с её отрисовкой.</p>\n","type":"html-css","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2020/10/DglYtvO7Bn0-7.jpg"}}},{"node":{"slug":"kak-primenyat-variativnie-shrifty-v-realnom-mire","content":"\n<p>Использование вариативных шрифтов в реальном мире становится все хитрее. Этот пост объясняет то, как мы разобрались с ними в нашем новом проекте для сайта Ampersand и что мы выучили в процессе обучения.</p>\n\n\n\n<p class=\"author\"><em>Это дополненный перевод статьи&nbsp;</em><a href=\"https://clearleft.com/posts/how-to-use-variable-fonts-in-the-real-world\"><em>How to use variable fonts in the real world</em></a></p>\n\n\n\n<p><strong>Вариативный шрифт&nbsp;</strong>— это единичный файл шрифта, который ведет себя по разному в разной стилизации. Есть множество сайтов, которые показывают возможности вариативных шрифтов и технологию вариации шрифтов в них, но для нового сайта Ampersand конференции мне хотелось показать то, как используются вариативные шрифты в реальном мире, то есть в контексте разработки. Возможно это первый коммерческий сайт, который вообще это сделал.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"680\" height=\"334\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_DeXFbrZsDLRLmZnPobJJkw.png\" alt=\"\" class=\"wp-image-29\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_DeXFbrZsDLRLmZnPobJJkw.png 680w, https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_DeXFbrZsDLRLmZnPobJJkw-300x147.png 300w\" sizes=\"(max-width: 680px) 100vw, 680px\" /></figure>\n\n\n\n<p id=\"5df6\">Два месяца назад поддержка браузерами вариативных шрифтов была на уровне 7%, но на данный момент их поддерживает&nbsp;<a href=\"https://caniuse.com/#search=variable%20fonts\">уже более 65% бразуеров.</a>&nbsp;Safari 11, Chrome 62+, Firefox 57+ и Edge 17+ все они поддерживают вариативные шрифты(<em>Firefox делает это только на маке и если то, если вы выставите нужные параметры</em>). Это говорит о том, что вариативные шрифты это уже вполне применяемая технология на данный момент. Но как вы видите, не все её равноценно поддерживают.</p>\n\n\n\n<p id=\"0dca\">Софт с поддержкой вариативных шрифтов уже присутствует на рынке гораздо в большем количестве, чем вы можете себе предположить. Для примера, последняя версия Photoshop и Illustrator их поддерживают и если вы используете macOS 10.13+ или iOS 11+ системный шрифт San Francisco, то он кстати широко использует вариативность шрифтов. Это говорит о том, что доступность вариативных шрифтов для использования в вебе сильно ограничена. На время написания статьи было только несколько коммерческих вариативных шрифтов,&nbsp;<a href=\"http://cjtype.com/dunbar/\">Dunbar</a>&nbsp;и&nbsp;<a href=\"https://djr.com/fit/\">Fit</a>&nbsp;заметные исключения, но есть и растущее число бесплатных и экспериментальных вариативных шрифтов, как продемонстрировано в песочнице&nbsp;<a href=\"https://www.axis-praxis.org/\">Axis Praxis</a>&nbsp;и на&nbsp;<a href=\"http://v-fonts.com/\">Variable Fonts.</a></p>\n\n\n\n<p id=\"8ad5\">Из этой ограниченной палитры шрифтов, мы выбрали Mutator Sans для отображаемого текста и Source Sans для основного текста в дизайне Saul Bass. Оба шрифта позволили нам воспользоваться вариативностью изменения их насыщенности. Оба выбранных шрифта привели нас к искусной, много-ступенчатой работе при применении вариативных шрифтов на сайте. Я покажу вам как мы все это сделали и применили на сайте, с использованием упрощенных примеров кода.</p>\n\n\n\n<h2 id=\"786c\"><strong>1. Ссылки на шрифты</strong></h2>\n\n\n\n<p id=\"edaa\">Чтобы применить вариативные шрифты и заставить их работать в простом виде вам нужно сделать несколько простых манипуляций. На время написания статьи у Safari и Chrome была самая полная поддержка. Если вы сделаете так, как описано ниже, то вам понадобится последняя версия одного из этих брузеров.</p>\n\n\n\n<p id=\"c85c\">Мы скачали Source Sans вариативный шрифт с&nbsp;<a href=\"https://github.com/adobe-fonts/source-sans-pro/releases\">Github</a>&nbsp;и применили&nbsp;<code>@font-face</code>&nbsp;с форматом&nbsp;<code>truetype-variations</code>, чтобы связать его со стилями.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>@font-face {\n  font-family: 'SourceSans';\n  src: url('source-sans-variable.ttf') format('truetype');\n}</code></pre>\n\n\n\n<p>Дальше мы могли бы выставить вариативный шрифт Source Sans, как основной на странице</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>html {\n  font-family: 'SourceSans', sans-serif;\n}</code></pre>\n\n\n\n<h2 id=\"eee7\"><strong>2. Выставляем насыщенность шрифта</strong></h2>\n\n\n\n<p id=\"f97f\">Исполнение вариативности шрифтов в CSS разработана, чтобы использовать существующие свойства для определенных предустановленных вариаций. Мы используем три варианта насыщенности в теле письма: обычный, полужирный и черный. Мы выставляем жирным шрифтам font-weight, обычным способом:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.hero { font-weight: 900; }\n.blurb { font-weight: 600; }</code></pre>\n\n\n\n<p id=\"5a77\">Тем не менее, это не работает как ожидалось без изменения правила&nbsp;<code>@font-face</code>. Когда вы применяете дескриптор&nbsp;<code>font-weight</code>&nbsp;в правиле&nbsp;<code>@font-face</code>, то вы говорите браузеру, что шрифт соответствует насыщенности и только этой насыщенности. Когда вы пропускаете&nbsp;<code>font-weight</code>&nbsp;дескриптор, браузер относится к правилу так, как если бы вы выставили&nbsp;<code>font-weight: 400</code>. В этом случае, является ли ваш шрифт вариативным с указанием насыщенности или нет, эта самая насыщенность будет сжата до&nbsp;<code>400</code>.</p>\n\n\n\n<p id=\"ccf3\">Чтобы использовать параметры насыщенности и чтобы&nbsp;<code>font-weight</code>&nbsp;свойства работали так, как ожидалось, нам надо добавить диапазон использования&nbsp;<code>font-weight</code>&nbsp;в&nbsp;<code>@font-face</code>&nbsp;правило:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>@font-face {\n  font-family: 'SourceSans';\n  src: url('source-sans-variable.ttf') format('truetype');\n  font-weight: 1 999;\n}</code></pre>\n\n\n\n<p id=\"06e4\">Диапазон использования позволяет вариативным шрифтам показывать в любой насыщенности от&nbsp;<code>1 до 999</code>. Конечно же вы можете указать более сложный и точный радиоус, если хотите. В ближайшем будущем CSS Fonts уровня 4 в спецификациях, позволят вам пропускать дескрипторы диапазонов, так как дефолтное значение получит новое значение auto, следовательно можно будет использовать полный диапазон насыщенности в вариативных шрифтах и по-умолчанию будет&nbsp;<code>normal</code>&nbsp;для статичных шрифтов. Тоже самое применится и для других дискрипторов, таких как&nbsp;<code>font-stretch</code>.</p>\n\n\n\n<p id=\"3232\">С вариативными шрифтами, насыщенность ваших шрифтов не обязательно должна быть ограничена шагом в&nbsp;<code>100</code>. Это может быть любое целое число в радиусе с&nbsp;<code>1 до 999</code>. Для основного хединга, мы использовали утонченные отличия в насыщенности для каждого символа, чтобы создать более рукописный эффект в дизайне:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>b:nth-child(1) { font-weight: 300; }\nb:nth-child(2) { font-weight: 250; }\nb:nth-child(3) { font-weight: 275; }</code></pre>\n\n\n\n<h2 id=\"8e87\"><strong>3. Частичное включение в подкатегорию и создание WOFF2</strong></h2>\n\n\n\n<p id=\"deb3\">Вариативный шрифт Source Sans довольно большой, файл TrueType весит 491Kb. В основном это из-за того, что он имеет большой набор символов, практически 2000 глифов, включая Greek, Cyrillic, альтернативные знаки и символы. Вашим первым шагом будет сокращение размеров файла и создание подкатегории частичного включения в шрифт, которая больше не будет включать в себя символы, которые вам вообще никогда не понадобятся.</p>\n\n\n\n<p id=\"5c58\">Мы решили быть довольно консервативными в том, что нам будет нужно, так что мы решили взять простую латиницу, дополнение Latin-1 и Latin Extended-A диапазон символов. Всего около 400 символов, покрывая почти все европейские языки. В Unicode это U+0020–007F, U+00A0–00FF and U+0100–017F.</p>\n\n\n\n<p id=\"92b1\">Есть множество онлайн инструментов для частичного включения шрифтов в подкатегории, например такие как&nbsp;<a href=\"https://www.fontsquirrel.com/tools/webfont-generator\">Fontsquirrel</a>. Тем не менее, все инструменты, которые я видел, вырезают разные данные. Это говорит о том, что вам нужно использовать подход командной строки. В итоге мы сделали все это, используя open source pyftsubset, компонент fonttools (Смотрите подробное&nbsp;<a href=\"https://michaeljherold.com/2016/05/04/creating-a-subset-font.html\">руководство по этому</a>) Если вам больше подходит Node, вы бы могли вместого этого использовать&nbsp;<a href=\"https://www.npmjs.com/package/glyphhanger\">Glyphhanger</a>.</p>\n\n\n\n<p id=\"4d86\">Glyphhanger и fonttools (Если вы установите&nbsp;<a href=\"https://github.com/google/woff2\">Brotli компрессию</a>) выдадут готовый подкатегоризированный файл как WOFF2. Нам по факту не нужен обычный WOFF, так как уже все браузеры, которые поддерживают вариативные шрифты, также поддерживают WOFF2.</p>\n\n\n\n<p id=\"7849\">Вся эта рутина с частичным включение в подкатегорию и конверсия в WOFF2 дали нам приятно маленький файл в 29kb. Соответственно мы обновили <code>@font-face</code> правило:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>@font-face {\n  font-family: 'SourceSans';\n  src: url('source-sans-variable.woff2') format('woff2');\n}</code></pre>\n\n\n\n<p>Итак, эта работа сделана для браузеров, которые поддерживают вариативные шрифты. Но это едва ли половина истории.</p>\n\n\n\n<h2 id=\"bd3a\"><strong>4. Задаем шрифты для неподдерживающих браузеров</strong></h2>\n\n\n\n<p id=\"3fb8\">Вариативные шрифты рендерятся на браузерах, которые не поддерживают вариативность в шрифтах, но очевидно у вас нет контроля над тем какая насыщенность или другой подобный пример будет использоваться.</p>\n\n\n\n<p id=\"c782\">Чтобы обойти это затруднение, вам надо предоставить невариативные шрифты для подобных браузеров. На время написания,&nbsp;<a href=\"https://www.w3.org/TR/2018/WD-css-fonts-4-20180410/#src-desc\">CSS Fonts Module Level 4</a>&nbsp;указывал, что вариативные шрифты могут быть обозначены с точным&nbsp;<code>fotmat()</code>&nbsp;значением:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>@font-face {\n   font-family: 'SourceSans';\n   src: url('source-sans-variable.woff2') format('woff2-variations');\n }</code></pre>\n\n\n\n<p>Это позволяет вам создать @font-face правила, как тут:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>@font-face {\n  font-family: 'SourceSans';\n  src: url('source-sans-variable.woff2') format('woff2-variations'),\n       url('source-sans-regular.woff2') format('woff2');\n  font-weight: 400; \n}\n\n@font-face {\n  font-family: 'SourceSans';\n  src: url('source-sans-variable.woff2') format('woff2-variations'),\n       url('source-sans-black.woff2') format('woff2');\n  font-weight: 900; \n}</code></pre>\n\n\n\n<p>Предшествующий код указывает на файлы шрифтов единого стиля с&nbsp;<code>@font-face</code>&nbsp;правилом включающим насыщенность шрифта, так же как и обычно. Вы затем можете повторить обращение к файлу вариативного шрифта в каждом правиле. Браузеры, которые поддерживают вариативные шрифты скачают файл отмеченный форматом&nbsp;<code>(‘woff2-variations’)</code>, а бразуеры которые не поддерживают, скачают одностильные шрифт, отмеченный как&nbsp;<code>(‘woff2’)</code>.</p>\n\n\n\n<p>НО! Только Safari поддерживает&nbsp;<code>format(‘woff2-variations’)</code>&nbsp;и этот&nbsp;<a href=\"https://medium.com/@clagnut/upcoming-changes-to-the-css-for-variable-fonts-4494b3b7ecdc\">синтаксис меняется</a>, что скорее приведет к беспорядку в действиях, если нам понадобятся другие поддерживаемые браузеры, чтобы получить вариативный шрифт. Таким образом, мы прибегли к другой, более многословной тактике. Во-первых, мы дали вариативному шрифту другое имя в первом одностилевом написании, таким образом это разделит ссылки на вариативные шрифты от одностилевых шрифтов:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>@font-face {\n  font-family: 'SourceSansVariable';\n  src: url('source-sans-variable.woff2') format('woff2');\n  font-weight: 1 999;\n}\n\n@font-face {\n  font-family: 'SourceSans';\n  src: url('source-sans-black.woff2') format('woff2'),\n         url('source-sans-black.woff') format('woff');\n  font-weight: 900; \n}\n\n@font-face {\n  font-family: 'SourceSans';\n  src: url('source-sans-semibold.woff2') format('woff2'),\n         url('source-sans-semibold.woff') format('woff');\n  font-weight: 600; \n}</code></pre>\n\n\n\n<p>Потом нам понадобится написать правило&nbsp;<code>@supports</code>, чтобы убедиться в том, что правильные шрифты попали в нужные браузеры:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>html {\n  font-family: 'SourceSans' sans-serif;\n}\n\n@supports (font-variation-settings: normal) {\n  html {\n    font-family: 'SourceSansVariable', sans-serif;\n  }\n}</code></pre>\n\n\n\n<p id=\"ceeb\">В коде выше, одностилевые шрифты указаны как стандарт, тем не менее, если браузер поддерживает вариативные шрифты&nbsp;<em>(это разумное предположение, которое может быть рассужено с помощью font-variation-setting)</em>, то он получит вариативный шрифт взамен.</p>\n\n\n\n<p id=\"b4d5\">И конечная шутка. Для точно работающего подхода, каждый раз когда вы видите вариативные шрифты, вы должны очевидно указывать насыщенность шрифта, даже когда она должна быть 400 или нормальной. С вариативным шрифтом, понимание браузерами дефолтной насыщенности шрифта может слегка отличаться друг от друга. В нашем тестировании, Firefox отрендерил стандартный текст значительно легче, чем Safari или Chrome, пока мы не сделали это:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>html {\n  font-family: 'SourceSans' sans-serif;\n   font-weight: 400;\n}\n\n@supports (font-variation-settings: normal) {\n  html {\n    font-family: 'SourceSansVariable', sans-serif;\n    font-variation-settings: \"wght\" 400;\n  }\n}</code></pre>\n\n\n\n<p></p>\n","date":"2020-10-28T11:45:40.000Z","title":"Как применять вариативные шрифты в реальном мире","id":"4b1e5798-655e-5734-9c65-d8ebd11e90d3","excerpt":"<p>Использование вариативных шрифтов в реальном мире становится все хитрее. Этот пост объясняет то, как мы разобрались с ними в нашем новом проекте для сайта Ampersand и что мы выучили в процессе обучения.</p>\n","type":"html-css","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2020/10/DglYtvO7Bn0-4.jpg"}}},{"node":{"slug":"bolee-dosutpnaya-razmetka-s-display-contents","content":"\n<p>CSS Grid позволяет вам превратить элемент в грид и поместить в него потомков дочерних селекторов этого элемента. Учитывая это, вы вполне можете искушать себя использовать поверхностную разметку, но чем меньше сути в ней, тем обычно меньше смысловой доступности. С&nbsp;<code>display: contents</code>, мы можем поместить потомков дочерних селекторов в грид, что позволит нам иметь д<mark>ос</mark>тупную разметку и красивый шаблон. Давайте углубимся в детали.</p>\n\n\n\n<p class=\"author\" id=\"2430\"><em>Это перевод статьи&nbsp;</em><a href=\"https://hiddedevries.nl/en/blog/2018-04-21-more-accessible-markup-with-display-contents\"><em>More accessible markup with display: contents</em></a></p>\n\n\n\n<p>Ниже я объясню более детально, что я имел ввиду под потомками, а так же потомками дочерних селекторов и затем покажу как мы можем использовать&nbsp;<code>display: contents</code>&nbsp;для улучшения все этого дела. Учтите, что на данный момент это работает криво, даже в поддерживаемых браузервах, ниже будет подробнее.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"215\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_ubYlVYiBPJOSfz0EtVesAw.png\" alt=\"\" class=\"wp-image-24\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_ubYlVYiBPJOSfz0EtVesAw.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_ubYlVYiBPJOSfz0EtVesAw-300x92.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<pre class=\"wp-block-code css\"><code>&lt;div class=\"container\">\n  &lt;h1 class=\"item\">Penne with tomato sauce&lt;/h1>\n  &lt;p class=\"item\">This simple recipe has few ingredients but tastes delicious.&lt;/p>\n  &lt;div class=\"item ingredients\">\n    &lt;h2>You'll need&lt;/h2>\n    &lt;ul>\n      &lt;li>canned tomatoes&lt;/li>\n      &lt;li>onions&lt;/li>\n      &lt;li>garlic&lt;/li>\n    &lt;/ul>\n  &lt;/div>\n&lt;/div></code></pre>\n\n\n\n<p>И у нас может быть вот такой CSS:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.container { \n  display: grid; /* element is now a grid container */\n  grid-template-columns: repeat( 4, 1fr );  /* grid now has 4 columns */\n\n.item:nth-child(1) {\n  grid-columns: 1 / 2; /* Place item between grid line 1 and 2 */\n}\n\n.item:nth-child(2) {\n  grid-columns: 2 / 4; /* Place item between grid line 2 and 4 */\n}\n\n.item:nth-child(3) {\n  grid-columns: 4 / 5; /* Place item between line 4 and 5 */\n}</code></pre>\n\n\n\n<p id=\"51ad\">Я использовал&nbsp;<code>.container</code>&nbsp;и&nbsp;<code>.item</code>&nbsp;как имена классов, так как в основе гридов лежат контейнеры и грид элементы (т.е. <code>items</code>). Но вы само собой можете использовать имена, которые вам удобнее.</p>\n\n\n\n<p id=\"4cb0\">Причина по которой мы можем спозиционировать эти элементы в грид, в том, что они прямые потомки грид-контейнера. Но посмотрите, что происходит если мы добавим список спонсоров, как тут:</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"243\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_WLOy8GCvX9AdcjSeKMqv0w.png\" alt=\"\" class=\"wp-image-25\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_WLOy8GCvX9AdcjSeKMqv0w.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_WLOy8GCvX9AdcjSeKMqv0w-300x104.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p>Мы могли бы добавить список в нашу разметку:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>&lt;div class=\"container\">\n  &lt;h1 class=\"item\">Penne with tomato sauce&lt;/h1>\n  &lt;p class=\"item\">This simple recipe has few ingredients but tastes delicious.&lt;/p>\n  &lt;div class=\"item ingredients\">\n    &lt;h2>You'll need&lt;/h2>\n    &lt;ul>\n      &lt;li>canned tomatoes&lt;/li>\n      &lt;li>onions&lt;/li>\n      &lt;li>garlic&lt;/li>\n    &lt;/ul>\n  &lt;/div>\n  &lt;ul class=\"item sponsors\">\n    &lt;li>Supermarket 1&lt;/li>\n    &lt;li>Supermarket 2&lt;/li>\n  &lt;/ul>\n&lt;/div></code></pre>\n\n\n\n<p>Но мы не сможем спозиционировать каждого спонсора в грид. Так происходит, потому что только&nbsp;<code>&lt;ul&gt;</code>&nbsp;является прямым потомком элемента контейнера и следовательно является грид элементом. А&nbsp;<code>&lt;li&gt;</code>&nbsp;уже нет, так как они не являются прямыми потомками того же контейнера, следовательно они уже не будут участвовать в грид-игре. Но что если мы реально захотим прировнять спонсоров к гридам?</p>\n\n\n\n<h2 id=\"8acb\"><strong>Поверхностная разметка</strong></h2>\n\n\n\n<p id=\"28e5\">Одним очевидным методом вовлечения в гриды спонсоров является удаление&nbsp;<code>&lt;ul&gt;</code>&nbsp;и использование&nbsp;<code>&lt;div&gt;</code>&nbsp;для каждого спонсора. Но что мы потом будем делать? Это просто сделает нашу разметку поверхностной и не точной.</p>\n\n\n\n<p>Выгода от использования&nbsp;<code>&lt;ul&gt;</code>&nbsp;элемента:</p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p></p><cite>Список останется вне контекста нашей страницы, для примера в Safari Reader Mode, он покажется как отдельный список.<br>Во время печати с отключенными стилями, он покажется опять таки как список. Для людей, которые используют скринридеры, это будет списком, соответственно устройство объявит, что это список из трех элементов.<br>Если мы сделаем нашу разметку поверхностной, то мы просто потеряем эти полезные свойства.</cite></blockquote>\n\n\n\n<h1 id=\"2aaf\"><strong>display: contents идёт на помощь</strong></h1>\n\n\n\n<p id=\"0a9e\">С помощью&nbsp;<code>display: contents</code>, мы может сохранить нашу разметку и наши гриды. Это свойство делает элемент таким, будто кажется, что его больше не существует. Оно не генерит бокс, так что фоны, границы и другие боксозависимые элементы не будут на нем работать. Грид свойства тоже не будут. Но все это будет работать для потомком элементов. Спицификация говорит, что элемент ведет себя так, будто бы он был перемещен&nbsp;<a href=\"https://drafts.csswg.org/css-display/#valdef-display-contents\">своим же контентом</a>. Если это звучит странно, то я рекомендую&nbsp;<a href=\"https://bitsofco.de/how-display-contents-works/\">прочитать эту статью</a>.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"700\" height=\"255\" src=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_uayWlU7VMZpQLDVAgs0udw.png\" alt=\"\" class=\"wp-image-26\" srcset=\"https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_uayWlU7VMZpQLDVAgs0udw.png 700w, https://stasonmars.ru/wp/wp-content/uploads/2020/10/1_uayWlU7VMZpQLDVAgs0udw-300x109.png 300w\" sizes=\"(max-width: 700px) 100vw, 700px\" /></figure>\n\n\n\n<p id=\"da76\">По факту, для наших целей в этом случае использование&nbsp;<code>display: contents</code>&nbsp;на элементе делает следующее: элемент перестает участвовать в гриде, а его контент с другой стороны, начинает. Это позволяет нам указывать спонсоров в гриде, вместо списка в который они помещены изначально.</p>\n\n\n\n<p id=\"66dc\">Это одни из самых интересных последних кейсов указанных в спецификациях, если свойство использовалось на элементах, таких как&nbsp;<code>img</code>&nbsp;или&nbsp;<code>video</code>.</p>\n\n\n\n<h1 id=\"5060\"><strong>Проблемы доступности в выполнении display: contents современными барузерами</strong></h1>\n\n\n\n<p id=\"df99\">Для людей, которые используют вспомогательные технологии(AT), браузеры применяют свойства доступности, включая role элементы на странице. Это такая штука, которая дает знать AT, что есть что на странице. Множество элементов идут с встроенным role из коробки, для примера у&nbsp;<code>list</code>&nbsp;уже есть&nbsp;<code>role</code>.</p>\n\n\n\n<p id=\"b940\">И вот где все идет не так с современными браузерами, которые поддерживают&nbsp;<code>display: contents</code>. Они не интерпретируют&nbsp;<code>display: contents</code>&nbsp;только как элемент разметки, они из него суть элемента на странице. Это проблематично и является багом, в соответствии с комментарием на спецификацию по влиянию на отображению шаблона:</p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p>Свойство display не имеет эффекта на семантику элемента: это определяется разметкой документа и не подвергается влиянию CSS. Помимо значения none, которое так же влияет на слуховой/голосовй вывод и интерактивность элемента, и его потомков, свойстов display само влияет только на визуальный шаблон: его цель — дать дизайнерам свободу в изменении шаблона поведения элемента без влияния на семантику документа, лежащую в основе.</p></blockquote>\n\n\n\n<p id=\"853b\">Смотря на пример списка спонсоров в нашем примере, это означает то, что элемент больше не является списком, но&nbsp;<a href=\"https://codepen.io/hidde/pen/gzbMeL\">теперь является чем-то другим.</a></p>\n\n\n\n<p id=\"0154\">Я добавил мои результаты тестов по браузерам ниже. В каждом из них, на&nbsp;<code>ul</code>&nbsp;получает правильный role без&nbsp;<code>display: contents</code>, но как только это свойстов применяется, элемент теряет свой role.</p>\n\n\n\n<h2 id=\"c5af\">Firefox 61</h2>\n\n\n\n<p id=\"005b\">Список получает role как text leaf. Update: теперь это исправлено и будет реализовано в Firefox 62 в августе 2018.</p>\n\n\n\n<h2 id=\"23a3\">Chrome 66</h2>\n\n\n\n<p id=\"c2f7\">Список показывется как ‘accessibility node not exposed, element not rendered’</p>\n\n\n\n<h2 id=\"46e0\">Safari</h2>\n\n\n\n<p id=\"8454\">Список показывается как ‘no accessibility information’</p>\n\n\n\n<p id=\"69f2\"><code>&lt;ul&gt;</code>&nbsp;это просто пример. Такое случается с любым элементом на котором применяется&nbsp;<code>display: contents</code>&nbsp;и у которого была&nbsp;<code>role</code>&nbsp;до этого.</p>\n\n\n\n<h2 id=\"9318\"><strong>Заключение</strong></h2>\n\n\n\n<p id=\"28ea\">С&nbsp;<code>display: contents</code>, вы можете размещать дочерние элементы потомков грид-контейнера в гриде. Это даст вам более семантически верную разметку, которая хороша в плане доступности. Вообще, чем больше осмысленности в разметке, тем больше деталей AT может дать пользователям. Однако тут есть одно предостережение: никто из браузеров, которые сейчас поддерживают&nbsp;<code>display: contents</code>, не воспринимают элементы с этим свойством в древе AT с их оригинальным свойством.</p>\n\n\n\n<p id=\"19f0\">Я убежден, что роли AT, не должны исчезать при применении&nbsp;<code>display: contents</code>, так как это нивелирует основное назначение&nbsp;<code>display: contents</code>. Я показал вам баги с Firefox, Chromium и Safari по этой теме. Реально надеюсь, что мы сможем использовать&nbsp;<code>display: contents</code>, сохраняя нетронутой доступность ролей в AT для элементов, таким образом мы будем иметь отличные шаблоны и потрясающий AT.</p>\n","date":"2020-10-28T11:06:21.000Z","title":"Более доступная разметка с display: contents","id":"dea8b17b-a810-5fd9-a6b6-971684f4f745","excerpt":"<p>CSS Grid позволяет вам превратить элемент в грид и поместить в него потомков дочерних селекторов этого элемента.</p>\n","type":"html-css","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2020/10/DglYtvO7Bn0-3.jpg"}}},{"node":{"slug":"zachem-ispolzovat-pravilo-supports","content":"\n<p>С ростом поддержки свойства определения поддержки функционала в CSS, под названием&nbsp;<code>@supports</code>, я понял, что это могло бы быть клёвой идеей взять и немного углубиться в эту тему, рассказав про неё как можно больше информации.</p>\n\n\n\n<p class=\"author\"><a rel=\"noreferrer noopener\" href=\"https://dommagnifi.co/2017/03/06/the-case-for-or-against-the-supports-rule.html\" target=\"_blank\"><em>Адаптированный перевод The Case for (or against) the CSS @supports rule</em></a></p>\n\n\n\n<p id=\"f023\">Итак, вот быстрое описание того, что же свойство&nbsp;<code>@supports</code>&nbsp;всё таки делает. По своей сути,&nbsp;<code>@supports</code>&nbsp;работает как обычный медиа запрос, но детектит определенный функционал, вместо размеров&nbsp;<code>viewport</code>, меида типов и т.д. Более менее, но это функция запроса. Использование <code>@supports</code> в браузерах, которые поддерживают его (Все, кроме IE11 и ниже в этом направлении), дает нам возможность проверять, поддерживается ли определенный функционал браузером или нет. Если да, то последующие CSS правила будут применены, а если браузер не поддерживает какое-либо свойство, то оно будет проигнорировано без какого-либо вреда для верстки.</p>\n\n\n\n<p id=\"da66\">Теоретически, тут суть в том, чтобы дать нам возможность условно применять CSS, основываясь на поддержке его функционала самим браузером. У меня есть четкое представление об этом, но в поисках материала для этого поста, мне было немного сложно найти примеры для этого правила, которые реально заслуживают внимания. Давайте посмотрим на некоторые простые сценарии, которые пришли мне на ум в первую очередь.</p>\n\n\n\n<h2 id=\"5395\"><strong>@supports(display: flexbox)</strong></h2>\n\n\n\n<p id=\"3453\">Итак, ваш коллега только что отправил вам отличный дизайн. Хороший сеточный шаблон. Настало время размять свои CSS мускулы и применить немного&nbsp;<code>flexbox</code>. Но нет! Аккаунт менеджеры только что сообщили вам, что вам нужна поддержка IE9. Хороший выстрел, ребята) Давайте разыграем сценарий, который бы имел место быть с&nbsp;<code>@supports</code>. Давайте применим классический кейс с&nbsp;<code>flexbox</code>. У вас есть несколько предметов (класс&nbsp;<code>.thing</code>) c заголовком и описанием внутри. Текст описания варьируется по длине и вам надо убедиться в том, что все&nbsp;<code>.thing</code>&nbsp;одной высоты, вне зависимости от длины контента. Может что-то типа этого нам подойдет?</p>\n\n\n\n<div class=\"wp-block-group\"><div class=\"wp-block-group__inner-container\">\n<div class=\"wp-block-group\"><div class=\"wp-block-group__inner-container\">\n<pre class=\"wp-block-code css\"><code>.thing {\n    border: 2px solid #efefef;\n    margin: 10px;\n    padding: 20px;\n\n    // Fallback for IE9 if browser\n    // doesn't support flexbox.\n    float: left;\n    width: calc(33.333333% - 20px);\n\n    h2 {\n      color: #2b2b2b;\n    }\n\n    .description {\n      font-size: 1rem;\n    }\n  }\n\n  // Insert fanciness here\n  @supports (display: flexbox) {\n    .thing-wrapper {\n      align-items: stretch;\n      display: flex;\n      justify-content: center;\n    }\n\n    .thing {\n      flex: 0 1 33.333333%;\n    }\n  }</code></pre>\n</div></div>\n</div></div>\n\n\n\n<p id=\"8767\">Отлично! Это выглядит как отличный пример использования&nbsp;<code>@supports</code>. У нас есть процентная ширина и флоаты, примененные к .thing, а также фолбэк, если не поддерживается&nbsp;<code>flexbox</code>!</p>\n\n\n\n<p id=\"5e6d\">Однако, давайте поиграем в адвоката дьявола и посмотрим, что же нас остановило от использования такого подхода:</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>.thing-wrapper {\n    align-items: stretch;\n    display: flex;\n    justify-content: center;\n  }\n\n  .thing {\n    border: 2px solid #efefef;\n    flex: 0 1 33.333333%;\n    margin: 10px;\n    padding: 20px;\n\n    //IE9 support\n    float: left;\n    width: calc(33.333333% - 60px);\n\n    h2 {\n      color: #2b2b2b;\n    }\n\n    .description {\n      font-size: 1rem;\n    }\n  }</code></pre>\n\n\n\n<p><code>.thing-wrapper</code>&nbsp;свойства будут проигнорированы, так как IE9 просто не воспримет их, а&nbsp;<code>float</code>&nbsp;и&nbsp;<code>width</code>&nbsp;свойства будут проигнорированы в новых браузерах из-за применения&nbsp;<code>display: flex</code>. Сейчас, в организационном плане, возможно было бы хорошим тоном откинуть старые свойства, которые не поддерживают старые браузеры. Но в функциональном плане, выгода кажется слегка ограниченной.</p>\n\n\n\n<h2 id=\"bef2\"><strong>Привет операторам</strong></h2>\n\n\n\n<p id=\"872e\">Давайте возьмем ещё один пример. Правило&nbsp;<code>@support</code>&nbsp;также принимает несколько дополнительных операторов:&nbsp;<code>not</code>,&nbsp;<code>and</code>&nbsp;и&nbsp;<code>or</code>. Вы можете связать эти операторы, чтобы улучшить свои результаты. Для примера, вы можете указать правилу&nbsp;<code>@supports</code>&nbsp;запускаться когда браузер не поддерживает CSS свойство.</p>\n\n\n\n<p id=\"398e\">Давайте, к примеру, попробуем новые модные CSS переменные. Если браузер не поддерживает CSS переменные, то мы запустим CSS код, который компенсирует это.</p>\n\n\n\n<pre class=\"wp-block-code css\"><code>@supports not (--color-1: #c0ffee) {\n    .coffee {\n      color: #c0ffee;\n    }\n  }</code></pre>\n\n\n\n<p id=\"eb61\">Простой пример, но он успешно делает свою работу. Что мы хотим тут сказать, так это то, что если браузер не поддерживает использование CSS переменных, то мы применяем цвет прямо к диву&nbsp;<code>.coffee</code>. Это звучит очень круто, но сейчас нам надо рассмотреть примет ли браузер этот код, даже поддерживая правило&nbsp;<code>@supports</code>. Если браузер не поддерживает правило&nbsp;<code>@supports</code>, с которого мы начинаем, этот отрезок кода будет пропущен и наш <code>div</code> .<code>coffee </code>не получит стилизации, которую мы ему выдали.</p>\n\n\n\n<p id=\"3cf0\">Для уточнения, CSS переменные не поддерживаются в EDGE v14. Однако&nbsp;<code>@supports</code>&nbsp;да. Следовательно, этот код будет работать! Что кстати великолепно, это определенно выглядит идеальным примером использования в этом случае.</p>\n\n\n\n<h2 id=\"08bb\"><strong>Дополнительные сценарии</strong></h2>\n\n\n\n<p id=\"c692\">Постарайтесь остаться непредвзятым как я после этих двух кейсов, я пробежался по нескольким другим сценариям, которые я не стал так описывать, как предидущие два.</p>\n\n\n\n<p id=\"5f62\">Я пытался найти некую выгоду в использовании правила для CSS&nbsp;<code>keyframes</code>, которая закончилась также как и в первом примере c&nbsp;<code>flexbox</code>. Я проверил новое свойство&nbsp;<code>display: flow-root</code>, это аккуратное свойство, которое замещает уже застоявшийся&nbsp;<code>clearfix</code>. Это был отличный кейс для оператора not, почти как и с нашим примером по теме CSS переменных. И в конце я проверил кейс с использованием CSS 3D трансформаций. И также как и с&nbsp;<code>flexbox</code>&nbsp;примером, выявил те же проблемы.</p>\n\n\n\n<h2 id=\"d1c4\"><strong>TL;DR</strong></h2>\n\n\n\n<p id=\"8178\">И под конец, конечно же&nbsp;<code>@supports</code>&nbsp;правило было бы фантастикой во былые времена, когда поддержка браузеров для разного CSS представляла собой невероятный беспорядок. Но сегодня, разработчики браузеров начинают поддерживать новые свойства чуть ли не одновременно. И даже если нет, то применяется не та логика, как в JavaScript. Если браузер не понимает CSS свойство, то он его пропускает и идет дальше. По факту, нет ощутимой выгоды в использовании&nbsp;<code>@supports</code>, пока что. Есть определенно хорошие кейсы его применения и оператора not. Особенно в старых версиях Edge, который не поддерживает такие фишки, как CSS переменные. Однако, для меня,&nbsp;<code>@supports</code>&nbsp;правило кажется скорее косметическим и дает ясный способ организации CSS свойств, которые необходимы для вашего нынешнего проекта, следуя его рекомендациям, которые могут не позволить вам использовать эти свойства в полной мере.</p>\n","date":"2020-08-17T14:14:38.000Z","title":"Зачем использовать правило @supports","id":"6e413258-accf-59e0-9ea5-7fecc5e34ce1","excerpt":"<p>С ростом поддержки свойства определения поддержки функционала в CSS, под названием @supports, я понял, что это могло бы быть клёвой идеей взять и немного углубиться в эту тему, рассказав про неё как можно больше информации.</p>\n","type":"html-css","featured_media":{"source_url":"https://stasonmars.ru/wp/wp-content/uploads/2020/08/DglYtvO7Bn0-1.jpg"}}}]}}}