https://habr.com/post/418949/Вопрос отслеживания изменения переменных (или свойств объектов) в javascript возникает, как правило, у разработчиков после какого-то времени проведенного за написанием кода. В тот самый момент, когда вопрос
«а как это сделать?» сменяется вопросом "
а как это сделать более оптимально?".
Согласитесь, «связать» свойство, отвечающее за какое-либо динамическое значение вашего web-приложения, с функцией обновления DOM дерева, или же с методами строящими расчеты, что бы в дальнейшем работать лишь с моделью, не думая о последующих необходимых манипуляциях — не только удобно, но и красиво с точки зрения архитектуры.
Если вы строите свое приложение на библиотеке или фреймворке, где существует реализация данного вопроса (
react предлагает к использованию метод
setstate,
vue дает в распоряжение пользователя свою
систему реактивности) то здесь все и так понятно.
Однако методы реализации поставленной задачи на чистом javascript «из коробки» несколько сложнее «простого» и не всегда удобны к использованию (Object.defineProperty(), Proxy). Суперлегковестная библиотека
floss-js (< 1кб) призвана предоставить функционал отслеживания изменения свойств и вызова методов-обработчиков.Работая под капотом с
Object.defineProperty библиотека хранит реальные значения в отдельном специальном хранилище данных, проксируя их через пользовательские объявленные свойства и отслеживая события обращения (возвращает значение из хранилища) и изменения (перезаписывает значение в хранилище и вызывает пользовательскую функцию обработчик).
Проще говоря: floss-js (
github) следит за переменными и свойствами объекта и выполняет пользовательский код по факту их изменения.
Установка
Добавить библиотеку в проект очень легко.
Создание события
Предположим есть небольшое web приложение, реализующее какой-то функционал. Какой именно для нас значения не имеет. В приложении существует переменная
state которая содержит в себе строку, сообщающую о текущем состоянии приложения (например: loading, expectation of the user, user writing..., saving..., unexpected error и т.д.); значение переменной может меняться как ввиду данных поступающих с сервера, так и из-за пользовательских манипуляций.
В DOM существует контейнер выводящий уведомления для пользователя:
<div id="state"></div>
Мы уже подключили FLOSS.min.js и теперь нам нужно повесить обработчик: при изменении значения
state должна вызываться функция обновляющая DOM дерево.
/* функция обновляющая состояние приложения в DOM */
let updateState = (state) => {
document.querySelector('#state').innerHTML = state;
}
Далее вешаем сам обработчик:
/* обработчик создается зарезервированной функций FLOSS */
FLOSS({
name: 'state',
value: 'Waiting for status',
action: (newState) => {
updateState(newState);
}
});
Рассмотрим более подробно:
name — имя переменной или свойства, за изменениями которого необходимо следить. Если переменной не существует, она будет создана глобально, как свойство объекта window. Если необходимо следить за свойством объекта, то сам объект также необходимо передать в свойство
bind функции
FLOSS.
value — default значение присваиваемое переменной. И, наконец,
action — функция обработчик, в которую передается новое значение переменной, после изменения. Впервые action срабатывает после создания FLOSS обработчика. Поэтому в данном примере функция updateState — отработает сразу и выведет пользователю «Waiting for status». Если первый вызов action необходимо отложить до факта изменения отслеживаемой переменной, то можно указать дополнительный параметр
defer: true.
Реализовав данный пример, можно прямо в консоли задать
state другое значение. FLOSS обработчик тут же среагирует и вызовет метод обновляющий DOM.
Все просто, не правда ли?
Давайте рассмотрим еще один, более сложный, пример использования микробиблиотеки.
Ситуация схожа: необходимо отслеживать изменения состояния приложения. Однако само состояние теперь храниться в специальном объекте и текст уведомление является вычисляемым свойством.
let server = {
state: {
200: 'OK',
201: 'Created',
203: 'Non-Authoritative Information',
526: 'Invalid SSL Certificate'
},
logs: '...',
status: '200',
notification: function(){
return `${this.state[this.status]}, status: ${this.status}`
}
}
Нас интересует свойство
notificaion. Однако оно является функцией, формирующей уведомление для пользователя. Соответственно отслеживать мы будем свойство
status.
FLOSS({
name: 'status',
value: server.status, /* параметр value определяем из исходного объекта */
action: function(){
updateState(server.notification());
},
defer: false,
bind: server /* объект, свойство которого необходимо отслеживать */
});
Естественно, использование следящих за состоянием переменных методов целесообразно не всегда. Зачастую в данном приеме необходимости нет, а если и есть, то всегда можно реализовать собственный узконаправленный метод, принимающий на вход новое значение, мутирующий необходимое свойство, а также вызывающий все необходимые функции обработчики. Однако если ваше детище балансирует между небольшим приложением и приложением требующем фундамента вроде REACT — c помощью
FLOSS можно сделать код более минималистичным и структурированным.
Спасибо за внимание.