最近vue3.0响应式原理引起前端阵阵狂热,所以我也下定决心将vue的响应式原理总结一下。
我们都知道vue2.0的响应式原理使用的一个核心API是Object.defineProperty.为我们要观察的数据设置getter和setter方法。
1.响应式数据只有一个的时候,我们可以这样实现
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>vue2.0响应式原理</title>
</head>
<body>
<div id="app">Hello</div>
<script>
const data = {
msg: 'Hello'
}
let vm = {}
Object.defineProperty(vm, 'msg', {
// 可遍历
enumerable: true,
// 可配置
configurable: true,
get() {
console.log('get', data.msg)
return data.msg
},
set(newValue) {
console.log("set", newValue)
if (data.msg === newValue) return
// 不用vm.msg原因是会引起 set方法一致执行从而造成内存泄漏
data.msg = newValue
document.getElementById('app').textContent = data.msg
}
})
// 测试
vm.msg = 'Hello snabbdom'
console.log(vm.msg)
</script>
</body>
</html>
2.如果响应式的数据有多个的时候,那我们就要循环遍历设置getter和setter方法
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Vue2.0响应式原理</title>
</head>
<body>
<div id="app">hello</div>
<script>
const data = {
msg: 'hello',
count: 10
}
let vm = {}
Object.keys(data).forEach(key => {
Object.defineProperty(vm, key, {
// 可遍历
enumerable: true,
// 可配置
configurable: true,
get() {
console.log("get", data[key])
return data[key]
},
set(newValue) {
console.log("set", newValue)
if (newValue === data[key]) {
return
}
// 不用vm[key]因是会引起 set方法一致执行从而造成内存泄漏
data[key] = newValue
document.getElementById('app').textContent = data[key]
}
})
})
// 测试
vm.msg = 'Hello snabbDOM'
vm.count = 100
</script>
</body>
</html>
我们可以看到如果响应式的数据多的时候,我们需要循环遍历data中的每一个key属性,这无疑是造成性能的下降。所以在vue3.0中就改变了这种实现方式而改为ES6中新增的proxy方式来实现。而这个API没有shim,也说明vue3.0彻底摒弃了一些低版本的浏览器。