目录
1. 回顾 Vue2 的 Object.defineProperty
1. 回顾 Vue2 的 Object.defineProperty
缺点:
- 深度监听需要一次性递归,影响性能
- 无法监听新增属性和删除属性(需要:Vue.set Vue.delete)
- 无法原生监听数组,需要特殊处理
2. Proxy 实现响应式
Proxy ES6 新增类
- 监听一个对象的相关操作,先创建一个这个对象的代理对象(Proxy 对象)
- 之后对修改对象的所有操作,都通过代理对象完成
- 代理对象可以监听到我们想要对原对象进行哪些操作
Reflect ES6 新增 API
- 它是一个对象,字面意思是反射
- 它提供了很多操作 JavaScript 对象的方法,有点像 Object 中操作对象的方法
- 比如 Reflect.getPrototypeOf(target) 类似于 Object.getPrototypeOf()
- 比如 Reflect.defineProperty(target, propertyKey, attributes)类似 Object.defineProperty()
- 和 Proxy 能力一一对应
- 规范化,标准化,函数式(之前:‘a’ in obj ;现在:Reflect.has(obj, 'a') )
- 替代掉 Object 上的工具函数(Object.getOwnPropertyNames(obj) =》Reflect.ownKeys(obj))使 Object 专注做一个数据结构,为 JS 服务,避免大而全,不利于编程
2.1 基本使用
// const data = {
// name: 'zhangsan',
// age: 20,
// }
const data = ['a', 'b', 'c']
const proxyData = new Proxy(data, {
get(target, key, receiver) {
// 只处理本身(非原型的)属性
const ownKeys = Reflect.ownKeys(target)
if (ownKeys.includes(key)) {
console.log('get', key) // 监听
}
const result = Reflect.get(target, key, receiver)
return result // 返回结果
},
set(target, key, val, receiver) {
// 重复的数据,不处理
if (val === target[key]) {
return true
}
const result = Reflect.set(target, key, val, receiver)
console.log('set', key, val)
// console.log('result', result) // true
return result // 是否设置成功
},
deleteProperty(target, key) {
const result = Reflect.deleteProperty(target, key)
console.log('delete property', key)
// console.log('result', result) // true
return result // 是否删除成功
}
})
2.2 实现响应式
- Proxy 深度监听性能更好
Vue2 的 Object.defineProperty 一次性递归监听
Vue3 的 Proxy 在 get 时才递归监听- Proxy 可监听 新增 / 删除属性
- 可原生监听数组变化
// 创建响应式
function reactive(target = {}) {
if (typeof target !== 'object' || target == null) {
// 不是对象或数组,则返回
return target
}
// 代理配置
const proxyConf = {
get(target, key, receiver) {
// 只处理本身(非原型的)属性
const ownKeys = Reflect.ownKeys(target)
if (ownKeys.includes(key)) {
console.log('get', key) // 监听
}
const result = Reflect.get(target, key, receiver)
// 深度监听
// 性能如何提升的?get 时才递归监听
return reactive(result)
},
set(target, key, val, receiver) {
// 重复的数据,不处理
if (val === target[key]) {
return true
}
const ownKeys = Reflect.ownKeys(target)
if (ownKeys.includes(key)) {
console.log('已有的 key', key)
} else {
console.log('新增的 key', key)
}
const result = Reflect.set(target, key, val, receiver)
console.log('set', key, val)
// console.log('result', result) // true
return result // 是否设置成功
},
deleteProperty(target, key) {
const result = Reflect.deleteProperty(target, key)
console.log('delete property', key)
// console.log('result', result) // true
return result // 是否删除成功
}
}
// 生成代理对象
const observed = new Proxy(target, proxyConf)
return observed
}
// 测试数据
const data = {
name: 'zhangsan',
age: 20,
info: {
city: 'beijing',
a: {
b: {
c: {
d: {
e: 100
}
}
}
}
}
}
const proxyData = reactive(data)
3. 总结
- Proxy 能规避 Object.defineProperty 的问题
- Proxy 无法兼容所有浏览器,无法 polyfill