MVVM (Model-View-ViewModel) — архитектурный паттерн, призванный отделить логику приложения от представления данных. В контексте веб-приложений это означает разделение на:
Knockout.js реализует MVVM в JavaScript, предоставляя мощный инструмент для двустороннего связывания данных (two-way data binding).
Observables — ключевая концепция Knockout.js. Это функции-обертки для значений, позволяющие автоматически уведомлять подписчиков об изменении состояния.
var firstName = ko.observable('Иван');
console.log(firstName()); // Получение значения
firstName('Пётр'); // Установка нового значения
Для коллекций используется observableArray:
var tasks = ko.observableArray([
{ title: 'Сделать домашнее задание', done: false },
{ title: 'Прочитать статью', done: true }
]);
tasks.push({ title: 'Новая задача', done: false }); // Добавление элемента
tasks.remove(task => task.done); // Удаление по условию
Ключевой момент: любые изменения observableArray автоматически отражаются на связанных элементах интерфейса.
Knockout.js обеспечивает синхронизацию состояния между ViewModel и View через data-bind атрибуты:
<input data-bind="value: firstName, valueUpdate: 'input'" />
<p data-bind="text: firstName"></p>
firstName в ViewModel.firstName в коде автоматически меняют текст
в <p>.Для коллекций используется foreach:
<ul data-bind="foreach: tasks">
<li>
<input type="checkbox" data-bind="checked: done" />
<span data-bind="text: title"></span>
</li>
</ul>
Каждый элемент observableArray автоматически создаёт повторяющиеся элементы интерфейса.
Computed observables позволяют создавать свойства, зависящие от других observables:
var fullName = ko.computed(() => firstName() + ' ' + lastName());
При изменении firstName или lastName
fullName автоматически пересчитывается. Это основа
реактивного программирования в MVVM.
Особенности:
Knockout.js позволяет подписываться на изменения observables:
firstName.subscribe(newValue => {
console.log('Имя изменилось на', newValue);
});
Это полезно для:
Для интеграции с сервером обычно используются observables совместно с AJAX:
var users = ko.observableArray([]);
fetch('/api/users')
.then(res => res.json())
.then(data => users(data));
Любые последующие изменения users автоматически
обновляют интерфейс, если используется foreach.
Knockout.js поддерживает компонентный подход через
ko.components.register:
ko.components.register('user-card', {
viewModel: function(params) {
this.user = params.user;
},
template: `
<div>
<h3 data-bind="text: user.name"></h3>
<p data-bind="text: user.email"></p>
</div>
`
});
Использование компонента в HTML:
<user-card params="user: currentUser"></user-card>
Преимущества:
Knockout.js поддерживает расширения и плагины для добавления функционала, например, Knockout Validation для проверки данных:
var age = ko.observable().extend({ required: true, min: 18 });
Расширения делают observables более мощными, сохраняя реактивность и двустороннее связывание.
Knockout.js предлагает мощный и компактный набор инструментов для построения реактивных интерфейсов, сохраняя строгую организацию данных в стиле MVVM. Этот подход упрощает поддержку больших приложений, делает код предсказуемым и легко тестируемым.