当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty
把这些 property 全部转为 getter/setter。
文章图片
数据劫持
vue2中数据劫持使用了Object.defineProperty
来实现Object.defineProperty(obj, prop, descriptor)
参数
- obj要定义属性的对象。
- prop要定义或修改的属性的名称或 Symbol 。
- descriptor要定义或修改的属性描述符。
模拟vue中的data选项
// 模拟 Vue 中的 data 选项
let data = https://www.it610.com/article/{
msg:'hello'
}// 模拟 Vue 的实例
let vm = {}// 数据劫持:当访问或者设置 vm 中的成员的时候,做一些干预操作
Object.defineProperty(vm, 'msg', {
// 可枚举(可遍历)
enumerable: true,
// 可配置(可以使用 delete 删除,可以通过 defineProperty 重新定义)
configurable: true,
// 当获取值的时候执行
get () {
console.log('get: ', data.msg)
return data.msg
},
// 当设置值的时候执行
set (newValue) {
console.log('set: ', newValue)
if (newValue =https://www.it610.com/article/== data.msg) {
return
}
data.msg = newValue
// 数据更改,更新 DOM 的值
document.querySelector('#app').textContent = data.msg
}
})// 测试
vm.msg = 'Hello World'
console.log(vm.msg)
文章图片
当data对象中有多个属性时,此时需要遍历vm,把每一个属性都转换成vm中的getter和setter
// 模拟 Vue 中的 data 选项
let data = https://www.it610.com/article/{
msg:'hello',
count: 10
}// 模拟 Vue 的实例
let vm = {}proxyData(data)function proxyData(data) {
// 遍历 data 对象的所有属性
Object.keys(data).forEach(key => {
// 把 data 中的属性,转换成 vm 的 setter/setter
Object.defineProperty(vm, key, {
enumerable: true,
configurable: true,
get () {
console.log('get: ', key, data[key])
return data[key]
},
set (newValue) {
console.log('set: ', key, newValue)
if (newValue =https://www.it610.com/article/== data[key]) {
return
}
data[key] = newValue
// 数据更改,更新 DOM 的值
document.querySelector('#app').textContent = data[key]
}
})
})
}// 测试
vm.msg = 'Hello World'
console.log(vm.msg)
文章图片
vue3中的数据劫持使用了ES6中的Proxy来实现,他可以代理一整个对象
const p = new Proxy(target, handler)
参数
- target要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
- handler一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。即执行代理行为的函数
const handler = {
get: function(obj, prop) {
return prop in obj ? obj[prop] : 37;
}
};
const p = new Proxy({}, handler);
p.a = 1;
p.b = undefined;
console.log(p.a, p.b);
// 1, undefined
console.log('c' in p, p.c);
// false, 37
测试示例
hello