Vue3设计思路 -- 响应式API,挑战华为社招

47 阅读4分钟

更多面试题

**《350页前端校招面试题精编解析大全》**内容大纲主要包括 HTML,CSS,前端基础,前端核心,前端进阶,移动端开发,计算机基础,算法与数据结构,项目,职业发展等等

开源分享:docs.qq.com/doc/DSmRnRG… })

setInterval(() => {

state.count++

}, 1000);

return state

}

const app = createApp({

setup(){

const state = useState()

return {state}

console.log('hello world')

}

})

app.mount('#app')

  • 因为vue3的响应式是基于Proxy的,所以为了这套更优雅的代码也不得不做出让步,没有办法兼容不支持Proxy的浏览器,如果浏览器不支持Proxy,就只能使用Vue2了

响应式实现的过程及原理

首先要明白的是能实现响应式其实靠的就是Proxy,其可以让我们知道何时触发了获取和修改事件。

几个关键的名词
  • effect 副作用函数

  • track 绑定值与副作用函数

  • trigger指定值的所有副作用函数执行

逻辑链路

响应式本质上是有在内存中存一种数据结构,类似于{state:{title:[effect,effect]}},其实efftec就是一个个的可以触发页面更新的函数,只要当这里的title更新了,就去遍历title对应的副作用数组,分别去触发即可实现页面的响应式更新

依赖收集与触发

整体思路就是:第一次初始化的时候就会触发第一次的effecteffect触发页面第一次更新,因为是proxy数据第一次更新只要有拿响应式对象的值就会触发track(依赖收集),之后我们修改响应式对象的值又会触发Proxysetset再触发trigger更新页面页面数据

非常的绕,但是多看代码多理解几次就能理解了,要手写下来确实是需要有很深的功力,我是肯定写不下来的,只能跟着视频操作边理解变操作的写下来,确实对依赖收集的概念有了很深的理解

上代码 – 这里主要要从reactive函数开始看

function reactive(obj) {

const proxy = new Proxy(obj, {

get(target, key) {

/*

render函数第一次渲染的时候会获取引用的值 所以第一次渲染就会走到这个 get 方便我们开始做依赖收集

*/

track(target, key) // 触发依赖收集

return target[key]

},

set(target, key, value) {

target[key] = value

console.log('proxy', key)

/*

修改的时候,去依赖收集的数据结构中 找到对应的key 把 key 对应的 更新函数都执行一遍,这就触发了页面的响应式

*/

trigger(target, key)

// app.update()

}

/*

proxy 的优势出了可以监听get 和 set之外 还是可以监听另外十多种情况,这个Object.defineProperty()做不到的

这个是语言层面上的升级

*/

})

return proxy

}

// 副作用函数 -- 这里是为了暂时的存放每一个副作用函数,当副作用函数已经和依赖关系建立好了之后再清除空间

const effectStack = []

function effect(fn) {

const eff = function () {

try {

effectStack.push(eff)

fn() // 执行 最重要的 render函数 页面才更新

} finally {

effectStack.pop()

}

}

eff()

return eff

}

// 依赖收集函数

/*

依赖收集的数据结构是这样的

{

state:{

title:[effect,effect] // effect 对应的就是一个个的更新函数,每个响应式对象的值都是存着更新函数的数组,当这个值变化的时候遍历执行数组里面的一个个effect函数

}

}

*/

const trackMap = {}

function track(target, key) {

/*

effectStack 是临时存放副作用函数的地方,每次关系建立完成之后就会再清空掉,所以获取数组的最后一个元素即可

*/

const effect = effectStack[effectStack.length - 1]

if (effect) {

let map = trackMap[target]

if (!map) {

map = trackMap[target] = {}

}

let deps = map[key]

if (!deps) {

deps = map[key] = []

}

// 将副作用函数放入 deps

if (deps.indexOf(effect) === -1) {

deps.push(effect)

}

}

}

// 触发 指定的 target 下指定的key 下所有的 副作用函数都执行一遍

function trigger(target, key) {

// 数据结构类似 {state:{title:[effect,effect]}}

const map = trackMap[target]

if (map) {

const effects = map[key]

effects.forEach(effect => effect())

}

}

function createApp(config) {

let app = {}

app.mount = function (id) {

this.rootDOM = document.getElementById(id)

if (!config.render) {

config.render = this.compile(this.rootDOM.innerHTML)

}

if (config.setup) {

this.setupCtx = config.setup()

} else {

this.dataCtx = config.data()

}

this.proxy = new Proxy(this, {

get(target, key) {

if (key in target.setupCtx) {

return target.setupCtx[key]

} else {

return target.dataCtx[key]

}

},

算法

  1. 冒泡排序

  2. 选择排序

  3. 快速排序

  4. 二叉树查找: 最大值、最小值、固定值

  5. 二叉树遍历

  6. 二叉树的最大深度

  7. 给予链表中的任一节点,把它删除掉

  8. 链表倒叙

  9. 如何判断一个单链表有环

由于篇幅限制小编,pdf文档的详解资料太全面,细节内容实在太多啦,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】