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)收集依赖

1545b4a2a6bdbc8d317674516e898a53.png

5)effect / track / trigger

  • effect 跟踪属性变化并调用回调函数
  • tarck 收集依赖
  • trigger 触发更新

6)ref

把一个基本数据类型数据,转成响应式对象,后续通过 .value 使用

7)reactive vs ref

  • ref 可以把基本数据类型数据,转成响应式对象
  • ref 返回的对象,重新赋值成对象也是响应式的
  • reactive 返回的对象,重新赋值丢失响应式
  • reactive 返回的对象不可以解构

9e0f37ae2472ae2d066d9bb6acc91cf8.png

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 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:kali系统的u盘安装过程_使用U盘安装Windows操作系统
下一篇:异化之地服务器维护,异化之地单机版

发表评论

最新留言

能坚持,总会有不一样的收获!
[***.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
从零开始,学会Python爬虫不再难!!! -- (1)开篇:初识爬虫,基础铺垫 丨蓄力计划 2019-04-27
从零开始,学会Python爬虫不再难!!! -- (2)承接:解析网页,抓取标签 丨蓄力计划 2019-04-27
AttributeError: module ‘urllib‘ has no attribute ‘quote‘的解决办法 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