帅照镇楼,哈哈哈 祝各位拿offer拿到手软
Vue3使用了ES6的Proxy来实现其底层的响应式系统,相比于Vue2的Object.defineProperty实现方式,具有更好的性能和扩展性。
reactive 函数
Vue3中,我们可以通过reactive函数将一个对象变成响应式对象。
import { reactive } from 'vue'
const state = reactive({
count: 0,
})
上面的代码中,我们将一个包含count属性的对象传入reactive函数,返回的结果是一个响应式对象state。当我们修改state.count属性时,相关的组件会自动更新。
reactive函数的实现如下:
function reactive(target) {
// 如果目标已经是一个Proxy对象了,则直接返回
if (target && target.__v_isReadonly) {
return target
}
// 创建一个响应式代理对象
const observed = new Proxy(target, baseHandlers)
// 将标记置为响应式对象
def(target, '__v_isReactive', true)
// 返回响应式对象
return observed
}
reactive函数接收一个普通的对象作为参数,并返回一个响应式代理对象。在这个函数中,我们主要做了以下几件事情:
- 判断传入的对象是否已经是响应式对象,如果是,则直接返回
- 创建一个响应式代理对象,使用
Proxy代理传入的对象target - 给
target添加一个__v_isReactive标志,表示这个对象已经变成了响应式对象 - 返回响应式代理对象
ref 函数
除了对象之外,Vue3还提供了一种基础类型数据的响应式实现方式,称为ref。
import { ref } from 'vue'
const count = ref(0)
上面的代码中,我们通过ref函数将数字0变成了一个响应式的数据count。
ref函数的实现如下:
function ref(value) {
// 如果value本身就是一个ref对象了,则直接返回
if (isRef(value)) {
return value
}
// 创建一个包含value属性的响应式对象
const obj = reactive({
value
})
// 定义get/set方法
const refImpl = {
get value() {
track(obj, 'value')
return obj.value
},
set value(newVal) {
if (newVal !== obj.value) {
obj.value = newVal
trigger(obj, 'value')
}
}
}
// 将标记置为ref对象
def(obj, '__v_isRef', true)
// 返回带有get/set方法的对象
return refImpl
}
ref函数接收一个值作为参数,并返回一个带有get和set方法的对象。在这个函数中,我们主要做了以下几件事情:
- 判断传入的值是否已经是一个
ref对象,如果是,则直接返回 - 创建一个包含值属性的响应式对象
- 定义
get方法和set方法,用于获取和设置值,并在值发生变化时触发更新 - 给响应式对象添加一个
__v_isRef标志,表示这个对象已经变成了ref对象 - 返回带有
get和set方法的对象
computed 函数
除了基础类型数据和对象之外,Vue3还提供了一种计算属性的实现方式,称为computed。
import { ref, computed } from 'vue'
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
上面的代码中,我们使用computed函数创建了一个计算属性doubleCount,它的值是count.value的两倍。
computed函数的实现如下:
function computed(getterOrOptions) {
let getter
let setter
// 如果传入的是一个函数,则将其视为getter函数
if (isFunction(getterOrOptions)) {
getter = getterOrOptions
setter = NOOP
} else {
getter = getterOrOptions.get
setter = getterOrOptions.set || NOOP
}
// 创建一个ref对象,用于缓存计算结果
const result = ref()
// 定义计算属性的get方法
const computedImpl = computedGetter({
getter,
result,
scope: currentScope,
isReadonly: true,
})
// 定义计算属性的set方法
computedImpl.effect = effect(computedImpl)
// 返回计算属性对象
return computedImpl
}
computed函数接收一个函数或者一个选项对象作为参数,并返回一个计算属性对象。在这个函数中,我们主要做了以下几件事情:
- 判断传入的参数类型,如果是函数,则将其视为
getter函数;如果是选项对象,则从中取出getter和setter函数。 - 创建一个
ref对象,用于缓存计算结果。 - 定义计算属性的
get方法,通过computedGetter函数创建一个响应式的getter函数,并传入getter函数、缓存结果的ref对象、所属的作用域以及是否只读等参数。 - 定义计算属性的
set方法,通过effect函数创建一个响应式的effect函数,并传入之前定义的computedGetter函数作为回调函数。 - 返回计算属性对象。
总结
Vue3底层的响应式系统是通过使用ES6中的Proxy代理对象来实现的,相比于Vue2的Object.defineProperty实现方式,具有更好的性能和扩展性。在Vue3中,我们可以通过reactive函数将一个对象变成响应式对象,通过ref函数将基础类型数据变成响应式数据,通过computed函数创建计算属性。这些函数都是基于Proxy实现的,从而实现了高效的响应式更新。
Vue3的响应式原理相比Vue2有较大改进,主要表现在Proxy代理的使用上,可以更加高效地监听数据变化,而且不需要像Vue2那样深度递归遍历对象属性,从而提高了性能。同时,Vue3还引入了Reactivity API,使我们能够更加灵活地控制响应式系统,并且支持了Composition API风格的组合式API,让我们能够更加方便地管理和组织组件代码。
最近做了一个gpt聊天小程序 白昼降临
学习交流群
加作者:aixuexidekkk