{"id":353528,"date":"2024-05-20T22:29:47","date_gmt":"2024-05-20T22:29:47","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=353528"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=353528","title":{"rendered":"<span>\u041f\u0430\u0442\u0442\u0435\u0440\u043d\u044b \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u0438 \u0432 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u043c JavaScript<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/webt\/ma\/po\/lv\/mapolvqq4uunxfqoaviv3g9km9y.jpeg\" data-src=\"https:\/\/habrastorage.org\/webt\/ma\/po\/lv\/mapolvqq4uunxfqoaviv3g9km9y.jpeg\" data-blurred=\"true\"\/>  <\/p>\n<p>  <\/p>\n<p>  <\/p>\n<p>&#171;\u0420\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c&#187; \u2014 \u044d\u0442\u043e \u0442\u043e, \u043a\u0430\u043a \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0440\u0435\u0430\u0433\u0438\u0440\u0443\u044e\u0442 \u043d\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445. \u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0442 \u0440\u0430\u0437\u043d\u044b\u0435 \u0442\u0438\u043f\u044b \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u0438, \u043d\u043e \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438, \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c \u2014 \u044d\u0442\u043e \u043a\u043e\u0433\u0434\u0430 \u043c\u044b \u0447\u0442\u043e-\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u043c \u0432 \u043e\u0442\u0432\u0435\u0442 \u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<p>  <\/p>\n<h2 id=\"patterny-reaktivnosti-yavlyayutsya-klyuchevymi-dlya-veb-razrabotki\">\u041f\u0430\u0442\u0442\u0435\u0440\u043d\u044b \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u0438 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u043c\u0438 \u0434\u043b\u044f \u0432\u0435\u0431-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438<\/h2>\n<p>  <\/p>\n<p>\u041c\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0441 \u0431\u043e\u043b\u044c\u0448\u0438\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e\u043c JS \u043d\u0430 \u0441\u0430\u0439\u0442\u0430\u0445 \u0438 \u0432 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u2014 \u044d\u0442\u043e \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0441\u0440\u0435\u0434\u0430. \u041c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0440\u0435\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c, \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043e\u0442\u0447\u0435\u0442\u044b, \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u0442\u044c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0438 \u0442.\u0434. \u042d\u0442\u043e \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0432 \u0441\u0435\u0431\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 UI, \u0441\u0435\u0442\u0435\u0432\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b, \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438 \u0438 URL \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u043a\u0430\u0441\u043a\u0430\u0434\u043d\u043e\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u043c \u0430\u0441\u043f\u0435\u043a\u0442\u043e\u043c \u0432\u0435\u0431-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438.<\/p>\n<p>  <\/p>\n<p>\u0420\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c, \u043e\u0431\u044b\u0447\u043d\u043e, \u0430\u0441\u0441\u043e\u0446\u0438\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0441 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430\u043c\u0438, \u043d\u043e \u043c\u043e\u0436\u043d\u043e \u043c\u043d\u043e\u0433\u043e\u043c\u0443 \u043d\u0430\u0443\u0447\u0438\u0442\u044c\u0441\u044f, \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u044f \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c \u043d\u0430 \u0447\u0438\u0441\u0442\u043e\u043c JS. \u041c\u044b \u043c\u043e\u0436\u0435\u043c \u0441\u043c\u0435\u0448\u0438\u0432\u0430\u0442\u044c \u0438 \u0438\u0433\u0440\u0430\u0442\u044c \u0441 \u044d\u0442\u0438\u043c\u0438 \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0430\u043c\u0438 \u0434\u043b\u044f \u043b\u0443\u0447\u0448\u0435\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<p>  <\/p>\n<blockquote><p>\u0418\u0437\u0443\u0447\u0435\u043d\u0438\u0435 \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u043e\u0432 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a \u0443\u043c\u0435\u043d\u044c\u0448\u0435\u043d\u0438\u044e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u043a\u043e\u0434\u0430 \u0438 \u043f\u043e\u0432\u044b\u0448\u0435\u043d\u0438\u044e \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e \u043e\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u043e\u0433\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430.<\/p><\/blockquote>\n<p>\u041c\u043d\u0435 \u043d\u0440\u0430\u0432\u0438\u0442\u0441\u044f \u0438\u0437\u0443\u0447\u0430\u0442\u044c \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u044b, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043e\u043d\u0438 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043c\u044b \u043a \u043b\u044e\u0431\u043e\u043c\u0443 \u044f\u0437\u044b\u043a\u0443 \u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u0435. \u041f\u0430\u0442\u0442\u0435\u0440\u043d\u044b \u043c\u043e\u0433\u0443\u0442 \u043a\u043e\u043c\u0431\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0447\u0430\u0441\u0442\u043e \u043f\u0440\u0438\u0432\u043e\u0434\u044f \u043a \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u043c\u0443 \u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u043e\u043c\u0443 \u043a\u043e\u0434\u0443.<\/p>\n<p><a name=\"habracut\"><\/a>  <\/p>\n<h2 id=\"izdatelpodpischik\">\u0418\u0437\u0434\u0430\u0442\u0435\u043b\u044c\/\u043f\u043e\u0434\u043f\u0438\u0441\u0447\u0438\u043a<\/h2>\n<p>  <\/p>\n<p>\u0418\u0437\u0434\u0430\u0442\u0435\u043b\u044c\/\u043f\u043e\u0434\u043f\u0438\u0441\u0447\u0438\u043a (Publisher\/Subscriber, PubSub) \u2014 \u043e\u0434\u0438\u043d \u0438\u0437 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u043e\u0432 \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u0438. \u0412\u044b\u0437\u043e\u0432 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>publish()<\/code> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u043e\u0434\u043f\u0438\u0441\u0447\u0438\u043a\u0430\u043c (\u043f\u043e\u0434\u043f\u0438\u0441\u0430\u0432\u0448\u0438\u043c\u0441\u044f \u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>subscribe()<\/code>) \u0440\u0435\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">const pubSub = {   events: {},   subscribe(event, callback) {     if (!this.events[event]) {       this.events[event] = []     }     this.events[event].push(callback)   },   publish(event, data) {     if (this.events[event]) {       this.events[event].forEach((callback) => {         callback(data)       })     }   },   \/\/ \u041f\u0440\u0438\u043c. \u043f\u0435\u0440.: \u0430\u0432\u0442\u043e\u0440 \u043f\u043e\u0447\u0435\u043c\u0443-\u0442\u043e \u0441\u0447\u0438\u0442\u0430\u0435\u0442, \u0447\u0442\u043e \u0443 PubSub \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u044d\u0442\u043e\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430   unsubscribe(event, callback) {     if (this.events[event]) {       this.events[event] = this.events[event].filter((cb) => cb !== callback)     }   } }  const handleUpdate = (data) => {   console.log(data) } pubSub.subscribe('update', handleUpdate) pubSub.publish('update', 'Some update') \/\/ Some update pubSub.unsubscribe('update', handleUpdate) pubSub.publish('update', 'Some update') \/\/ \u041d\u0438\u0447\u0435\u0433\u043e<\/code><\/pre>\n<p>  <\/p>\n<h2 id=\"kastomnye-sobytiya---nativnyy-brauzernyy-interfeys-dlya-pubsub\">\u041a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u2014 \u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f PubSub<\/h2>\n<p>  <\/p>\n<p>\u0411\u0440\u0430\u0443\u0437\u0435\u0440 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 API \u0434\u043b\u044f \u0432\u044b\u0437\u043e\u0432\u0430 \u0438 \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0438 \u043d\u0430 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f (custom events). \u041c\u0435\u0442\u043e\u0434 <a href=\"https:\/\/developer.mozilla.org\/ru\/docs\/Web\/API\/EventTarget\/dispatchEvent\" rel=\"nofollow noopener noreferrer\">dispatchEvent()<\/a> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u0441\u043e\u0431\u044b\u0442\u0438\u0435, \u043d\u043e \u0438 \u043f\u0440\u0438\u043a\u0440\u0435\u043f\u043b\u044f\u0442\u044c \u043a \u043d\u0435\u043c\u0443 \u0434\u0430\u043d\u043d\u044b\u0435:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">const pizzaEvent = new CustomEvent('pizzaDelivery', {   detail: {     name: 'Supreme',   }, })  const handlePizzaEvent = (e) => {   console.log(e.detail.name) } window.addEventListener('pizzaDelivery', handlePizzaEvent) window.dispatchEvent(pizzaEvent) \/\/ Supreme<\/code><\/pre>\n<p>  <\/p>\n<p>\u041c\u044b \u043c\u043e\u0436\u0435\u043c \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0442\u044c \u043e\u0431\u043b\u0430\u0441\u0442\u044c \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438 (scope) \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u043e\u0433\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u043b\u044e\u0431\u044b\u043c \u0443\u0437\u043b\u043e\u043c DOM. \u0412 \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u043d\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 <code>window<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0442\u0430\u043a\u0436\u0435 \u0438\u0437\u0432\u0435\u0441\u0442\u0435\u043d \u043a\u0430\u043a &#171;\u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u0430\u044f \u0448\u0438\u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0439&#187; (event bus).<\/p>\n<p>  <\/p>\n<pre><code class=\"html\">&lt;div id=\"pizza-store\">&lt;\/div><\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"javascript\">const pizzaEvent = new CustomEvent('pizzaDelivery', {   detail: {     name: 'Supreme',   }, })  const pizzaStore = document.getElementById('pizza-store') const handlePizzaEvent = (e) => {   console.log(e.detail.name) } pizzaStore.addEventListener('pizzaDelivery', handlePizzaEvent) pizzaStore.dispatchEvent(pizzaEvent) \/\/ Supreme<\/code><\/pre>\n<p>  <\/p>\n<h2 id=\"ekzemplyary-kastomnyh-sobytiy---sozdanie-podklassov-eventtarget\">\u042d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u044b \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0445 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u2014 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u043e\u0434\u043a\u043b\u0430\u0441\u0441\u043e\u0432 EventTarget<\/h2>\n<p>  <\/p>\n<p>\u041c\u044b \u043c\u043e\u0436\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043f\u043e\u0434\u043a\u043b\u0430\u0441\u0441\u044b \u0446\u0435\u043b\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u044f (event target) \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0432 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u043a\u043b\u0430\u0441\u0441\u0430:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">class PizzaStore extends EventTarget {   constructor() {     super()   }   addPizza(flavor) {     \/\/ \u0412\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u043f\u0440\u044f\u043c\u043e \u043d\u0430 \u043a\u043b\u0430\u0441\u0441\u0435     this.dispatchEvent(       new CustomEvent('pizzaAdded', {         detail: {           pizza: flavor,         },       }),     )   } }  const Pizzas = new PizzaStore() const handleAddPizza = (e) => {   console.log('Added pizza:', e.detail.pizza) } Pizzas.addEventListener('pizzaAdded', handleAddPizza) Pizzas.addPizza('Supreme') \/\/ Added pizza: Supreme<\/code><\/pre>\n<p>  <\/p>\n<p>\u041d\u0430\u0448\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u043d\u0430 \u043a\u043b\u0430\u0441\u0441\u0435, \u0430 \u043d\u0435 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e (\u043d\u0430 <code>window<\/code>). \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u043c\u043e\u0433\u0443\u0442 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0442\u044c\u0441\u044f \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u043a \u044d\u0442\u043e\u043c\u0443 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0443.<\/p>\n<p>  <\/p>\n<h2 id=\"nablyudatel\">\u041d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u044c<\/h2>\n<p>  <\/p>\n<p>\u041f\u0430\u0442\u0442\u0435\u0440\u043d &#171;\u041d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u044c&#187; (Observer) \u043f\u043e\u0445\u043e\u0436 \u043d\u0430 PubSub. \u041e\u043d \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0441\u0443\u0431\u044a\u0435\u043a\u0442\u0430 (Subject). \u0414\u043b\u044f \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u0434\u043f\u0438\u0441\u0447\u0438\u043a\u043e\u0432 \u043e\u0431 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u0443\u0431\u044a\u0435\u043a\u0442 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u043c\u0435\u0442\u043e\u0434 <code>notify()<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">class Subject {   constructor() {     this.observers = []   }   addObserver(observer) {     this.observers.push(observer)   }   removeObserver(observer) {     this.observers = this.observers.filter((o) => o !== observer)   }   notify(data) {     this.observers.forEach((observer) => {       observer.update(data)     })   } }  class Observer {   update(data) {     console.log(data)   } }  const subject = new Subject() const observer = new Observer()  subject.addObserver(observer) subject.notify('Hi, observer!') \/\/ Hi, observer! subject.removeObserver(observer) subject.notify('Are you still here?') \/\/ \u041d\u0438\u0447\u0435\u0433\u043e<\/code><\/pre>\n<p>  <\/p>\n<h2 id=\"reaktivnye-svoystva-obekta---proksi\">\u0420\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u2014 \u043f\u0440\u043e\u043a\u0441\u0438<\/h2>\n<p>  <\/p>\n<p><a href=\"https:\/\/developer.mozilla.org\/ru\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Proxy\" rel=\"nofollow noopener noreferrer\">Proxy<\/a> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0435\/\u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u0441\u0432\u043e\u0439\u0441\u0442\u0432 \u043e\u0431\u044a\u0435\u043a\u0442\u0430:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">const handler = {   get(target, property) {     console.log(`Getting property ${property}`)     return target[property]   },   set(target, property, value) {     console.log(`Setting property ${property} to value ${value}`)     target[property] = value     return true \/\/ \u0418\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430   }, }  const pizza = {   name: 'Margherita',   toppings: ['mozzarella', 'tomato sauce'], } const proxiedPizza = new Proxy(pizza, handler)  console.log(proxiedPizza.name) \/\/ 'Getting property name' \u0438 'Margherita' proxiedPizza.name = 'Pepperoni' \/\/ Setting property name to value Pepperoni<\/code><\/pre>\n<p>  <\/p>\n<h2 id=\"reaktivnost-otdelnyh-svoystv-obekta\">\u0420\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u0441\u0432\u043e\u0439\u0441\u0442\u0432 \u043e\u0431\u044a\u0435\u043a\u0442\u0430<\/h2>\n<p>  <\/p>\n<p><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Object\/defineProperty\" rel=\"nofollow noopener noreferrer\">Object.defineProperty()<\/a> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c \u0430\u043a\u0441\u0435\u0441\u0441\u043e\u0440\u044b (\u0433\u0435\u0442\u0442\u0435\u0440\u044b \u0438 \u0441\u0435\u0442\u0442\u0435\u0440\u044b) \u043f\u0440\u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0438 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u043e\u0431\u044a\u0435\u043a\u0442\u0430:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">const pizza = {   _name: 'Margherita', \/\/ \u0412\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e }  Object.defineProperty(pizza, 'name', {   get() {     console.log('Getting property name')     return this._name   },   set(value) {     console.log(`Setting property name to value ${value}`)     this._name = value   }, })  console.log(pizza.name) \/\/ 'Getting property name' \u0438 'Margherita' pizza.name = 'Pepperoni' \/\/ Setting property name to value Pepperoni<\/code><\/pre>\n<p>  <\/p>\n<p><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Object\/defineProperties\" rel=\"nofollow noopener noreferrer\">Object.defineProperties()<\/a> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c \u0430\u043a\u0441\u0435\u0441\u0441\u043e\u0440\u044b \u0434\u043b\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0441\u0432\u043e\u0439\u0441\u0442\u0432 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e.<\/p>\n<p>  <\/p>\n<h2 id=\"asinhronnye-reaktivnye-dannye---promisy\">\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u2014 \u043f\u0440\u043e\u043c\u0438\u0441\u044b<\/h2>\n<p>  <\/p>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u043d\u0430\u0448\u0438\u0445 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u0435\u0439 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c\u0438! \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u0435\u0439 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">class AsyncData {   constructor(initialData) {     this.data = initialData     this.subscribers = []   }    \/\/ \u041f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c\u0441\u044f \u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445   subscribe(callback) {     if (typeof callback !== 'function') {       throw new Error('Callback must be a function')     }     this.subscribers.push(callback)   }    \/\/ \u041e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u0436\u0434\u0435\u043c \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439   async set(key, value) {     this.data[key] = value      const updates = this.subscribers.map(async (callback) => {       await callback(key, value)     })      await Promise.allSettled(updates)   } }  const data = new AsyncData({ pizza: 'Pepperoni' })  data.subscribe(async (key, value) => {   await new Promise((resolve) => setTimeout(resolve, 1000))   console.log(`Updated UI for ${key}: ${value}`) })  data.subscribe(async (key, value) => {   await new Promise((resolve) => setTimeout(resolve, 500))   console.log(`Logged change for ${key}: ${value}`) })  \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u044f \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439 async function updateData() {   await data.set('pizza', 'Supreme') \/\/ \u0412\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u0432\u0441\u0435\u0445 \u043f\u043e\u0434\u043f\u0438\u0441\u0447\u0438\u043a\u043e\u0432 \u0438 \u0436\u0434\u0435\u043c \u0438\u0445 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u044f   console.log('All updates complete.') }  updateData() \/**   \u0447\u0435\u0440\u0435\u0437 500 \u043c\u0441   Logged change for pizza: Supreme   \u0447\u0435\u0440\u0435\u0437 1000 \u043c\u0441   Updated UI for pizza: Supreme   All updates complete.  *\/<\/code><\/pre>\n<p>  <\/p>\n<h2 id=\"reaktivnye-sistemy\">\u0420\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b<\/h2>\n<p>  <\/p>\n<p>\u0412 \u043e\u0441\u043d\u043e\u0432\u0435 \u043c\u043d\u043e\u0433\u0438\u0445 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432 \u043b\u0435\u0436\u0430\u0442 \u0441\u043b\u043e\u0436\u043d\u044b\u0435 \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b: \u0445\u0443\u043a\u0438 (Hooks) \u0432 React, \u0441\u0438\u0433\u043d\u0430\u043b\u044b (Signals) \u0432 SolidJS, \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0435\u043c\u044b\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 (Observables) \u0432 Rx.js \u0438 \u0442.\u0434. \u041a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u0438\u0445 \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0435\u0439 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u0439 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u0438\u043b\u0438 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u043e\u0432 DOM \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<p>  <\/p>\n<h3 id=\"observables-rxjs\">Observables (Rx.js)<\/h3>\n<p>  <\/p>\n<p>\u041f\u0430\u0442\u0442\u0435\u0440\u043d &#171;\u041d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u044c&#187; \u0438 Observables (\u0447\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0443\u0441\u043b\u043e\u0432\u043d\u043e \u043f\u0435\u0440\u0435\u0432\u0435\u0441\u0442\u0438 \u043a\u0430\u043a &#171;\u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0435\u043c\u044b\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438&#187;) \u2014 \u044d\u0442\u043e \u043d\u0435 \u043e\u0434\u043d\u043e \u0438 \u0442\u043e\u0436\u0435, \u043a\u0430\u043a \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u043f\u0435\u0440\u0432\u044b\u0439 \u0432\u0437\u0433\u043b\u044f\u0434.<\/p>\n<p>  <\/p>\n<p>Observables \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c (produce) \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c (sequence) \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u0432 \u0442\u0435\u0447\u0435\u043d\u0438\u0435 \u0432\u0440\u0435\u043c\u0435\u043d\u0438. \u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432 Observable, \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0439 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u043f\u043e\u0434\u043f\u0438\u0441\u0447\u0438\u043a\u0430\u043c, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044f \u0438\u043c \u0440\u0435\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">class Observable {   constructor(producer) {     this.producer = producer   }    \/\/ \u041c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0438 \u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f   subscribe(observer) {     \/\/ \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432     if (typeof observer !== 'object' || observer === null) {       throw new Error('Observer must be an object with next, error, and complete methods')     }      if (typeof observer.next !== 'function') {       throw new Error('Observer must have a next method')     }      if (typeof observer.error !== 'function') {       throw new Error('Observer must have an error method')     }      if (typeof observer.complete !== 'function') {       throw new Error('Observer must have a complete method')     }      const unsubscribe = this.producer(observer)      \/\/ \u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u0441 \u043c\u0435\u0442\u043e\u0434\u043e\u043c \u0434\u043b\u044f \u043e\u0442\u043f\u0438\u0441\u043a\u0438     return {       unsubscribe: () => {         if (unsubscribe &amp;&amp; typeof unsubscribe === 'function') {           unsubscribe()         }       },     }   } }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043d\u043e\u0432\u044b\u0439 observable, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u0442\u0440\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0435\u0442\u0441\u044f const observable = new Observable(observer => {   observer.next(1)   observer.next(2)   observer.next(3)   observer.complete()    \/\/ \u041e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e: \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043e\u0447\u0438\u0441\u0442\u043a\u0438   return () => {     console.log('Observer unsubscribed')   } })  \/\/ \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c observer \u0441 \u043c\u0435\u0442\u043e\u0434\u0430\u043c\u0438 next, error \u0438 complete const observer = {   next: value => console.log('Received value:', value),   error: err => console.log('Error:', err),   complete: () => console.log('Completed'), }  \/\/ \u041f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c\u0441\u044f \u043d\u0430 observable const subscription = observable.subscribe(observer)  \/\/ \u041e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u0430\u044f \u043e\u0442\u043f\u0438\u0441\u043a\u0430 \u043f\u0440\u0435\u043a\u0440\u0430\u0449\u0430\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 subscription.unsubscribe()<\/code><\/pre>\n<p>  <\/p>\n<p>\u041c\u0435\u0442\u043e\u0434 <code>next()<\/code> \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u044f\u043c. \u041c\u0435\u0442\u043e\u0434 <code>complete()<\/code> \u0437\u0430\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u043f\u043e\u0442\u043e\u043a \u0434\u0430\u043d\u043d\u044b\u0445 (stream). \u041c\u0435\u0442\u043e\u0434 <code>error()<\/code> \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043e\u0448\u0438\u0431\u043e\u043a. <code>subscribe()<\/code> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u043e\u0434\u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0434\u0430\u043d\u043d\u044b\u0435, \u0430 <code>unsubscribe()<\/code> \u2014 \u043e\u0442\u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f \u043e\u0442 \u043d\u0438\u0445.<\/p>\n<p>  <\/p>\n<p>\u0421\u0430\u043c\u044b\u043c\u0438 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u043c\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u043c\u0438, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u044d\u0442\u043e\u0442 \u043f\u0430\u0442\u0442\u0435\u0440\u043d, \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f <a href=\"https:\/\/rxjs.dev\/\" rel=\"nofollow noopener noreferrer\">Rx.js<\/a> \u0438 <a href=\"https:\/\/mobx.js.org\/\" rel=\"nofollow noopener noreferrer\">MobX<\/a>.<\/p>\n<p>  <\/p>\n<h3 id=\"signals-solidjs\">Signals (SolidJS)<\/h3>\n<p>  <\/p>\n<p>\u0412\u0437\u0433\u043b\u044f\u043d\u0438\u0442\u0435 \u043d\u0430 <a href=\"https:\/\/frontendmasters.com\/courses\/reactivity-solidjs\/?utm_source=blog&amp;utm_medium=website&amp;utm_campaign=reactivity\" rel=\"nofollow noopener noreferrer\">\u043a\u0443\u0440\u0441 \u043f\u043e \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u0438 \u0441 SolidJS<\/a> \u043e\u0442 Ryan Carniato.<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">const context = []  export function createSignal(value) {   const subscriptions = new Set()    const read = () => {     const observer = context[context.length - 1]     if (observer) {       subscriptions.add(observer)     }     return value   }   const write = (newValue) => {     value = newValue     for (const observer of subscriptions) {       observer.execute()     }   }    return [read, write] }  export function createEffect(fn) {   const effect = {     execute() {       context.push(effect)       fn()       context.pop()     },   }    effect.execute() }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">import { createSignal, createEffect } from '.\/reactive'  const [count, setCount] = createSignal(0)  createEffect(() => {   console.log(count()) }) \/\/ 0  setCount(10) \/\/ 10<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 <a href=\"https:\/\/gist.github.com\/1Marc\/09e739caa6a82cc176ab4c2abd691814\" rel=\"nofollow noopener noreferrer\">\u0437\u0434\u0435\u0441\u044c<\/a>. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e \u0441\u0438\u0433\u043d\u0430\u043b\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0447\u0438\u0442\u0430\u0442\u044c <a href=\"https:\/\/habr.com\/ru\/companies\/timeweb\/articles\/725504\/\">\u0437\u0434\u0435\u0441\u044c<\/a>.<\/p>\n<p>  <\/p>\n<h3 id=\"nablyudaemye-znacheniya-frontend-masters\">\u041d\u0430\u0431\u043b\u044e\u0434\u0430\u0435\u043c\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f (Frontend Masters)<\/h3>\n<p>  <\/p>\n<p>\u041d\u0430\u0448 \u0432\u0438\u0434\u0435\u043e\u043f\u043b\u0435\u0435\u0440 \u0438\u043c\u0435\u0435\u0442 \u043c\u043d\u043e\u0433\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f \u0432 \u043b\u044e\u0431\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u0434\u043b\u044f \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u0432\u0438\u0434\u0435\u043e. Kai \u0438\u0437 \u043d\u0430\u0448\u0435\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043b <a href=\"https:\/\/github.com\/FrontendMasters\/observablish-values\" rel=\"nofollow noopener noreferrer\">\u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0435\u043c\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f (observable-ish values)<\/a>, \u0447\u0442\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u0435\u0449\u0435 \u043e\u0434\u0438\u043d \u043f\u0440\u0438\u043c\u0435\u0440 \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u043d\u0430 \u0447\u0438\u0441\u0442\u043e\u043c JS.<\/p>\n<p>  <\/p>\n<p>\u041d\u0430\u0431\u043b\u044e\u0434\u0430\u0435\u043c\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u2014 \u044d\u0442\u043e \u0441\u043e\u0447\u0435\u0442\u0430\u043d\u0438\u0435 PubSub \u0441 \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c\u044b\u043c\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c\u0438 (computed values), \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u043c\u0438 \u0441\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0442\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0438\u0437\u0434\u0430\u0442\u0435\u043b\u0435\u0439.<\/p>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u0434\u043f\u0438\u0441\u0447\u0438\u043a\u0430 \u043e\u0431 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">const fn = function (current, previous) {}  const obsValue = ov('initial') obsValue.subscribe(fn) \/\/ \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0430 \u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f obsValue() \/\/ 'initial' obsValue('initial') \/\/ 'initial', \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u043d\u0435 \u0431\u044b\u043b\u043e obsValue('new') \/\/ fn('new', 'initial') obsValue.value = 'silent' \/\/ \u0442\u0438\u0445\u043e\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435<\/code><\/pre>\n<p>  <\/p>\n<p>\u041c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u043c\u0430\u0441\u0441\u0438\u0432\u043e\u0432 \u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u043d\u0435 \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u0435\u0442 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f, \u0430 \u0437\u0430\u043c\u0435\u043d\u044f\u0435\u0442 \u0438\u0445:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">const obsArray = ov([1, 2, 3]) obsArray.subscribe(fn) obsArray().push(4) \/\/ \u0442\u0438\u0445\u043e\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 obsArray.publish() \/\/ fn([1, 2, 3, 4]); obsArray([4, 5]) \/\/ fn([4, 5], [1, 2, 3]);<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u0435\u0440\u0435\u0434\u0430\u0447\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043a\u044d\u0448\u0438\u0440\u0443\u0435\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043a\u0430\u043a \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435. \u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b \u043f\u0435\u0440\u0435\u0434\u0430\u044e\u0442\u0441\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0438. \u041d\u0430\u0431\u043b\u044e\u0434\u0430\u0435\u043c\u044b\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438, \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c\u044b\u0435 \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043f\u043e\u0434\u043f\u0438\u0441\u0447\u0438\u043a\u0430\u043c\u0438, \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u044d\u0442\u0438\u0445 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u043c\u0443 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f.<\/p>\n<p>  <\/p>\n<p>\u0415\u0441\u043b\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043f\u0440\u043e\u043c\u0438\u0441, \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u0440\u0438\u0441\u0432\u0430\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e \u043f\u043e\u0441\u043b\u0435 \u0435\u0433\u043e \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u044f.<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">const a = ov(1) const b = ov(2) const computed = ov((arg) => {   a() + b() + arg }, 3) computed.subscribe(fn) computed() \/\/ fn(6) a(2) \/\/ fn(7, 6)<\/code><\/pre>\n<p>  <\/p>\n<h2 id=\"reaktivnyy-rendering-ui\">\u0420\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0439 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433 UI<\/h2>\n<p>  <\/p>\n<p>\u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u044b \u0447\u0442\u0435\u043d\u0438\u044f \u0438 \u0437\u0430\u043f\u0438\u0441\u0438 \u0432 DOM \u0438 CSS.<\/p>\n<p>  <\/p>\n<h3 id=\"rendering-dannyh-s-pomoschyu-shablonnyh-literalov\">\u0420\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0448\u0430\u0431\u043b\u043e\u043d\u043d\u044b\u0445 \u043b\u0438\u0442\u0435\u0440\u0430\u043b\u043e\u0432<\/h3>\n<p>  <\/p>\n<p>\u0428\u0430\u0431\u043b\u043e\u043d\u043d\u044b\u0435 \u043b\u0438\u0442\u0435\u0440\u0430\u043b\u044b (template literals) \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u043f\u043e\u043b\u044f\u0446\u0438\u044e \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445, \u0447\u0442\u043e \u043e\u0431\u043b\u0435\u0433\u0447\u0430\u0435\u0442 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044e \u0448\u0430\u0431\u043b\u043e\u043d\u043e\u0432 HTML:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">function PizzaRecipe(pizza) {   return `&lt;div class=\"pizza-recipe\">     &lt;h1>${pizza.name}&lt;\/h1>     &lt;h3>Toppings: ${pizza.toppings.join(', ')}&lt;\/h3>     &lt;p>${pizza.description}&lt;\/p>   &lt;\/div>` }  function PizzaRecipeList(pizzas) {   return `&lt;div class=\"pizza-recipe-list\">     ${pizzas.map(PizzaRecipe).join('')}   &lt;\/div>` }  const allPizzas = [   {     name: 'Margherita',     toppings: ['tomato sauce', 'mozzarella'],     description: 'A classic pizza with fresh ingredients.',   },   {     name: 'Pepperoni',     toppings: ['tomato sauce', 'mozzarella', 'pepperoni'],     description: 'A favorite among many, topped with delicious pepperoni.',   },   {     name: 'Veggie Supreme',     toppings: [       'tomato sauce',       'mozzarella',       'bell peppers',       'onions',       'mushrooms',     ],     description: 'A delightful vegetable-packed pizza.',   }, ]  \/\/ \u0420\u0435\u043d\u0434\u0435\u0440\u0438\u043c \u0441\u043f\u0438\u0441\u043e\u043a function renderPizzas() {   document.querySelector('body').innerHTML = PizzaRecipeList(allPizzas) }  renderPizzas() \/\/ \u041f\u0435\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0439 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433  \/\/ \u041f\u0440\u0438\u043c\u0435\u0440 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0433\u043e \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430 function addPizza() {   allPizzas.push({     name: 'Hawaiian',     toppings: ['tomato sauce', 'mozzarella', 'ham', 'pineapple'],     description: 'A tropical twist with ham and pineapple.',   })    renderPizzas() \/\/ \u0420\u0435\u043d\u0434\u0435\u0440\u0438\u043c \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a }  \/\/ \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043d\u043e\u0432\u0443\u044e \u043f\u0438\u0446\u0446\u0443 \u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043c \u0441\u043f\u0438\u0441\u043e\u043a addPizza()<\/code><\/pre>\n<p>  <\/p>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u043c \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u043e\u043c \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u0432\u0441\u0435\u0433\u043e DOM \u043f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0435. \u0422\u0430\u043a\u0438\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438, \u043a\u0430\u043a <a href=\"https:\/\/www.npmjs.com\/package\/lit-html\" rel=\"nofollow noopener noreferrer\">lit-html<\/a>, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c DOM \u0431\u043e\u043b\u0435\u0435 \u0438\u043d\u0442\u0435\u043b\u043b\u0435\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e, \u043a\u043e\u0433\u0434\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043c\u043e\u0434\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0447\u0430\u0441\u0442\u0438.<\/p>\n<p>  <\/p>\n<h3 id=\"reaktivnye-atributy-dom---mutationobserver\">\u0420\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0435 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b DOM \u2014 MutationObserver<\/h3>\n<p>  <\/p>\n<p>\u041e\u0434\u043d\u0438\u043c \u0438\u0437 \u0441\u043f\u043e\u0441\u043e\u0431 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u044f \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u0438 DOM \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430\u043c\u0438 HTML-\u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432. <a href=\"https:\/\/developer.mozilla.org\/ru\/docs\/Web\/API\/MutationObserver\" rel=\"nofollow noopener noreferrer\">MutationObserver API<\/a> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u044c \u0437\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435\u043c \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u0432 \u0438 \u0440\u0435\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u043d\u0438\u0445 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">const mutationCallback = (mutationsList) => {   for (const mutation of mutationsList) {     if (       mutation.type !== 'attributes' ||       mutation.attributeName !== 'pizza-type'     )       return      console.log('Old:', mutation.oldValue)     console.log('New:', mutation.target.getAttribute('pizza-type'))   } } const observer = new MutationObserver(mutationCallback) observer.observe(document.getElementById('pizza-store'), { attributes: true })<\/code><\/pre>\n<p>  <\/p>\n<p><em>\u041f\u0440\u0438\u043c. \u043f\u0435\u0440.: <code>MutationObserver<\/code> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u044c \u0437\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435\u043c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u0432, \u043d\u043e \u0442\u0430\u043a\u0436\u0435 \u0437\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435\u043c \u0442\u0435\u043a\u0441\u0442\u0430 \u0446\u0435\u043b\u0435\u0432\u043e\u0433\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u0438 \u0435\u0433\u043e \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432.<\/em><\/p>\n<p>  <\/p>\n<h3 id=\"reaktivnye-atributy-v-veb-komponentah\">\u0420\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0435 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b \u0432 \u0432\u0435\u0431-\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u0445<\/h3>\n<p>  <\/p>\n<p>\u0412\u0435\u0431-\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b (Web Components) \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u043d\u0430\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u044f \u0437\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f\u043c\u0438 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u0432:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 HTML class PizzaStoreComponent extends HTMLElement {   static get observedAttributes() {     return ['pizza-type']   }    constructor() {     super()     const shadowRoot = this.attachShadow({ mode: 'open' })     shadowRoot.innerHTML = `&lt;p>${       this.getAttribute('pizza-type') || 'Default content'     }&lt;\/p>`   }    attributeChangedCallback(name, oldValue, newValue) {     if (name === 'pizza-type') {       this.shadowRoot.querySelector('div').textContent = newValue       console.log(`Attribute ${name} changed from ${oldValue} to ${newValue}`)     }   } }  customElements.define('pizza-store', PizzaStoreComponent)<\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"html\">&lt;!-- \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0432 \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0443 --> &lt;pizza-store pizza-type=\"Supreme\">&lt;\/pizza-store><\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ \u041c\u043e\u0434\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u0435\u043c \u0430\u0442\u0440\u0438\u0431\u0443\u0442 `pizza-store` document.querySelector('pizza-store').setAttribute('pizza-type', 'BBQ Chicken');<\/code><\/pre>\n<p>  <\/p>\n<h3 id=\"reaktivnaya-prokrutka---intersectionobserver\">\u0420\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u0430\u044f \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u0430 \u2014 IntersectionObserver<\/h3>\n<p>  <\/p>\n<p><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Intersection_Observer_API\" rel=\"nofollow noopener noreferrer\">IntersectionObserver API<\/a> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0440\u0435\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u0435 \u0446\u0435\u043b\u0435\u0432\u043e\u0433\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u0441 \u0434\u0440\u0443\u0433\u0438\u043c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u043c \u0438\u043b\u0438 \u043e\u0431\u043b\u0430\u0441\u0442\u044c\u044e \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 (viewport):<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">const pizzaStoreElement = document.getElementById('pizza-store')  const observer = new IntersectionObserver((entries) => {   entries.forEach((entry) => {     if (entry.isIntersecting) {       entry.target.classList.add('animate-in')     } else {       entry.target.classList.remove('animate-in')     }   }) })  observer.observe(pizzaStoreElement)<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u043c\u043e\u0442\u0440\u0438\u0442\u0435 <a href=\"https:\/\/codepen.io\/1Marc\/pen\/wvEKOEr\" rel=\"nofollow noopener noreferrer\">\u043f\u0440\u0438\u043c\u0435\u0440 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u043f\u0440\u0438 \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u0435 \u043d\u0430 CodePen<\/a>.<\/p>\n<p>  <\/p>\n<p><em>\u041f\u0440\u0438\u043c. \u043f\u0435\u0440.: \u043a\u0440\u043e\u043c\u0435 <code>MutationObserver<\/code> \u0438 <code>IntersectionObserver<\/code>, \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0435\u0449\u0435 \u043e\u0434\u0438\u043d \u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u044c \u2014 <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/ResizeObserver\" rel=\"nofollow noopener noreferrer\">ResizeObserver<\/a>.<\/em><\/p>\n<p>  <\/p>\n<h3 id=\"zaciklivanie-animacii---requestanimationframe\">\u0417\u0430\u0446\u0438\u043a\u043b\u0438\u0432\u0430\u043d\u0438\u0435 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u2014 requestAnimationFrame<\/h3>\n<p>  <\/p>\n<p>\u041f\u0440\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0438\u0433\u0440, \u043f\u0440\u0438 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 Canvas \u0438\u043b\u0438 WebGL \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u0447\u0430\u0441\u0442\u043e \u0442\u0440\u0435\u0431\u0443\u044e\u0442 \u0437\u0430\u043f\u0438\u0441\u0438 \u0432 \u0431\u0443\u0444\u0435\u0440 \u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0437\u0430\u043f\u0438\u0441\u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u0432 \u0446\u0438\u043a\u043b\u0435, \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u0442\u043e\u043a \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430 (rendering thread) \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u043c. \u041e\u0431\u044b\u0447\u043d\u043e, \u043c\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u044d\u0442\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/window\/requestAnimationFrame\" rel=\"nofollow noopener noreferrer\">requestAnimationFrame<\/a>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">function drawStuff() {   \/\/ \u041b\u043e\u0433\u0438\u043a\u0430 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430 \u0438\u0433\u0440\u044b \u0438\u043b\u0438 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 }  \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 function animate() {   drawStuff()   requestAnimationFrame(animate) \/\/ \u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u043c \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c `animate` \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u043c \u043a\u0430\u0434\u0440\u0435 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430 }  \/\/ \u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e animate()<\/code><\/pre>\n<p>  <\/p>\n<h3 id=\"reaktivnye-animacii---web-animations\">\u0420\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0435 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u2014 Web Animations<\/h3>\n<p>  <\/p>\n<p><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Web_Animations_API\" rel=\"nofollow noopener noreferrer\">Web Animations API<\/a> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0435 \u0433\u0440\u0430\u043d\u0443\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438. \u041f\u0440\u0438\u043c\u0435\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u044d\u0442\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0434\u043b\u044f \u0430\u043d\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0430, \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 \u0446\u0432\u0435\u0442\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">const el = document.getElementById('animated-element')  \/\/ \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 const animation = el.animate(   [     \/\/ \u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u043a\u0430\u0434\u0440\u044b (keyframes)     {       transform: 'scale(1)',       backgroundColor: 'blue',       left: '50px',       top: '50px',     },     {       transform: 'scale(1.5)',       backgroundColor: 'red',       left: '200px',       top: '200px',     },   ],   {     \/\/ \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u0438     \/\/ \u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c     duration: 1000,     \/\/ \u041d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435     fill: 'forwards',   }, )  \/\/ \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u0432 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 `0` \/\/ \u0434\u043b\u044f \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 animation.playbackRate = 0  \/\/ \u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043a\u043b\u0438\u043a\u0430 el.addEventListener('click', () => {   \/\/ \u0415\u0441\u043b\u0438 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0430, \u0432\u043e\u0437\u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c \u0435\u0435   if (animation.playbackRate === 0) {     animation.playbackRate = 1   } else {     \/\/ \u0415\u0441\u043b\u0438 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0441\u044f, \u043c\u0435\u043d\u044f\u0435\u043c \u0435\u0435 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435     animation.reverse()   } })<\/code><\/pre>\n<p>  <\/p>\n<p>\u0420\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c \u0442\u0430\u043a\u043e\u0439 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u043e\u043d\u0430 \u043c\u043e\u0436\u0435\u0442 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f (\u043a\u0430\u043a \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0441\u043c\u0435\u043d\u044b \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0432 \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u043d\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435). \u0410\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u044b CSS \u0442\u0430\u043a\u043e\u0433\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442.<\/p>\n<p>  <\/p>\n<h3 id=\"reaktivnyy-css---kastomnye-svoystva-i-calc\">\u0420\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0439 CSS \u2014 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0438 calc<\/h3>\n<p>  <\/p>\n<p>\u041c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u0438\u0441\u0430\u0442\u044c \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0439 CSS \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0445 \u0441\u0432\u043e\u0439\u0441\u0442\u0432 \u0438 <code>calc<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">barElement.style.setProperty('--percentage', newPercentage)<\/code><\/pre>\n<p>  <\/p>\n<p>\u041c\u044b \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u043e\u0433\u043e \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0432 JS.<\/p>\n<p>  <\/p>\n<pre><code class=\"css\">.bar {   width: calc(100% \/ 4 - 10px);   height: calc(var(--percentage) * 1%);   background-color: blue;   margin-right: 10px;   position: relative; }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0418 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u043c \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u044d\u0442\u043e\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0432 CSS. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0437\u0430 \u0441\u0442\u0438\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 CSS, \u043a\u0430\u043a \u0438 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c.<\/p>\n<p>  <\/p>\n<p>\u041f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u043e\u0433\u043e \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u043c\u043e\u0436\u043d\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">getComputedStyle(barElement).getPropertyValue('--percentage')<\/code><\/pre>\n<p>  <\/p>\n<p>\u041a\u0430\u043a \u0432\u0438\u0434\u0438\u0442\u0435, \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439 JS \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0434\u043e\u0441\u0442\u0438\u0433\u0430\u0442\u044c \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u0438 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e\u043c \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u0432. \u041c\u044b \u043c\u043e\u0436\u0435\u043c \u043a\u043e\u043c\u0431\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u0438 \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u044b \u0434\u043b\u044f \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430, \u043b\u043e\u0433\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u0430\u043d\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0438 \u0434\u0440\u0443\u0433\u0438\u0445 \u0432\u0435\u0449\u0435\u0439, \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u044f\u0449\u0438\u0445 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/757770\/\"> https:\/\/habr.com\/ru\/articles\/757770\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/webt\/ma\/po\/lv\/mapolvqq4uunxfqoaviv3g9km9y.jpeg\" data-src=\"https:\/\/habrastorage.org\/webt\/ma\/po\/lv\/mapolvqq4uunxfqoaviv3g9km9y.jpeg\" data-blurred=\"true\"\/>  <\/p>\n<p>  <\/p>\n<p>  <\/p>\n<p>&#171;\u0420\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c&#187; \u2014 \u044d\u0442\u043e \u0442\u043e, \u043a\u0430\u043a \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0440\u0435\u0430\u0433\u0438\u0440\u0443\u044e\u0442 \u043d\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445. \u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0442 \u0440\u0430\u0437\u043d\u044b\u0435 \u0442\u0438\u043f\u044b \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u0438, \u043d\u043e \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438, \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c \u2014 \u044d\u0442\u043e \u043a\u043e\u0433\u0434\u0430 \u043c\u044b \u0447\u0442\u043e-\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u043c \u0432 \u043e\u0442\u0432\u0435\u0442 \u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<p>  <\/p>\n<h2 id=\"patterny-reaktivnosti-yavlyayutsya-klyuchevymi-dlya-veb-razrabotki\">\u041f\u0430\u0442\u0442\u0435\u0440\u043d\u044b \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u0438 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u043c\u0438 \u0434\u043b\u044f \u0432\u0435\u0431-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438<\/h2>\n<p>  <\/p>\n<p>\u041c\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0441 \u0431\u043e\u043b\u044c\u0448\u0438\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e\u043c JS \u043d\u0430 \u0441\u0430\u0439\u0442\u0430\u0445 \u0438 \u0432 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u2014 \u044d\u0442\u043e \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u0441\u0440\u0435\u0434\u0430. \u041c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0440\u0435\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c, \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043e\u0442\u0447\u0435\u0442\u044b, \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u0442\u044c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0438 \u0442.\u0434. \u042d\u0442\u043e \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0432 \u0441\u0435\u0431\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 UI, \u0441\u0435\u0442\u0435\u0432\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b, \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438 \u0438 URL \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u043a\u0430\u0441\u043a\u0430\u0434\u043d\u043e\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u043c \u0430\u0441\u043f\u0435\u043a\u0442\u043e\u043c \u0432\u0435\u0431-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438.<\/p>\n<p>  <\/p>\n<p>\u0420\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c, \u043e\u0431\u044b\u0447\u043d\u043e, \u0430\u0441\u0441\u043e\u0446\u0438\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0441 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430\u043c\u0438, \u043d\u043e \u043c\u043e\u0436\u043d\u043e \u043c\u043d\u043e\u0433\u043e\u043c\u0443 \u043d\u0430\u0443\u0447\u0438\u0442\u044c\u0441\u044f, \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u044f \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c \u043d\u0430 \u0447\u0438\u0441\u0442\u043e\u043c JS. \u041c\u044b \u043c\u043e\u0436\u0435\u043c \u0441\u043c\u0435\u0448\u0438\u0432\u0430\u0442\u044c \u0438 \u0438\u0433\u0440\u0430\u0442\u044c \u0441 \u044d\u0442\u0438\u043c\u0438 \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0430\u043c\u0438 \u0434\u043b\u044f \u043b\u0443\u0447\u0448\u0435\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<p>  <\/p>\n<blockquote><p>\u0418\u0437\u0443\u0447\u0435\u043d\u0438\u0435 \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u043e\u0432 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a \u0443\u043c\u0435\u043d\u044c\u0448\u0435\u043d\u0438\u044e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u043a\u043e\u0434\u0430 \u0438 \u043f\u043e\u0432\u044b\u0448\u0435\u043d\u0438\u044e \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e \u043e\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u043e\u0433\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430.<\/p><\/blockquote>\n<p>\u041c\u043d\u0435 \u043d\u0440\u0430\u0432\u0438\u0442\u0441\u044f \u0438\u0437\u0443\u0447\u0430\u0442\u044c \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u044b, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043e\u043d\u0438 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043c\u044b \u043a \u043b\u044e\u0431\u043e\u043c\u0443 \u044f\u0437\u044b\u043a\u0443 \u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u0435. \u041f\u0430\u0442\u0442\u0435\u0440\u043d\u044b \u043c\u043e\u0433\u0443\u0442 \u043a\u043e\u043c\u0431\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0447\u0430\u0441\u0442\u043e \u043f\u0440\u0438\u0432\u043e\u0434\u044f \u043a \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u043c\u0443 \u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u043e\u043c\u0443 \u043a\u043e\u0434\u0443.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-353528","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/353528","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=353528"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/353528\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=353528"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=353528"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=353528"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}