Vue3的响应式原理解析,开发一个web站点

13 阅读2分钟
Vue2响应式原理回顾

// 1.对象响应化:遍历每个key,定义getter、setter

// 2.数组响应化:覆盖数组原型方法,额外增加通知逻辑

const originalProto = Array.prototype

const arrayProto = Object.create(originalProto)

;['push', 'pop', 'shift', 'unshift', 'splice', 'reverse', 'sort'].forEach(

method => {

arrayProto[method] = function () {

originalProto[method].apply(this, arguments)

notifyUpdate()

}

}

)

function observe (obj) {

if (typeof obj !== 'object' || obj == null) {

return

}

// 增加数组类型判断,若是数组则覆盖其原型

if (Array.isArray(obj)) {

Object.setPrototypeOf(obj, arrayProto)

} else {

const keys = Object.keys(obj)

for (let i = 0; i < keys.length; i++) {

const key = keys[i]

defineReactive(obj, key, obj[key])

}

}

}

function defineReactive (obj, key, val) {

observe(val) // 解决嵌套对象问题

Object.defineProperty(obj, key, {

get () {

return val

},

set (newVal) {

if (newVal !== val) {

observe(newVal) // 新值是对象的情况

val = newVal

notifyUpdate()

}

}

})

}

function notifyUpdate () {

console.log('页面更新!')

}

vue2响应式弊端:

响应化过程需要递归遍历,消耗较大

新加或删除属性无法监听

数组响应化需要额外实现

Map、Set、Class等无法响应式

修改语法有限制

Vue3响应式原理剖析

vue3使用ES6的Proxy特性来解决这些问题。

function reactive (obj) {

if (typeof obj !== 'object' && obj != null) {

return obj

}

// Proxy相当于在对象外层加拦截

// es6.ruanyifeng.com/#docs/proxy

const observed = new Proxy(obj, {

get (target, key, receiver) {

// Reflect用于执行对象默认操作,更规范、更友好

// Proxy和Object的方法Reflect都有对应

// es6.ruanyifeng.com/#docs/refle…

const res = Reflect.get(target, key, receiver)

console.log(获取${key}:${res})

return res

},

set (target, key, value, receiver) {

const res = Reflect.set(target, key, value, receiver)

console.log(设置${key}:${value})

return res

},

deleteProperty (target, key) {

const res = Reflect.deleteProperty(target, key)

console.log(删除${key}:${res})

return res

}

})

return observed

}

//代码测试

const state = reactive({

foo: 'foo',

bar: { a: 1 }

})

// 1.获取

state.foo // ok

// 2.设置已存在属性

state.foo = 'fooooooo' // ok

// 3.设置不存在属性

state.dong = 'dong' // ok

// 4.删除属性

delete state.dong // ok

嵌套对象响应式

测试:嵌套对象不能响应

// 设置嵌套对象属性

react.bar.a = 10 // no ok

添加对象类型递归

// 提取帮助方法

const isObject = val => val !== null && typeof val === 'object'

function reactive (obj) {

//判断是否对象

总结一下

面试前要精心做好准备,简历上写的知识点和原理都需要准备好,项目上多想想难点和亮点,这是面试时能和别人不一样的地方。

还有就是表现出自己的谦虚好学,以及对于未来持续进阶的规划,企业招人更偏爱稳定的人。

万事开头难,但是程序员这一条路坚持几年后发展空间还是非常大的,一切重在坚持。

为了帮助大家更好更高效的准备面试,特别整理了《前端工程师面试手册》电子稿文件。

前端面试题汇总

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