什么是响应式?
追踪数据的变化,在数据被访问时做出一定的动作(翻译翻译:数据发生变化后,会重新渲染页面)。
Vue2
Vue2 官网:当把一个 JS 对象传入 Vue 实例作为 data 选项时,Vue 将遍历这个对象的所有属性,并使用 Object.defineProperty() 把这些属性全部转化为 getter/setter。这些 gettet/setter 对用户来说是不可见的,但是在内部它们让 Vue 可以追踪依赖,在属性被修改时通知变更。
Object.defineProperty
所以我们得先搞清楚如何使用 Object.defineProperty
:
let obj = {
a: 0
}
Object.defineProperty(obj, 'a', {
get: () => {
console.log('get') // 获取属性 a 时执行的动作
return a
},
set: (newVal) => {
console.log('set') // 设置属性 a 时执行的动作
a = newVal
}
})
obj.a = 100 // 输出 'set'
obj.a // 输出 'get'
复制代码
封装
然后简单封装一下:
现在我们有一个已知的复杂对象 obj
:
let obj = {
a: 0,
b: [1, 2, 3],
c: {
d: 4
}
}
复制代码
我们想办法设计一个 observe
函数将这个 obj
变成响应式的:
observe(obj) // 将 obj 传递给 observe 来实现 obj 的响应式
复制代码
observe
函数:
function observe(data) {
if (!data || typeof data !== 'object') {
return
}
for (var key in data) {
let val = data[key]
Object.defineProperty(data, key, {
enumerable: true, // 当前key是可枚举的
configurable: true, // 当前key是可配置的(可修改、可删除...)
get: () => {
console.log('get') // 获取属性时执行的动作
return val
},
set: (newVal) => {
console.log('set') // 设置属性时执行的动作
val = newVal
}
})
if (typeof val === 'object') {
observe(val) // 发现属性也是对象时,继续调用observe(深度遍历)
}
}
}
复制代码
这样执行 observe(obj)
后,obj 对象里面的 a
、b
、b[0]
、b[1]
、b[2]
、c
、c.d
都是响应式的。但如果是新增属性,例如 obj.e
或者 obj.b[3]
就不是响应式的。
Vue3
Proxy
从 Object.defineProperty
升级为 Proxy
了
Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)
先看看 Proxy
的使用方式:
let obj = {
a: 0
}
let handler = {
get(target, prop) {
console.log('get') // 获取属性时执行的动作
return Reflect.get(...arguments) // return target[prop]
},
set(target, key, value) {
console.log('set') // 设置属性时执行的动作
return Reflect.set(...arguments) // return target[key] = value
}
}
let proxy = new Proxy(obj, handler) // 将对象obj进行代理
proxy.a // 输出 'get'
proxy.a = 1 // 输出 'set'
复制代码
封装
然后简单的封装一下:
let obj = {
a: 0,
b: [1, 2, 3],
c: {
d: 4
}
}
function reactive(data) {
let handler = {
get(target, prop, receiver) {
console.log('get') // 获取属性时执行的动作
let value = Reflect.get(...arguments)
if (typeof value === 'object') {
return reactive(value) // 发现属性也是对象时,继续调用 reactive 来进行代理
} else {
return value
}
},
set(target, key, value, receiver) {
console.log('set') // 设置属性时执行的动作
return Reflect.set(...arguments)
}
}
return new Proxy(data, handler)
}
let proxy = reactive(obj) // 将对象obj进行代理
复制代码
这样执行 reactive(obj)
后,proxy 对象里面的 a
、b
、b[0]
、b[1]
、b[2]
、c
、c.d
都是响应式的。并且如果有新增属性,例如 proxy.e
或者 proxy.b[3]
也是响应式的。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END