Vue 2 那个时代基本只有两个技术选型,Facebook 家的 Flow.js 和微软家的 TypeScript
Vue 2 选 Flow.js ,但是现在 Flow.js 已停止维护了
Vue 3 选择了 TypeScript。TS带来更方便的提示,和让代码更健壮
Vue 2 的响应式机制
是基于 Object.defineProperty() API 实现的, defineProperty 的使用,要明确地写在代码里
Object.defineProperty(obj, 'title', {
get() {},
set() {},
})
当项目里“读取 obj.title”和“修改 obj.title”的时候被 defineProperty 拦截,但 defineProperty 对不存在的属性无法拦截,所以 Vue 2 中所有数据必须要在 data 里声明。
而且,如果 title 是一个数组的时候,对数组的操作,并不会改变 obj.title 的指向,虽然可以通过拦截.push 等操作实现部分功能,但是对数组的长度的修改等操作还是无法实现拦截,所以还需要额外的 $set 等 API
Vue 2 新增功能基本都得修改 data、method 等配置,并且代码多了之后,会经常上下data和method之前反复跳,开发很痛苦
Vue 3 的响应式机制
是基于Proxy 代理,并且响应式独立了出来
new Proxy(obj, {
get() { },
set() { },
})
Proxy 拦截 obj 这个数据,Proxy 不关心 obj 具体是什么属性,统一都拦截
vue3所有 API 都是 import 引入的,对 Tree-shaking 很友好,没用到功能,打包的时候会被清理掉
响应式解读
JS 里的变量,是没有响应式这个概念的。 JS被是自上而下执行代码
看下面的代码,即使修改了 count 的值后,double 的值也不会有任何改变。
let count = 1
let double = count * 2
console.log(double) //2
count = 2
console.log(double) //仍然是2
如果我们想让 doube 能够跟着 count 的变化而变化,那么就需要在每次 count 的值修改后,重新计算 double
let count = 1
// 计算过程封装成函数
let getDouble = (n) => n * 2 //箭头函数
let double = getDouble(count)
console.log(double) //2
count = 2
double = getDouble(count) // 再次调用函数,重新计算double
console.log(double) //4
vue2响应机制原理
Object.defineProperty() 直接在一个对象上定义一个新属性,或者修改一个已存在属性,并返回这个对象
3参数:1对象,2对象需要定义或修改的属性名,3属性描述
let getDouble = (n) => n * 2
let obj = {}
let count = 1
let double = getDouble(count)
Object.defineProperty(obj, 'count', {
get() {
return count
},
set(val) {
count = val
double = getDouble(val)
}
})
console.log(double) // 打印2
obj.count = 2
console.log(double) // 打印4 有种自动变化的感觉
但 defineProperty API 作为 Vue 2 实现响应式的原理,它的语法中也有些缺陷。比如我们删除 obj.count 属性,set 函数就不会执行,double 还是之前的数值。这也是为什么在 Vue 2 中,需要 $delete 一个专门的函数去删除数据
vue3响应机制的原理
Proxy 是针对对象来监听,而不是针对某个具体属性,所以不仅可以代理那些定义时不存在的属性,还可以代理更丰富的数据结构,比如 Map、Set 等,并且我们也能通过 deleteProperty 实现对删除操作的代理。
let getDouble = (n) => n * 2
let obj = {}
let count = 1
let double = getDouble(count)
let proxy = new Proxy(obj, {
get: function (target, prop) {
return target[prop]
},
set: function (target, prop, value) {
console.log(target, '-', prop, '-', value) //{} - count - 2
target[prop] = value
if (prop === 'count') {
double = getDouble(value)
}
},
deleteProperty(target, prop) {
delete target[prop]
if (prop === 'count') {
double = NaN
}
}
})
console.log(obj.count, double) //undefined 2
proxy.count = 2 //set(target=obj, prop=count, value=2)
console.log(obj.count, double) //2 4
delete proxy.count
console.log(obj.count, double) //undefined NaN
Vue 3 的 reactive 函数可以把一个对象变成响应式数据,而 reactive 就是基于 Proxy 实现的。
Vue 3 中还有另一个响应式实现,是用 ref 这个 API 的实现。
const b = reactive({ name: 2 }) //reactive 是Proxy对象
console.log(b) //Proxy {name: 2}
const a = ref() // ref 是RefImpl对象
console.log(a) //RefImpl
ref原理类似如下
let getDouble = (n) => n * 2
let _value = 1
double = getDouble(_value)
let count = {
get value() {
return _value
},
set value(val) {
_value = val
double = getDouble(_value)
}
}
console.log(count.value, double) //1 2
count.value = 2
console.log(count.value, double) //2 4
网友评论