vue3的响应式操作劫持
vue3响应式劫持操作主要用到了es6中的Proxy代理 与Reflect执行原有操作行为;
劫持操作 判断是否使用作为判断的指定属性名
//如
if (prop === '_is_readonly') return true;
前提定义
// 定义 readonlyHandler 处理函数
const readonlyHandler = {
get(target, prop) {
if (prop === '_is_readonly') return true;
const result = Reflect.get(target, prop);
console.log('拦截到了读取数据', prop, result);
return result
},
set(target, prop, value) {
console.warn("只能读取数据,不能修改数据或者添加数据");
return true;
},
deleteProperty(target, prop) {
console.log('只能读取数据,不能删除数据');
return true;
}
}
// 定义一个shallowReadonly函数
function shallowReadonly(target) {
// 需要判读当前的数据是不是对象
if (target && typeof target === 'object') {
return new Proxy(target, readonlyHandler)
}
return target
}
// 定义一个readonly 函数
function readonly(target) {
// 需要判读当前的数据是不是对象
if (target && typeof target === 'object') {
// 判断target是不是数组
if (Array.isArray(target)) {
target.forEach((item, index) => {
target[index] = readonly(item);
})
}
// 判断target是否是对象
else {
// 遍历对象
Object.keys(target).forEach(key => {
target[key] = readonly(target[key]);
})
}
return new Proxy(target, readonlyHandler)
}
// 如果不是对象或者数组 自己返回
return target
}
// 定义一个reactiveHandler处理对象
const reactiveHandler = {
// 获取属性值
get(target, prop) {
if (prop === '_is_reactive') return true
const result = Reflect.get(target, prop);
console.log('拦截了读取数据', prop, result);
return result
},
// 修改属性值/添加属性
set(target, prop, value) {
const result = Reflect.set(target, prop, value);
console.log('拦截了修改属性值或者是添加属性', prop, value);
return result
},
deleteProperty(target, prop) {
const result = Reflect.deleteProperty(target, prop);
console.log('拦截了删除数据', prop);
return result
}
}
function reactive(target) {
// 判断当前的目标对象是否是object类型(对象/数组)
if (target && typeof target === 'object') {
// 对数组或者对象中所有的数据进行reactive的递归处理
// 判断当前的数据是否是数组
if (Array.isArray(target)) {
// 数组的数据进行遍历操作
target.forEach((item, index) => {
target[index] = reactive(item)
})
} else {
// 判断当前的数据是否是对象
// 对象的数据也要进行遍历的操作
Object.keys(target).forEach((key) => {
target[key] = reactive(target[key])
})
}
return new Proxy(target, reactiveHandler)
}
// 如果传入的目标对象是基本类型的数据,则直接返回
return target
}
// 定义一个sallowRef函数
function shallowRef(target) {
return {
// 保存target数据保存起来
_value: target,
get value() {
console.log('劫持得到了读取数据');
return this._value
},
set value(value) {
console.log("劫持到了修改数据,",
value);
this._value = value;
}
}
}
// 定义一个ref函数
function ref(target) {
target = reactive(target);
return {
// 标识当前对象时ref对象
_is_ref: true,
// 保存target数据保存起来
_value: target,
get value() {
console.log('劫持得到了读取数据');
return this._value
},
set value(value) {
console.log("劫持到了修改数据,",
value);
this._value = value;
}
}
}
定义 函数
// 定义 一个函数isRef,判断当前的对象是不是ref对象
function isRef(obj) {
return obj && obj._is_ref
}
// 定义一个函数isReactive,判断当前的对象是不是reactive对象
function isReactive(obj) {
return obj && obj._is_reactive
}
// 定义一个函数isReadonly,判断当前的对象是不是readonly对象
function isReadonly(obj) {
return obj && obj._is_readonly
}
// 定义一个函数isProxy,判断当前的对象是不是reactive对象或者readonly对象
function isProxy(obj) {
return isReactive(obj) || isReadonly(obj);
}
检验
console.log('isRef', isRef(ref({})));
console.log('isReactive', isReactive(reactive({})));
console.log('isReadonly', isReadonly(readonly({})));
console.log('isProxy', isProxy(readonly({})));
console.log('isProxy', isProxy(reactive({})));
测试完整代码
index.js
/*
* @Descripttion:
* @version:
* @Author: HHH
* @Date: 2021-02-22 17:12:08
* @LastEditors: HHH
* @LastEditTime: 2021-02-23 14:00:14
*/
// 定义 readonlyHandler 处理函数
const readonlyHandler = {
get(target, prop) {
if (prop === '_is_readonly') return true;
const result = Reflect.get(target, prop);
console.log('拦截到了读取数据', prop, result);
return result
},
set(target, prop, value) {
console.warn("只能读取数据,不能修改数据或者添加数据");
return true;
},
deleteProperty(target, prop) {
console.log('只能读取数据,不能删除数据');
return true;
}
}
// 定义一个shallowReadonly函数
function shallowReadonly(target) {
// 需要判读当前的数据是不是对象
if (target && typeof target === 'object') {
return new Proxy(target, readonlyHandler)
}
return target
}
// 定义一个readonly 函数
function readonly(target) {
// 需要判读当前的数据是不是对象
if (target && typeof target === 'object') {
// 判断target是不是数组
if (Array.isArray(target)) {
target.forEach((item, index) => {
target[index] = readonly(item);
})
}
// 判断target是否是对象
else {
// 遍历对象
Object.keys(target).forEach(key => {
target[key] = readonly(target[key]);
})
}
return new Proxy(target, readonlyHandler)
}
// 如果不是对象或者数组 自己返回
return target
}
// 定义一个reactiveHandler处理对象
const reactiveHandler = {
// 获取属性值
get(target, prop) {
if (prop === '_is_reactive') return true
const result = Reflect.get(target, prop);
console.log('拦截了读取数据', prop, result);
return result
},
// 修改属性值/添加属性
set(target, prop, value) {
const result = Reflect.set(target, prop, value);
console.log('拦截了修改属性值或者是添加属性', prop, value);
return result
},
deleteProperty(target, prop) {
const result = Reflect.deleteProperty(target, prop);
console.log('拦截了删除数据', prop);
return result
}
}
function reactive(target) {
// 判断当前的目标对象是否是object类型(对象/数组)
if (target && typeof target === 'object') {
// 对数组或者对象中所有的数据进行reactive的递归处理
// 判断当前的数据是否是数组
if (Array.isArray(target)) {
// 数组的数据进行遍历操作
target.forEach((item, index) => {
target[index] = reactive(item)
})
} else {
// 判断当前的数据是否是对象
// 对象的数据也要进行遍历的操作
Object.keys(target).forEach((key) => {
target[key] = reactive(target[key])
})
}
return new Proxy(target, reactiveHandler)
}
// 如果传入的目标对象是基本类型的数据,则直接返回
return target
}
// 定义一个sallowRef函数
function shallowRef(target) {
return {
// 保存target数据保存起来
_value: target,
get value() {
console.log('劫持得到了读取数据');
return this._value
},
set value(value) {
console.log("劫持到了修改数据,",
value);
this._value = value;
}
}
}
// 定义一个ref函数
function ref(target) {
target = reactive(target);
return {
// 标识当前对象时ref对象
_is_ref: true,
// 保存target数据保存起来
_value: target,
get value() {
console.log('劫持得到了读取数据');
return this._value
},
set value(value) {
console.log("劫持到了修改数据,",
value);
this._value = value;
}
}
}
// 定义 一个函数isRef,判断当前的对象是不是ref对象
function isRef(obj) {
return obj && obj._is_ref
}
// 定义一个函数isReactive,判断当前的对象是不是reactive对象
function isReactive(obj) {
return obj && obj._is_reactive
}
// 定义一个函数isReadonly,判断当前的对象是不是readonly对象
function isReadonly(obj) {
return obj && obj._is_readonly
}
// 定义一个函数isProxy,判断当前的对象是不是reactive对象或者readonly对象
function isProxy(obj) {
return isReactive(obj) || isReadonly(obj);
}
index.html
<!--
* @Descripttion:
* @version:
* @Author: HHH
* @Date: 2021-02-22 16:04:16
* @LastEditors: HHH
* @LastEditTime: 2021-02-23 14:00:40
-->
<!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>Document</title>
<script src="./index.js"></script>
</head>
<body>
<script type="text/javascript">
console.log('isRef', isRef(ref({})));
console.log('isReactive', isReactive(reactive({})));
console.log('isReadonly', isReadonly(readonly({})));
console.log('isProxy', isProxy(readonly({})));
console.log('isProxy', isProxy(reactive({})));
</script>
</body>
</html>