Vue源码解读学习

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.datathis._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 = newValdep.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 = nullclass Watch {constructor(vm, render, cb) {this.vm = vmthis.render = renderthis.cb = cbthis.deps = []this.depsIds = new Set()this.newDeps = []this.newDepsIds = new Set()this.value = this.get()this.cb(this.value)}get() {Dep.target = thisthis.newDeps = []this.newDepsIds = new Set()const value = this.render()Dep.target = nullthis.deps.forEach(oldDep => {const notExistInNewDeps = !this.newDepsIds.has(oldDep.id)if (notExistInNewDeps) {oldDep.removeSub(this)}})this.deps = this.newDepsthis.depsIds = this.newDepsIdsreturn value}addDep(dep) {const depId = dep.idif (!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.mzph.cn/pingmian/6.shtml

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

相关文章

解决npm run dev跑项目,发现node版本不匹配,怎么跑起来?【已解决】

首先问题点就是我们npm run dev 运行项目的时候发现出错&#xff0c;跑不起来&#xff0c;类型下面这种 这里的出错的原因在于我们的node版本跟项目的版本不匹配 解决办法 我这里的问题是我的版本是node14的&#xff0c;然后项目需要node20的&#xff0c;执行下面的就可以正…

html接入高德地图

1.申请key key申请地址&#xff1a;https://console.amap.com/dev/key/app 官方文档 https://lbs.amap.com/api/javascript-api-v2/summary 2.html接入示例 需要将YOUR_KEY替换成自己的key <!doctype html> <html> <head><meta charset"utf-…