Vue源码解读学习

news2024/12/24 3:52:20

Vue源码

观察者模式 & 发布订阅
观察者模式:中心一对多 + 系统单点间的灵活和拓展(广播的方式)
发布订阅:将注册列表遍历发布给订阅者
在这里插入图片描述

initInject initState initProvide他们挂载顺序为什么这样设计?

initstate 是将 data | props & methods & watch | computed 初始化
那么你需要 provide 就必须要存在 data | props…等等初始化数据

inject 为什么要在 initstate 之前呢?

因为如果我们当前实例有用到 Inject 的地方 那么必须要先 inject 才能操作它

Vue3做了哪些优化

源码结构上:

monorepo(原子结构 可独立拆分引用)(可作业务上的拆分)

性能上:

移除了很多使用率比较低的api
tree-shaking => 打包产物优化 按需引入

编译上:
compoile阶段   静态模板 进行分析 => 分析树 <= PatchFlag
数据劫持上:
Object.defineProperty 本身无法检测对象属性的增加或者删除
Vue2使用$set $delete  数组 push pop ... 层级较深 => 递归遍历
Vue3 proxy => 底层优化
模板编译分段

词法分析阶段: template(baseCompile => baseParse) => AST
指令和语法的转化阶段(transform => node节点打标签): AST => 解析不同的节点进行区分 => 不同类型转化
可执行函数的生成阶段(generate):转化后的AST生成渲染函数

基于Proxy的响应式

数据劫持 | 数据响应(reactive):数据变化 => 函数监听执行
依赖收集(effect)
当前vm实例上挂载effect => 当前activeEffect切换为effect => 在effect上创建deps
属性,用于传递依赖

Vue2中 Watcher和Dep之间怎么处理的?

在这里插入图片描述

本质上就是 当render函数读取getter响应式变量的时候 会触发依赖收集 创建一个Watcher
当这个变量被setter的时候 会告诉Watcher去让组件重新生成render函数

手写一个响应式

class Vue {
    constructor(options) {
        const data = options.data
        this._data = data

        // 数据劫持 => initData
        _proxy(this, '_data', data)

        // 核心逻辑
        observe(data)

        new Watch(this, function() {
            return data.name + '创建响应式'
        }, function() {
            console.log('watch cb:', this.value)
        })
    }
}

const _proxy = function(vm, sourceKey, data) {
    const keys = Object.keys(data);

    keys.forEach(key => {
        Object.defineProperty(vm, key, {
            get() {
                return vm[sourceKey][key]
            },
            set(val) {
                vm[sourceKey][key] = val
            }
        })
    })
}

const observe = function(data) {
    const ob = new Observer(data)
}

class Observer {
    constructor(data) {
        this.walk(data)
    }
    walk(data) {
        Object.keys(data).forEach(key => {
            defineReactive(data, key)
        })
    }
}

const defineReactive = function(obj, key) {
    let val = obj[key]
    const dep = new Dep()

    Object.defineProperty(obj, key, {
        enumerable: true,
        configurable: true,
        get() {
            console.log('依赖收集')
            dep.depend()
            return val
        },
        set(newVal) {
            console.log('派发更新')
            val = newVal
            dep.notify()
        }
    })
}

class Dep {
    constructor() {
        this.id = Dep.uid++
        this.subs = []
    }

    addSub(sub) {
        this.subs.push(sub)
    }

    depend() {
        if (Dep.target) {
            Dep.target.addDep(this)
        }
    }

    notify() {
        this.subs.forEach(sub => sub.update())
    }

    removeSub(sub) {
        const subIndex = this.subs.indexOf(sub)
        this.subs.splices(subIndex, 1)
    }
}
Dep.uid = 0
Dep.target = null

class Watch {
    constructor(vm, render, cb) {
        this.vm = vm
        this.render = render
        this.cb = cb

        this.deps = []
        this.depsIds = new Set()
        this.newDeps = []
        this.newDepsIds = new Set()

        this.value = this.get()
        this.cb(this.value)
    }

    get() {
        Dep.target = this
        this.newDeps = []
        this.newDepsIds = new Set()

        const value = this.render()

        Dep.target = null
        this.deps.forEach(oldDep => {
            const notExistInNewDeps = !this.newDepsIds.has(oldDep.id)
            if (notExistInNewDeps) {
                oldDep.removeSub(this)
            }
        })
        this.deps = this.newDeps
        this.depsIds = this.newDepsIds

        return value
    }

