在之前我利用 Object.defineProperty 以及闭包完成的这个任务
数据响应在学习了 ES6 的 Proxy 之后,我希望可以用 proxy 完成这个
Es6 proxy需要完成的:
- 能响应深层数据的变化
- 能响应数组的变化
- 如果改变后的也是对象,能响应新对象的变化
那么先简单测试一下 proxy 的功能
let dog = {
foods:["食物1","食物2","食物3"],
}
let proxy = new Proxy(dog.foods,{
get(target,key){
return target[key]
},
set(target,key,val){
console.log("change")
target[key] = val;
return true
}
})
proxy.push("食物3")//change change
发现可以响应数组的变化,不过多了一次响应。猜测应该是数组的长度和内容都发生了变化引起的。
有了前面的基础,很容易就能得到这个能响应数据变化的对象
function observe(value, cb) {
//声明需要返回的对象
let proxyObj = value;
Object.keys(proxyObj).forEach((key) => {
//如果下一级是函数或者数组,进行内部的代理
if(typeof proxyObj[key]=="object") proxyObj[key] = observe(proxyObj[key],cb)
})
//返回代理对象
return proxyObj = defineReactive(proxyObj,cb)
}
function defineReactive (obj, cb) {
//控制只触发一次回调函数
let once = true;
let proxy = new Proxy(obj,{
get(target,key){
return target[key]
},
set(target,key,val){
if(typeof val=="object"){
//如果新值也是对象,返回代理对象
val = observe(val,cb)
}
target[key] = val;
if(once){
cb();
once = false
}
return true
}
});
return proxy
}
class Vue {
constructor(options) {
this._data = observe(options.data,options.render)
}
}
下面进行测试
let app = new Vue({
el: '#app',
data: {
text: [1,2,3,4],
text2:{
text3:1
}
},
render(){
console.log("render");
}
})
//数组改变
app._data.text.push(5)//"render"
//对象替换为新对象
app._data.text2 = {
text4:[1]
}//"render"
//新对象再次改变
app._data.text2.text4.push(2)//"render"
console.log(app._data.text2.text4)//Proxy {0: 1, 1: 2, length: 2}
基本需求完成了,但是还有两个问题
- app._data.text 返回的是 proxy 对象,这不是我想要的结果
- app._data.text 操作才会触发 set,我们需要一种方便的方法通过 app.text 直接设置就能触发 set
先留个坑,下次有好方法了来解决吧