We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Set、Map、WeakMap、Reflect、Proxy
reactive 用来将需要观察的对象转换成可以观察的对象。 effect 定义了一个回调函数,当其中某个可观察对象发生变化时,触发回调。
import { reactive } from './reactive' import { effect } from './effect' const state = reactive({ count: 0, age: 18 }) effect(() => { console.log('effect: ' + state.count) })
export function reactive(target) { const observed = new Proxy(target, handler) return observed }
当要观察的数据结构是 Set, Map, WeakSet, WeakMap 时,用 collectionHandlers others : baseHandlers
collectionHandlers 又分为 mutableCollectionHandlers、readonlyCollectionHandlers baseHandlers 分 mutableHandlers、readonlyHandlers
export const mutableHandlers = { get: createGetter(false), set, deleteProperty, has, ownKeys }; function createGetter(isReadonly: boolean, shallow = false) { return function get(target: object, key: string | symbol, receiver: object) { const res = Reflect.get(target, key, receiver); // 把 effect 的回调保存起来 track(target, TrackOpTypes.GET, key); return isObject(res) ? isReadonly ? // need to lazy access readonly and reactive here to avoid // circular dependency readonly(res) : reactive(res) : res; }; } function set(target, key, value, receiver) { const hadKey = hasOwn(target, key); const oldValue = target[key]; const result = Reflect.set(target, key, value, receiver); if (!hadKey) { trigger(target, "add", key); } else if (value !== oldValue) { trigger(target, "set", key); } return result; } function deleteProperty(target, key) { const hadKey = hasOwn(target, key); const oldValue = target[key]; const result = Reflect.deleteProperty(target, key); if (hadKey) { trigger(target, "delete", key); } return result; } // 拦截判断对象是否具有某个属性时的操作,返回一个布尔值 function has(target: object, key: string | symbol): boolean { const result = Reflect.has(target, key); track(target, TrackOpTypes.HAS, key); return result; } // 拦截对象自身属性的读取操作 Object.keys() for...in function ownKeys(target: object): (string | number | symbol)[] { track(target, TrackOpTypes.ITERATE, ITERATE_KEY); return Reflect.ownKeys(target); }
现在还差 effect 的实现、get 中 track 的实现,set 中 trigger 的实现 存储数据的结构如下图所示。
const targetMap = new WeakMap(); const effectStack = []; // 记录 effect export function effect(fn) { const effect = run(effect, fn, null); effect(); return effect; } function run(effect, fn, args) { if (effectStack.indexOf(effect) === -1) { try { effectStack.push(effect); return fn(...args); } finally { effectStack.pop(); } } } export function track(target, operationType, key) { const effect = effectStack[effectStack.length - 1]; if (effect) { let depsMap = targetMap.get(target); if (depsMap === void 0) { targetMap.set(target, (depsMap = new Map())); } let dep = depsMap.get(key); if (dep === void 0) { depsMap.set(key, (dep = new Set())); } if (!dep.has(effect)) { dep.add(effect); } } }
track 就是将 effect 回调函数添加到其中使用的被观察对象的 set 集合中。当触发 trriger 函数时取出来触发回调。
export function trigger(target, operationType, key) { const depsMap = targetMap.get(target); if (depsMap === void 0) { return; } const effects = new Set(); if (key !== void 0) { // 将依赖这个key的所有监听函数推到相应队列中 const dep = depsMap.get(key); dep && dep.forEach(effect => { effects.add(effect); }); } if (operationType === "add" || operationType === "set") { // 如果原始数据是数组,则key为length,否则为Symbol,这里最后会讲 const iterationKey = Array.isArray(target) ? "length" : Symbol("iterate"); const dep = depsMap.get(iterationKey); dep && dep.forEach(effect => { effects.add(effect); }); } effects.forEach(effect => { effect(); }); }
当观察对象是 Set, Map, WeakSet, WeakMap 时使用 collectionHandlers 因为集合没有 set 方法,所以新创建了一个和集合对象具有相同属性和方法的普通对象,在集合对象 get 操作时将 target 对象换成新创建的普通对象。
const mutableInstrumentations: Record<string, Function> = { get(this: MapTypes, key: unknown) { return get(this, key, toReactive) }, get size(this: IterableCollections) { return size(this) }, has, add, set, delete: deleteEntry, clear, forEach: createForEach(false) }
其实是 Proxy 的能力,可以监听数组的 index 和 length
const arr = [0]; const obj = new Proxy(arr, { get: function(target, propKey, receiver) { console.log(`getting ${propKey}!`); return Reflect.get(target, propKey, receiver); }, set: function(target, propKey, value, receiver) { console.log(`setting ${propKey}!`); return Reflect.set(target, propKey, value, receiver); } }); obj.push(0);
The text was updated successfully, but these errors were encountered:
No branches or pull requests
前置知识
Set、Map、WeakMap、Reflect、Proxy
使用
reactive 用来将需要观察的对象转换成可以观察的对象。
effect 定义了一个回调函数,当其中某个可观察对象发生变化时,触发回调。
实现
Reactive
当要观察的数据结构是 Set, Map, WeakSet, WeakMap 时,用 collectionHandlers
others : baseHandlers
collectionHandlers 又分为 mutableCollectionHandlers、readonlyCollectionHandlers
baseHandlers 分 mutableHandlers、readonlyHandlers
effect
现在还差 effect 的实现、get 中 track 的实现,set 中 trigger 的实现
![1](https://user-images.githubusercontent.com/22735996/84582195-a8f1f280-ae1b-11ea-9669-fe86c61bc1fc.png)
存储数据的结构如下图所示。
track 就是将 effect 回调函数添加到其中使用的被观察对象的 set 集合中。当触发 trriger 函数时取出来触发回调。
当观察对象是 Set, Map, WeakSet, WeakMap 时使用 collectionHandlers
因为集合没有 set 方法,所以新创建了一个和集合对象具有相同属性和方法的普通对象,在集合对象 get 操作时将 target 对象换成新创建的普通对象。
为什么可以监听数组
其实是 Proxy 的能力,可以监听数组的 index 和 length
The text was updated successfully, but these errors were encountered: