![1b933d7d14b279ab0ea649fe2ae93330.png](https://i-blog.csdnimg.cn/blog_migrate/9f7e4b91d73029d97f2fd356a286e6eb.jpeg)
作者:大转转FE
转发链接:https://mp.weixin.qq.com/s/Jb5NKXNhlb1Enq0R1p9DcA
看完上两章 初入茅庐 小试牛刀 之后,大家应该对vue-next(Vue 3.0) 的 API 使用已经了如指掌了。好奇的同学一定对 vue-next 响应式的原理充满好奇,本章就带你解密!
带你了解 vue-next(Vue 3.0)之 初入茅庐【实践】
带你了解 vue-next(Vue 3.0)之 小试牛刀【实践】
前言
最新 vue-next 的源码发布了,虽然是 pre-alpha 版本,但这时候其实是阅读源码的比较好的时机。在 vue 中,比较重要的东西当然要数它的响应式系统,在之前的版本中,已经有若干篇文章对它的响应式原理和实现进行了介绍,这里就不赘述了。在 vue-next 中,其实现原理和之前还是相同的,即通过观察者模式和数据劫持,只不过对其实现方式进行了改变。
因此,这篇文章我也打算按这种风格来写一下利用最近空闲时间阅读 vue-next 响应式模块的源码的一些心得与体会,算是抛砖引玉,同时实现一个极简的响应式系统。
如有错误,还望指正。
vue-next 数据响应机制 - Proxy
在学习 vue-next之前,你必须要先熟练掌握ES6中的 Proxy、 Reflect 及 ES6中为我们提供的 Map、 Set两种数据结构
先应用再说原理:
const { reactive, effect} = Vuelet p = reactive({name:'zhuanzhuan'});// effect方法会立即被触发effect(()=>{ console.log(p.name);})p.name = '转转'; // 修改属性后会再次触发effect方法
源码是采用 ts编写,为了便于大家理解原理,这里我们采用js来从0编写,之后再看源码就非常的轻松啦!
reactive方法实现
看源码
function reactive(target) { // if trying to observe a readonly proxy, return the readonly version. if (readonlyToRaw.has(target)) { return target; } // target is explicitly marked as readonly by user if (readonlyValues.has(target)) { return readonly(target); } return createReactiveObject( target, rawToReactive, reactiveToRaw, mutableHandlers, mutableCollectionHandlers ); }function createReactiveObject( target, toProxy, toRaw, baseHandlers, collectionHandlers ) { if (!isObject(target)) { { console.warn(`value cannot be made reactive: ${String(target)}`); } return target; } // target already has corresponding Proxy let observed = toProxy.get(target); if (observed !== void 0) { return observed; } // target is already a Proxy if (toRaw.has(target)) { return target; } // only a whitelist of value types can be observed. if (!canObserve(target)) { return target; } const handlers = collectionTypes.has(target.constructor) ? collectionHandlers : baseHandlers; observed = new Proxy(target, handlers); toProxy.set(target, observed); toRaw.set(observed, target); return observed; }
稍微精简下
function reactive(target) { const handlers = collectionTypes.has(target.constructor) ? collectionHandlers : baseHandlers observed = new Proxy(target, handlers) return observed}
const collectionTypes = new Set([Set, Map, WeakMap, WeakSet]);
基本上除了 Set, Map, WeakMap, WeakSet,都是 baseHandlers。
baseHandlers实现:
function createGetter(isReadonly, shallow = false) { return function get(target, key, receiver) { const res = Reflect.get(target, key, receiver); if (isSymbol(key) && builtInSymbols.has(key)) { return res; } if (shallow) { track(target, "get" /* GET */, key); // TODO strict mode that returns a shallow-readonly version of the value return res; } if (isRef(res)) { return res.value; } track(target, "get" /* GET */, key); return isObject(res) ? isReadonly // need to lazy access readonly and reactive here to avoid // circular dependency readonly(res) : reactive(res) : res; }; }
返回值如果是 object,就再走一次 reactive,实现深度
下面我们自己写个案例,通过proxy 自定义获取、增加、删除等行为
function reactive(target){ // 创建响应式对象 return createReactiveObject(target);}function isObject(target){ return typeof target === 'objec