dep 添加prop实现类型的绑定,为什么要这么做那?使用proxy代理后,你假如wahcter对象下的几个元素,此时的deps将同时存在这几个元素,你触发依赖的时候,这些依赖都会执行。因此,通过key值绑定观察事件,触发时,能完成对象的正确触发。
watcher、utils
import { parsePath } from './utils'; import { pushTarget, popTarget } from './dep' export default class Watcher { constructor(vm, expOrFn, cb) { // dep id集合 this.depIds = new Set(); this.vm = vm; this.getter = parsePath(expOrFn); this.cb = cb; this.value = this.get(); } get () { pushTarget(this); let value = this.getter.call(this.vm, this.vm); popTarget(); return value; } update() { const oldValue = this.value; this.value = this.get(); this.cb.call(this.vm, this.value, oldValue); } addDep (prop, dep) { const id = dep.id; if (!this.depIds.has(id)) { this.depIds.add(id); dep.addSub(prop, this); } } }
utils.js
/** * 解析简单路径 */ const bailRE = /[^\w.$]/; export function parsePath (path) { if (bailRE.test(path)) { return; } const segments = path.split('.'); return function (obj) { for (let i = 0; i < segments.length; i++) { if (!obj) return; obj = obj[segments[i]]; } return obj; }; } /** * Define a property. */ export function def (obj, key, val, enumerable) { Object.defineProperty(obj, key, { value: val, enumerable: !!enumerable, writable: true, configurable: true }) } /** * Quick object check - this is primarily used to tell * Objects from primitive values when we know the value * is a JSON-compliant type. */ export function isObject (obj) { return obj !== null && typeof obj === 'object' } /** * Check whether an object has the property. */ const hasOwnProperty = Object.prototype.hasOwnProperty export function hasOwn (obj, key) { return hasOwnProperty.call(obj, key) }
Utils.js/Watchers.js与Vue 2.x类似,这里就不多介绍了。
测试一下
test.js
import Observer from './observer'; import Watcher from './watcher'; let data = { name: 'lijincai', password: '***********', address: { home: '安徽亳州谯城区', }, list: [{ name: 'lijincai', password: 'you know it Object', }], }; const newData = new Observer(data); let index = 0; const watcherName = new Watcher(newData, 'value.name', (newValue, oldValue) => { console.log(`${index++}: name newValue:`, newValue, ', oldValue:', oldValue); }); const watcherPassword = new Watcher(newData, 'value.password', (newValue, oldValue) => { console.log(`${index++}: password newValue:`, newValue, ', oldValue:', oldValue); }); const watcherAddress = new Watcher(newData, 'value.address', (newValue, oldValue) => { console.log(`${index++}: address newValue:`, newValue, ', oldValue:', oldValue); }); const watcherAddressHome = new Watcher(newData, 'value.address.home', (newValue, oldValue) => { console.log(`${index++}: address.home newValue:`, newValue, ', oldValue:', oldValue); }); const watcherAddProp = new Watcher(newData, 'value.addProp', (newValue, oldValue) => { console.log(`${index++}: addProp newValue:`, newValue, ', oldValue:', oldValue); }); const watcherDataObject = new Watcher(newData, 'value.list', (newValue, oldValue) => { console.log(`${index++}: newValue:`, newValue, ', oldValue:', oldValue); }); newData.value.name = 'resetName'; newData.value.password = 'resetPassword'; newData.value.name = 'hello world name'; newData.value.password = 'hello world password'; newData.value.address.home = 'hello home'; newData.value.address.home = 'hello home2'; newData.value.addProp = 'hello addProp'; newData.value.addProp ={ name: 'ceshi', }; newData.value.addProp.name = 'ceshi2'; newData.value.list.push('1'); newData.value.list.splice(0, 1); newData.value.list.sort(); newData.value.list.reverse(); newData.value.list.push('1'); newData.value.list.unshift({name: 'nihao'}); newData.value.list[0] = { name: 'lijincai', password: 'you know it Array', }; newData.value.list[0].name = 'you know it array after'; newData.value.list.pop(); newData.value.list.shift(); newData.value.list.length = 1;
我们使用对象、数组测试一下我们的ES6 Proxy检测。
20:17:44.725 index.js?afc7:20 0: name newValue: resetName , oldValue: lijincai 20:17:44.725 index.js?afc7:24 1: password newValue: resetPassword , oldValue: *********** 20:17:44.725 index.js?afc7:20 2: name newValue: hello world name , oldValue: resetName 20:17:44.725 index.js?afc7:24 3: password newValue: hello world password , oldValue: resetPassword 20:17:44.726 index.js?afc7:32 4: address.home newValue: hello home , oldValue: 安徽亳州谯城区 20:17:44.726 index.js?afc7:32 5: address.home newValue: hello home2 , oldValue: hello home 20:17:44.726 index.js?afc7:36 6: addProp newValue: hello addProp , oldValue: undefined 20:17:44.727 index.js?afc7:36 7: addProp newValue: Proxy {name: "ceshi", __dep__: Dep, __parent__: {…}} , oldValue: hello addProp 20:17:44.727 index.js?afc7:40 0: newValue: Proxy {0: Proxy, 1: "1", __dep__: Dep, __parent__: {…}} , oldValue: Proxy {0: Proxy, 1: "1", __dep__: Dep, __parent__: {…}} 20:17:44.728 index.js?afc7:40 1: newValue: Proxy {0: "1", __dep__: Dep, __parent__: {…}} , oldValue: Proxy {0: "1", __dep__: Dep, __parent__: {…}} 20:17:44.729 index.js?afc7:40 2: newValue: Proxy {0: "1", __dep__: Dep, __parent__: {…}} , oldValue: Proxy {0: "1", __dep__: Dep, __parent__: {…}} 20:17:44.731 index.js?afc7:40 3: newValue: Proxy {0: "1", __dep__: Dep, __parent__: {…}} , oldValue: Proxy {0: "1", __dep__: Dep, __parent__: {…}} 20:17:44.734 index.js?afc7:40 4: newValue: Proxy {0: "1", 1: "1", __dep__: Dep, __parent__: {…}} , oldValue: Proxy {0: "1", 1: "1", __dep__: Dep, __parent__: {…}} 20:17:44.735 index.js?afc7:40 5: newValue: Proxy {0: Proxy, 1: "1", 2: "1", __dep__: Dep, __parent__: {…}} , oldValue: Proxy {0: Proxy, 1: "1", 2: "1", __dep__: Dep, __parent__: {…}} 20:17:44.735 index.js?afc7:40 6: newValue: Proxy {0: Proxy, 1: "1", 2: "1", __dep__: Dep, __parent__: {…}} , oldValue: Proxy {0: Proxy, 1: "1", 2: "1", __dep__: Dep, __parent__: {…}} 20:17:44.736 index.js?afc7:40 7: newValue: Proxy {0: Proxy, 1: "1", 2: "1", __dep__: Dep, __parent__: {…}} , oldValue: Proxy {0: Proxy, 1: "1", 2: "1", __dep__: Dep, __parent__: {…}} 20:17:44.737 index.js?afc7:40 8: newValue: Proxy {0: Proxy, 1: "1", __dep__: Dep, __parent__: {…}} , oldValue: Proxy {0: Proxy, 1: "1", __dep__: Dep, __parent__: {…}} 20:17:44.738 index.js?afc7:40 9: newValue: Proxy {0: "1", __dep__: Dep, __parent__: {…}} , oldValue: Proxy {0: "1", __dep__: Dep, __parent__: {…}} 20:17:44.738 index.js?afc7:40 10: newValue: Proxy {0: "1", __dep__: Dep, __parent__: {…}} , oldValue: Proxy {0: "1", __dep__: Dep, __parent__: {…}}
我们看到了ES6 Proxy后实现了Object/Array的检测,虽然还存在一些问题,但是基本的侦测变化的功能都已经具备了。
总结