在这里,我们 new了一个 vue实例,并且拿到了这个实例 vm ,在这个实例身上,我们在data里面定义了两条状态数据
const vm = new Vue({ //vue 的实例
data: {
title: "学习vue",
index: "数据代理"
}
})
console.log(vm);
当我们这里打印 vm 这个实例时,会发现我们定义的数据,被直接收录在 vm 实例上面。如果我们通过vm.index 或者vm.title,是绝对能够拿到我们的值的
大家如果继续往下看,就会发现,vm 实例身上,还有一个 _data 它身上,也有一个title,和index,并且值,也是我们定义的值 。这里其实就是一个数据代理,,那么可能会有疑问,那是谁代理了谁的数据呢? 这里其实就是,vm实例身上的值,是代理的_data身上的值,你可以这么理解,_data 身上的值才是真正的数据值 。而实例身上的那个值,是代理的_data身上的。
当我们在new vue实例对象的时候,在data里面定义了数据的时候,这时,vue 实例就把我们定义的数据整合到了_data里面,然后_data里面的值,又被实例代理到了最外边,我们通过实例直接.属性名就可以拿到数据了。
这时候大家可能又有疑问,那如果我需要更改实例身上的值,会怎么样?通过vm.index=“XXX”的时候,实例身上的值又是谁呢?通过上面介绍数据代理的概念,可以得知,vm.index和vm._data.index是一样的,它们是一体的。所以说,其中一个值,发生更改,另一个数据,也会同步更改,但这里的同步更改,有点不一样。实际上这里更新的原理是:当我们 vm.index=“XXX” 的时候,并不就是更改的vm.index,而是更改的 vm._data.index 。vm._data.index 更改后,代理_data数据的vm.index,也随着 vm._data.index 的更新而更新。
这里数据代理的原理其实就是用的 Object.defineProperty()的get() set() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
以下例子:
let a = {} //定义一个空对象
Object.defineProperty(a, "name", { //调用方法,参数一:要定义的变量名,参数二:定义的属性名 参数三:一个对象方法
get() { //get当我读取对象属性的时候,get方法触发,并返回一个值
console.log("get调用");
return 100
},
set(value) { //当我修改对象属性值的时候,set 触发,并且接收一个参数(也可接收两个参数),这个参数就是你修改时,赋值的那个值
console.log("set调用", value);
vm._data.index = value;
//这里就好比,我本来修改的是vm.index,触发了set 拿到了 修改的值,我却把值赋给了 vm._data.index
}
})
a.name = "666" //触发set方法
console.log(a.name); //触发get方法
至于为什么要数据代理?
有一方面是为了更加方便的读取和修改data中的数据,
还有一点最核心的就是便于更高效的监视数据的变化,数据状态一发生变化,视图也随之发生变化。