响应式入门,你了解vue3.0响应式数据怎么实现吗( 二 )


以上是目前es6支持的proxy , 具体的用法不做赘述 , 有兴趣的可以到阮一峰老师的es6入门去研究每种的具体用法 , 其实思想都是一样的 , 只是每种对应了一些不同的功能~
实际场景中 Proxy 可以做什么?
实现私有变量
js的语法中没有private这个关键字来修饰私有变量 , 所以基本上所有的class的属性都是可以被访问的 , 但是在有些场景下我们需要使用到私有变量 , 现在业界的一些做法都是使用”_变量名“来”约定“这是一个私有变量 , 但是如果哪天被别人从外部改掉的话 , 我们还是没有办法阻止的 , 然而 , 当Proxy出现后 , 我们可以用代理来处理这种场景 , 看代码:const obj = {_name: 'nanjin',age: 19,getName: () => {return this._name;},setName: (newName) => {this._name = newName;}}const proxyObj = obj => new Proxy(obj, {get: (target, key) => {if(key.startsWith('_')){throw new Error(`${key} is private key, please use get${key}`)}return Reflect.get(target, key);},set: (target, key, newVal) => {if(key.startsWith('_')){throw new Error(`${key} is private key, please use set${key}`)}return Reflect.set(target, key, newVal);}})const newObj = proxyObj(obj);console.log(newObj._name) // Uncaught Error: _name is private key, please use get_namenewObj._name = 'newname'; // Uncaught Error: _name is private key, please use set_nameconsole.log(newObj.age) // 19console.log(newObj.getName()) // nanjin
可见 , 通过proxyObj方法 , 我们可以实现把任何一个对象都过滤一次 , 然后返回新的代理对象 , 被处理的对象会把所有_开头的变量给拦截掉 , 更进一步 , 如果有用过mobx的同学会发现mobx里面的store中的对象都是类似于这样的
有handler 和 target , 说明mobx本身也是用了代理模式 , 同时加上Decorator函数 , 在这里就相当于把proxyObj使用装饰器的方式来实现 , Proxy + Decorator 就是mobx的核心原理啦~
vue响应式数据实现
VUE的双向绑定涉及到模板编译 , 响应式数据 , 订阅者模式等等 , 有兴趣的可以看这里  , 因为这篇文章的主题是proxy , 因此我们着重介绍一下数据响应式的过程 。
2.x版本
在当前的vue2.x的版本中 , 在data中声名一个obj后 , vue会利用Object.defineProperty来递归的给data中的数据加上get和set , 然后每次set的时候 , 加入额外的逻辑 。来触发对应模板视图的更新 , 看下伪代码:const defineReactiveData = https://www.xysc168.com/guoxue/data => {Object.keys(data).forEach(key => {let value = https://www.xysc168.com/guoxue/data[key];Object.defineProperty(data, key, {get : function(){console.log(`getting ${key}`)return value;},set : function(newValue){console.log(`setting ${key}`)notify() // 通知相关的模板进行编译value = newValue;},enumerable : true,configurable : true})})}
这个方法可以给data上面的所有属性都加上get和set , 当然这只是伪代码 , 实际场景下我们还需要考虑如果某个属性还是对象我们应该递归下去 , 来试试:const data = https://www.xysc168.com/guoxue/{name:'nanjing',age: 19}defineReactiveData(data)data.name // getting name 'nanjing'data.name = 'beijing'; // setting name
可以看到当我们get和set触发的时候 , 已经能够同时触发我们想要调用的函数拉 , Vue双向绑定过程中 , 当改变this上的data的时候去更新模板的核心原理就是这个方法 , 通过它我们就能在data的某个属性被set的时候 , 去触发对应模板的更新 。