vue3手写isRefisReactiveisReadonlyisProxy

Posted web半晨

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue3手写isRefisReactiveisReadonlyisProxy相关的知识,希望对你有一定的参考价值。


1、包含的功能及函数

isRef、isReactive、isReadonly、isProxy、shallowReactive、reactive、shallowReadonly、readonly、shallowRef、ref


2、函数实现

// 定义一个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;
  


// 01--------------------------------------
// shallowReactive
// 定义一个shallowReactive函数,传入一个目标对象
function shallowReactive(target) 
  // 判断当前的目标对象是不是object类型(对象/数组)
  if (target && typeof target === 'object') 
    return new Proxy(target, reactiveHandler);
  
  // 如果传入的数据是基本类型的数据,那么就直接返回
  return target;


// 02--------------------------------------
// reactive
// 定义一个reactive函数,传入一个目标对象
function reactive(target) 
  // 判断当前的目标对象是不是object类型(对象/数组)
  if (target && typeof target === 'object') 
    // 对数组或者是对象中所有的数据进行reactive的递归处理
    // 先判断当前的数据是不是数组
    if (Array.isArray(target)) 
      // 数组的数据要进行遍历操作0
      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;


// ===============================================================
// 定义了一个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.warn('只能读取数据,不能删除数据');
    return true;
  


// 03--------------------------------------
// shallowReadonly
// 定义一个shallowReadonly函数
function shallowReadonly(target) 
  // 需要判断当前的数据是不是对象
  if (target && typeof target === 'object') 
    return new Proxy(target, readonlyHandler);
  
  return target;


// 04--------------------------------------
// readonly
// 定义一个readonly函数
function readonly(target) 
  // 需要判断当前的数据是不是对象
  if (target && typeof target === 'object') 
    // 判断target是不是数组
    if (Array.isArray(target)) 
      // 遍历数组
      target.forEach((item, index) => 
        target[index] = readonly(item);
      );
     else 
      // 判断target是不是对象
      // 遍历对象
      Object.keys(target).forEach(key => 
        target[key] = readonly(target[key]);
      );
    
    return new Proxy(target, readonlyHandler);
  
  // 如果不是对象或者数组,那么直接返回
  return target;


// ===============================================================
// 05--------------------------------------
// shallowRef
// 定义一个shallowRef函数
function shallowRef(target) 
  return 
    // 保存target数据保存起来
    _value: target,
    get value() 
      console.log('劫持到了读取数据');
      return this._value;
    ,
    set value(val) 
      console.log('劫持到了修改数据,准备更新界面', val);
      this._value = val;
    
  


// 06--------------------------------------
// ref
// 定义一个ref函数
function ref(target) 
  target = reactive(target);
  return 
    _is_ref: true, // 标识当前的对象是ref对象
    // 保存target数据保存起来
    _value: target,
    get value() 
      console.log('劫持到了读取数据');
      return this._value;
    ,
    set value(val) 
      console.log('劫持到了修改数据,准备更新界面', val);
      this._value = val;
    
  


// ===============================================================
// 定义一个函数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);


3、函数调用

// 01--------------------------------------
// shallowReactive
const proxyUser1 = shallowReactive(
  name: '小明',
  car: 
    color: 'red'
  
);
// 拦截到了读和写的数据
proxyUser1.name += '==';
// 拦截到了读取数据,但是拦截不到写的数据
proxyUser1.car.color + '==';
// 拦截到了删除数据
delete proxyUser1.name;
// 只拦截到了读,但是拦截不到删除
delete proxyUser1.car.color;

// 02--------------------------------------
// reactive
const proxyUser2 = reactive(
  name: '小明',
  car: 
    color: 'red'
  
);
// 拦截到了读和修改的数据
proxyUser2.name += '==';
// 拦截到了读和修改的数据
proxyUser2.car.color = '==';
// 拦截了删除
delete proxyUser2.name;
// 拦截到了读和拦截到了删除
delete proxyUser2.car.color;

// 03--------------------------------------
// shallowReadonly
const proxyUser3 = shallowReadonly(
  name: '小明',
  cars: ['奔驰', '宝马']
);
// 可以读取
console.log(proxyUser3.name);
// 不能修改
proxyUser3.name = '==';
// 不能删除
delete proxyUser3.name;
// 拦截到了读取,可以修改
proxyUser3.cars[0] = '奥迪';
// 拦截到了读取,可以删除
delete proxyUser3.cars[0];

// 04--------------------------------------
// readonly
const proxyUser4 = readonly(
  name: '小明',
  cars: ['奔驰', '宝马']
);
// 拦截到了读取
console.log(proxyUser4.name);
console.log(proxyUser4.cars[0]);
// 只读的
proxyUser4.name = '哈哈';
// 只读的
proxyUser4.cars[0] = '哈哈';
delete proxyUser4.name;
delete proxyUser4.cars[0];

// 05--------------------------------------
// shallowRef
const ref1 = shallowRef(
  name: '小明',
  car: 
    color: 'red'
  
);
console.log(ref1.value);
// 劫持到
ref1.value = '==';
// 劫持不到
ref1.value.car = '==';

// 06--------------------------------------
// ref
const ref2 = ref(
  name: '小明',
  car: 
    color: 'red'
  
);
console.log(ref2.value);
// 劫持到
ref2.value = '==';
// 劫持到
ref2.value.car = '==';

// 07--------------------------------------
console.log(isRef(ref()));
console.log(isReactive(reactive()));
console.log(isReadonly(readonly()));
console.log(isProxy(reactive()));
console.log(isProxy(readonly()));

以上是关于vue3手写isRefisReactiveisReadonlyisProxy的主要内容,如果未能解决你的问题,请参考以下文章

手写vue3源码——ref, computed 等

vue3手写isRefisReactiveisReadonlyisProxy

vue3源码分析——实现组件的挂载流程

vue3源码分析——实现组件的挂载流程

vue3源码分析——rollup打包monorepo

vue3源码分析——rollup打包monorepo