我来为你详细讲解 JavaScript 中的 get
和 set
方法(即 getter 和 setter),它们是对象属性描述符的一部分,用于定义属性的访问和修改行为。之后我会结合 Vue 3 的 ref
原理,帮你理解它们在响应式中的作用,并提供简单示例。
什么是 get
和 set
?
在 JavaScript 中,get
和 set
是对象属性的一种特殊定义方式,属于存取器属性(Accessor Property),与普通的数据属性(Data Property)相对。它们允许你自定义当访问或修改属性时的逻辑。
get
:定义一个 getter 函数,当读取属性时调用。set
:定义一个 setter 函数,当赋值给属性时调用。
特点
- 看起来像普通属性:使用时不需要加括号,像访问普通变量一样(
obj.prop
而不是obj.prop()
)。 - 动态计算:可以根据其他数据动态返回或处理值。
- 控制访问:可以拦截属性的读取和修改操作。
基本语法
定义方式 1:对象字面量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
const obj = { _value: 0, // 私有变量(约定用下划线) get value() { console.log('正在读取 value'); return this._value; }, set value(newValue) { console.log('正在设置 value 为', newValue); this._value = newValue; } }; // 测试 console.log(obj.value); // 输出: "正在读取 value",然后 0 obj.value = 10; // 输出: "正在设置 value 为 10" console.log(obj.value); // 输出: "正在读取 value",然后 10 |
定义方式 2:Object.defineProperty
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
const obj = { _value: 0 }; Object.defineProperty(obj, 'value', { get() { console.log('读取 value'); return this._value; }, set(newValue) { console.log('设置 value 为', newValue); this._value = newValue; } }); // 测试 console.log(obj.value); // 输出: "读取 value",然后 0 obj.value = 5; // 输出: "设置 value 为 5" |
工作原理
- Getter:
- 当你访问
obj.value
时,JavaScript 调用get value()
方法。 - 返回值由 getter 逻辑决定。
- Setter:
- 当你执行
obj.value = 新值
时,JavaScript 调用set value(newValue)
方法。 newValue
是赋给属性的值。
- 隐藏实现:
- 通常搭配私有变量(如
_value
)使用,外部无法直接访问_value
,只能通过value
的 getter 和 setter 操作。
与 Vue 3 ref
的关系
Vue 3 的 ref
实现依赖于类似 get
和 set
的机制,用于创建响应式引用。下面是简化的 ref
实现,展示其原理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
function ref(initialValue) { const state = { _value: initialValue }; return { get value() { console.log('依赖收集'); return state._value; // 模拟 track }, set value(newValue) { if (newValue !== state._value) { state._value = newValue; console.log('触发更新'); // 模拟 trigger } } }; } // 测试 const count = ref(0); console.log(count.value); // 输出: "依赖收集",然后 0 count.value = 1; // 输出: "触发更新" console.log(count.value); // 输出: "依赖收集",然后 1 |
联系点:
get
:在ref
中,访问.value
时触发依赖收集(track
),记录哪些副作用(如渲染函数)依赖这个值。set
:修改.value
时触发更新(trigger
),通知依赖重新运行。- 响应式核心:Vue 通过这种拦截机制实现数据变化与视图更新的绑定。
学习示例
示例 1:动态计算属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
const person = { firstName: 'John', lastName: 'Doe', get fullName() { return `${this.firstName} ${this.lastName}`; }, set fullName(name) { const [first, last] = name.split(' '); this.firstName = first; this.lastName = last; } }; console.log(person.fullName); // 输出: "John Doe" person.fullName = 'Jane Smith'; console.log(person.firstName); // 输出: "Jane" console.log(person.lastName); // 输出: "Smith" |
示例 2:限制属性值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
const counter = { _count: 0, get count() { return this._count; }, set count(value) { if (value >= 0) { this._count = value; } else { console.log('值不能为负数'); } } }; counter.count = 5; console.log(counter.count); // 输出: 5 counter.count = -1; // 输出: "值不能为负数" console.log(counter.count); // 输出: 5 |
常见问题
- 不能与数据属性同名:
1 2 3 4 |
const obj = { value: 1, get value() { return 2; } // 报错:不能同时定义数据属性和 getter }; |
- 没有参数:
get
不能接收参数。set
只能接收一个参数(新值)。
- 性能:
- getter 和 setter 的执行成本高于直接访问属性,适合需要动态逻辑的场景。
总结
get
:定义属性读取时的行为,返回动态值。set
:定义属性赋值时的行为,控制修改逻辑。- 应用:在 Vue 3 的
ref
中,get
和set
是实现响应式的基石,拦截值的访问和修改,驱动依赖收集和更新。