文章前言

笔记来源:拉勾教育 大前端高薪训练营

阅读建议:内容较多,建议通过左侧导航栏进行阅读

Vue 3.0 响应式系统原理

基础回顾

Vue.js 响应式回顾

  • Proxy 对象实现属性监听
  • 多层属性嵌套,在访问属性过程中处理下一级属性
  • 默认监听动态添加的属性
  • 默认监听属性的删除操作
  • 默认监听数组索引和 length 属性
  • 可以作为单独的模块使用

Proxy 对象回顾

'use strict'
// 问题1: set 和 deleteProperty 中需要返回布尔类型的值
//        在严格模式下,如果返回 false 的话会出现 Type Error 的异常
const target = {foo: 'xxx',bar: 'yyy'
}
// Reflect.getPrototypeOf()
// Object.getPrototypeOf()
/*** @param { Object } target 目标对象* @param { Object } {} 处理器 / 监听器,处理函数*/
const proxy = new Proxy(target, {get (target, key, receiver) {// return target[key]return Reflect.get(target, key, receiver)},set (target, key, value, receiver) {// target[key] = valuereturn Reflect.set(target, key, value, receiver)},deleteProperty (target, key) {// delete target[key]return Reflect.deleteProperty(target, key)}
})proxy.foo = 'zzz'
// delete proxy.foo

// 问题2:Proxy 和 Reflect 中使用的 receiver// Proxy 中 receiver:Proxy 或者继承 Proxy 的对象
// Reflect 中 receiver:如果 target 对象中设置了 getter,getter 中的 this 指向 receiverconst obj = {get foo() {console.log(this)return this.bar}
}const proxy = new Proxy(obj, {get (target, key, receiver) {if (key === 'bar') { return 'value - bar' }return Reflect.get(target, key, receiver)}
})
console.log(proxy.foo)

reactive

  • reactive 返回的对象,重新赋值丢失响应式
  • reactive 返回的对象不可以解构

