Vue3.0响应式实现
Posted qqprincekin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue3.0响应式实现相关的知识,希望对你有一定的参考价值。
基于Proxy
// 弱引用映射表 es6 防止对象不能被回收 let toProxy = new WeakMap(); // 原对象: 代理过得对象 let toRaw = new WeakMap(); // 被代理过的对象: 原对象 // 判断为对象 function isObject(val) { return typeof val === ‘object‘ && val !== null } // 区分改变数组长度还是数值 function hasOwn(target, key) { return target.hasOwnProperty(key) } function reactive(target) { // 创建响应式对象 return createReactiveObject(target) } // 创建响应式对象 function createReactiveObject(target) { if (!isObject(target)) { return target } let proxy = toProxy.get(target); // 如果已经代理过 直接返回代理结果 if (proxy) { return proxy; } if (toRaw.has(target)) { // 防止对象被多次代理 return target; } let baseHandler = { // Reflect优点: 不报错 有返回值 会替代Object 上的方法 // Proxy + reflect 反射 get(target, key, receiver) { // console.log(‘查询‘); let result = Reflect.get(target, key, receiver); // 收集依赖订阅 把当前key 和effect对应 track(target, key); // result 当前获取到的值 return isObject(result) ? reactive(result) : result; // 深层次代理 多层代理 (递归) }, set(target, key, value, receiver) { // console.log(‘设置‘); // 区分改变数组长度还是数值 let hadKey = hasOwn(target, key); let oldValue = target[key]; let res = Reflect.set(target, key, value, receiver); if (!hadKey) { trigger(target, ‘add‘, key); // console.log(‘新增属性‘) } else if (oldValue !== value) { // 表示属性修改 // console.log(‘修改属性‘) trigger(target, ‘set‘, key); }// // 设置成功返回值 return res; }, deleteProperty(target, key) { // console.log(‘删除‘); let res = Reflect.deleteProperty(target, key) return res; } } let observed = new Proxy(target, baseHandler); toProxy.set(target, observed); toRaw.set(observed, target); return observed } // let proxy = reactive({name: {n: ‘wyq‘}}); // proxy.name.n = ‘王瘦瘦‘ // console.log(proxy.name.n) // let arr = [1, 2, 3]; // let proxy = reactive(arr) // proxy.length = 100; // 发布订阅模式 // 栈结构 let activeEffectStacks = []; // 栈型结果 let targetsMap = new WeakMap(); // 集合和哈希表 function track(target, key) { // target中的key变化 执行数组方法 let effect = activeEffectStacks[activeEffectStacks.length - 1]; if (effect) { // 有对应关系 创建关联 let depsMap = targetsMap.get(target); if (!depsMap) { targetsMap.set(target, depsMap = new Map()); } let deps = depsMap.get(key); if (!deps) { depsMap.set(key, deps = new Set()); } if (!deps.has(effect)) { deps.add(effect); } // 动态创建依赖关系 } // 不管 } function trigger(target, type, key) { let depsMap = targetsMap.get(target); if (depsMap) { let deps = depsMap.get(key); if (deps) { // 当前key 对应effect 依次执行 deps.forEach((effect) => { effect(); }) } } } // 响应式 副作用 function effect(fn) { // 把fn包装成响应式函数 let effect = createReactiveEffect(fn); effect(); // 先执行一次 } function createReactiveEffect(fn) { // 高阶函数 let effect = function () { // is 创建的响应式的effect return run(effect , fn); // 1.让fn执行 2.存入栈 }; return effect; } function run(effect, fn) { try { activeEffectStacks.push(effect); fn(); }finally { activeEffectStacks.pop(); } } let obj = reactive({name: ‘wyq‘}); effect(() => { // effect默认执行两次 默认先执行一次 依赖数据变化在执行一次 console.log(obj.name) }); obj.name = ‘王瘦瘦‘; obj.name = ‘王瘦瘦‘; obj.name = ‘SpongeBob‘;
以上是关于Vue3.0响应式实现的主要内容,如果未能解决你的问题,请参考以下文章
敲黑板,划重点!!!Vue3.0响应式实现原理 —— proxy()