前端Vue架构

1

理解:

  • 创建视图的函数(render)和数据之间的关联;

  • 当数据发生变化的时候,希望render重新执行;

  • 监听数据的读取和修改;

    • defineProperty:监听范围比较窄,只能通过属性描述符去监听已有属性的读取和赋值;兼容性更好;(要求监听数据是对象)
    • proxy:监听范围更广;兼容性较差,只能兼容支持ES6 的浏览器(要求监听数据是对象)

如何知晓数据对应的函数;

function track(target, key) {
  console.log(`依赖收集:${key}`, 'color: #f00');
}

function trigger(target, key) {
  console.log(`派发更新:${key}`, 'color: #f00');
}

function isObject(value) {
  return typeof value === 'object' && value !== null;
}
const handlers = {
  get(target, key) {
    // 依赖收集
    track(target, key);
    return target[key]; // 返回对象的相应属性值
  },

  set(target, key, value) {
    // 派发更新
    trigger(target, key);

    // target[key] = value; // 设置对象的相应属性值
    // return true;
    // 赋值成功返回true,赋值失败返回false;这里可以使用try catch
    return Reflect.set(target, key, value)
    // 也可以使用Reflect.set(target, key, value)。它会直接返回true或者false
  },
}
// 同一个对象,调用两次reactive,会生成不一样的Proxy对象,没有意义
const targetMap = new WeakMap();
function reactive(target) {
  if (!isObject(target)) {
    return target; // 如果不是对象,直接返回
  }
  if (targetMap.has(target)) {
    return targetMap.get(target);// 如果已经代理过了,直接返回;
  }

  const proxy = new Proxy(target, handlers);

  targetMap.set(target, proxy);
  return proxy;
}
const state = reactive({
  a: 1,
  b: 2,
});

// fn函数中用到了state数据
function fn() {
  state.a;
  state.b;
}

fn();
state.a++; // 先读取,再赋值

依赖收集:a color: #f00
依赖收集:b color: #f00
依赖收集:a color: #f00
派发更新:a color: #f00

const obj = {
  a: 1,
  b: 2,
  get c() {
    return this.a + this.b;
  }
};

const state = reactive(obj);
state.c;

这样写的话,依赖收集只能收集到属性c;因为this指向obj;
可以这样操作:

get(target, key, receiver) {
  // 依赖收集
  track(target, key);
  // receiver指的是代理对象
  return Reflect.get(target, key, receiver) ; 
  // 改变this指向,将this指向为代理对象
  // return target[key]; // 返回对象的相应属性值
},

下面的用法,只能收集到c,收集不到c1

const obj = {
  a: 1,
  b: 2,
  c: {
    c1: 1,
  },
};

const state = reactive(obj);
state.c.c1;

可以这样操作
如果访问的属性值还是一个对象,对属性值再次进行代理;

const obj = {
includes: () => {},
indexOf: () => {},
};
const handlers = {
  get(target, key, receiver) {
    // 依赖收集
    track(target, key);
    // 对于数组来说,无法在代理对象中找到时,去原始数组中重新找一次
    // const obj = {};
    // const arr = [1, obj, 3];
    // const state = reactive(arr);
    // state.includes(obj);
    if ((obj.hasOwnProperty(key) && Array.isArray(target)) {
    	return obj[key];
    }
    // receiver指的是代理对象
    const result = Reflect.get(target, key, receiver) ; 
    if (isObject(result)) {
      return reactive(result);
    }
  },
}

简易的模型已经写好;

2 读信息 进行依赖升级

Object.keys和let i in obj用的都是ownKeys;
‘a’ in obj; 用的是has;
obj.a 用的是get;

这里的读不光是通过state.a来读取a属性
还可能通过’e’ in state;来查看’e’属性在不在state中;

const obj = {};
const state = reactive(obj);
'e' in state;

解决办法:新增has方法

const TrackOpTypes = {
  GET: 'get', // 读取属性值
  HAS: 'has', // 判断属性是否存在
  ITERATE: 'iterate', // 迭代对象
};

function track(target, trackOpType, key) {
  console.log(`依赖收集:${key},收集方法:${trackOpType}`, 'color: #f00');
}
const handlers = {
  get(target, key, receiver) {
    // 依赖收集
    track(target, TrackOpTypes.GET, key);
	// ...
  },
  set(target, key, value, receiver) {},
  has(target, key) {
    track(target, TrackOpTypes.HAS, key);
    return Reflect.has(target, key); // 判断对象是否有key属性
  }
}

在这里插入图片描述

同理

const TriggerOpTypes = {
  SET: 'set', // 设置属性值
  ADD: 'add', // 添加属性值
  DELETE: 'delete', // 删除属性
}

function trigger(target, triggerOpType, key) {
  console.log(`派发更新:${key}, 更改方法:${triggerOpType}`, 'color: #f00');
}

还有一种情况

const handlers = {
  get,
  set,
  has,
  ownKeys(target) {
    track(target, TrackOpTypes.ITERATE);
    return Reflect.ownKeys(target); // 返回对象的所有属性名
  },
}
function track(target, trackOpType, key) {
  if (trackOpType === TrackOpTypes.ITERATE) {
    console.log(`依赖收集方法:${trackOpType}`, 'color: #f00');
    return;
  }
  console.log(`依赖收集:${key},收集方法:${trackOpType}`, 'color: #f00');
}
const obj = { a: '1'};
const obj2 = {}
const state = reactive(obj);
const state2 = reactive(obj2);
for (let i in state) {}
Object.keys(state2);

Object.keys和let i in obj用的都是ownKeys;

依赖收集方法:iterate color: #f00
依赖收集方法:iterate color: #f00

3 新增属性

 set(target, key, value, receiver) {
    // 派发更新
    const type = target.hasOwnProperty(key)
    ? TriggerOpTypes.SET
    : TriggerOpTypes.ADD;
    trigger(target, type, key);
    return Reflect.set(target, key, value, receiver);
  },

在这里插入图片描述

4 删除属性

 deleteProperty(target, key) {
    trigger(target, TriggerOpTypes.DELETE, key);
    return Reflect.deleteProperty(target, key); // 删除对象的相应属性
  }
delete state.a;

5 数据和函数的内在联系

相关推荐

  1. 深入浅出微前端架构

    2024-05-13 07:14:03       26 阅读
  2. vue 项目代码架构

    2024-05-13 07:14:03       18 阅读
  3. 前端八股文(vue篇)

    2024-05-13 07:14:03       58 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-05-13 07:14:03       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-05-13 07:14:03       72 阅读
  3. 在Django里面运行非项目文件

    2024-05-13 07:14:03       58 阅读
  4. Python语言-面向对象

    2024-05-13 07:14:03       69 阅读

热门阅读

  1. react如何拿输入框的值

    2024-05-13 07:14:03       28 阅读
  2. 嵌入式交叉编译:ffmpeg及相关库

    2024-05-13 07:14:03       35 阅读
  3. SASS预处理器的用法

    2024-05-13 07:14:03       30 阅读
  4. Elasticsearch 8.1官网文档梳理 -综述

    2024-05-13 07:14:03       23 阅读
  5. 抽象类与接口

    2024-05-13 07:14:03       24 阅读
  6. C++简易贪吃蛇

    2024-05-13 07:14:03       35 阅读
  7. linux中passwd --stdin命令含义

    2024-05-13 07:14:03       30 阅读