# ractive 方法剖析与实现
# 完整代码实现
import { isArray, isObject, hasChanged } from '../utils/index'; | |
import { effect, track, trigger } from './effect'; | |
export function reactive(target: any) { | |
if (!isObject(target)) return target; | |
if (isReactive(target)) return target; | |
if (reactiveMap.has(target)) return reactiveMap.get(target); | |
const reactiveProxy: Record<string | number | symbol, any> = new Proxy( | |
target, | |
{ | |
get(target, key) { | |
if (key === '_isReactive') return true; | |
track(target, key); | |
const res = Reflect.get(target, key); | |
return isObject(res) ? reactive(res) : res; | |
}, | |
set(target, key, newValue) { | |
const oldValue = Reflect.get(target, key); | |
const oldLength = Reflect.get(target, 'length'); | |
const res = Reflect.set(target, key, newValue); | |
if (hasChanged(oldValue, newValue)) { | |
trigger(target, key); | |
if ( | |
isArray(target) && | |
oldLength != Reflect.get(target, 'length') && | |
key !== 'length' | |
) { | |
trigger(target, 'length'); | |
} | |
} | |
return res; | |
}, | |
} | |
); | |
reactiveMap.set(target, reactiveProxy); | |
return reactiveProxy; | |
} | |
export function isReactive(target: any) { | |
return !!(target && target.__isReactive); | |
} |
# 边界处理(对特殊情况的处理)
target的类型不为Object时:- 利用
isObject方法判断target的类型是否为Object isObject方法的返回值为false时,即target的类型不为Object, 则直接返回target, 不做接下来的响应式处理
- 利用
target本身已经为一个响应式代理时:- 利用
isRective方法判断target是否为响应式代理 isReactive方法的返回值为true时, 即target已经为一个响应式代理,则直接返回target,不再做接下来的处理
- 利用
target已经被做过响应式代理时:- 利用
reactiveMap.has(target)方法来判断target是否已经被做过响应式代理 reactiveMap.has(target)方法返回值为true时, 即target已经被做过响应式代理,则直接调用reactiveMap.get(targey)方法返回它的响应值代理
- 利用
# 响应式处理
# 整体概述
利用 Proxy 对 target 做一个数据代理,拦截其 getter and setter , 最后返回这个数据代理
# 详细步骤
拦截 getter
- 做边界处理
if(key === '_isReactive')判断其要获取的key是否为_isReactive, 当if判断为true时,则直接返回false,不再进行接下来的处理
- 收集副作用
- 调用
track方法来收集副作用函数,将其收集到target对应的key的对应的Set里面,等待setter被触发,并修改target[key]的时候调用trigger来将这个Set里面存储的副作用函数一一触发. - ps: (track 方法的讲解请点击这里奥)
- 调用
- 返回
target[key]的值,做深度响应式处理- 利用
Reflect.get(target, key)取出target[key]的值 - 判断
target[key]的值的类型是否为Object, 当为Object时,则返回reactive(target[key])对其做深度响应式处理,当不为Object时,则直接返回target[key]
- 利用
- 做边界处理
拦截 setter
- 取出相关数据, 进行更新操作
- 利用
Reflect.get方法取出没有修改前的target[key]即oldValueand 没有修改前的target[length]即oldLength, 利用Reflect.set进行对target[key]的更新
- 利用
- 判断是否需要调用对应的
key对应的Set存储的副作用函数- 利用
hasChanged()判断新旧值是否发生了改变,如果没有改变则不进行接下来的处理。如果发生了改变,则调用trigger方法,来调用对应的key对应的Set存储的副作用函数 - ps: trigger 方法的讲解请点击这里奥
- 利用
- 判断
target是否为Array, 并且数组的长度是否发生了改变- 利用
isArray判断target,并利用Reflect.get()取得更新后数组的长度,并与之前数组的长度oldLength比较,看是否发生了改变,如果发生了改变,则调用tigger方法,来调用length对应的Set存储的副作用。(之所以要这样做,是因为当给数组增加 or 删除元素的时候,数组的length就已经改变了, 当对length的更新的拦截的时候,就会发现新值和旧值是一样的,就不会触发trigger)
- 利用
- 取出相关数据, 进行更新操作
将响应式代理存储起来,并返回响应式代理
- 调用
reactiveMap.set方法,将响应式代理和target关联起来并存储,以便于做上文的边界处理 (target已经被做过响应式代理时) - 返回响应式代理
- 调用