VUE中实现数据代理和数据劫持
1.VUE中实现数据代理
把所有data中的数据代理到new出来的Vue实例上
class Vue {
//options是传过来的参数类似一个对象
constructor(options){
//把options存起来,可能会在实例中用到
this.$options = options
//data可能会是函数
this._data = options.data
this.initData()
}
initData() {
let data = this._data;
//获取到data对象中所有的键
let keys = Object.keys(data)
//循环遍历
for(let i = 0 ; i < keys.length ; i++){
//第一个参数是this也就是Vue实例,现在的目标就是把data中的数据代理到Vue实例上
//第二个参数是需要代理的属性
Object.defineProperty(this,keys[i],{
//设置为true,表示可以被遍历
enumerable:true,
//可以删除属性,或者修改其特性(writable,configurable,enumerable)
configurable:true,
//获取值的时候触发
get:function proxyGetter(){
//获取到的值返回出去
return data[keys[i]]
},
//修改值的时候触发
set:function proxySetter(value) {
//改变值的时候,给获取到的值赋值新值value
data[keys[i]] = value
}
})
}
}
}
//测试,设置和获取值 自己在控制台上测试一下设置和取值
<script>
let vm = new Vue({
data:{
list:[1,2,3,4],
msg:'10086'
}
})
</script>
2.Vue中数据代理和数据劫持
上边数据代理把所有data中的数据代理到new出来的Vue实例上,这样的话,就是对Vue实例上数据的存取等同于对data数据的存取,但是data本身还不是一个响应式的,对data的存取还没有触发我们想要的回调函数,所以用上Vue数据劫持
class Vue {
//options是传过来的参数类似一个对象
constructor(options){
//把options存起来,可能会在实例中用到
this.$options = options
//data可能会是函数
this._data = options.data
this.initData()
}
initData() {
let data = this._data;
//获取到data对象中所有的键
let keys = Object.keys(data)
//循环遍历 实现数据代理到Vue实例上,
for(let i = 0 ; i < keys.length ; i++){
Object.defineProperty(this,keys[i],{
//设置为true,表示可以被遍历
enumerable:true,
//可以删除属性,或者修改其特性(writable,configurable,enumerable)
configurable:true,
//获取值的时候触发
get:function proxyGetter(){
//获取到的值返回出去
return data[keys[i]]
},
//修改值的时候触发
set:function proxySetter(value) {
//改变值的时候,给获取到的值赋值新值value
data[keys[i]] = value
}
})
}
//调研判断是基本类型还是复杂类型的数据 来实现数据劫持
observe(data)
}
}
//判断类型的函数observe
/**
*
*
* @param {*} data
*/
function observe(data) {
//判断data的数据类型
let type = Object.prototype.toString.call(data)
//如果是基本类型就直接返回
if(type !== '[object Object]' && type !== '[object Array]'){
return
}
//如果是复杂类型,new一个实例
new Observer(data)
}
//创建一个观察值类,观察data中的数据变化
class Observer {
constructor(data) {
//调用函数
this.walk(data)
}
//walk函数
walk(data) {
let keys = Object.keys(data)
for(let i = 0; i < keys.length; i++){
//代用抽离出去的函数,此时是实现data中的数据劫持,使data成为响应式的
//第一个参数就是data对象,第二个是属性,第三个是改变之前的值
defineReactive(data,keys[i],data[keys[i]])
}
}
}
//抽离函数
/**
*
*
* @param {*} obj 传进来的对象
* @param {*} key 属性
* @param {*} value 之前的值
*/
function defineReactive(obj,key,value){
//递归,判断数据类型
observe(obj[key])
Object.defineProperty(obj,key,{
enumerable:true,
configurable:true,
//获取到属性值时调用该函数
get:function reactiveGetter(){
console.log(`${key}数据劫持取值`)
//或取到的值返回出去
return value
},
//设置值的时候掉用该函数
set:function reactiveSetter(val){
//对比新设置的值和原来的值是否相同
if(val === value){
//相同的话直接返回
return
}
//否则,设置新值
console.log(`${key}数据劫持的值发生变化`)
value = val
}
})
}
//测试
let vm = new Vue({
data:{
message:'hello',
person:{
name:'zs',
city:{
cityName:'wuhan'
}
}
}
})
vm.person.city.cityName = 'beijing'
//打印结果
person数据劫持取值
city数据劫持取值
cityName数据劫持的值发生变化