    addDep(dep) {
        const depId = dep.id
        if (!this.newDepsIds.has(depId)) {
            this.newDeps.push(dep)
            this.newDepsIds.add(depId)

            if (!this.depsIds.has(depId)) {
                dep.addSub(this)
            }
        }
    }

    update() {
        this.value = this.get()
        this.cb(this.value)
    }
}

let zhaowa = new Vue({
    data: {
        name: 'yy',
        course1: 100,
        course2: 99
    }
})

zhaowa.course1 = 1
zhaowa.course2 = 2

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1605285.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL行格式(row format)

MySQL行格式&#xff08;row format&#xff09; 表的行格式决定了其行的物理存储方式&#xff0c;这反过来又会影响查询和 DML 操作的性能。随着单个磁盘页面容纳更多行&#xff0c;查询和索引查找可以更快地工作&#xff0c;缓冲池中需要的高速缓存内存更少&#xff0c;写出…

京西商城——前端项目的创建以及前后端联调

创建VUE项目 在jingxi_shop_project文件夹中再创建一个 frontend 文件夹用来存放前端项目 /jingxi_shop_project/backend/jingxi_shop_project....../frontend/jingxi_shop_web......首先要安装 node.js 和 VUE cli&#xff0c;进入到项目目录内创建项目 vue create jingxi_…

[Vision Board创客营]学习片上Flash移植FAL

文章目录 [Vision Board创客营]学习片上Flash移植FAL介绍环境搭建使用组件测试porbeerasewriteread 结语 [Vision Board创客营]学习片上Flash移植FAL 水平较菜&#xff0c;大佬轻喷。&#x1f630;&#x1f630;&#x1f630; 介绍 &#x1f680;&#x1f680;Vision-Board 开…

解锁流量密码:如何利用HubSpot打造高效的获客策略?(下)

在当今数字化时代&#xff0c;流量是企业成功的关键。HubSpot作为一款全面的营销自动化工具&#xff0c;为我们提供了强大的支持&#xff0c;帮助企业打造高效的流量获取策略。接下来&#xff0c;我们将从社交媒体与SEO优化、自动化营销流程、数据分析与效果评估以及流量获取策…

【R语言】组合图:散点图+箱线图+平滑曲线图+柱状图

用算数运算符轻松组合不同的ggplot图&#xff0c;如图&#xff1a; 具体代码如下&#xff1a; install.packages("devtools")#安装devtools包 devtools::install_github("thomasp85/patchwork")#安装patchwork包 library(ggplot2) library(patchwork) #p1是…

Linux进程和任务管理

目录 一.程序和进程的关系 程序 进程 线程 线程与进程的区别 二.查看进程信息ps 方法一 常用选项 方法二 三.TOP动态查看进程信息 进程信息区各列解释 top常用命令 系统查看命令总结 查看进程信息pgrep 查看进程树pstree 四.控制进程 进程的启动方式 进程的前…

electron的webview和内嵌网页如何通信

在 Electron 的世界里&#xff0c;webview 标签相当于一个小盒子&#xff0c;里面可以装一个完整的网页&#xff0c;就像一个迷你浏览器。当你想和这个小盒子里的内容说话时&#xff08;也就是进行通信&#xff09;&#xff0c;这里有几个方法可以帮你做到&#xff1a; 这里只写…

LIUNX文件系统

目录 1.磁盘的物理结构 2.CHS定位法 3.磁盘的逻辑存储 4.系统层面 inode.block[15] 创建文件的流程 查找文件的流程 了解文件系统&#xff0c;首先要了解磁盘是如何存储和读取数据的。 1.磁盘的物理结构 可以理解这个盘上有很多的小磁铁&#xff0c;通过旋转盘面和摆动…

LeetCode-热题100:114. 二叉树展开为链表

题目描述 给你二叉树的根结点 root &#xff0c;请你将它展开为一个单链表&#xff1a; 展开后的单链表应该同样使用 TreeNode &#xff0c;其中 right 子指针指向链表中下一个结点&#xff0c;而左子指针始终为 null 。展开后的单链表应该与二叉树 先序遍历 顺序相同。 示例…

