# Vue2 计算属性详解文档

## 一、基本概念

计算属性（Computed Properties）是 Vue2 中用于声明式地定义派生数据的特性。它们基于响应式依赖进行缓存，只在相关依赖发生改变时才重新计算。

## 二、代码示例解析

```html
<div id="app">
    姓：<input type="text" v-model="firstName">
    名：<input type="text" v-model="lastName">
    全名：<span>{{fullName}}</span>
</div>

<script>
    const vm = new Vue({
        el: "#app",
        data() {
            return {
                firstName: "",
                lastName: ""
            }
        },
        computed: {
            fullName: {
                get() {
                    return `${this.firstName}-${this.lastName}`
                },
                set(val) {
                    // 可选的setter
                }
            }
        }
    })
</script>
```

## 三、核心特性

### 1. 计算属性 vs 方法

| 特性     | 计算属性                   | 方法                        |
| -------- | -------------------------- | --------------------------- |
| 缓存     | 有缓存，依赖不变不重新计算 | 每次调用都执行              |
| 调用方式 | 作为属性访问               | 需要调用执行                |
| 适用场景 | 派生数据                   | 事件处理/需要重复执行的逻辑 |

### 2. 完整语法结构

```javascript
computed: {
    属性名: {
        get() {
            // 计算逻辑
            return 派生值
        },
        set(value) {
            // 可选的反向更新逻辑
        }
    }
}
```

### 3. 简写形式（只读场景）

```javascript
computed: {
    fullName() {
        return `${this.firstName}-${this.lastName}`
    }
}
```

## 四、最佳实践

1. **命名规范**：
   - 使用名词形式（如 `fullName`）
   - 避免动词开头（这是方法的命名习惯）

2. **纯计算逻辑**：
   - 不要在getter中执行异步操作或副作用
   - 复杂计算考虑拆分为多个计算属性

3. **setter使用场景**：
   - 当需要反向更新依赖数据时
   - 示例：
     ```javascript
     set(val) {
         const parts = val.split('-');
         this.firstName = parts[0] || '';
         this.lastName = parts[1] || '';
     }
     ```

## 五、高级用法

### 1. 依赖多个数据源

```javascript
computed: {
    summary() {
        return `总计：${this.items.length}件，${this.totalPrice}元`
    }
}
```

### 2. 结合过滤器使用

```javascript
computed: {
    formattedDate() {
        return dayjs(this.rawDate).format('YYYY-MM-DD')
    }
}
```

### 3. 计算属性嵌套

```javascript
computed: {
    baseInfo() {
        return { ...this.user, age: this.calcAge }
    },
    calcAge() {
        return new Date().getFullYear() - this.user.birthYear
    }
}
```

## 六、性能优化

1. **减少大数组计算**：
   ```javascript
   computed: {
       visibleItems() {
           return this.items.filter(item => 
               item.name.includes(this.search) && 
               item.status === 'active'
           )
       }
   }
   ```

2. **避免频繁计算**：
   - 对于复杂计算考虑使用 `methods` + 防抖
   - 或使用 `watch` 手动控制计算时机

3. **缓存利用**：
   - 相同依赖多次访问不会重复计算
   - 模板中可安全多次引用同一计算属性

## 七、常见问题

1. **为什么计算属性不更新？**
   - 检查依赖数据是否是响应式的
   - 确保没有在getter中意外修改了依赖数据

2. **何时使用计算属性 vs watch？**
   - 计算属性：基于多个数据的派生数据
   - watch：需要在数据变化时执行异步或开销较大的操作

3. **计算属性能接收参数吗？**
   - 不能直接接收参数，如需参数化应使用方法
   - 替代方案：返回函数或使用闭包
