普通的数据代理(数据劫持)就是利用
Object.defineProperty()来给对象添加属性值或者修改某值,数据代理是通过一个对象代理对另一个对象中的属性进行操作,在Vue中是将data中的属性代理到了Vue实例中,并将data数据存放到了_data中进行保存。但是它不支持监听数组的变化,Vue 2.x 使用的是 Object.defineProperty()(Vue 在 3.x 版本之后改用 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>数据代理</title>
<!-- 数据代理是通过一个对象代理对另一个对象中的属性进行操作 -->
</head>
<body>
<script>
let obj1 = {
x: 100
}
let obj2 = {
y: 300
}
Object.defineProperty(obj2, 'x', {
get() {
return obj1.x
},
set(value) {
obj1.x = value
}
})
</script>
</body>
</html>
Proxy
Proxy 在 ES2015 规范中被正式加入,它的支持度虽然不如 Object.defineProperty(),但其实也基本支持了 (除了 IE 和 Opera Mini 等少数浏览器,所以使用起来问题也不太大。
在数据劫持这个问题上,Proxy 可以被认为是 Object.defineProperty() 的升级版。外界对某个对象的访问,都必须经过这层拦截。因此它是针对 整个对象,而不是 对象的某个属性,所以也就不需要对 keys 进行遍历。这解决了上述 Object.defineProperty() 的第二个问题。并且支持数组。
let obj = {
name: 'Eason',
age: 30
}
let handler = {
get (target, key, receiver) {
console.log('get', key)
return Reflect.get(target, key, receiver)
},
set (target, key, value, receiver) {
console.log('set', key, value)
return Reflect.set(target, key, value, receiver)
}
}
let proxy = new Proxy(obj, handler)
proxy.name = 'Zoe' // set name Zoe
proxy.age = 18 // set age 18
let arr = [1,2,3]
let proxy = new Proxy(arr, {
get (target, key, receiver) {
console.log('get', key)
return Reflect.get(target, key, receiver)
},
set (target, key, value, receiver) {
console.log('set', key, value)
return Reflect.set(target, key, value, receiver)
}
})
proxy.push(4)
// 能够打印出很多内容
// get push (寻找 proxy.push 方法)
// get length (获取当前的 length)
// set 3 4 (设置 proxy[3] = 4)
// set length 4 (设置 proxy.length = 4)