内业减少80%人工操作,林地地形轻松测!

林业作为维护生态平衡和保护环境的关键领域&#xff0c;其科学管理和合理利用是当前林业工作的重中之重。林业调查旨在全面了解当前林业资源的状况&#xff0c;其中林地地形测量是林业调查的基础工作。通过对林地地形的准确测量&#xff0c;可获取森林的地理位置、面积、地貌、…

探索VR数字展厅,对企业未来展示新模式

在数字化浪潮的推动下&#xff0c;企业展示也在经历着一场革命&#xff0c;VR数字展厅正在以一种全新的方式重塑我们的生活和工作空间&#xff0c;不仅重塑了客户的观展体验&#xff0c;也为企业营销打开了新的渠道。 VR数字展厅作为实体展厅的数字化延伸&#xff0c;正以其沉浸…

C++笔记:引用

目录 概念&#xff1a; ​编辑 引用的特性&#xff1a; 引用中的权限问题&#xff1a; 引用与指针的区别&#xff1a; 引用的使用&#xff1a; 概念&#xff1a; 引用是给已存在变量取一个别名&#xff0c;编译器不会为引用变量开辟内存空间。 引用的符号&#xff1a;&…

物联网网络传输,STM32和ESP32

2024.4.17 今天主要是记录一下我这个STM32F407和esp8266组成的互联网板子的一些例程运行心得&#xff0c; 下面这个例程是STM32发AT指令给esp8266&#xff0c;使得esp8266作为tcp client连接到我的手机热点&#xff0c;然后我用电脑连接wifi&#xff0c;打开tcp server&#x…

上海晋名室外气瓶暂存柜海盐项目落地

上周海盐县人民医院武原分院的SAVEST室外气瓶暂存柜项目成功交付验收&#xff0c;此次项目主要用于医院气瓶等室外暂存安全。 用户单位在日常工作运营中涉及到氧气瓶、杜瓦罐等室外安全储存问题&#xff0c;用户在寻找解决方案的过程中搜索到上海晋名的室外气瓶暂存柜系列后挺感…

贪心问题:134. 加油站

https://leetcode.cn/problems/gas-station/ 贪心算法还没找到规律&#xff0c;记录一下该题的思路吧。。。 每个加油站的剩余量rest[i]为gas[i] - cost[i]。 首先如果总油量减去总消耗大于等于零那么一定可以跑完一圈&#xff0c;说明 各个站点的加油站 剩油量rest[i]相加一定…

【AI学习中常见专业英文缩写词的解释】

前言&#xff1a; 为了看着不无聊&#xff0c;文中插入了一些AI生成的狗图片 AI(Artificail Intelligence)人工智能&#xff1a; 让机器模拟和展示人类智能的技术。 GAI(Generative Artificail Intelligence)生成式人工智能: 利用复杂的算法、模型和规则&#xff0c;从大规…

19.leetcode---设计循环队列(Java版)

题目链接:https://leetcode.cn/problems/design-circular-queue/ 题解: 代码: 测试:

LeetCode 506.和为K的子数组

目录 题目描述 方法一 三重循环暴力 思路&#xff1a; 代码&#xff1a; 方法二 暴力一点点前缀和 思路&#xff1a; 代码&#xff1a; 方法三 前缀和哈希表 思路&#xff1a; 代码&#xff1a; 题目描述 给你一个整数数组 nums 和一个整数 k &#xff0c;请你统计并…

超净实验室用耐强酸碱耐高温PFA酸缸进口透明聚四氟塑料方槽

PFA清洗槽是四氟清洗桶后的升级款&#xff0c;主要用于半导体光伏光电等行业&#xff0c;一体成型&#xff0c;无需担心漏液&#xff0c;表面光滑无毛刺。 别名PFA浸泡桶、PFA酸缸、PFA方槽等&#xff0c;可定制尺寸&#xff0c;可配套盖子&#xff0c;盖子有PFA/PTFE两种材质…

idea连接Docker数据库

我们在docker下创建了数据库&#xff0c;想要更方便的查看和操作该数据库&#xff0c;idea和DataGrip或者其他人家都可以。在数据库连接时需要填写数据库名字&#xff0c;主机&#xff0c;端口&#xff0c;数据库用户名和密码。 输入之后先不要点击OK和按Enter键&#xff0c;我…