vue解构赋值_vue.js 3.0响应式系统原理实现
发布日期:2022-02-19 00:02:22
浏览次数:5
分类:技术文章
本文共 5816 字,大约阅读时间需要 19 分钟。
1)Vue.js 响应式回顾
- Proxy 对象实现属性监听
- 多层属性嵌套,在访问属性过程中处理下一级属性
- 默认监听动态添加的属性
- 默认监听属性的删除操作
- 默认监听数组索引和 length 属性
- 可以作为单独的模块使用
2)Proxy
'use strict' // 问题1: set 和 deleteProperty 中需要返回布尔类型的值 // 在严格模式下,如果返回 false 的话会出现 Type Error 的异常 const target = { foo: 'xxx', bar: 'yyy' } // Reflect.getPrototypeOf() // Object.getPrototypeOf() const proxy = new Proxy(target, { // 访问 // receiver 表示当前的 proxy 对象或者继承的 proxy对象 get (target, key, receiver) { // return target[key] // Reflect(用来操作对象的成员) 反射 es6中新增的成员 代码运行期间用来获取或者设置对象的成员 // https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect return Reflect.get(target, key, receiver) }, // 赋值 set (target, key, value, receiver) { // target[key] = value return 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 指向 receiver const 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)
3)reactive
- 接收一个参数,判断这参数是否是对象
- 创建拦截器对象 handler, 设置 get/set/deleteProperty
- 返回 Proxy 对象
4)收集依赖
5)effect / track / trigger
- effect 跟踪属性变化并调用回调函数
- tarck 收集依赖
- trigger 触发更新
6)ref
把一个基本数据类型数据,转成响应式对象,后续通过 .value 使用
7)reactive vs ref
- ref 可以把基本数据类型数据,转成响应式对象
- ref 返回的对象,重新赋值成对象也是响应式的
- reactive 返回的对象,重新赋值丢失响应式
- reactive 返回的对象不可以解构
8)toRefs
将reactive()创建出来的响应式对象,转换为普通对象,只不过这个对象上的每个属性节点,都是ref()类型的响应式数据
9)实现代码
// index.js// 判断是否是对象const isObject = val => val!==null && typeof val ==='object'// 判断是否是对象,如果是转换成响应式对象,不是则返回本身const convert = target => isObject(target) ? reactive(target) : target// 判断某个对象本身是否具有指定的属性const hasOwnProperty = Object.prototype.hasOwnPropertyconst hasOwn = (target, key) => hasOwnProperty.call(target, key)export function reactive (target) { if(!isObject(target)) return target // const handler = { get (target, key, receiver) { // 收集依赖 // console.log('get', target) 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 = true if (oldValue !== value) { result = Reflect.set(target, key, value, receiver) // 触发更新 // console.log('set', key, value) trigger(target, key) } return result }, deleteProperty (target, key) { const hadKey = hasOwn(target, key) const result = Reflect.deleteProperty(target, key) if (hadKey && result) { //触发更新 // console.log('delete', key) trigger(target, key) } return result } } return new Proxy(target, handler)}let activeEffect = nullexport function effect (callback) { activeEffect = callback callback() // 访问响应式对象属性,去收集依赖 activeEffect = null}let targetMap = new WeakMap()// 收集依赖export function track (target, key) { if (!activeEffect) return let 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) { // console.log(" ~ file: index.js ~ line 79 ~ trigger ~ target", target) // console.log(" ~ file: index.js ~ line 87 ~ trigger ~ targetMap", targetMap) const depsMap = targetMap.get(target) // console.log(" ~ file: index.js ~ line 80 ~ trigger ~ depsMap", depsMap) if (!depsMap) return const dep = depsMap.get(key) if (dep) { dep.forEach(effect => { effect() }) }}export function ref (raw) { // 判断 raw 是否是 ref 创建的对象,如果是的话直接返回 if (isObject(raw) && raw.__v_isRef) { return } // raw 如果是对象,调用 reactive 转换成响应式对象 let value = convert(raw) const r = { __v_isRef: true, get value () { track(r, 'value') return value }, set value (newValue) { if (newValue !== value) { raw = newValue value = convert(raw) trigger(r, 'value') } } } return r}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}function toProxyRef (proxy, key) { const r = { __v_isRef: true, get value () { return proxy[key] }, set value (newValue) { proxy[key] = newValue } } return r}export function computed (getter) { const result = ref() // effect(() => (result.value = getter())) effect(() => result.value = getter()) return result}
10)测试代码
index.html
Document
effect-demo.html
Document
ref.html
Document
toRefs.html
Document
computed.html
Document
转载地址:https://blog.csdn.net/weixin_34238178/article/details/112310885 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
能坚持,总会有不一样的收获!
[***.219.124.196]2024年04月24日 20时12分12秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
C++面经总结之《Effective C++》(二)
2019-04-27
打开我的收藏夹 -- Python爬虫篇(2)
2019-04-27
这是什么“虎狼之词”啊!!!程序员的健康问题,看一线老中医怎么说!!!
2019-04-27
打开我的收藏夹 -- Python数据分析杂谈
2019-04-27
上手Pandas,带你玩转数据(1)-- 实例详解pandas数据结构
2019-04-27
上手Pandas,带你玩转数据(2)-- 使用pandas从多种文件中读取数据
2019-04-27
上手Pandas,带你玩转数据(3)-- pandas数据存入文件
2019-04-27
爬虫遇上不让右击、不让F12的网站,该怎么办?
2019-04-27
上手Pandas,带你玩转数据(4)-- 数据清洗
2019-04-27
上手Pandas,带你玩转数据(5)-- 数据转换与数据定位
2019-04-27
上手Pandas,带你玩转数据(6)-- 摆脱对pandas可视化丑图的刻板印象吧
2019-04-27
linux shell — 6.初识 EXT2 文件系统
2019-04-27
Java — String(字符串)
2019-04-27
linux shell — 7.linux 磁盘与文件系统管理
2019-04-27
linux shell — 8.linux 磁盘与文件系统管理(2)
2019-04-27
Java — 事件监听、事件处理 初体验
2019-04-27
linux — Centos 7(第一天) 使用时出现的问题及解决方法
2019-04-27