← Назад к вопросам

В чем разница между вычисляемыми свойствами и секцией data?

2.2 Middle🔥 191 комментариев
#Vue.js

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Вычисляемые свойства (computed) и data секция

В Vue.js data и computed — это два различных способа хранения и предоставления состояния компонента. Хотя оба доступны через this в шаблоне, они имеют разные назначение, производительность и поведение.

Основные различия

Параметрdatacomputed
НазначениеХранение реактивного состоянияПроизводные значения на основе data
ИзменяемостьМожет быть изменено напрямуюТолько для чтения (или с setter)
ПересчетНе пересчитываетсяКэшируется, пересчитывается при изменении зависимостей
Синтаксисdata() { return { ... } }computed: { ... }
ИспользованиеДля хранения исходных данныхДля трансформации/комбинирования data

Data секция

Data используется для хранения реактивного состояния компонента. Каждое изменение в data немедленно обновляет компонент.

export default {
  data() {
    return {
      firstName: "Alice",
      lastName: "Johnson",
      count: 0,
      user: {
        id: 1,
        email: "alice@example.com"
      }
    };
  }
};
<template>
  <div>
    <p>{{ firstName }}</p> <!-- Выводит: Alice -->
    <p>{{ lastName }}</p>  <!-- Выводит: Johnson -->
    <button @click="count++">Счетчик: {{ count }}</button>
  </div>
</template>

Computed свойства

Computed используются для создания производных значений из data. Они автоматически пересчитываются только когда изменяется их зависимость.

export default {
  data() {
    return {
      firstName: "Alice",
      lastName: "Johnson"
    };
  },
  computed: {
    // Геттер (по умолчанию)
    fullName() {
      return `${this.firstName} ${this.lastName}`;
    }
  }
};
<template>
  <div>
    <p>{{ fullName }}</p> <!-- Выводит: Alice Johnson -->
    <input v-model="firstName" />
    <!-- При изменении firstName автоматически пересчитается fullName -->
  </div>
</template>

Кэширование vs Method

Важная особенность computed — кэширование. Значение пересчитывается только если изменилась его зависимость.

export default {
  data() {
    return {
      count: 0
    };
  },
  computed: {
    // Кэшируется, пересчитывается только при изменении count
    doubleCount() {
      console.log("Вычисляю doubleCount");
      return this.count * 2;
    }
  },
  methods: {
    // Вызывается каждый раз, без кэширования
    doubleCountMethod() {
      console.log("Вычисляю через метод");
      return this.count * 2;
    }
  }
};
<template>
  <div>
    <!-- Вызывается 1 раз, результат кэшируется -->
    <p>{{ doubleCount }}</p>
    <p>{{ doubleCount }}</p>
    
    <!-- Вызывается 2 раза -->
    <p>{{ doubleCountMethod() }}</p>
    <p>{{ doubleCountMethod() }}</p>
  </div>
</template>

Выход консоли:

Вычисляю doubleCount         // 1 раз
Вычисляю через метод        // 1 раз
Вычисляю через метод        // 2 раз

Setter в computed свойствах

export default {
  data() {
    return {
      firstName: "Alice",
      lastName: "Johnson"
    };
  },
  computed: {
    // Полный синтаксис с getter и setter
    fullName: {
      get() {
        return `${this.firstName} ${this.lastName}`;
      },
      set(value) {
        const names = value.split(" ");
        this.firstName = names[0];
        this.lastName = names[1];
      }
    }
  }
};
<template>
  <div>
    <!-- Может быть использовано в v-model -->
    <input v-model="fullName" />
    <!-- При изменении будет вызван setter -->
  </div>
</template>

Практические примеры

1. Фильтрация списка

export default {
  data() {
    return {
      users: [
        { id: 1, name: "Alice", active: true },
        { id: 2, name: "Bob", active: false },
        { id: 3, name: "Charlie", active: true }
      ],
      searchQuery: ""
    };
  },
  computed: {
    // Пересчитывается только при изменении users или searchQuery
    filteredUsers() {
      return this.users.filter(user =>
        user.name.toLowerCase().includes(this.searchQuery.toLowerCase())
      );
    }
  }
};
<template>
  <div>
    <input v-model="searchQuery" placeholder="Поиск..." />
    <ul>
      <li v-for="user in filteredUsers" :key="user.id">
        {{ user.name }}
      </li>
    </ul>
  </div>
</template>

2. Сложные вычисления

export default {
  data() {
    return {
      price: 100,
      quantity: 5,
      taxRate: 0.1
    };
  },
  computed: {
    subtotal() {
      return this.price * this.quantity;
    },
    tax() {
      return this.subtotal * this.taxRate;
    },
    total() {
      return this.subtotal + this.tax;
    }
  }
};
<template>
  <div>
    <p>Подитого: ${{ subtotal }}</p>
    <p>Налог: ${{ tax }}</p>
    <p>Итого: ${{ total }}</p>
  </div>
</template>

3. Статусные вычисления

export default {
  data() {
    return {
      password: "",
      confirmPassword: ""
    };
  },
  computed: {
    isPasswordValid() {
      return this.password.length >= 8;
    },
    passwordsMatch() {
      return this.password === this.confirmPassword;
    },
    canSubmit() {
      return this.isPasswordValid && this.passwordsMatch;
    }
  }
};
<template>
  <form>
    <input
      v-model="password"
      type="password"
      placeholder="Пароль"
    />
    <input
      v-model="confirmPassword"
      type="password"
      placeholder="Подтвердите пароль"
    />
    <button :disabled="!canSubmit">Отправить</button>
  </form>
</template>

Производительность

// Плохо: дорогое вычисление в шаблоне
export default {
  data() {
    return {
      items: []
    };
  }
};
<!-- Это вычисляется каждый раз при рендере -->
<p>{{ items.filter(item => item.active).map(item => item.name).join(", ") }}</p>

<!-- Даже если items не изменились -->
// Хорошо: используй computed
export default {
  data() {
    return {
      items: []
    };
  },
  computed: {
    // Кэшируется и пересчитывается только при изменении items
    activeItemNames() {
      return this.items
        .filter(item => item.active)
        .map(item => item.name)
        .join(", ");
    }
  }
};
<p>{{ activeItemNames }}</p>

Когда использовать что

Используй data для:

  • Исходных данных формы
  • Состояния компонента
  • Флагов видимости
  • Загруженных данных с сервера
data() {
  return {
    formData: { name: "", email: "" },
    isLoading: false,
    isModalOpen: false
  };
}

Используй computed для:

  • Производных значений
  • Преобразований данных
  • Фильтраций и сортировок
  • Проверок статуса
  • Комбинирования нескольких data свойств
computed: {
  displayName() {
    return `${this.firstName} ${this.lastName}`;
  },
  isValid() {
    return this.email && this.password.length >= 8;
  }
}

Вывод

  • data — хранилище реактивного состояния, изменяется напрямую
  • computed — производные значения, автоматически пересчитываются
  • computed кэшируется, что улучшает производительность
  • Используй data для исходных данных, computed для преобразований
  • Не вычисляй сложное в шаблоне — выноси в computed
  • computed имеет доступ к this (текущему контексту компонента)