Vue3.0 简化版数据响应式原理
// vue3响应式原理:利用Proxy对象对数据拦截const toProxy = new WeakMap() // 形如 obj: observed
const toRaw = new WeakMap() // 形如 observed: obj
function isObject(obj) {
return typeof obj === 'object' && obj !== null
}
function hasOwn(obj, key) {
return obj.hasOwnProperty(key)
}
function reactive(obj) {
if (!isObject(obj)) {
return obj
}
// 查找缓存
if (toProxy.has(obj)) {
return toProxy.get(obj)
}
// 传入obj就是代理对象,此时不用反复代理
if (toRaw.has(obj)) {
return obj
}
const observed = new Proxy(obj, {
get(target, key, receiver) {
// 访问
const res = Reflect.get(target, key, receiver)
console.log(`获取${key}: ${res}`)
// 依赖收集
track(target, key)
return isObject(res) ? reactive(res) : res
},
set(target, key, value, receiver) {
// 新增和更新
const hadKey = hasOwn(target, key) // ADD 或 SET
const oldVal = target[key]
const res = Reflect.set(target, key, value, receiver)
if (!hadKey) {
console.log(`新增${key}:${value}`)
trigger(target, 'ADD', key)
} else if (oldVal !== value) {
console.log(`设置${key}:${value}`)
trigger(target, 'SET', key)
}
return res
},
deleteProperty(target, key) {
// 删除
const hadKey = hasOwn(target, key)
const res = Reflect.deleteProperty(target, key)
// key存在并且删除成功
if (res && hadKey) {
console.log(`删除${key}:${res}`)
trigger(target, 'DELETE', key)
}
return res
}
})
// 缓存
toProxy.set(obj, observed)
toRaw.set(observed, obj)
return observed
}
const activeReativeEffectStack = []
// 依赖收集执行
// 基本结构{target:{key:[eff1,eff2]}}
let targetsMap = new WeakMap()
function track(target, key) {
// 从栈中获取响应函数
const effect = activeReativeEffectStack[activeReativeEffectStack.length - 1]
if (effect) {
let depsMap = targetsMap.get(target)
if (!depsMap) {
// 首次访问target
depsMap = new Map()
targetsMap.set(target, depsMap)
}
// 存放key
let deps = depsMap.get(key)
if (!deps) {
deps = new Set()
depsMap.set(key, deps)
}
if (!deps.has(effect)) {
deps.add(effect)
}
}
}
function effect(fn) {
// 1.异常处理
// 2.执行函数
// 3.放置到activeReativeEffectStack
const rxEffect = function(...args) {
try {
activeReativeEffectStack.push(rxEffect)
return fn(...args) // 执行函数触发依赖收集
} finally {
activeReativeEffectStack.pop()
}
}
rxEffect() // 默认立即执行
return rxEffect
}
// 触发target.key对应响应函数
function trigger(target, type, key) {
// 获取依赖表
const depsMap = targetsMap.get(target)
if (depsMap) {
// 获取响应函数集合
const deps = depsMap.get(key)
const effects = new Set()
if (deps) {
// 执行所有响应函数
deps.forEach(effect => {
// effect()
effects.add(effect)
})
}
// 数组新增或删除
if (type === 'ADD' || type === 'DELETE') {
if (Array.isArray(target)) {
const deps = depsMap.get('length')
if (deps) {
deps.forEach(effect => {
effects.add(effect)
})
}
}
}
// 获取已存在的Dep Set执行
effects.forEach(effect => effect())
}
}
const data = { foo: 'foo', bar: { a: 1 } }
const react = reactive(data)
// 1.获取
// react.foo // ok
// 2.设置已存在属性
// react.foo = 'foooooooo'
// 3.设置不存在属性
// react.baz = 'bazzzzzz'
// 4.嵌套对象
// react.bar.a = 10
// 避免重复代理
// console.log(reactive(data) === react) // true
// reactive(react)
effect(() => {
console.log('数据发生了变化:', react.foo)
// dom
})
react.foo = 'fooooooo'
// vue3响应式原理:利用Proxy对象对数据拦截
const toProxy = new WeakMap() // 形如 obj: observed
const toRaw = new WeakMap() // 形如 observed: obj
function isObject(obj) {
return typeof obj === 'object' && obj !== null
}
function hasOwn(obj, key) {
return obj.hasOwnProperty(key)
}
function reactive(obj) {
if (!isObject(obj)) {
return obj
}
// 查找缓存
if (toProxy.has(obj)) {
return toProxy.get(obj)
}
// 传入obj就是代理对象,此时不用反复代理
if (toRaw.has(obj)) {
return obj
}
const observed = new Proxy(obj, {
get(target, key, receiver) {
// 访问
const res = Reflect.get(target, key, receiver)
console.log(`获取${key}: ${res}`)
// 依赖收集
track(target, key)
return isObject(res) ? reactive(res) : res
},
set(target, key, value, receiver) {
// 新增和更新
const hadKey = hasOwn(target, key) // ADD 或 SET
const oldVal = target[key]
const res = Reflect.set(target, key, value, receiver)
if (!hadKey) {
console.log(`新增${key}:${value}`)
trigger(target, 'ADD', key)
} else if (oldVal !== value) {
console.log(`设置${key}:${value}`)
trigger(target, 'SET', key)
}
return res
},
deleteProperty(target, key) {
// 删除
const hadKey = hasOwn(target, key)
const res = Reflect.deleteProperty(target, key)
// key存在并且删除成功
if (res && hadKey) {
console.log(`删除${key}:${res}`)
trigger(target, 'DELETE', key)
}
return res
}
})
// 缓存
toProxy.set(obj, observed)
toRaw.set(observed, obj)
return observed
}
const activeReativeEffectStack = []
// 依赖收集执行
// 基本结构{target:{key:[eff1,eff2]}}
let targetsMap = new WeakMap()
function track(target, key) {
// 从栈中获取响应函数
const effect = activeReativeEffectStack[activeReativeEffectStack.length - 1]
if (effect) {
let depsMap = targetsMap.get(target)
if (!depsMap) {
// 首次访问target
depsMap = new Map()
targetsMap.set(target, depsMap)
}
// 存放key
let deps = depsMap.get(key)
if (!deps) {
deps = new Set()
depsMap.set(key, deps)
}
if (!deps.has(effect)) {
deps.add(effect)
}
}
}
function effect(fn) {
// 1.异常处理
// 2.执行函数
// 3.放置到activeReativeEffectStack
const rxEffect = function(...args) {
try {
activeReativeEffectStack.push(rxEffect)
return fn(...args) // 执行函数触发依赖收集
} finally {
activeReativeEffectStack.pop()
}
}
rxEffect() // 默认立即执行
return rxEffect
}
// 触发target.key对应响应函数
function trigger(target, type, key) {
// 获取依赖表
const depsMap = targetsMap.get(target)
if (depsMap) {
// 获取响应函数集合
const deps = depsMap.get(key)
const effects = new Set()
if (deps) {
// 执行所有响应函数
deps.forEach(effect => {
// effect()
effects.add(effect)
})
}
// 数组新增或删除
if (type === 'ADD' || type === 'DELETE') {
if (Array.isArray(target)) {
const deps = depsMap.get('length')
if (deps) {
deps.forEach(effect => {
effects.add(effect)
})
}
}
}
// 获取已存在的Dep Set执行
effects.forEach(effect => effect())
}
}
const data = { foo: 'foo', bar: { a: 1 } }
const react = reactive(data)
// 1.获取
// react.foo // ok
// 2.设置已存在属性
// react.foo = 'foooooooo'
// 3.设置不存在属性
// react.baz = 'bazzzzzz'
// 4.嵌套对象
// react.bar.a = 10
// 避免重复代理
// console.log(reactive(data) === react) // true
// reactive(react)
effect(() => {
console.log('数据发生了变化:', react.foo)
// dom
})
react.foo = 'fooooooo'
以上是 Vue3.0 简化版数据响应式原理 的全部内容, 来源链接: utcz.com/z/379669.html