基础实现

  • 接收一个参数,判断参数是否是对象

  • 创建拦截器对象 handler,设置 get / set / deleteProperty

  • 返回 Proxy 对象

    // 判断 target 是否是对象
    const isObject = val => val !== null && typeof val === 'object'
    // 当返回的数据还是对象时,需要递归调用,收集依赖
    const convert = target => isObject(target) ? reactive(target) : target// 判断某个对象本身是否有指定的属性
    const hasOwnProperty = Object.prototype.hasOwnProperty
    const hasOwn = (target, key) = hasOwnProperty(target, key)export function  reactive (target) {if (!isObject(target)) return targetconst handler = {get (target, key, receiver) {// 收集依赖track(target, key)const result = Reflect.get(target, key, receiver)return convert(result)},set (target, key, value, receiver) {const oldValue = Reflect.get(target, key, receiver)let result = trueif (oldValue !== value) {result = Reflect.set(target, key, value, receiver)// 触发更新trigger(target, key)}return result},deleteProperty (target, key) {const hasKey = hasOwn(target, key)const result = Reflect.defineProperty(target, key)if (hasKey && result) {// 触发更新trigger(target, key)}return result}}return new Proxy(target, handler)
    }
    

收集依赖

  • 功能结构,如图所示:

  • 代码实现,如下所示:

    // 收集依赖
    let activeEffect = null
    export function effect (callback) {activeEffect = callbackcallback() // 访问响应式对象属性,去收集依赖activeEffect = null
    }let targetMap = new WeakMap()
    export function track (target, key) {if (!activeEffect) returnlet depsMap = targetMap.get(target)if (!depsMap) {targetMap.set(target, (depsMap = new Map()))}let dep = depsMap.get(key)if (!dep) {depsMap.set(key, (dep = new Set()))}dep.add(activeEffect)
    }
    

触发更新

  • 具体代码实现,如下所示:

    // 触发更新
    export function trigger (target, key) {const depsMap = targetMap.get(target)if (!depsMap) returnconst dep = depsMap.get(key)if (dep) {dep.forEach(effect => {effect()})}
    }
    

ref

  • ref 可以把基本数据类型数据,转成响应式对象

  • ref 返回的对象,重新赋值成对象也是响应式的

    export function ref(raw) {// 判断 raw 是否是 ref 创建的对象,如果是的话,直接返回if (isObject(raw) && raw.__v_isRef) returnlet value = convert(raw)const r = {__v_isRef: true,get value() {track(r, 'value')return value},set value(newValue) {if (newValue !== value) {raw = newValuevalue = convert(raw)trigger(r, 'value')}}}return r
    }
    

toRefs

  • 接收一个 reactive 返回的响应式对象,即一个 Proxy 对象

  • 把传入对象的属性转化为类似于 ref 返回的对象

  • 把转换后的属性,挂载到一个新的对象上,进行返回

    // 接收一个 reactive 返回的响应式对象,即一个 Proxy 对象
    export function toRefs (proxy) {const ret = proxy instanceof Array ? new Array(proxy.length) : {}// 把转换后的属性,挂载到一个新的对象上,进行返回for (const key in proxy) {ret[key] = toProxyRef(proxy, key)}return ret
    }
    // 把传入对象的属性转化为类似于 ref 返回的对象
    function toProxyRef (proxy, key) {const r = {__v_isRef: true,get value () {return proxy[key]},set value (newValue) {proxy[key] = newValue}}return r
    }
    

computed

  • 监听内部响应式数据的变化

    export function computed(getter) {const result = ref()effect(() => {result.value = getter()})return result
    }
    

【Vue 3.0 新特性(四)】Vue 3.0 响应式系统原理相关推荐

  1. input change获取改变之前的值和改变之后的值_使用Vue3.0新特性造轮子 WidgetUI3.0 (Input输入框组件)

    我们先看看组件效果图: 基本用法 type属性(type="password") 占位符(placeholder="请输入") 带清除按钮(clear) 输入限 ...

  2. accept 返回0_使用Vue3.0新特性造轮子 WidgetUI3.0 (Upload上传文件组件)

    我们先看看组件效果: 基本使用 可选参数( icon='icon-service') props属性: title(类型 String) 组件显示的文本,默认"上传'. icon(类型 St ...

  3. Servlet 3.0 新特性概述

    Servlet 3.0 新特性概述 Servlet 3.0 作为 Java EE 6 规范体系中一员,随着 Java EE 6 规范一起发布.该版本在前一版本(Servlet 2.5)的基础上提供了若 ...

  4. Servlet 3.0 新特性详解

    https://www.ibm.com/developerworks/cn/java/j-lo-servlet30/ Servlet 3.0 新特性概述 Servlet 3.0 作为 Java EE ...

  5. 安卓6.0、7.0、8.0新特性总结异同

    android6.0 参考一:简书Android 6.0 新特性详解 参考二:关于Android6.0以上系统的权限问题 参考三:值得你关注的Android6.0上的重要变化(一) 参考四:值得你关注 ...

  6. JDK5.0新特性系列---目录

    JDK5.0新特性系列---目录 JDK5.0新特性系列---1.自动装箱和拆箱 JDK5.0新特性系列---2.新的for循环 JDK5.0新特性系列---3.枚举类型 JDK5.0新特性系列--- ...

  7. 背水一战 Windows 10 (1) - C# 6.0 新特性

    背水一战 Windows 10 (1) - C# 6.0 新特性 原文:背水一战 Windows 10 (1) - C# 6.0 新特性 [源码下载] 背水一战 Windows 10 (1) - C# ...

  8. 背水一战 Windows 10 (43) - C# 7.0 新特性

    背水一战 Windows 10 (43) - C# 7.0 新特性 原文: 背水一战 Windows 10 (43) - C# 7.0 新特性 [源码下载] 背水一战 Windows 10 (43) ...

  9. 老子学不动系列:Vue 3.0 新特性预览

    尤大昨天在 Vue Toronto 的主题演讲中预览了 Vue 3 .通过利用现代浏览器支持的新功能,Vue 3 将成为我们已经了解和喜爱的Vue.js 的改进版本. 我们期待的 Vue 3 将会是: ...

最新文章

  1. ubuntu package XXX needs to be reinstalled,but I can't find an archive 问题修复
  2. Python 输入输出
  3. 10-异步爬虫(线程池/asyncio协程)实战案例
  4. mysql 连接 指定字符集_关于Mysql连接池配置指定字符集的问题
  5. java实现代理服务器,接收客户端连接,发送到对应服务器
  6. 老式计算机如何设置u盘启动,技嘉主板老式bios设置u盘启动教程
  7. php 泛型编程,泛型是什么,C++泛型编程又是什么?
  8. 微信支付服务商平台(商户平台)扫码登录后提示“登录超时,请重新登录”时该怎么处理?
  9. SpaceEye :12种地球实时卫星照片壁纸
  10. 省选LN站2023游记Day1
  11. 如何对待每逢佳节被逼婚
  12. 怀念—伤心者,不痛不痒,冷暖自知
  13. 编译安装mysql5.5
  14. java 一元 二元 三元_一元到三元关系 二元
  15. 澳大利亚兽医伏特加酒当点滴救活给中毒小狗
  16. Pandas数据可视化的备忘录
  17. 什么?你还没妹子?教你如何借助Python俘获女孩子芳心
  18. Matalb更换YaHei Consolas Hybrid字体
  19. 邪教日记之神兵篇: 一
  20. html5富文本编辑器图片,漂亮的富文本编辑器WYSIWYG

热门文章

  1. 最短路径——Floyd算法HDU Today(hdu2112)
  2. 并查集——食物链(poj1182)
  3. 在pycharm中导入anaconda的库
  4. 数据预处理-数据规约-属性规约
  5. LeetCode 258. Add Digits
  6. 9203精英挑战赛注意事宜 一
  7. 双层循环嵌套打印矩形 java
  8. dj鲜生-10-用户注册的继续-错误提示的前端显示-防重名验证
  9. scp带密码后台传输
  10. LC_ALL: cannot change locale (en_US.UTF8)问题解决