Vue 3 源码解析 reactive (pre-alpha)

10.5号凌晨,发布了vue 3的 pre-alpha源码,出于我对Vue的热爱,火烧眉毛的就从github上拉了源码,想看看Vue 3 更新了哪些有趣的变化~~

Vue最让人感兴趣的天然是它的响应式拉~ Vue 3改变了Vue 2采用Object.defineProperty的方法去而采用Proxy的监听模式vue

Proxy的官方定义是Proxy 对象用于定义基本操做的自定义行为(如属性查找,赋值,枚举,函数调用等)react

Proxy的语法为:git

let p = new Proxy(target, handler);复制代码

target参数用于监听的目标对象(能够是任何类型的对象,包括原生数组,函数,甚至能够是另外一个代理)

handler则是一个对象,其实最经常使用的则是set和get方法

由target的定义就能够看出,proxy解决了Vue 2中不能监听数组改变的缺点github

注:Vue 2中之因此能够监听到数组改变的缘由是由于对数组方法进行了从新的包装,这七个方法分别为push, pop,shift,unshift,splice,reverse,sort数组

Vue 3将Observer重命名为reactivebash

在用法上,建议reactive监听复杂类型的数据,而ref采用简单类型的数据函数

为何要这么说呢?是由于ref源码中有一个convert函数,它会先判断value是否为一个Object,若是为一个Object的状况下会调用reactive方法学习

源码以下:ui

const convert = (val: any): any => (isObject(val) ? reactive(val) : val)复制代码

简单说了下reactive和ref的一点不一样(ref我会在下一节文章中讲解~),接下来仍是要说reactive的实现拉~(点题^∀^)this

reactive中会先判断是否为readonly,若是在readonly的状况下,就返回readonly的target

if (readonlyToRaw.has(target)) {   
 return target  
}
if (readonlyValues.has(target)) { 
   return readonly(target)
}
return createReactiveObject(  
   target,   
   rawToReactive,
   reactiveToRaw,
   mutableHandlers,
   mutableCollectionHandlers
)复制代码

最后调用了一个createReactiveObject方法,reactive的核心就是这个拉~,终于接触到了核心,让咱们来看看~~

我将createReactiveObject的源码来进行分开讲解

if (!isObject(target)) {
  if (__DEV__) {
    console.warn(`value cannot be made reactive: ${String(target)}`)  
    }  
    return target
}复制代码

首先isObject就是判断当前的target是否为一个object类型,源码以下:

export const isObject = (val: any): val is Record<any, any> =>  
    val !== null && typeof val === 'object'复制代码

__DEV__是一个Boolean类型的全局变量,因此第一段代码的意思就是当target不是对象的时候会出现“不能响应target值”的警告( ớ ₃ờ)

let observed = toProxy.get(target)
if (observed !== void 0) {
  return observed
}复制代码

toProxy是一个WeakMap<any,any>类型,来看一下WeakMap接口的源码~

interface WeakMap<K extends object, V> {   
   delete(key: K): boolean;   
   get(key: K): V | undefined;
   has(key: K): boolean;
   set(key: K, value: V): this;
}复制代码

因此当target若是有相应的代理了就会返回target而再也不执行下去

注:void 运算符对给定的表达式进行求值,而后返回undefined,因此void 0undefined

if (toRaw.has(target)) {   
    return target
}复制代码

toRaw的类型和toProxy同样,也是WeakMap,这段代码即判断target已是proxy的状况下会返回target

即:toProxy和toRaw咱们能够经过他们找到代理过的数据是否存在(或经过代理数据找到原始数据)

接下来就是判断target是否能够监听

if (!canObserve(target)) {
   return target
 }复制代码

canObserve(target)的target类型必须是Object|Array|Map|Set|WeakMap|WeakSet

处理完了target,接下来就是handler拉 ≖‿≖✧

const handlers = collectionTypes.has(target.constructor)    
    ? collectionHandlers
    : baseHandlers复制代码

const collectionTypes: Set<any> = new Set([Set, Map, WeakMap, WeakSet])复制代码

能够从collectionTypes中看出,若是target.constructor是collectionTypes中声明的类型就执行collectionHandlers,不然就是baseHandlers

在处理完target和handler以后,就能够建立Proxy对象拉(Proxy介绍看本文开头)~(ง •̀_•́)ง

observed = new Proxy(target, handlers)
toProxy.set(target, observed)
toRaw.set(observed, target)
if (!targetMap.has(target)) {
  targetMap.set(target, new Map())
}
return observed复制代码

最终用Proxy构造一个Proxy对象,返回observed对象,这时候,vue的响应式核心部分就差很少结束了~~

国庆结束拉,接下来回学校作毕设上课~,Vue 3的源码刚发布,复杂度不是过高很是方便阅读,因此接下来会继续看Vue源码~

本文到这里就结束拉~,若是哪里写的很差,麻烦你们帮我指出~,一块儿学习,谢谢~ 

相关文章
相关标签/搜索