[Hard] 📄 Двустороннее связывание данных
1. Объясните базовый принцип реализации двустороннего связывания в Vue2 и Vue3
Объясните внутренний механизм двустороннего связывания в Vue2 и Vue3.
Чтобы понять двустороннее связывание Vue, необходимо разобраться в том, как работает система реактивности и как Vue2 и Vue3 реализуют её по-разному.
Реализация Vue2
Vue2 использует Object.defineProperty для реализации реактивности. Он оборачивает свойства объекта с помощью getter и setter, чтобы отслеживать чтение/запись.
1. Перехват данных
При инициализации данных компонента в Vue2 Vue обходит каждое свойство и конвертирует его в getter/setter через Object.defineProperty, чтобы можно было наблюдать за чтением и записью.
2. Сбор зависимостей
Когда функция рендеринга выполняется и читает реактивные свойства, срабатывает getter. Vue записывает зави симости, чтобы затронутые компоненты могли быть уведомлены позже.
3. Отправка обновлений
Когда данные изменяются, срабатывает setter. Vue уведомляет зависимые watchers/компоненты и запускает перерисовку для обновления DOM.
Пример Vue2
function defineReactive(obj, key, val) {
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter() {
console.log(`get ${key}: ${val}`);
return val;
},
set: function reactiveSetter(newVal) {
console.log(`set ${key}: ${newVal}`);
val = newVal;
},
});
}
const data = { name: 'Pitt' };
defineReactive(data, 'name', data.name);
console.log(data.name); // срабатывает getter
data.name = 'Vue2 Reactivity'; // срабатывает setter
Ограничения Vue2
Object.defineProperty имеет ряд ограничений:
- Не может обнаружить добавление/удаление свойств без
Vue.set()/Vue.delete() - Не может надёжно обнаружить прямое присваивание по индексу массива без патченных методов массива
- Накладные расходы на производительность из-за глубокого обхода и предварительного определения getter/setter
Реализация Vue3
Vue3 использует ES6 Proxy, что обеспечивает более широкие возможности перехвата и лучшие характеристики производительности.
1. Перехват данных на основе Proxy
Vue3 оборачивает целые объекты с помощью new Proxy вместо определения getter/setter для каждого ключа. Это позволяет перехватывать больше операций, включая добавление/удаление свойств.