tag:blogger.com,1999:blog-26954820422090929192024-03-05T02:32:56.279-08:00My Own Self DevelopmentВпечатления и размышления о моих опытах в саморазвитии<br>Переводы некоторых соответствующих текстовOleksiy Musiyezdovhttp://www.blogger.com/profile/08448866771044815897noreply@blogger.comBlogger162125tag:blogger.com,1999:blog-2695482042209092919.post-10534256190901985642022-02-11T01:36:00.005-08:002022-02-11T01:37:44.793-08:00I am a software developer<p>7 лет назал я защитил докторскую диссертацию по социологии, а год назад я вышел на работу как программист.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgc6FuepUdSmGV0uRcUHB8JaWPGDmQJl3ILb6AWzDFAjElVyP9SX9hGdJrOtxD3nhDv6DCQItskTl7f3tvbpys3WTXIVYFAchlM-ne5mYxfFRmpflnwMaQuDpriKczxsYK7j-8fOZQrg0KJbqJOAR2Vs8PP7TAY0hDaW6h6H6fSzKDcsVVPn4tfF_RRZw=s1334" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1334" data-original-width="1334" height="320" src="https://blogger.googleusercontent.com/img/a/AVvXsEgc6FuepUdSmGV0uRcUHB8JaWPGDmQJl3ILb6AWzDFAjElVyP9SX9hGdJrOtxD3nhDv6DCQItskTl7f3tvbpys3WTXIVYFAchlM-ne5mYxfFRmpflnwMaQuDpriKczxsYK7j-8fOZQrg0KJbqJOAR2Vs8PP7TAY0hDaW6h6H6fSzKDcsVVPn4tfF_RRZw=s320" width="320" /></a></div>Oleksiy Musiyezdovhttp://www.blogger.com/profile/08448866771044815897noreply@blogger.com0tag:blogger.com,1999:blog-2695482042209092919.post-62398991756716685052021-01-04T03:38:00.004-08:002021-01-04T03:38:32.379-08:00 A programmer: JavaScript #29. Некоторые пробелы в образовании в React<p>Когда я больше месяца назад взялся сделать тестовое заданиепо MERN, то по неопытности своей сказал, что сделаю меньше, чем за неделю. Не справился и за полторы, потому что постоянно вылазили какие-то не первый взгляд не слишком принципиальные пробелы в образовании, которые оказывались критическими в каждый данный момент времени. Разбираюсь с ними до сих пор, часто - с советами и помощью от добрых людей. Так, например, пагинацию (вывод данных постранично) делал больше недели, а затыков было несколько:</p><p>Во-первых, не знал, как передавать параметр в обработчик события. Во-вторых, делал setState асинхронным, хотя он предполагает колбек. В итоге посоветовали сделать так:</p><p><b><code>setCurrentPage = p => e => this.setState({ currentPage: p }, this.registerHandler);</code></b><br /></p><p>Я такой записи не видел раньше, но пришлось вчитаться в документацию ещё раз (<a href="https://learn-reactjs.ru/basics/handling-events" target="_blank"><b>тут</b></a> и <a href="https://reactjs.org/docs/react-component.html#setstate" target="_blank"><b>тут</b></a>):</p><p><b><code><button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button><br /><button onClick={this.deleteRow.bind(this, id)}>Delete Row</button></code></b><br /></p><p>У меня:</p><p><b><code>onClick={this.setCurrentPage(p)}</code></b><br /></p><p></p><p>Таки да - как видим, аргументом передается параметр, а setState колбеком вызывает то, что и нужно было выполнить после изменения state.</p><p>В-третьих, был затык с тем, что я сравнивал число со строкой, не замечая этого, и для того, чтобы всё работало, как надо, надо было делать приведение типов:</p><b><code><p>parseInt(this.state.currentPage) === p</p></code></b>При этом это эквивалентно, если вместо parseInt просто поставить "+" - этого я точно нигде не встречал.<p>В четвертых, забыл, что в map() надо указывать уникальный ключ - поэтому при правильно работающем переключении страниц и запросах, отрисовывалось то же, что и было, потому что ключи не менялись.</p><p></p><p>Итого: Сейчас я писал через классы и без внешнего стейта, значит, надо переписать - 1) сделать внешний стейт, 2) классы заменить на функциональные компоненты и сделать всё через хуки, 3) разделить презентацию и бизнес-логику.<br /></p>Oleksiy Musiyezdovhttp://www.blogger.com/profile/08448866771044815897noreply@blogger.com0tag:blogger.com,1999:blog-2695482042209092919.post-61848294638915791382020-12-26T09:41:00.004-08:002020-12-26T09:44:38.703-08:00 A programmer: JavaScript #28. Routing in React <p>Некоторое время назад делал я тестовое задание по стеку <b>MERN (MongoDB, ExpressJS, React, NodeJS)</b>. Сделать вовремя не сумел, но добрые люди согласились мне помочь доделать его - для себя, просто чтобы разобраться. Важный комментарий был мне дан по поводу того, что при маршрутизации моя программа перезагружает страницу, чего не должно быть, поскольку в этом случае теряется вся логика <b>Single Page Application</b>, для чего, собственно, и разработан <b>React</b>. Логика, напомню, состоит в том, что вместо загрузки необходимых страниц с сервера по каждому запросу, должно загружаться всё и сразу (кроме баз данных), и в зависимости от запроса - отрисовываться на клиенте то, что нужно, но без перезагрузки страницы. И понял я, что с маршрутизацией в React'e мне, оказывается, ещё нужно разобраться получше.</p><p>Итак, для маршрутизации в React'e существует модуль <b>react-router-dom</b>, который предоставляет несколько ключевых инструментов:</p><p><b>BrouserRouter</b> (обычно импортируемый как просто <b>Router</b>) - модуль, в котором, собственно, должна быть описана маршрутизация.</p><p><b>Router </b>- в сущности, аналог <b>href </b>- в нем прописывается путь, в зависимости от которого должно быть отрисовано нужное содержание.</p><p>Если кроме непосредственных ссылок надо обработать отсутствующую страницу, то Route'ы надо обернуть в <b>Switch</b>.</p><p>Кроме того, можно использовать <b>Redirect</b>, <b>Link </b>и <b>NavLink</b> (который отличается от Link тем, что в нем можно ещё и ссылаться не описание стилей для линков).</p><p>Так вот, в моем случае надо было использовать Link вместо Route - в этом случае страница не перезагружается, и маршрутизация осуществляется на клиенте, в противном случае идет запрос на сервер:</p><b><code><Link to="/"><button type="button">Home</button></Link></code></b><p>Информация взята <a href="https://reactrouter.com/web/guides/primary-components" target="_blank"><b>отсюда</b></a>, <a href="https://reactgo.com/reactrouter/programaticallynavigation/" target="_blank"><b>отсюда </b></a>и <a href="https://www.youtube.com/watch?v=Wm62LRtxomk" target="_blank"><b>отсюда</b></a>.</p>Oleksiy Musiyezdovhttp://www.blogger.com/profile/08448866771044815897noreply@blogger.com0tag:blogger.com,1999:blog-2695482042209092919.post-62338000094084840102020-12-18T13:30:00.003-08:002020-12-18T23:41:27.578-08:00A programmer: JavaScript #27. Hooks in React<p>Поскольку, грубо говоря, в JavaScript всё есть объект, то и компоненты React тоже вполне логично интерпретируются как объекты. А у объектов, как известно, есть состояние (state) и есть поведение. Состояние хранится в самом объекте, и его можно в нем же менять через this.setState. Но в последнее время разработчики React стараются отходить от такой практики и использовать компоненты как "функциональные компоненты", или просто функции. А функции не имеют состояния (stateless). Но состояние - вещь необходимая, и возникшую проблему надо решать - для этого и придумали хуки (hooks). Хук - это функция, которая меняет состояние, которое хранится в локальной переменной.</p><p>Классический пример - использование хука useState для счетчика (сначала его
надо импортировать и библиотеки 'react'):</p><b><code><p>const [count, setCount] = useState(0);</p></code></b><p>Здесь происходит "деструктуризация массива" - объявляются и переменная состояния (count), и собственно хук (setCount). То есть запись
эквивалентна следующей:</p><b><code><p>var countStateVariable = useState(0);</p><p>var count = countStateVariable[0]; // Объявление
переменной состояния</p><p>count = 0; // Присваивание начального значения</p><p>var setCount = сountStateVariable[1]; // Объявление хука</p></code></b><p>Теперь к ним можно обращаться в рендере:</p><p><b><code>button onClick={() => setCount(count + 1)}</code></b></p><p>Другой классический пример – хук useEffect. Он определяет действия, которые должны быть выполнены после каждого рендера – то есть заменяет собой встроенные методы, которые связанны с жизненным циклом компонента (componentDidMount, componentDidUpdate и др.). Поскольку перерисовка компонента обычно связана с изменением состояния (за которое обычно отвечает useState), то часто оба эти хука используются вместе:</p><b><code><p>const [count, setCount] = useState(0);</p><p>useEffect(() => { document.title = `Вы нажали ${count} раз` });</p></code></b><p>В данном случае document.title будет перерисовываться при каждом изменении состояния.</p><p>Существуют и другие хуки, а также можно написать собственные.</p><p>Информация взята <a href="https://ru.reactjs.org/docs/hooks-intro.html" target="_blank"><b>отсюда</b></a>, <a href="https://www.youtube.com/watch?v=9KJxaFHotqI&t=1577s" target="_blank"><b>отсюда</b></a>, <a href="https://www.youtube.com/watch?v=P1Y8GFJa_Io" target="_blank"><b>отсюда</b></a>.</p>Oleksiy Musiyezdovhttp://www.blogger.com/profile/08448866771044815897noreply@blogger.com0tag:blogger.com,1999:blog-2695482042209092919.post-20972972205842696792020-12-16T07:27:00.003-08:002020-12-16T07:32:29.426-08:00A programmer: JavaScript #26. A conditional statement in React<p>Некоторое время назад мучился с небольшой проблемой: вроде бы программа работала правильно, но в консоли браузера откуда-то выскакивало сообщение <b>"GET http://localhost:3000/undefined"</b>. Расследование показало, что это связано с тем, что я добавляю в базу данных объект без картинки, при этом у меня должен отрисовываться элемент, который имеет свойство</p><p><b><code>backgroundImage: `url(${this.state.picture})`</code></b></p><p>То есть, когда картинки нет, он выбрасывает <b>undefined</b>, что логично. Мне посоветовали написать так:</p><b><code><p>this.state.picture && { backgroundImage: `url(${this.state.picture})` }<br /></p></code></b><p></p><p>"Странная запись" - подумал я, имея в виду оператор "<b>И</b>", и пошел разбираться. Оказалось, что всё логично: React читает эту строчку последовательно слева направо. Если картинка в <b>state </b>есть, то он И отрисовывает её, а если её нет, то на операторе "И" прекращает читать строку, потому что вне зависимости от того, что дальше, значение будет <b>false</b>, и до запроса на вывод картинки дело не доходит.<br /></p>Oleksiy Musiyezdovhttp://www.blogger.com/profile/08448866771044815897noreply@blogger.com0tag:blogger.com,1999:blog-2695482042209092919.post-50881823383330144732020-12-15T02:01:00.004-08:002020-12-15T02:05:30.517-08:00A programmer: JavaScript #25. Widdleware in ExpressJS<p>Тема, которая почему-то вообще не попадалась мне на глаза раньше, но оказалась полезной и достаточно несложной. Напомню, что ExpressJS - это фреймворк для более простой работы с вебсервером. Грубо говоря, если в "ванильном" варианте надо было работать с XMLHttpRequest-объектом (XHR) NodeJS'a, то в ExpressJS создается свой объект <b>app</b>, через каторый и идет взаимодействие с сервером. Так вот, маршрутизация предполагает, что серверная часть имеет эндпойнты (например, <b>"/api"</b>), при обращении к которым выполняются некоторые действия. Например:</p><code><p>app.get("/api", (req, res) => {</p><p> // code<br /></p><p>})<br /></p></code><p>Так вот, существует возможность указать некоторые функции, которые должны быть выполнены ПЕРЕД выполнением данного года. Для этого определяется некоторая функция, кроме <b>req </b>и <b>res</b> она принимает параметр <b>next</b>, который вызывается в конце этой функции, чтобы передать выполнение следующему middleware или собственно основному коду (если надо выдать ошибку, она передается как параметр внутри <b>next(error)</b>, никакой другой параметр там передаваться не может). Например:<br /></p><code><p>const middleware = (req, res, next) => {</p><p> // code</p><p> next(); <br /></p><p>}</p></code><p>Чтобы подключить middleware, надо указать:</p><code><p>app.use("/api", middleware);<br /></p></code><p>Если указать без указания на рут, middleware будет "подключено" глобально, то есть будет выполняться в любом руте:</p><code><p>app.use(middleware);</p></code><p>Ну и, разумеется middleware, как и любой кусок кода можно импортировать извне, а внутри только подключать.</p><p>Информация взята <a href="https://expressjs.com/en/guide/writing-middleware.html" target="_blank"><b>отсюда</b></a>, <a href="https://www.youtube.com/watch?v=lY6icfhap2o" target="_blank"><b>отсюда </b></a>и <a href="https://www.youtube.com/watch?v=AZDTM0DiLG8" target="_blank"><b>отсюда</b></a>.</p>Oleksiy Musiyezdovhttp://www.blogger.com/profile/08448866771044815897noreply@blogger.com0tag:blogger.com,1999:blog-2695482042209092919.post-72330927266939077422020-11-24T11:26:00.005-08:002020-11-25T00:24:06.603-08:00A programmer: JavaScript #24. AJAX, XMLHttpRequest, fetch(), async/await<p>Когда я первый раз узнал об AJAX-запросах, это было связано с необходимостью получать данные с сервера, не перезагружая страницу. И выглядело это приблизительно так:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_1CF-58Pa6aSN-If60NxPA_NIk68rl3En_uRZpL2XMnG2VcOtUMMvCere72XGVMVVwWa8n6n_SIy6ncddSUV1S4Hq9KEo8Y0ggmCAEhG4hIsrTasnct_TtFhAJFE9zmdZHhZFRu_v4ASe/s922/code.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="586" data-original-width="922" height="254" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_1CF-58Pa6aSN-If60NxPA_NIk68rl3En_uRZpL2XMnG2VcOtUMMvCere72XGVMVVwWa8n6n_SIy6ncddSUV1S4Hq9KEo8Y0ggmCAEhG4hIsrTasnct_TtFhAJFE9zmdZHhZFRu_v4ASe/w400-h254/code.png" width="400" /></a></div><p>Что означало: при нажатии кнопки на клавиатуре в поле "<b>login</b>", взять данные и передать их методом POST в обработчик <b>ajax.php</b> (название файла, разумеется, может быть любым - скрин с php-проекта), и в случае успешной отработки обработчика, вывести результат на страницу в элемент с названием "<b>#login_warning</b>".</p><p>И, собственно, вся асинхронность у меня стала после этого ассоциироваться с тем, что оказалось всего-лишь частью библиотеки jQuery. Но принципиально - это только частный случай <span class="aCOpRe"><span><b>Asynchronous JavaScript And XML (AJAX)</b>. О чем идет речь?</span></span></p><p><span class="aCOpRe"><span>Ранее я говорил, что </span></span><span class="aCOpRe"><span><b><span>promise</span> </b>- это способ справиться с асинхронностью - сделать так, чтобы команды выполнялись последовательно, поскольку часто бывает так, что для выполнения следующей функции нужен результат предыдущей, а в JavaScript это не гарантировано. Чаще всего это нужно при отправке http-запросов, когда данные должны быть выведены после получения ответа от сервера.<br /></span></span></p><p><span class="aCOpRe"><span>Без </span></span><span class="aCOpRe"><span><span>promise'</span>ов это коротко выглядит так: создается специальный объект <b>XMLHttpRequest</b>, не нем открывается соединение и посылается запрос. Заранее определяется, что должно выполниться при том или ином ответе сервера:</span></span></p><p><span class="aCOpRe"></span></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwxPV0qcGC0hdx0em5F7BDt-1dVy79chj1j1h1zhoDhkbt0fHCCS-DvSdYnAwm0b7CW39k-Xpped_BrSCXDP5mml38xwFvDqZ0UskQ8EMqk6bWTFCWMyCdqGOgRizoF7zklH3wS97mZDWP/s922/code.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="548" data-original-width="922" height="238" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwxPV0qcGC0hdx0em5F7BDt-1dVy79chj1j1h1zhoDhkbt0fHCCS-DvSdYnAwm0b7CW39k-Xpped_BrSCXDP5mml38xwFvDqZ0UskQ8EMqk6bWTFCWMyCdqGOgRizoF7zklH3wS97mZDWP/w400-h238/code.png" width="400" /></a></div><p><br /><span><b>fetch()</b> - это интерфейс получения запросов - то есть способ сделать то же самое. "Под капотом" он создает объект request'a, посылает его, но возвращает promise с обработкой response'а:</span></p><p><span></span></p><p><span></span></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgHqR-KZbe5gwnzcSVqQTVyKYBuLxgAEsT1i_CvZRnOri6rKOrtnbmtZF3vyVC_CelkE8G0Qs3YZ6d6dBuRzZRKNDhUsbKr4LLlNLDk_14fmIBTbOwncjZWdm_OcReahGiPEmkT7XFnI6z/s942/code.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="282" data-original-width="942" height="120" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgHqR-KZbe5gwnzcSVqQTVyKYBuLxgAEsT1i_CvZRnOri6rKOrtnbmtZF3vyVC_CelkE8G0Qs3YZ6d6dBuRzZRKNDhUsbKr4LLlNLDk_14fmIBTbOwncjZWdm_OcReahGiPEmkT7XFnI6z/w400-h120/code.png" width="400" /></a></div> <p></p><p>На самом деле там вставляются ещё проверки, формат вывода данных, а в случае POST-запроса ещё и дополнительные параметры, но принцип таков.<br /></p><p><span>Ну и <b>async/await</b> - это приблизительно то же самое. <b>async </b>перед функцией указвает на то, что функция возвращает promise, соответственно, внутри функция будет ждать результата от promise'a (в этом месте пишется </span><span><span><b>await</b></span>). Ну и поскольку promise может завершиться с ошибкой, то всё это оборачивается в try-catch:</span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAlTGCFfEXeZ5rHwPjhNMbRsrB-fAcT1CD8Rs-dYdBeXemV0vikRORKTOFC5oQFW5n629IijzXAwNC5Tk6qkiWVw3tAbCbl_GWs8NAdGqs-MuBjkiVe6ghj2ortyu1VAX8u34A_b4Ce1a9/s922/code.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="662" data-original-width="922" height="288" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAlTGCFfEXeZ5rHwPjhNMbRsrB-fAcT1CD8Rs-dYdBeXemV0vikRORKTOFC5oQFW5n629IijzXAwNC5Tk6qkiWVw3tAbCbl_GWs8NAdGqs-MuBjkiVe6ghj2ortyu1VAX8u34A_b4Ce1a9/w400-h288/code.png" width="400" /></a></div><span><br /></span><p></p><p></p><p><span class="aCOpRe"><span>Информация - <b><a href="https://itgid.info/unit/javascript-2?unit=ajax-javascript" target="_blank">отсюда</a></b>, <b><a href="https://www.youtube.com/watch?v=eKCD9djJQKc" target="_blank">отсюда</a></b>, <b><a href="https://learn.javascript.ru/async-await" target="_blank">отсюда</a></b>, <b><a href="https://learn.javascript.ru/fetch" target="_blank">отсюда</a></b>, <b><a href="https://www.youtube.com/watch?v=eKCD9djJQKc" target="_blank">отсюда</a></b>. На самом деле ещё много откуда, но это самые последние по времени использования ресурсы.</span></span></p><p><span class="aCOpRe"><span>UPD: </span></span></p><p><span class="aCOpRe"><span>1. Нашел ещё один очень удобный ресурс - <b><a href="https://www.youtube.com/watch?v=SF5yHkfiZkY" target="_blank">вот он</a></b>. Здесь показаны разные варианты работы с асинхронными запросами в одном видео.</span></span></p><p><span class="aCOpRe"><span>2. Про популярный нынче <b>axios </b>ничего не писал, но там логика приблизительно такая же.<br /></span></span></p>Oleksiy Musiyezdovhttp://www.blogger.com/profile/08448866771044815897noreply@blogger.com0tag:blogger.com,1999:blog-2695482042209092919.post-46099876282578437012020-11-19T12:04:00.009-08:002020-11-19T13:35:24.729-08:00A programmer: JavaScript #23. Prototype inheritance (Прототипное наследование)<p>Если коротко, наследование - это способ получения полей и методов без того, чтобы явно декларировать их в самом объекте. Осуществляется это указанием, что данный объект является "наследником" какого-то другого объекта, а значит, он по умолчанию имеет те же поля и методы, что и "родитель", плюс обычно добавляет какие-то собственные или переопределяет родительские. Это удобно.</p><p>В JavaScript используется "прототипное наследование". Что это значит и в чем отличие от "классического" наследования. Под классическим наследованием я здесь буду понимать то, которое используется в Java. В классическом наследовании наследуются не объекты, а классы. А объект имеет те поля и методы, которые должны иметь объекты его класса (включая наследуемые от классов-родителей). Это создает структуру наследования, что имеет свои преимущества и недостатки.</p><p>Прототипное наследование отличается тем, что наследуются именно объекты и именно от объектов. То есть некоторый объект может объявить другой объект своим прототипом:</p><p><code>var object = Object.create(prototypeObject);</code></p><p>Здесь <b>object </b>объявляет себя наследником объекта <b>prototypeObject</b>, слеовательно, он имеет такие же, как у него поля и методы.</p><p>Собственно, можно наследовать не только объект от объекта, но и класс от класса - через конструкторы:</p><p><code>ClassA.prototype = Object.create(ClassB.prototype);</code></p><p>Только в этом случае сам конструктор тоже наследуется - и у <b>ClassA </b>будет конструктор от <b>ClassB</b>. Чтобы этого не происходило нужно отдельно его прописать (как бы "вернуть" себе обратно):</p><p><code>ClassA.prototype.constructor = ClassA;</code></p><p>Технически это выглядит так, что любой объект имеет скрытое свойство <b>[[Prototype]]</b>, которое можно явно задать (иначе оно равно null):<br /></p><p><code>let object.__proto__ = prototypeObject;</code></p><p> Здесь <b>__proto__</b> - геттер/сеттер для <b>[[Prototype]]</b>,в более поздних версиях языка он заменяется функциями <b>Object.getPrototypeOf</b> и <b>, хотя <b>__proto__ </b>тоже поддерживается.</b></p><p>Метод, которого нет в наследнике, но естьь в прототипе, может быть в переопределен в наследнике, но не в прототипе. Исключением являются вызываемые наследником геттеры и сеттеры, существующие в прототипе.</p><p>Важно отметить, что <b>this</b> всегда указывает на сам объект, но не на его протоип. То есть прототип выступает для наследника как хранилище объектов. Поясняю:</p><p>Пусть в прототипе есть метод:</p><p><code>setState() {</code></p><p> this.state = true; <br /></p><p>}</p><p>Если его вызвать на экземпляре наследника (<b>object.setState()</b>), то <b>state = true</b> будет присвоен наследнику, а не прототипу.<br /></p><p>Информация взята <b><a href="https://learn.javascript.ru/prototype-inheritance" target="_blank">отсюда</a></b>, <a href="https://medium.com/devschacht/eric-elliott-common-misconceptions-about-inheritance-in-javascript-f6137fc3a45a" target="_blank"><b>отсюда</b></a> и <b><a href="https://monsterlessons.com/project/lessons/prototipnoie-nasliedovaniie-v-javascript" target="_blank">отсюда</a></b>.<br /></p>Oleksiy Musiyezdovhttp://www.blogger.com/profile/08448866771044815897noreply@blogger.com0tag:blogger.com,1999:blog-2695482042209092919.post-39936767313246070402020-11-19T00:04:00.005-08:002020-11-19T00:09:25.401-08:00A programmer: JavaScript #22. Closures (Замыкания)<p>Короткая и простая тема. Думал я поначалу. Есть, как минимум, два объяснения, что это такое.</p><p>Во-первых, замыкания - это, грубо говоря, способ создать приватное свойство. То есть есть свойство объявляется внутри функции, а сама функция его возвращает с помощию внутренней функции. Это означает, что свойство остается неизменным, кто бы ни вызывал функцию, потому что область его видимости остается внутри. Например, функция:</p><code><p>function private() {</p><p> let a = 0;</p><p> return function() {</p><p> return a;</p><p> };</p><p>};</p></code><p>В ней никто не имеет доступа к переменной <b>а</b> извне, и потому не может её изменить.</p><p>Во-вторых, замыкания - это функция внутри функции. Основная польза от этого в том, что её можно присвоить какой-то переменной, а вызвать потом через эту переменную. Например, результатом присвоения
<b>
let variable = private();</b>
будет <b>variable</b>, которая при вызове <b>variable()</b> будет возвращать <b>а</b>.
Одним из самых распространенных применеий замыканий является счетчик:<code> </code></p><p><code>function private() {</code></p><p><code> let a = 0;</code></p><p><code> return function() {</code></p><p><code> return a++;</code></p><p><code> }</code></p><p><code>}</code></p><p><code>let counter = private(); </code></p><p>тогда при каждом вызове <b>counter()</b> будет возвращаться значение, на единицу большее, чем при предыдущем вызове функции.</p><p>Вот тут-то мне и стало непонятно: если функция отработала, то она должна была бы уничтожиться? Тогда в следующий раз заново бы создавалась и инициализировалась новая <b>let a = 0;</b>? Тогда о каком счетчике может быть речь?</p><p>Ответ пришлось поискать, и вот он: объект существует пока существует ссылка на него. И здесь мы имеем, что да, функция <b>private()</b> отработала, но внутренняя по отношению к ней функция продолжает существовать, поскольку в момент вызова <b>private()</b> её присвоили другому объекту (где она может ожидать своего вызова). А значит, и <b>private()</b> не уничтожена, а переменная изменила своё значение (в данном случае <b>а = а+1</b>)!</p><p>Если детализировать, то:</p><p>1. При вызове функции создается лексическое окружение (этой функции) - <b>LexicalEnvironment</b>, в котором, например, будут искаться переменные, если они не были найдены локально внутри. Грубо говоря, это внешняя область видимости по отношению к данной функции.</p><p>2. Также создании любая функции получает скрытое свойство <b>[[Environment]]</b>, которое ссылается на её окружение (и тем самым как бы "запоминает" его).
Для внутренней функции окружением будет внешняя функция с теми значениями переменных, которые на данный момент в ней есть.</p><p>То есть в момент вызова <b>counter()</b> значение переменной <b>а</b> будет находится во внешней по отношению к ней <b>private()</b>, и равняться это значение будет тому, которое существует на момент очередного вызова <b>counter()</b>. Другими словами, каждый новый <b>counter()</b> будет находить новую переменную <b>а</b> в своем окружении (имеющую то значение, которое осталось в результате предыдущего вызова <b>counter()</b>). Вот вам и счетчик.</p><p>Подробнее - <b><a href="https://learn.javascript.ru/closure" target="_blank">здесь</a></b>. <br /></p>Oleksiy Musiyezdovhttp://www.blogger.com/profile/08448866771044815897noreply@blogger.com0tag:blogger.com,1999:blog-2695482042209092919.post-64260047859444337162020-11-12T04:42:00.011-08:002020-12-17T02:21:38.824-08:00 A programmer: JavaScript #21. Event loop + Promises <p>JavaScript - однопоточный язык, то есть у него один стек, следовательно, только одна комманда может быть выполнена в единицу времени. Но если у тебя только один поток, как у JavaScript, это может привести к серьёзным задержкам. Проблема с однопоточностью решается "асинхронностью". То есть JavaScript использует дополнительные ресурсы браузера или NodeJS или какого-либо другого окружения, кроме собственно основного движка, для того, чтобы иметь возможность что-то делегировать этим ресурсам и не ждать окончания одной операции, чтобы приступить к следующей.<br /></p><p>Это реализуется через "цикл событий" (<b>"event loop"</b>):</p><ol style="text-align: left;"><li>Когда функция вызывается, она загружается в стек.</li><li>Но потом она начинает выполняться в "дополнительных ресурсах" пока не выполнится до конца.</li><li>Пока она выполняется "в стороне", другие функции из стека могут быть в него загружены.</li><li>Когда функция выполнена, она возвращается сначала в "очередь на возвращение" (<b>"task queue"</b>) и обратно в стек.<br /></li></ol><p><b>Event loop</b>
- потому что JavaScript циклом мечется между стеком, и
"очередью", проверяя, 1) пустой ли стек, и если стек пустой, то 2) есть ли в очереди то, что нужно возвращать. И если ещё
нету, бежит дальше по кругу, если есть - помещает это (то, что первое в очереди) в стек.</p><p>И здесь есть большая проблема: часто мы не можем знать, в какой очередности будут выполняться функции. То есть что выполнится первым - то, что идет следующим в коде или то, что вернется из очереди?</p><p></p><p>Так вот, чтобы избежать синхронности придумали колбеки (<b>"callback"</b>). Колбек - это функция, которая передается в качестве параметра в другую функцию, если нужно, чтобы она была выполнена после той, в которую передана (или в нужном месте внутри). Например:</p><code><p>function callback() {</p><p> console.log('I am callback!');<br /></p><p>};</p><p>let a = 'I am a parameter of anotherFunction!'; <br /></p><p>function anotherFunction(a, callback) {</p><p> console.log(a);</p><p> callback();</p><p>}<br /></p></code><p>Тогда, если нам важна очередность выполнения, мы должны вкладывать колбек в колбек в колбек и т.д. В этом коде легко запутаться, особенно потому, что переданные функции могут быть описаны совершенно в другом месте, а здесь только вызваны - это называется "ад колбеков".<br /></p><p>Чтобы его избежать, придумали (например) промисы (<b>"promises"</b>).<br /></p><p></p><p>Промис - это объект, который "обещает" выполнить то, что внутри. Он принимает функцию, которая имеет параметры resolve и reject, которые, соответственно, вызываются в случае успешного или неуспешного выполнения (вызываются с необходимыми параметрами). То есть, промис не только имеет возвращаемое значение той функции, которая выполнялась внутри него, но и состояние, успешно или нет прошло выполнение. И это состояние можно использовать - в случае неуспешного выполнения - ловить ошибку, добавив к промису через точку catch(...), а в случае успешного - вызывать следующую функцию, добавив к промису через точку then(...). Ну и соответственно, можно промисы цеплять в цепочку один за одним, если принципиально последовательное выполнение определенных функций.</p><p>И поскольку я вчера тупил, и не смог написать промис на собеседовании, то вот пример:</p><code><p>let promise = new Promise(function(resolve, request) {</p><p> let data = 5 + 3;</p><p> resolve(data); <br /></p><p>}).then(function(data) {</p><p> console log(data + 125);<br /></p><p>});</code><br /></p>Как-то так.<br />Oleksiy Musiyezdovhttp://www.blogger.com/profile/08448866771044815897noreply@blogger.com0tag:blogger.com,1999:blog-2695482042209092919.post-39485881556337462412020-11-09T03:40:00.012-08:002020-12-17T01:48:49.639-08:00A programmer: JavaScript #20. Pattern "Observer"<p>В общих чертах петтерн "observer" (обозреватель, наблюдатель) предполагает, что есть некий объект, который меняет своё состояние и оповещает об этом тех, кто подписан на уведомления (<b>subscribers</b>). Применительно к React'у это более, чем актуально, поскольку при изменении состояния (данных), компоненты должны перерисовываться, а значит, должны следить за изменениями сообветствующих данных.</p><p>При этом компоненты, которые себя перерисовывают, получают данные, зависят от них, но <b>state</b>, который хранит состояние, не должен зависеть от них - то есть он не должен сам вызывать метод перерисовки, находящийся в компонентах. Тогда как компоненты узнают, что <b>state </b>изменился?</p><p>А вот как: </p><p>С одной стороны, файл, где происходит отрисовка компонентов (допустим, index.js) вызывает <b>rerender()</b> и передает туда <b>state</b>, который предварительно импортирует:</p><span style="color: #073763;"><code><p><b>rerender(state)</b>;</p></code></span><p>То есть <b>index.js</b> зависит от <b>state</b>'а, как и положено.</p><p>Но <b>index.js</b> также вызывает метод <b>subscribe </b>и передает туда вызов свой <b>rerender():</b></p><b><code><p><span style="color: #073763;">subscribe(rerender);</span></p></code></b><p>Теперь <b>rerender() </b>может быть вызван прямо в <b>state</b>, при этом <b>state </b>от него не зависит, а только использует реализацию.</p><p>С другой стороны, при изменении <b>state </b>вызывает <b>callSubscriber()</b>, но его реализацию он получает в распоряжение из метода <b>subscribe():</b></p><span style="color: #073763;"><code><p><b>// некоторые изменения данных</b></p><p><b>callSubscriber();</b></p></code></span><p>В самом <b>state </b>он описывается приблизительно так:</p><p></p><p><b><span style="color: #073763;"><code>export const subscribe = (observer) => {<br /> rerender = observer;<br />}</code></span></b></p><p>То есть теперь <b>callSubscriber</b><b>(), </b>вызываемый в state, - это тот самый <b>rerender()</b>, который реализован в <b>index.js</b>.<br /></p><p>Следовательно, теперь при любом изменениии state, он вызывает метод перерисовки, который он получил через <b>subscribе</b>. Это означает, что <b>state </b>по-преженему не зависит от UI, потому что ему всё равно, как реализована перерисовка - он её только вызывает, но не импортирует.<br /></p><p>P.S.: Обычно паттерн "observer" объясняют на примере Java. В некотором смысле оно понятнее, потому что там есть интерфейсы как отдельные сущности. Но вот мне помогло <a href="https://www.youtube.com/watch?v=iN6QXbHedQc&list=PLcvhF2Wqh7DNVy1OCUpG3i5lyxyBWhGZ8&index=36" target="_blank">объяснение в исполнении Димыча</a>.</p><p></p>Oleksiy Musiyezdovhttp://www.blogger.com/profile/08448866771044815897noreply@blogger.com0tag:blogger.com,1999:blog-2695482042209092919.post-75108619181195085792020-11-08T12:38:00.008-08:002020-11-08T22:44:27.628-08:00A programmer: JavaScript #19 The logic of React. Part 1<p class="MsoNormal" style="text-align: left;"><span style="font-family: arial;"><span><span style="font-size: small;"><span>Снова про </span><span lang="EN-US">React</span><span>. На этот раз вдохновился довольно объёмным курсом от Димыча (IT-KAMASUTRA, "</span></span></span><a class="yt-simple-endpoint style-scope yt-formatted-string" dir="auto" href="https://www.youtube.com/watch?v=gb7gMluAeao&list=PLcvhF2Wqh7DNVy1OCUpG3i5lyxyBWhGZ8" spellcheck="false">Курс "React JS - путь самурая 1.0", уроки, практика</a></span><span style="font-family: arial;"><span style="font-size: small;"><span>") - он объясняет всё очень подробно и понятно, действительно большой молодец, рекомендую. <br /></span></span></span></p><p class="MsoNormal" style="text-align: left;"><span style="font-family: arial;"><span style="font-size: small;"><span lang="EN-US">React</span><span lang="EN-US"> </span><span>– библиотека для фронтенда, то есть для удобной отрисовки страницы, которая
должна быть видна в браузере. Собственно, пишу только об основных принципах и
ключевых особенностях.</span></span></span></p><div style="margin-left: 40px; text-align: left;"><span style="font-family: arial;"><span style="font-size: small;">
</span></span></div><p class="MsoListParagraphCxSpFirst" style="margin-left: 40px; text-align: left; text-indent: -18pt;"><span style="font-family: arial;"><span style="font-size: small;"><span><span>1.<span style="font-feature-settings: normal; font-kerning: auto; font-language-override: normal; font-size-adjust: none; font-stretch: normal; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal;"> </span></span></span><span lang="EN-US">React
</span><span>используется</span><span> </span><span>для</span><span> <span lang="EN-US">Single Page Application. </span></span><span>«Классический вариант» работы с сайтом предполагает,
что когда нужно показать что-то с данного сайта, браузер посылает запрос на
сервер, и сервер присылает новую страницу. В свою очередь логика </span><span lang="EN-US">Single</span><span lang="EN-US"> </span><span lang="EN-US">Page</span><span lang="EN-US"> </span><span lang="EN-US">Application</span><span> предполагает, что практически всё необходимое
загружается в браузер сразу, и при запросах на новый контент уже сам браузер
отрисовывает его, не обращаясь к серверу.</span></span></span></p><div style="margin-left: 40px; text-align: left;"><span style="font-family: arial;"><span style="font-size: small;">
</span></span></div><p class="MsoListParagraphCxSpMiddle" style="margin-left: 40px; text-align: left; text-indent: -18pt;"><span style="font-family: arial;"><span style="font-size: small;"><span><span>2.<span style="font-feature-settings: normal; font-kerning: auto; font-language-override: normal; font-size-adjust: none; font-stretch: normal; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal;"> </span></span></span><span>Для этого
используется модульность и виртуальный </span><span lang="EN-US">DOM</span><span>. Если
</span><span lang="EN-US">DOM</span><span> (</span><span lang="EN-US">Document</span><span lang="EN-US"> </span><span lang="EN-US">Object</span><span lang="EN-US"> </span><span lang="EN-US">Model</span><span>) – это модель документа,
то виртуальный </span><span lang="EN-US">DOM</span><span lang="EN-US"> </span><span>– это копия этой модели в памяти </span><span lang="EN-US">React</span><span lang="UK">’</span><span>а. В
соответствии с виртуальным </span><span lang="EN-US">DOM</span><span>’ом </span><span lang="EN-US">React</span><span lang="EN-US"> </span><span>«собирает»
страницу из компонентов. Если нужно что-то перерисовать, он вносит необходимые
изменения а нужный компонент, <i>реагирует</i>
на изменения – поэтому и «</span><span lang="EN-US">React</span><span>». В каждом компоненте
есть метод </span><span lang="EN-US">render</span><span>(), который, собственно, и отрисовывает его. Поэтому
не затрагиваются все остальные элементы страницы, что обеспечивает быструю работу.</span></span></span></p><div style="margin-left: 40px; text-align: left;"><span style="font-family: arial;"><span style="font-size: small;">
</span></span></div><p class="MsoListParagraphCxSpMiddle" style="margin-left: 40px; text-align: left; text-indent: -18pt;"><span style="font-family: arial;"><span style="font-size: small;"><span><span>3.<span style="font-feature-settings: normal; font-kerning: auto; font-language-override: normal; font-size-adjust: none; font-stretch: normal; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal;"> </span></span></span><span>Сложность
состоит в том, что слои отображения (</span><span lang="EN-US">User</span><span lang="EN-US"> </span><span lang="EN-US">Interface</span><span> (</span><span lang="EN-US">UI</span><span>) – то, чем и являются
компоненты) и бизнес-логика должны быть разделены. Изменения </span><span lang="EN-US">view</span><span> предполагают операции с данными, но данные не должны храниться в самих
компонентах – компоненты должны использовать <i>только</i> те данные, которые пришли из слоя бизнес-логики. Следовательно,
их надо как-то передавать из уровня бизнес-логики в </span><span lang="EN-US">UI</span><span lang="EN-US"> </span><span>и обратно.</span></span></span></p><div style="margin-left: 40px; text-align: left;"><span style="font-family: arial;"><span style="font-size: small;">
</span></span></div><p class="MsoListParagraphCxSpMiddle" style="margin-left: 40px; text-align: left; text-indent: -18pt;"><span style="font-family: arial;"><span style="font-size: small;"><span><span>4.<span style="font-feature-settings: normal; font-kerning: auto; font-language-override: normal; font-size-adjust: none; font-stretch: normal; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal;"> </span></span></span><span>Из уровня бизнес-логики
в </span><span lang="EN-US">UI</span><span lang="EN-US"> </span><span>данные передаются через </span><b><span lang="EN-US">props</span></b><span>’ы – атрибуты компонентов.
Они могут передаваться от родительских компонентов в наследников, в которых они
становятся элементами </span><b><span lang="EN-US">state</span><span lang="EN-US"> </span></b><span>– состояния данного компонента.</span></span></span></p><div style="margin-left: 40px; text-align: left;"><span style="font-family: arial;"><span style="font-size: small;">
</span></span></div><p class="MsoListParagraphCxSpMiddle" style="margin-left: 40px; text-align: left; text-indent: -18pt;"><span style="font-family: arial;"><span style="font-size: small;"><span><span>5.<span style="font-feature-settings: normal; font-kerning: auto; font-language-override: normal; font-size-adjust: none; font-stretch: normal; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal;"> </span></span></span><span>Нюанс состоит
в том, что если нужно передать </span><span lang="EN-US">props</span><span>’ы на несколько уровней,
то и прописывать их нужно на каждом уровне, что неудобно. Чтобы этого не
делать, используют </span><span lang="EN-US">Context</span><span lang="EN-US"> </span><span>– некоторое хранилище данных. Компонент, в котором он создаётся, помещается
в обёртку </span><b><span lang="EN-US">Context</span><span>.</span><span lang="EN-US">Provider</span></b><span>, который и передаёт
необходимые </span><span lang="EN-US">props</span><span>’ы, а остальные помещаются в обёртку </span><b><span lang="EN-US">Context</span><span>.</span><span lang="EN-US">Consumer</span></b><span>. Что означает, что
они имеют доступ ко всем </span><span lang="EN-US">props</span><span>’ам, которые предоставляет </span><span lang="EN-US">Context</span><span>.</span><span lang="EN-US">Provider</span><span>.</span></span></span></p><div style="margin-left: 40px; text-align: left;"><span style="font-family: arial;"><span style="font-size: small;">
</span></span></div><p class="MsoListParagraphCxSpMiddle" style="margin-left: 40px; text-align: left; text-indent: -18pt;"><span style="font-family: arial;"><span style="font-size: small;"><span><span>6.<span style="font-feature-settings: normal; font-kerning: auto; font-language-override: normal; font-size-adjust: none; font-stretch: normal; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal;"> </span></span></span><span>Для того,
чтобы передать некоторые данные из </span><span lang="EN-US">UI</span><span lang="EN-US"> </span><span>на уровень бизнес-логики, в тех же </span><span lang="EN-US">props</span><span>’ах компонентам передаются и необходимые методы. Сами методы прописаны на
уровне бизнес-логики, но передаётся возможность их вызова.</span></span></span></p><div style="margin-left: 40px; text-align: left;"><span style="font-family: arial;"><span style="font-size: small;">
</span></span></div><p class="MsoListParagraphCxSpMiddle" style="margin-left: 40px; text-align: left; text-indent: -18pt;"><span style="font-family: arial;"><span style="font-size: small;"><span><span>7.<span style="font-feature-settings: normal; font-kerning: auto; font-language-override: normal; font-size-adjust: none; font-stretch: normal; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal;"> </span></span></span><span><span></span>На уровне бизнес-логики создают </span><span lang="EN-US">store</span><span lang="EN-US"> </span><span>–
хранилище данных (состояний компонентов). С помощью переданных им методов
компоненты передают туда данные. С помощью переданных компонентам </span><span lang="EN-US">props</span><span>’ов компоненты перерисовывают себя – это постоянно работающий цикл. Такое «архитектурное
решение» называется </span><span lang="UK">Flux</span><span>. Для его реализации существуют «системы управления состоянием» («</span><span lang="EN-US">state</span><span lang="EN-US"> </span><span lang="EN-US">management</span><span lang="EN-US"> </span><span lang="EN-US">system</span><span>»), наиболее известная из них – </span><span lang="EN-US">Redux</span><span>.</span></span></span></p><div style="margin-left: 40px; text-align: left;"><span style="font-family: arial;"><span style="font-size: small;">
</span></span></div><p class="MsoListParagraphCxSpMiddle" style="margin-left: 40px; text-align: left; text-indent: -18pt;"><span style="font-family: arial;"><span style="font-size: small;"><span><span>8.<span style="font-feature-settings: normal; font-kerning: auto; font-language-override: normal; font-size-adjust: none; font-stretch: normal; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal;"> </span></span></span><span>В </span><span lang="EN-US">React</span><span> возможет функциональный и объектно-ориентированный (ООП) подходы. В первом
случае оперируют функциями, во втором – классами. Классы могут содержать и
собственный </span><b><span lang="EN-US">state</span><span lang="EN-US"> </span></b><span>– состояние, и собственные функции. Если объект вызывает собственный метод,
используется </span><b><span lang="EN-US">this</span></b><span>. Но если мы передаем метод куда-либо, то контекст
выполнения меняется, тогда </span><span lang="EN-US">this</span><span lang="EN-US"> </span><span>будет указывать на другой объект. Чтобы не
происходило путаницы, метод привязывают к его контексту с помощью метода </span><b><span lang="EN-US">bind()</span></b><span>.</span></span></span></p><div style="margin-left: 40px; text-align: left;"><span style="font-family: arial;"><span style="font-size: small;">
</span></span></div><p class="MsoListParagraphCxSpLast" style="margin-left: 40px; text-align: left; text-indent: -18pt;"><span style="font-family: arial;"><span style="font-size: small;"><span><span>9.<span style="font-feature-settings: normal; font-kerning: auto; font-language-override: normal; font-size-adjust: none; font-stretch: normal; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal;"> </span></span></span><span>В </span><span lang="EN-US">Store</span><span> кроме данных содержатся методы для работы с данными. Обычно их выносят в
общий метод, называемый </span><b><span lang="EN-US">dispatch</span></b><span><b>()</b>, и передают ему (кроме необходимых данных) объект
</span><b><span lang="EN-US">action</span></b><span>, который имеет определенный тип. В зависимости от
типа </span><span lang="EN-US">dispatch</span><span>() выполняет нужный функционал. Это сокращает
запись в компонентах (вместо того, чтобы прописывать разные отдельные методы).</span></span></span></p><p class="MsoListParagraphCxSpLast" style="margin-left: 40px; text-align: left; text-indent: -18pt;"><span style="font-family: arial;"><span style="font-size: small;"><span> Продолжение следует. <br /></span></span></span></p><span style="font-family: arial;"><span style="font-size: small;">
</span></span>Oleksiy Musiyezdovhttp://www.blogger.com/profile/08448866771044815897noreply@blogger.com0tag:blogger.com,1999:blog-2695482042209092919.post-69932710973018789462020-08-21T08:10:00.000-07:002020-08-21T08:10:41.583-07:00A programmer: PHP #2 Странный WordPress<div dir="ltr" style="text-align: left;" trbidi="on">
Вопрос был вот в чем. Есть сайт на WordPress, точнее - интернет-магазин. Страница выводит товары с помощью цикла и функции <span style="color: blue;"><b>get_posts()</b><span style="color: black;">, и делает этот вывод для каждой категории товаров, чтобы можно было дальше взаимодействовать с ними уже на странице.</span><b><br /></b></span><br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAySWtFi9wTwtwjPlPlypzgOpC77qS7mnunRhTKOcVai7vF1bGU0uF-b-DqhaHAQmneKAq1NmHWm2uM7YS6uQD60z7m-gYv51NxNDE_JoaWyXkBSlhiP4ElrpYjNBj7XLMB88tdNcJPNAa/s1600/code.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1600" data-original-width="1059" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAySWtFi9wTwtwjPlPlypzgOpC77qS7mnunRhTKOcVai7vF1bGU0uF-b-DqhaHAQmneKAq1NmHWm2uM7YS6uQD60z7m-gYv51NxNDE_JoaWyXkBSlhiP4ElrpYjNBj7XLMB88tdNcJPNAa/s640/code.png" width="423" /></a></div>
<br />
Но в админке WordPress'а категории товаров указаны нормальными человеческими словами, а тут, как мы видим, ID. Возникает вопрос, как соотнести названия категорий и их ID?<br />
<br />
Ответ оказался весьма интересным:<br />
<br />
<b>"Как посмотреть ID категории?- Зайдите в Консоль-> Записи Рубрики,
кликните на заданную рубрику и в адрресной строке после ID= будет номер
категории"</b><br />
<br />
Огромное спасибо автору, а полный текст статьи <a href="https://www.wptheme.us/2014/09/kak-vyvesti-zapisi-opredelennoj-kategorii-v-wordpress/" target="_blank">здесь</a>.<br />
<br />
<br />
<br /></div>
Oleksiy Musiyezdovhttp://www.blogger.com/profile/08448866771044815897noreply@blogger.com0tag:blogger.com,1999:blog-2695482042209092919.post-42393277308420383902020-08-03T10:28:00.002-07:002020-08-03T10:28:17.976-07:00A programmer: JavaScript #18 Heroku<div>Пару слов об опыте решения проблемы, которая, в общем, оказалась проблемой невнимательности (как часто бывает). Дело в том, что запушенное мной на Heroku приложение, написанное на React'e, не запускалось. Смотрел логи, гуглил ошибки и прочее - непонятно. В итоге оказалось, что не подумал о двух вещах. Во-первых, для запуска вебприложения нужен вебсервер! Вот ведь новость какая :) Написал, добавил в проект. Во-вторых (и это было неочевидно), его нужно было явно прописать в Procfile'e. Значит, надо его создать в нем написать (в моем случае):</div><div><br /></div><div> <b><span style="color: #073763;">web: node server.js</span></b><br /></div><div><br /></div><div>Где <b><span style="color: #073763;">web</span></b><span style="color: #073763;"><span style="color: black;"> - тип </span></span>контейнера, <b><span style="color: #073763;"><b><span style="color: #073763;">server.js </span></b></span></b>- название файла с сервером.<b><span style="color: #073763;"><b><span style="color: #073763;"> </span></b></span></b>И еще: чтобы не заморачиваться с отдельным гитом для Heroku, можно подключить собственный гитха, с которого он будет брать код, а потом либо вручную либо автоматически деплоить его. В документации это всё есть.</div><div><br /> </div><div><b><span style="color: #073763;"><b><span style="color: #073763;"><br /></span></b></span></b></div>Oleksiy Musiyezdovhttp://www.blogger.com/profile/08448866771044815897noreply@blogger.com0tag:blogger.com,1999:blog-2695482042209092919.post-48586675125679216692020-07-09T09:03:00.000-07:002020-08-03T10:28:39.830-07:00A programmer: JavaScript #17 React + Heroku<div dir="ltr" style="text-align: left;" trbidi="on">
Хочется похвастаться. Я искал бесплатный или недорогой сервер, на котором можно было бы запускать Node.js и на нем всё остальное. Давно слышал про Heroku, но только сегодня руки дошли разобраться - создал один тестовый проект прямо там и второй просто туда задеплоил, оба на React'е. Собственно, пересказывать, как это делать, смысла не вижу, поскольку есть очень понятный мануал: <a href="https://devcenter.heroku.com/articles/getting-started-with-nodejs">https://devcenter.heroku.com/articles/getting-started-with-nodejs</a>. А ещё - отличное видео:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/vuVs7MypC8Y/0.jpg" src="https://www.youtube.com/embed/vuVs7MypC8Y?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div>
<br />
<br /></div>
Oleksiy Musiyezdovhttp://www.blogger.com/profile/08448866771044815897noreply@blogger.com0tag:blogger.com,1999:blog-2695482042209092919.post-53638011310914965672020-07-07T09:59:00.000-07:002020-07-07T10:00:04.135-07:00A programmer: JavaScript #16 React (vs. Angular)<div dir="ltr" style="text-align: left;" trbidi="on">
Продолжаю метаться между JavaScript'ом и Data Science. В первом случае интересны работающие программы, во втором - извлечение информации. Имея в виду лучшые возможности найти работу, JavaScript побеждает. Поэтому решил разобраться с React'ом Angular'ом. Сегодня про React.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHp8E-CF_GB_DuhbG9B6uJC2rfpjD6iaODpR83QqZ9o1lLYpahvWBLfALieoHCzx39YtP5J-wbxIbAR0dbgG0OMPAUYLDgpI6bR7kMJ8lWPT0qdx9ShNh_jXlrGZOmwLfiKy4zdbd8P0Ao/s1600/react.jpeg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="534" data-original-width="1600" height="212" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHp8E-CF_GB_DuhbG9B6uJC2rfpjD6iaODpR83QqZ9o1lLYpahvWBLfALieoHCzx39YtP5J-wbxIbAR0dbgG0OMPAUYLDgpI6bR7kMJ8lWPT0qdx9ShNh_jXlrGZOmwLfiKy4zdbd8P0Ao/s640/react.jpeg" width="640" /></a></div>
<br />
Итак, React - это фреймворк для web development'а. Ключевая особенность - модульность. То есть ты создаешь компоненты (куски твоего сайта) и вставляешь из в один общий элемент. Всё это с помощью JavaScript, разумеется:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEis3YVcPTJmUmDEW1tWY07YEMxMFgLvQBGBFYEBYid-MgKVHabZGQCkl21a3aGMn5SJJwz8ek6S34O1i-KCRPFiAH501pNnfS1lMU27rHqDle4OHXp7c5YtSSZ4cUr6v-gun9d9mxxYT6V4/s1600/code.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="662" data-original-width="954" height="222" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEis3YVcPTJmUmDEW1tWY07YEMxMFgLvQBGBFYEBYid-MgKVHabZGQCkl21a3aGMn5SJJwz8ek6S34O1i-KCRPFiAH501pNnfS1lMU27rHqDle4OHXp7c5YtSSZ4cUr6v-gun9d9mxxYT6V4/s320/code.png" width="320" /></a></div>
<br />
Здесь функция render получает параметры 1) что вставлять и 2) куда вставлять. Сами вставляемые компонеты структурно состоят из двух файлов, один из которых отрисовывает кусок страницы, а второй - стили к нему:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgticA7eBVkrGTBBCz6NdevMo6EI5k6-scmIEVLrGCXC4Olm7qGiu3iF9AjKXsBItRHVLXfs9zQTwvI8_Y3iB57MBW1v1OHeSqK966n4oGbcqXn2JB5okwD8BMz-PVlIskIJWStXWfqfaAV/s1600/code.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="624" data-original-width="954" height="209" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgticA7eBVkrGTBBCz6NdevMo6EI5k6-scmIEVLrGCXC4Olm7qGiu3iF9AjKXsBItRHVLXfs9zQTwvI8_Y3iB57MBW1v1OHeSqK966n4oGbcqXn2JB5okwD8BMz-PVlIskIJWStXWfqfaAV/s320/code.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
То же самое можно делать не через функции, а через классы. При отрисовке компонента на странице можно передавать специфические для него данные (props), которые передаются в конструктор как параметры. Значения внутри компонента (класса) называются state. По сути, это локальная пересенная (объект), для доступа к которому извне, соответственно, нужны сеттеры и геттеры. Ну и плюс особенности маршрутизации (свой js-пакет) и синтаксиса (jsx). В общем, мне понравилось - ничего сложного.<br />
<br />
В Angular, в свою очередь, тоже модульность, тоже особенности синтаксиса и маршрутизации, но:<br />
- очень большой фреймворк - занимает много места;<br />
- его надо отдельно запускать (кроме веб-сервера на node.js, например);<br />
- долго запускается;<br />
- очень зависит от настроек - и своих, и браузера (в этом месте у меня случился затык, поэтому дальше я пока не пошел).<br />
<br />
Пока что так.</div>
Oleksiy Musiyezdovhttp://www.blogger.com/profile/08448866771044815897noreply@blogger.com0tag:blogger.com,1999:blog-2695482042209092919.post-44940003000316583732020-06-02T07:35:00.001-07:002020-06-02T07:41:23.577-07:00Data Science mini-courses - Done<div dir="ltr" style="text-align: left;" trbidi="on">
Во время карантина прошел 6 миникурсов по Data Science на <a href="http://datacamp.org/"><span dir="ltr"><span class="_3l3x"></span></span></a><a data-lynx-mode="asynclazy" data-lynx-uri="https://l.facebook.com/l.php?u=https%3A%2F%2Fwww.datacamp.com%2F%3Ffbclid%3DIwAR36ASsZAqljwxbXgQgAhjEID5QOLqfuCD5ZRVmm7U9-rokhpKbWzPQNBK4&h=AT0vKyUL4hNcjiandgAAa7YL6glmeHdxS_9W3dgo8NtAQPjjALAj79rrBO0U1r5pZphyLQJPhsMlxBWxNCEGKTgy5zQZu_qr36T4UkxGVGPZ01RH1hP4ynTXHzTIN6KVLuY" href="https://www.datacamp.com/" rel="nofollow noopener" target="_blank">http://www.datacamp.com/</a>:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdk-KLvBLnNHai-JM9kiedo0K-TA4uDdnKQgZTFJ4JeOrlFC-azpkGZAZslTgSULzMES15Rjr1QDC3lT5a6MMLU2otRJPKJdWoyz5t4pp4REclROiwMyrLDlZKpaiRrX469UGDlIWGg_Hb/s1600/DatabaseDesign.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="572" data-original-width="991" height="184" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdk-KLvBLnNHai-JM9kiedo0K-TA4uDdnKQgZTFJ4JeOrlFC-azpkGZAZslTgSULzMES15Rjr1QDC3lT5a6MMLU2otRJPKJdWoyz5t4pp4REclROiwMyrLDlZKpaiRrX469UGDlIWGg_Hb/s320/DatabaseDesign.png" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSgbLtexIAuu1Oc8XYQZfq2LS8RypfHNJAaGN8X_6_LoRhNt2-ZsQnZrpqVFIm501H07GaveZjHtt_Qp8i_GfyLYXqlLUG5h1DJiO2-y53VeRgdF-XAGSh5JOenB7mZitPjbzJMwi-euuC/s1600/DataScience.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="552" data-original-width="958" height="184" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSgbLtexIAuu1Oc8XYQZfq2LS8RypfHNJAaGN8X_6_LoRhNt2-ZsQnZrpqVFIm501H07GaveZjHtt_Qp8i_GfyLYXqlLUG5h1DJiO2-y53VeRgdF-XAGSh5JOenB7mZitPjbzJMwi-euuC/s320/DataScience.png" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJ0UgQvYXoaLNE7WqDYA_nOBLuCGgpqNZybofBwprHZ2L2uAT_9MJLAKcDI3tkOtglpRnpTmzCDDo3Je5zt1ns1O2EDGtmcMriiTkgmOCV08yAhfZ0ymT7IYYj_rz3D9uTfjej_Drp8Kuc/s1600/IntermPython.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="609" data-original-width="1059" height="184" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJ0UgQvYXoaLNE7WqDYA_nOBLuCGgpqNZybofBwprHZ2L2uAT_9MJLAKcDI3tkOtglpRnpTmzCDDo3Je5zt1ns1O2EDGtmcMriiTkgmOCV08yAhfZ0ymT7IYYj_rz3D9uTfjej_Drp8Kuc/s320/IntermPython.png" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEioR8-WH_mW5bzXRsmvneGKhcCnpGpqSurXTsEHMxmHh4hcIhuRvQa2OrIyGjNtgVN3ovjzqaMn8vuXrMYZ8O24WZA20ioKDNHfzLfFcsEFSUEr73GI7n_hLPKyooe6BkwT0VUf73TCa7yf/s1600/IntroDSPython.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="605" data-original-width="1061" height="182" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEioR8-WH_mW5bzXRsmvneGKhcCnpGpqSurXTsEHMxmHh4hcIhuRvQa2OrIyGjNtgVN3ovjzqaMn8vuXrMYZ8O24WZA20ioKDNHfzLfFcsEFSUEr73GI7n_hLPKyooe6BkwT0VUf73TCa7yf/s320/IntroDSPython.png" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNxw4F2g8_BrawqFLkEPpLi5JNfCIB9YnIpQoYYZHJNwuKyOn7XZHsWHaiNsTMUYZprmIUSsloNKnNOIbMjj1ZsaYmzTVoh60MMgej26Jz2xP-EZIWTY-LEf42f0bvMC8zi3zaXShPHvhF/s1600/IntroPython.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="607" data-original-width="1063" height="182" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNxw4F2g8_BrawqFLkEPpLi5JNfCIB9YnIpQoYYZHJNwuKyOn7XZHsWHaiNsTMUYZprmIUSsloNKnNOIbMjj1ZsaYmzTVoh60MMgej26Jz2xP-EZIWTY-LEf42f0bvMC8zi3zaXShPHvhF/s320/IntroPython.png" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAgVryjIi2cxBiIwIuaWL4rMpnHEMzWUoutzi6odzc71Aom3VlFepaWvmkOiU5Ky9-blGNZUK-fhMgFuG5z8LueSTiEGXUBglWN38cANNWNkMW5SEjVqWNFgO6Nqc3e7Iac79eSEerPrae/s1600/IntroR.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="571" data-original-width="995" height="183" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAgVryjIi2cxBiIwIuaWL4rMpnHEMzWUoutzi6odzc71Aom3VlFepaWvmkOiU5Ky9-blGNZUK-fhMgFuG5z8LueSTiEGXUBglWN38cANNWNkMW5SEjVqWNFgO6Nqc3e7Iac79eSEerPrae/s320/IntroR.png" width="320" /></a></div>
<br />
<br />
<br /></div>
Oleksiy Musiyezdovhttp://www.blogger.com/profile/08448866771044815897noreply@blogger.com0tag:blogger.com,1999:blog-2695482042209092919.post-5244838402517506652020-05-31T08:06:00.001-07:002020-05-31T08:06:18.399-07:00Facebook sharing problem solved<div dir="ltr" style="text-align: left;" trbidi="on">
Вчера столкнулся с проблемой: при расшаривании вебстраницы в Фейсбуке превьюшка отражала неправильную информацию. Мне посоветовали <a href="https://developers.facebook.com/docs/sharing/webmasters/" target="_blank">A Guide to Sharing for Webmasters</a>. И за это спасибо, потому что там есть информация о том, как сделать правильно. Если коротко, но надо прописать нужные <b><span style="color: blue;">property </span></b>в <span style="color: blue;"><b>meta</b></span> в <b><span style="color: blue;">head</span></b> сайта, что я и сделал. Но! Ничего не менялось!<br />
<br />
Потому что фейсбуковский краулер, который индексирует страницы, посещает их раз в 30 дней. Но есть выход! На странице <a href="https://developers.facebook.com/tools/debug/" target="_blank">Sharing Debugger</a> вы не только можете посмотреть, какую информацию проиндексировал краулер, и как давно, но и нажать кнопочку "Scrape again" - и он проиндексирует вашу страницу прямо сейчас. Solved.</div>
Oleksiy Musiyezdovhttp://www.blogger.com/profile/08448866771044815897noreply@blogger.com0tag:blogger.com,1999:blog-2695482042209092919.post-48404291354049664592020-04-20T08:17:00.001-07:002020-04-20T08:18:11.423-07:00Карантин и интроверты<div dir="ltr" style="text-align: left;" trbidi="on">
Вообще-то карантин для меня обернулся, скорее, благом, чем злом по разным причинам (по крайней мере, пока). Среди прочего, потому, что я интроверт, и мне обычно не надо много общения - в большинстве случаев социальных сетей и мессенджеров мне вполне хватает. Плюс моя работа - это работа за компьютером, в основном. Но, как известно, работа дома оказывается сложной потому, что сложно переключаться в рабочее состояние. Так вот, на прошлой неделе я натолкнулся на интересное - один товарищ стримил свой рабочий процесс из дома. Не то, что именно он делал, а сам процесс сидения за компьютером, чего-то делания, слушания фоном музыки, периодических отлучек из-за стола и т.д. То есть того, что ты мог бы наблюдать, работая в офисе. Имея к тому же возможность этот виртуальный офис выключить в любой момент, такой стрим - идеальный способ войти в рабочее состояние: "Вот он что-то делает, а я-то что тунеядствую?!" Жаль, что зрителей было мало, и товарищ прекратил эту практику. Так кто же этот таинственный незнакомец? Рекомендую - youtube-канал <a href="https://www.youtube.com/channel/UCeObZv89Stb2xLtjLJ0De3Q" target="_blank">АйТиБорода</a>. Там периодически встречаются интересные интервью. Мне вот, например, понравилось:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/v0ttYrw3KjA/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/v0ttYrw3KjA?feature=player_embedded" width="320"></iframe></div>
<br /></div>
Oleksiy Musiyezdovhttp://www.blogger.com/profile/08448866771044815897noreply@blogger.com0tag:blogger.com,1999:blog-2695482042209092919.post-30836966232863648152020-03-25T03:58:00.001-07:002020-04-20T07:59:35.942-07:00Снова про git<div dir="ltr" style="text-align: left;" trbidi="on">
<br />
Когда-то я писал про основы git:<a href="https://myownselfdevelopment.blogspot.com/2018/09/a-programmer-javascript-8.html" target="_blank"> https://myownselfdevelopment.blogspot.com/2018/09/a-programmer-javascript-8.html</a>. Есть необходимость кое-что добавить.<br />
<br />
Например, мне пришлось переключаться с githab'a на gitlab. Это оказалось несколько нетривиальной задачей почему-то. В итоге оказалось, что надо просто переназначить url:<br />
<br />
<b><span style="color: blue;">git remote set-url origin https://gitlab.com/oleksiy76/phpwebapp.git</span></b><br />
<br />
А посмотреть, куда ты подключен можно так:<br />
<span style="color: blue;"><b><br /></b></span>
<span style="color: blue;"><b>git remote -v</b></span><br />
<br />
UPD: Ещё один неплохой курс про git:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/Fq9gDH_u2no/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/Fq9gDH_u2no?feature=player_embedded" width="320"></iframe></div>
<br /></div>
Oleksiy Musiyezdovhttp://www.blogger.com/profile/08448866771044815897noreply@blogger.com0tag:blogger.com,1999:blog-2695482042209092919.post-17042240404843807152020-03-25T02:28:00.002-07:002020-03-25T02:28:58.058-07:00How to work from home<div dir="ltr" style="text-align: left;" trbidi="on">
На самом деле это просто перепост видео:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/EhDYJUSYoXg/0.jpg" src="https://www.youtube.com/embed/EhDYJUSYoXg?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div>
<br />
<br />
Эти советы очень часто повторяются, но к ним Стив Павлина, например, добавляет ещё один. Я сейчас быстро не нашел ссылку, где именно об этом говорит - можете поискать здесь: <a href="https://www.stevepavlina.com/">https://www.stevepavlina.com/</a>. Совет такой: натренируйте себе "bad eye" - строгий взгляд, которым вы будете отпугивать домашних, когда они будут приходить отвлекать вас (а они будут).<br />
<br />
<br /></div>
Oleksiy Musiyezdovhttp://www.blogger.com/profile/08448866771044815897noreply@blogger.com0tag:blogger.com,1999:blog-2695482042209092919.post-43122397695826412112020-02-29T10:26:00.000-08:002020-02-29T11:50:18.908-08:00A programmer: PHP #1<div dir="ltr" style="text-align: left;" trbidi="on">
Проблема с тем, что бесплатный хостинг доступен почти исключительно на Apahe и заточен под PHP и MySQL, решилась тем, что пришлось разбираться с этим стеком.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGV7I8F8Me71t9Sa026gxJXWcl7X7U69LeNl33COdx_qHimqnuHxCzrqOy8fPLJS1qM14e_aJ9Vjly4ze5osLxtkAupQESYdamXWnsImuFQ3tSiOhjGzv-P9tdg8yEnbLGBajRk_pXRUN6/s1600/1280px-PHP-logo.svg.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="691" data-original-width="1280" height="172" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGV7I8F8Me71t9Sa026gxJXWcl7X7U69LeNl33COdx_qHimqnuHxCzrqOy8fPLJS1qM14e_aJ9Vjly4ze5osLxtkAupQESYdamXWnsImuFQ3tSiOhjGzv-P9tdg8yEnbLGBajRk_pXRUN6/s320/1280px-PHP-logo.svg.png" width="320" /></a></div>
Во-первых, учил PHP, точнее, переписывал свой сайт, где это было необходимо. Всё, на самом деле, довольно просто - прописываешь кусок кода прямо внутри вёрстки, что удобно, подключаешь куда надо другие файлы. Единственное, с чем бился долго - это проверка длины имени при вводе в форму, но только потому, что долго не мог правильно сформулировать запрос. Дело в том, что у меня уже было это реализовано на JavaScript'e - жалко было отказываться, но никуда не денешься. Плюс хотелось, чтобы всё это проверялось без перезагрузки страницы. JavaScript'овые варианты выходили как-то криво, плюс они ведь работают только на клиенте, а мне нужно было, чтобы была связь с сервером. Оказалось, нужны AJAX-запросы - разобрался с ними.<br />
<br />
Во-вторых, устанавливал локально всё - Apahe, PHP, MySQL и phpMyAdmin. С MySQL долго бился, потому что имя моего компьютера содержало кириллические буквы. А с phpMyAdmin - потому что настройки шифрования клиента (phpMyAdmin ) и сервера не совпадали (MySQL). Но в итоге всё получилось, и я доволен собой в конце концов.<br />
<br />
<br /></div>
Oleksiy Musiyezdovhttp://www.blogger.com/profile/08448866771044815897noreply@blogger.com0tag:blogger.com,1999:blog-2695482042209092919.post-73931298667962808992019-08-19T10:59:00.002-07:002019-08-19T11:03:54.933-07:00A programmer: JavaScript #15<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
Написал скрипт с для проверки длины имени и фамилии на стороне клиента. Файл <b>javascript </b>с использованием <b>eventListener</b>. Но получалось, что для двух разных полей (имени и фамилии) нужно писать два идентичных скрипта, что неправильно. Я решил заменить два скрипта на один, заменив, соответственно, <b>eventListener </b>в скрипте на <b>onchange </b>в тэге. Но получалась странная ситуация: судя по туториалам, надо или внешний скрипт подключать ко всей странице, или писать <b>onchang</b>, но тогда скрипт надо писать в <b>html</b>'e. Или-или.</div>
<br />
<span class="tL8wMe EMoHub" dir="ltr" id=":9a.co" style="text-align: left;">Посоветовали (дословно): "</span><span class="tL8wMe EMoHub" dir="ltr" id=":9a.co" style="text-align: left;"><b><span class="tL8wMe EMoHub" dir="ltr" id=":a2.co" style="text-align: left;">во внешнем файле функцию имей, файл подключи, а функцию эту вызывай</span></b>". И вот получилось!</span><br />
<span class="tL8wMe EMoHub" dir="ltr" id=":9a.co" style="text-align: left;"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3OAgIAHmxHGJpGj-nwKDmFDiIGwLnY4eUBKFASmNdrJd0Qm0ixtYZV1E3nYCfrKoY-fV0IZ8Ib5_zVWUdCisxDrEUyuLbWMtPWi0FhtOISAQTU_aILq1Vp0whCQDqd_KnE6yQjaZXOr_J/s1600/validation.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="422" data-original-width="601" height="280" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3OAgIAHmxHGJpGj-nwKDmFDiIGwLnY4eUBKFASmNdrJd0Qm0ixtYZV1E3nYCfrKoY-fV0IZ8Ib5_zVWUdCisxDrEUyuLbWMtPWi0FhtOISAQTU_aILq1Vp0whCQDqd_KnE6yQjaZXOr_J/s400/validation.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<span class="tL8wMe EMoHub" dir="ltr" id=":9a.co" style="text-align: left;"></span>
<span class="tL8wMe EMoHub" dir="ltr" id=":9a.co" style="text-align: left;">Разумеется, файл был подключен, </span><span class="tL8wMe EMoHub" dir="ltr" id=":9a.co" style="text-align: left;"><span class="tL8wMe EMoHub" dir="ltr" id=":an.co" style="text-align: left;">а в полях было указано:</span></span><br />
<span class="tL8wMe EMoHub" dir="ltr" id=":9a.co" style="text-align: left;"><span class="tL8wMe EMoHub" dir="ltr" id=":an.co" style="text-align: left;"><br /><span style="color: blue;"><b>onchange="listen('first_name')"<br />onchange="listen('last_name')"</b></span></span></span><br />
<br />
День прожит не зря :)<br />
<span class="tL8wMe EMoHub" dir="ltr" id=":9a.co" style="text-align: left;"><br /></span></div>
Oleksiy Musiyezdovhttp://www.blogger.com/profile/08448866771044815897noreply@blogger.com2tag:blogger.com,1999:blog-2695482042209092919.post-4548771842782081812019-08-14T11:41:00.001-07:002019-08-14T11:41:07.156-07:00A programmer: JavaScript #14<div dir="ltr" style="text-align: left;" trbidi="on">
Хотел я, значит, запустить веб-сервер на NodeJS на удаленном сервере, чтобы протестировать одну штуку. Ну а там крутится Apache, разумеется. Сделать это (как выяснилось после долгих разбирательств) можно. Но если всякие разные настройки Апача для конкретный папок можно прописывать в файле .htaccess, то конкретно эти настройки нельзя - только в httpd.config, доступ к которому - только root. Следовательно, или обходиться апачем, или искать хостинг, который поддерживает Node JS, или покупать выделенный сервер, где сам себе root и делай, что хочешь.<br />
<br /></div>
Oleksiy Musiyezdovhttp://www.blogger.com/profile/08448866771044815897noreply@blogger.com0tag:blogger.com,1999:blog-2695482042209092919.post-41572914952181050622019-08-04T00:45:00.003-07:002019-08-04T00:49:59.290-07:00A programmer: JavaScript #13<div dir="ltr" style="text-align: left;" trbidi="on">
<br />
Сегодня речь о нескольких нюансах, которые знатокам покажутся очевидными, но у меня вызвали затруднения в последние дни.<br />
<br />
1.<br />
Когда мы экспортируем модуль, экспортируется не функция, а объект:<br />
<span style="color: blue;">module.exports = { message: message }</span><br />
<br />
то есть когда мы хотим вызвать функцию message из этого модуля, надо писать не <span style="color: blue;">message();,</span> а <span style="color: blue;">message.message()</span>;.<br />
<br />
Разумеется, предполагается, что модуль импортирован:<br />
<span style="color: blue;">var message = require('./module.js');</span><br />
<br />
2.<br />
В других языках ответ на этот вопрос находился быстро, а тут пришлось поискать, как сравнить два объекта (а не значения переменных). Ответ вот:<br />
<span style="color: blue;">Object.is(value1, value2);</span><br />
<br />
3.<br />
Ну и по мелочи - проверять все мелочи. Например, не путать атрибуты html-формы <span style="color: blue;">"id"</span> и <span style="color: blue;">"name"</span>. Или не забывать про <span style="color: blue;">urlencodedParser</span>, когда пишешь обработчик для POST-метода (а то у меня был шок, когда <span style="color: blue;">body </span>вообще не обнаруживалось). Или просто уточнять синтаксис.<br />
<br />
<br /></div>
Oleksiy Musiyezdovhttp://www.blogger.com/profile/08448866771044815897noreply@blogger.com2