核心
-
主要是处于性能上面的考虑。
-
如果对象有 100 个属性,Object.defineProperty 要循环 100 次来劫持每一个属性;
-
而由于 Proxy 直接可以代理整个对象,一次就可以搞定,免去了循环100次来劫持每个属性的性能消耗。
-
Object.defineProperty对后面新增的数据无法实现数据的双向绑定,而 Proxy 对后续新增的属性也具有响应式。
接下来给大家从代码,详细分析下两者的区别,性能提高提现在了哪里。
Vue2中的通过Object.defineProperty实现数据的劫持
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<p id="oP"></p>
<input type="text" id="oInput">
<script>
const data = {
name: '张三丰',
age: 18,
};
// console.log(data)
// 数据劫持:就是把数据都变成 getter/setter 形式,能做到对数据操作的时候,也能添加一些额外的功能(例如修改视图)
// 对象、属性、描述/配置
const copyData = { ...data };
// ['name', 'age']
Object.keys(data).forEach(key => {
Object.defineProperty(data, key, {
get() {
// !这儿给了你自由,获取数据的时候想干啥干啥
// 获取 name 的时候,会触发这儿
return copyData[key]
},
set(newValue) {
// #1
oP.innerHTML = newValue
oInput.value = newValue
// 设置 name 的时候,会触发这儿
copyData[key] = newValue
}
});
})
oInput.oninput = function (e) {
// 边输入,边设置,边触发 #1 处的 set
data.name = e.target.value
}
</script>
</body>
</html>
从代码中可以看到,Object.defineProperty实现数据的劫持,用到了for循环,也就是说,如果你的数据越大,那么性能消耗的也就随着变大。
Vue3 中的Proxy实现数据的劫持
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<p id="oP"></p>
<input type="text" id="oInput">
<script>
const data = {};
// proxyData => 代理对象
// 对代理的操作 proxyData => 会影响到原始值 data
const proxyData = new Proxy(data, {
get(target, attr) {
// 获取数据的时候会触发这儿
// target => 原数据
// attr => 属性
// console.log(target === data)
return target[attr]
},
set(target, attr, newValue) {
oP.innerHTML = newValue
oInput.value = newValue
// 设置数据的时候会触发这儿
target[attr] = newValue
}
})
oInput.oninput = function (e) {
proxyData.address = e.target.value
}
</script>
</body>
</html>
总结:
- 两者对比,不难看出,两者的数据劫持都用到了set和get的方法,但是明显可以看出来,Proxy中的数据劫持,并没有用到循环,也就是性能上面的一个提升。
- Proxy中他劫持的是整个对象,包含了后面新增的一些属性,也能够实现数据的响应式变化,而Object.defineProperty是通过循环遍历的原来对象的键,因此后面加进来的属性,无法实现响应式的变化。