0.回顾Object.defineProperty()方法
let number = 18
let person = {
name:'张三',
sex:'男',
}
Object.defineProperty(person,'age',{
// value:18,
// enumerable:true, //控制属性是否可以枚举,默认值是false
// writable:true, //控制属性是否可以被修改,默认值是false
// configurable:true //控制属性是否可以被删除,默认值是false
//当有人读取person的age属性时,get函数(getter)就会被调用,且返回值就是age的值
get(){
console.log('有人读取age属性了')
return number
},
//当有人修改person的age属性时,set函数(setter)就会被调用,且会收到修改的具体值
set(value){
console.log('有人修改了age属性,且值是',value)
number = value
}
})
1.数据代理
- Vue中的数据代理:
通过vm对象来代理data对象中属性的操作(读/写) - Vue中数据代理的好处:
更加方便的操作data中的数据 - 基本原理:
- 通过Object.defineProperty()把data对象中所有属性添加到vm上。
- 为每一个添加到vm上的属性,都指定一个getter/setter。
- 在getter/setter内部去操作(读/写)data中对应的属性。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>何为数据代理</title>
</head>
<body>
<!-- 数据代理:通过一个对象代理对另一个对象中属性的操作(读/写)-->
<script type="text/javascript" >
let obj = {x:100}
let obj2 = {y:200}
Object.defineProperty(obj2,'x',{
get(){
return obj.x
},
set(value){
obj.x = value
}
})
</script>
</body>
</html>
2.数据劫持
定义一个Observer (数据的观察者),使用Object.defineProperty()来劫持各个属性,让数据对象的读写操作都处于自己的监管之下。
- 劫持一层数据结构的数据
//创建一个监视的实例对象,用于监视data中属性的变化
const obs = new Observer(data)
console.log(obs)
//准备一个vm实例对象
let vm = {}
vm._data = data = obs
//下面的方法只能解析一层解构,多层数据结构需要用到递归
function Observer(obj){
//汇总对象中所有的属性形成一个数组
const keys = Object.keys(obj)
//遍历
keys.forEach((k)=>{
Object.defineProperty(this,k,{
get(){
return obj[k]
},
set(val){
console.log(`${k}被改了,我要去解析模板,生成虚拟DOM.....我要开始忙了`)
obj[k] = val
}
})
})
}
- 劫持多层数据结构的数据
observer(data)
function observer(target) {
if (typeof target !== 'object' || !target) {
return target
}
for (const key in target) {
if (target.hasOwnProperty(key)) {
const value = target[key]
observerObject(target, key, value)
}
}
}
function observerObject(target, name, value) {
if (typeof value === 'object' || Array.isArray(target)) {
observer(value);
}
Object.defineProperty(target, name, {
get() {
return value
},
set(newVal) {
if (newVal !== value) {
if (typeof value === 'object' || Array.isArray(value)) {
observer(value)
}
value = newVal
}
renderView() //模拟视图渲染操作
}
})
}