1.介绍
本内容是为了方便自己以后查阅同时让基础比较薄弱的人也能看懂vue的源码,所以采用的方式比较啰嗦,勿喷。不喜欢直接划走即可!!!
这里的代码和vue的源码不是完全一样的。但是核心的代码以及思路是一样的。当你学会当前的代码再去阅读源码会容易很多
这里为了编写文档时方便 且方便理解 我将所有的内容全部写到一个文件中了,后续会在main分支将所有代码抽离
reactive这个API核心只做了一件事 就是将对象变成代理对象,然后内部在做一些边界判断 所以还是比较容易懂的
不过在此之前你应该学会使用reactive api 官网都有介绍
2.开始编写
第一步 肯定是要创建并且导出reactive函数,然后将核心的步骤写出来
export const isObject = (value) => value !== null && typeof value === 'object'
export const mutableHandlers = {
get(target, key, receiver) {
return Reflect.get(target, key, receiver)
},
set(target, key, value, receiver) {
return Reflect.set(target, key, value, receiver)
},
}
export function reactive(target) {
// reacitve 只接收对象类型的数据
if (!isObject(target)) return
// 创建proxy代理
return proxy = new Proxy(target,mutableHandlers)
}
第二步。我们来考略边界情况
// 情况一 obj已经被代理过一次了,不需要再次代理,否则会浪费性能
// 解决思路 创建一个缓存表 每次代理之前先去缓存中查看是否代理过 如果代理过就直接返回
const obj = {
name: 'zs',
age: 19
}
const proxyObj1 = reactive(obj)
const proxyObj2 = reactive(obj)
// 情况二 代理 代理对象
/**
* 解决思路 利用get 给当前被代理对象添加一个标识符 标识该对象已经被代理了
* 具体做法
* 当代码走到reactive函数的if (target[ReactiveFlags.IS_REACTIVE]) return target这段其实就会触发get (target[ReactiveFlags.IS_REACTIVE]主要是这部分触发的get) 这时候给原对象添加标识符即可 第一次肯定不存在这个标识符 所以会被代理
*
* 那么即使再代理这个代理对象 就像下面proxyObj2一样,也不会继续代理 因为target[ReactiveFlags.IS_REACTIVE]的结果是true
*/
const obj = {
name: 'zs',
age: 19,
}
const proxyObj1 = reactive(obj)
const proxyObj2 = reactive(proxyObj1)
解决方案
export const mutableHandlers = {
get(target, key, receiver) {
// 解决情况二
if (!target[ReactiveFlags.IS_REACTIVE])
target[ReactiveFlags.IS_REACTIVE] = true
return Reflect.get(target, key, receiver)
},
set(target, key, value, receiver) {
return Reflect.set(target, key, value, receiver)
},
}
const reactiveMap = new WeakMap()
export function reactive(target) {
// reactive 只接收对象
if (!isObject(target)) return
// 解决情况一 如果当前对象已经被代理过 无需二次代理
const existProxy = reactiveMap.get(target)
if (existProxy) return existProxy
// 解决情况二
if (target[ReactiveFlags.IS_REACTIVE]) return target
// 创建proxy代理
const proxy = new Proxy(target, mutableHandlers)
// 解决情况一 缓存代理结果
reactiveMap.set(target, proxy)
return proxy
}
现在还有一个问题
// 情况三
/*
如下代码 info并不是一个代理对象那么当数据发生变化就不会自动更新
原因是 Proxy只能浅层的代理
解决方案 使用递归代理 在get中判断key是否是对象 如果是则继续用reactive代理*/
const obj = {
name: 'zs',
info: {
age: 19
}
}
console.log(obj.info)
解决方案
export const mutableHandles = {
get(target, key, receiver) {
// 解决情况一
if (!target[ReactiveFlags.IS_REACTIVE])
target[ReactiveFlags.IS_REACTIVE] = true
// 解决情况三
if (isObject(target[key])) return reactive(target[key])
return Reflect.get(target, key, receiver)
},
}
至此 reactive api 已经开发完毕 没错就是这么简单 不要有心里压力。那么你将解锁下一章effect的编写