> Как реализована реактивность во Vue 2 и Vue 3 и в чем их отличия (Vue.js)

Уровень: senior · Роль: frontend · Категория: Технические вопросы

Компании: MTS, 1221 Systems

Стек: Vue.js

> Пример ответа

Короткий ответ

Во Vue 2 реактивность реализована через Object.defineProperty, что требует предварительного объявления всех полей в data и не отслеживает добавление/удаление свойств. Vue 3 использует Proxy, который перехватывает любые операции с объектом - добавление, удаление, изменение по индексу массива. Это даёт полную реактивность без ограничений Vue 2, а также улучшает производительность за счёт ленивой инициализации зависимостей.

Подробное объяснение

Во Vue 2 каждый объект из data рекурсивно обходится, и на каждое свойство навешивается геттер/сеттер через Object.defineProperty. Это работает, но есть ограничения: нельзя добавлять новые свойства (нужен Vue.set), удаление не отслеживается, изменение по индексу массива тоже (требуется splice). Кроме того, все поля должны быть объявлены заранее, иначе они не будут реактивными.

Vue 3 перешёл на Proxy, который создаёт прокси-объект, перехватывающий операции get, set, deleteProperty, has и другие. Это позволяет:

  • отслеживать добавление и удаление свойств без специальных методов;
  • работать с массивами по индексу и через length;
  • не требовать предварительного объявления полей;
  • лениво собирать зависимости - геттер вызывается только при реальном чтении, а не при инициализации.

Также изменилась система зависимостей: во Vue 2 использовались глобальные Dep и Watcher, во Vue 3 - WeakMap и effect из @vue/reactivity, что уменьшает накладные расходы на память.

На практике

При миграции с Vue 2 на Vue 3 нужно учитывать:

  • Vue.set и Vue.delete больше не нужны - просто присваивайте новые свойства;
  • массивы можно менять по индексу напрямую: arr[0] = value;
  • Object.assign и деструктуризация работают корректно, если обновлять через прокси;
  • this.$set и this.$delete также удалены из экземпляра компонента;
  • watch с deep: true в Vue 3 работает быстрее, так как не создаёт копию объекта.

Для глубоких объектов Vue 3 всё равно рекурсивно оборачивает вложенные объекты в reactive, но делает это лениво - только при обращении.

Пример кода

JAVASCRIPT
// Vue 2 - требуется предварительное объявление
data() {
return {
user: { name: 'Alice' }
}
}
// Добавление нового свойства:
this.$set(this.user, 'age', 30) // иначе не реактивно
// Vue 3 - работает напрямую
import { reactive } from 'vue'
const user = reactive({ name: 'Alice' })
user.age = 30 // реактивно, без дополнительных методов
// Массивы в Vue 2:
this.items[0] = 'new' // не реактивно
this.items.splice(0, 1, 'new') // реактивно
// Массивы в Vue 3:
items[0] = 'new' // реактивно

Как отвечать на собеседовании

Начните с ключевого отличия - Object.defineProperty vs Proxy. Упомяните ограничения Vue 2: невозможность отслеживать добавление/удаление свойств и изменение по индексу массива. Затем объясните, как Proxy решает эти проблемы и какие преимущества даёт (ленивая реактивность, производительность, меньше кода). Если спросят про глубину - скажите, что вложенные объекты оборачиваются рекурсивно, но только при обращении. Хорошо бы упомянуть, что во Vue 2 при инициализации обходится всё дерево, а во Vue 3 - только при чтении.

Что проверяет интервьюер

  • Понимание внутреннего механизма реактивности, а не только API.
  • Знание ограничений Vue 2 и причин перехода на Proxy.
  • Умение объяснить разницу в производительности и памяти.
  • Понимание, как изменения в системе реактивности влияют на повседневную разработку.
  • Глубину - знает ли кандидат про WeakMap, ленивую инициализацию, сборку зависимостей.

Типичные ошибки

  • Говорить, что Vue 3 использует Proxy только для массивов - на самом деле для всех реактивных объектов.
  • Утверждать, что во Vue 3 не нужно вызывать reactive - нужно, но внутри компонента data уже оборачивает автоматически.
  • Путать ref и reactive - ref использует Proxy только для значений, а reactive для объектов.
  • Думать, что во Vue 3 нет проблем с производительностью - глубокие объекты всё равно оборачиваются, но лениво.
  • Забывать, что Object.freeze в обоих версиях отключает реактивность.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью