一.什么是proxy和懒代理?
什么是proxy?
proxy对象是用于定义基本操作的自定义行为(如:属性查找,赋值,枚举,函数调用等等)。
什么是懒代理?
懒代理:在初始化的时候不会进行全部代理,而是在访问的时候进行代理,这样就使得cpu的压力分配到不同的阶段,就不会产生很大的开销。
二.reactive与readonly的区别是什么?又该如何进行优化的?
reactive与readonly的区别:
reactive一般只接受ES普通的引用数据类型,尽管它可以接受Proxy对象,但是没有意义,没有必要,
但是,Readonly可以接受Proxy对象且有实际的意义,它可以获取纯对象或者Proxy或者Reflmpl,返回原始代理的只读代理。总的来说,它进行了两步操作,首先是reactive其次另生成了一个只读的Proxy
readonly的只读是深层的只读:访问的任何嵌套property也是只读的。
readonly存在的意义有2个,一个是保护数据不被修改,另一个是提升性能。
例子:
<template>
<div>
<button @click="h.b.c++">count is: {{ h.b.c }}</button>
<button @click="t.b.c++">count is: {{ t.b.c }}</button>
</div>
</template>
<script>
import { reactive, readonly } from "vue";
export default {
setup() {
let h = reactive({a: 1, b: {c: 2}});//不只读,深层
let t = readonly({a: 1, b: {c: 2}});//只读,深层
return {
h,t
};
},
};
</script>
运行结果:
第二个由于用的是可读的所以值不会发生变化。
优化:
因为reactive与readonly函数代码的高度相似从而进一步的抽离他们的相同点,对其进行优化,增加代码的可读性
优化步骤:
1.重构get,set操作:vue3把get放入到了一个高阶函数creatGetter中,高阶函数返回get,set也同理,我们现在来封装一下:其中get我们可以通过给定一个传参去判断是否是readonly,而readonly的set有些特殊我们先不进行修改~但是这个代码还是不够美观,继续优化
function createGetter(isReadonly = true) {
return function get(target, key) {
const res = Reflect.get(target, key)
if (isReadonly) {
track(target, key)
}
return res
}
}
function createSetter() {
return function set(target, key, value, receiver) {
const res = Reflect.set(target, key, value, receiver)
trigger(target, key)
return res
}
}
export const reactive = (raw) => {
return new Proxy(raw, {
get: createGetter(),
set: createSetter()
})
}
export const readonly = (raw) => {
return new Proxy(raw, {
get: createGetter(false),
set(target, key, value, receiver) {
return true
},
})
}
2.baseHandlers: 在src目录下新建一个baseHandlers.ts文件并且把之前封装好的creatGetter,creatSetter提取到这个文件夹中
3.createActiveObject函数:为了语义化vue3又把new Proxy的操作也抽离成了createActiveObject函数
4.优化get和set捕获器:我们回到baseHandlers.ts文件里来,最后一步优化
5.警告用户不能set操作:这还没有结束,我们的readonly还差一个触发set操作时,警告用户无法set的功能
拓展:
什么是柯里化?
函数柯里化 概念:只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数。