(function (global) {
// 存储所有依赖,使用 Weakmap 保持键名对象的弱引用,浏览器会忽略 WeakMap 键名对象的引用关系
const targetDepsMap = new WeakMap()
let currentFn = () => { }
// 收集依赖
function track(target, key) {
let depsMap = targetDepsMap.get(target)
if (!depsMap) {
depsMap = new Map()
targetDepsMap.set(target, depsMap)
}
let deps = depsMap.get(key)
if (!deps) {
deps = new Set()
depsMap.set(key, deps)
}
deps.add(currentFn)
}
function run(fn) {
if (fn.options && fn.options.hooks) {
fn.options.hooks(fn)
} else {
fn()
}
}
// 触发依赖更新 watchEffect 回调
function trigger(target, key) {
const depsMap = targetDepsMap.get(target)
if (depsMap) {
const deps = depsMap.get(key)
if (deps) {
deps.forEach(fn => {
run(fn)
})
}
}
}
const baseHandler = {
get(target, key, receiver) {
const res = Reflect.get(target, key)
track(target, key)
return (typeof res === 'object' && res !== null) ? reactive(res) : res
},
set(target, key, value, receiver) {
const res = Reflect.set(target, key, value)
trigger(target, key)
return res
},
}
function createEffect(fn, options = {}) {
const effect = () => {
currentFn = effect
const res = fn()
currentFn = () => { }
return res
}
effect.options = options
effect.raw = fn
return effect
}
function reactive(target) {
return new Proxy(target, baseHandler)
}
function watchEffect(fn, options) {
const effect = createEffect(fn, options)
effect()
return effect
}
function computed(fn) {
return {
get value() {
return fn()
}
}
}
function ref (value) {
return reactive({
value
})
}
global.MVue = {
reactive,
watchEffect,
computed,
ref
}
})(window);
(function test () {
const { reactive, ref, computed, watchEffect } = MVue
const person = reactive({
name: 'Zhang San',
age: 19,
})
const personInfo = computed(() => 'Name:' + person.name + ' Age:' + person.age)
const count = ref(0)
console.log('personInfo: ' + personInfo.value)
console.log('count:' + count.value)
watchEffect(() => {
console.log(`watchEffect age: ${person.age}`)
})
setInterval(() => {
person.age++
}, 3000)
})()
console