Vue数据双向绑定探究( 二 )


为了给每一个变量都设置一个类 。并且很好地控制监视更新的匿名函数的行为 , 我们把上面的代码做一些调整:
let target = () => { total = price * quantity };dep.depend();target();
修改为:
watcher(() => { total = price * quantity });
然后我们在函数里面来做刚刚上面的的设置和执行的功能
function watcher(fn) {target = fn;dep.depend();target();target = null;// 重置一下 , 等待储存和执行下一次}
这儿就是官方文档提到的订阅者模式:在每次函数执行的时候 , 把参数fn设置成为我们全局目标属性 , 调用dep.()将目标添加为订阅者 , 调用然后重置
然后再继续
我们的目标是把每一个变量都设置一个类 , 但是这儿有个问题:
先存一下数据:
let data = http://www.kingceram.com/post/{ price: 5, quantity: 3}
假设我们每个属性都有自己的内部类
当我们运行代码时:
watcher(() => { total = data.price * data.quantity})
由于访问了data.price值 , 希望price属性的类将我们的匿名函数(存储在目标中)推送到其订阅者数组(通过调用dep.()) 。由于访问了data. , 还希望属性类将此匿名函数(存储在目标中)推送到其订阅者数组中 。
如果有另一个匿名函数 , 只访问data.price , 希望只推送到价格属性类 。
什么时候想要在价格订阅者上调用dep.()?我希望在设定价格时调用它们 。为此 , 我们需要一些方法来挂钩数据属性(价格或数量) , 所以当它被访问时我们可以将目标保存到我们的订阅者数组中 , 当它被更改时 , 运行存储在我们的订阅者数组中的函数 。let's go
.来解决这个问题
.函数是简单的ES5。它允许我们为属性定义和函数 。继续啃
let data = http://www.kingceram.com/post/{ price: 5, quantity: 3};let value = data.priceObject.defineProperty(data, 'price', {getter() {console.log(`获取price的值: ${value}`);return value;},setter(newValue) {console.log(`更改price的值': ${newValue}`);value = newValue;}})total = data.price * data.quantity;data.price = 10;// 更改price的值
上面通过方法给price设置了获取和修改值的操作
如何给data对象所有的都加上这个方法去设置值
大家还记得.keys这个方法吗?返回对象键的数组 , 咱们把上面的代码改造一下
let data = http://www.kingceram.com/post/{ price: 5, quantity: 3 };Object.keys(data).forEach(key => {let value = data[key];Object.defineProperty(data, key, {getter() {console.log(`获取 ${key} 的值: ${value}`);return value;},setter(newValue) {console.log(`更改 ${key} 值': ${newValue}`);value = newValue;}})})total = data.price * data.quantity;data.price = 10; // 更改price的值
接着上面的东西 , 在每次运行完获取key的值 , 我们希望key能记住这个匿名函数() , 这样有key的值变化的时候 , 它将触发这个函数来重新计算 , 大致思路是这样的:
函数执行的时候 , 记住这个匿名函数 , 当值在发生变化的时候再次运行它
函数执行的时候 , 运行保存的匿名函数 , 把当前的值存起来
用上面定义的类来说就是:
执行 , 调用dep.()来保存当前的
执行 , 在key上调用dep.() , 重新运行所有的
来来来 , 把上面的东西结合到一起来
let data = http://www.kingceram.com/post/{ price: 5, quantity: 3 };let total = 0;let target = null;class Depend {constructor() {this.subscribers = [];}depend() {if (target && this.subscribers.includes(target)) {this.subscribers.push(target);}}notify() {this.subscribers.forEach(sub => sub());}}Object.keys(data).forEach(key => {let value = data[key];const dep = new Depend();Object.defineProperty(data, key, {getter() {dep.depend();return value;},setter(newValue) {value = newValue;dep.notify();}})});function watcher(fn) {target = fn;target();target = null;}watcher(() => {total = data.price * data.quantity;});