1 vue2
Vue2.0中使用ES5中的Object.defineProperty方法实现响应式数据
缺点
无法监测到对象属性的动态添加和删除
无法监测到数组的下标和length属性的变更
解决方案
Vue2.0提供Vue.set方法用于动态给对象添加属性
Vue2.0提供Vue.delete方法用于动态删除对象的属性
重写vue中数组的方法,用于监测数组的变更
<body>
<script>
// vue会做一个数据劫持,,,监视数据的变化,一旦数据变化了,更新DOM
const data = {
name: 'zs',
age: 18
}
for (let k in data) {
let temp = data[k]
Object.defineProperty(data, k, {
get() {
console.log(`我劫持了${k}的获取`)
return temp
},
set(value) {
console.log(`我劫持了${k}的设置,值${value}`)
temp = value
}
})
}
// Object.defineProperty有缺点
// 1. 无法监视到新增的属性的变更和删除
// 2. 无法劫持到数组的下标和长度
</script>
</body>
<body>
<div id="app">
<h1>vue的例子</h1>
<p>{{car.brand}} --- {{car.color}} ---{{car.price}}</p>
<p>{{arr}}</p>
</div>
<script src="https://unpkg.com/vue@2.6.12/dist/vue.js"></script>
<script>
// vue中需要使用$set方法动态的增加一个响应式属性
const vm = new Vue({
el: '#app',
data: {
car: {
brand: '奔驰',
color: 'blue'
},
arr: ['张三', '李四']
}
})
</script>
</body>
2 vue3
通过Proxy(代理): 拦截对data任意属性的任意(13种)操作, 包括属性值的读写, 属性的添加, 属性的删除等...
通过 Reflect(反射): 动态对被代理对象的相应属性进行特定的操作
Vue3.0中使用ES6中的proxy语法实现响应式数据
优点
可以检测到代理对象属性的动态添加和删除
可以监测到数组的下标和length属性的变更
缺点
ES6的proxy语法对于低版本浏览器不支持,IE11
Vue3.0会针对于IE11出一个特殊的版本用于支持ie11
<body>
<div></div>
<script>
const data = {
name: 'zs',
age: 18
}
// 能够监测到对象动态新增的属性以及删除的属性
// proxy
const proxyData = new Proxy(data, {
get(target, name) {
console.log(`检测到${name}的获取`)
return target[name]
},
set(target, name, value) {
console.log(`检测到${name}的设置,值为${value}`)
target[name] = value
},
deleteProperty(target, key) {
console.log(`监测到删除${key}`)
return delete target[key]
}
})
</script>
</body>
<body>
<div id="app">
<h1>vue的例子</h1>
<p>{{car.brand}} --- {{car.color}} ---{{car.price}}</p>
<p>{{arr}}</p>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
const App = {
data() {
return {
car: {
brand: '宝马',
color: 'green'
},
arr: ['张三', '李四']
}
},
methods: {
fn() {
this.car.brand = '奔驰' //不再需要vue2中的$set方法就用代理更新
// 会在DOM更新后才会执行回调函数
nextTick(function () {
// vue为了性能考虑,不会改变完数据就立即更新DOM
console.log(document.querySelector('p').innerHTML)
})
}
}
}
const vm = Vue.createApp(App).mount('#app')
</script>
</body>
new Proxy(data, {
// 拦截读取属性值
get (target, prop) {
return Reflect.get(target, prop)
},
// 拦截设置属性值或添加新属性
set (target, prop, value) {
return Reflect.set(target, prop, value)
},
// 拦截删除属性
deleteProperty (target, prop) {
return Reflect.deleteProperty(target, prop)
}
})
proxy.name = 'tom'
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Proxy 与 Reflect</title>
</head>
<body>
<script>
const user = {
name: "John",
age: 12
};
/*
proxyUser是代理对象, user是被代理对象
后面所有的操作都是通过代理对象来操作被代理对象内部属性
*/
const proxyUser = new Proxy(user, {
get(target, prop) {
console.log('劫持get()', prop)
return Reflect.get(target, prop)
},
set(target, prop, val) {
console.log('劫持set()', prop, val)
return Reflect.set(target, prop, val); // (2)
},
deleteProperty (target, prop) {
console.log('劫持delete属性', prop)
return Reflect.deleteProperty(target, prop)
}
});
// 读取属性值
console.log(proxyUser===user)
console.log(proxyUser.name, proxyUser.age)
// 设置属性值
proxyUser.name = 'bob'
proxyUser.age = 13
console.log(user)
// 添加属性
proxyUser.sex = '男'
console.log(user)
// 删除属性
delete proxyUser.sex
console.log(user)
</script>
</body>
</html>