vue-java-tutorials/vue2-tutorials/import-script/4-理解数据代理.md

105 lines
3.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# JavaScript 数据代理实现文档
## 一、基本概念
数据代理是指通过一个对象(代理对象)间接访问和操作另一个对象(目标对象)的属性。本示例展示了如何使用 `Object.defineProperty` 实现简单的数据代理。
## 二、代码实现解析
```javascript
let obj1 = { x: 100 }; // 目标对象(被代理对象)
let obj2 = { y: 200 }; // 代理对象
// 在obj2上定义x属性的代理
Object.defineProperty(obj2, "x", {
get() {
return obj1.x; // 读取时返回obj1的x属性
},
set(value) {
obj1.x = value; // 设置时修改obj1的x属性
}
});
```
## 三、核心机制说明
1. **代理原理**
- 通过 `Object.defineProperty` 在代理对象obj2上定义新属性
- 使用 getter/setter 方法实现对目标对象obj1属性的间接访问
2. **访问流程**
- 读取 `obj2.x` → 触发 getter → 返回 `obj1.x` 的值
- 设置 `obj2.x` → 触发 setter → 将值赋给 `obj1.x`
3. **特性**
- 透明的属性访问(使用者无需知道代理存在)
- 可以在访问前后执行额外逻辑(如验证、日志等)
## 四、应用场景
| 场景 | 说明 | 示例 |
| -------- | -------------------- | ------------------------------ |
| 属性转发 | 跨对象访问属性 | 本示例实现 |
| 数据验证 | 设置属性前检查有效性 | setter中添加验证逻辑 |
| 访问控制 | 限制某些属性的访问 | getter中添加权限检查 |
| 日志记录 | 跟踪属性访问 | getter/setter中添加console.log |
## 五、扩展实现
### 1. 多属性代理
```javascript
function proxyProperties(target, source, props) {
props.forEach(prop => {
Object.defineProperty(target, prop, {
get() {
return source[prop];
},
set(value) {
source[prop] = value;
}
});
});
}
// 使用示例
proxyProperties(obj2, obj1, ['x', 'a', 'b']);
```
### 2. Vue2 风格的数据代理
```javascript
function observe(obj) {
const handler = {
get(target, prop) {
console.log(`读取 ${prop}`);
return target[prop];
},
set(target, prop, value) {
console.log(`设置 ${prop}${value}`);
target[prop] = value;
return true;
}
};
return new Proxy(obj, handler);
}
const observed = observe(obj1);
```
## 六、注意事项
1. **性能考虑**
- 每个代理属性都会增加访问开销
- 避免在性能关键路径上过度使用
2. **引用关系**
- 代理对象和目标对象保持独立
- 修改代理属性会影响原始对象
3. **枚举特性**
- 默认情况下代理属性不可枚举
- 需要显式设置 `enumerable: true`
4. **兼容性**
- `Object.defineProperty` 是 ES5 特性
- 现代开发可考虑使用 ES6 Proxy