# 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]
即oldValue
and 没有修改前的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
已经被做过响应式代理时) - 返回响应式代理
- 调用