The two-way binding proxy vue3

Before eliminated Vue2.xbased on Object.definePropertya number of limitations that exist to achieve: Unable to listen add and remove attributes , array index and change length , and can support Map, Set, WeakMapand WeakSet!

What is a Proxy?

The MDN  - is so described in the Proxycustom behavior object that defines the basic operations (such as property search, evaluation, enumerations, function calls, etc.).

In fact, before the operation of the target object provides interception, can be filtered to the outside world and rewrite, modify the default behavior of some operations, so we can not directly manipulate the object itself, but through a proxy object manipulation objects indirectly the operation target object to achieve the desired ~

Look at an example:

obj = the let { 
    name: {name: 'HHH' }, 
    ARR: [ 'eat', 'drink', 'play' ] 
} 
// Proxy poor compatibility can broker 13 SET method GET 
// Defineproperty only specific properties intercept 

the let Handler = { 
    GET (target, Key) { // target attribute which is to take obj obj Key is inside 
        console.log ( 'collection for a dependence' )
         return target [Key] 
    }, 
    SET (target, Key, value ) { 
        the console.log ( 'triggered updates' ) 
        target [Key] = value 
    } 
} 

the let Proxy = new newThe Proxy (obj, Handler)
 // through the object and the value of the proxy settings 
proxy.arr 
proxy.name = '123'

 

 

It defines an object obj, the original object to the operation by the object (upper proxy) the agent. When the value of the time will go get method returns the corresponding value when setting values ​​when it will take the set method, triggered updates. But this is the old wording, the new wording is using Reflect.

Reflect is built-in objects, the operation target for the new API provided, the method Object belonging internal language objects placed on the object Reflect, i.e. Object method to take the object from the internal Reflect object. If the error returns false

Simply rewrite the example above

let handler = {
    get (target,key) { //target就是obj key就是要取obj里面的哪个属性
        console.log('收集依赖')
        // return target[key]
        //Reflect 反射 这个方法里面包含了很多api
        return Reflect.get(target,key)
    },
    set (target,key,value) {
        console.log('触发更新')
        // target[key] = value //这种写法设置时如果不成功也不会报错 比如这个对象默认不可配置
        Reflect.set(target,key,value)
    }
}

let proxy = new Proxy(obj,handler)
//通过代理后的对象取值和设置值
proxy.arr
proxy.name = '123'

但是有一个问题,这个对象是多层对象,之前Object.defineProperty方法是一开始就会对这个多层对象进行递归处理,而Proxy不会。它是懒代理。如果对这个对象里面的值进行代理就取不到值。就像上面我们只对name进行了代理,并没有对name.name进行代理,所以他就取不到这个值,需要代理之后才能取到。

let obj = {
    name:{name:'hhh'},
    arr: ['吃','喝','玩']
}
//proxy兼容性差 可以代理13种方法 get set
//defineProperty 只对特定 的属性进行拦截 

let handler = {
    get (target,key) { //target就是obj key就是要取obj里面的哪个属性
        console.log('收集依赖')
        if(typeof target[key] === 'object' && target[key] !== null){
            //递归代理,只有取到对应值的时候才会代理
            return new Proxy(target[key],handler)
        }
        
        // return target[key]
        //Reflect 反射 这个方法里面包含了很多api
        return Reflect.get(target,key)
    },
    set (target,key,value) {
        console.log('触发更新')
        // target[key] = value //这种写法设置时如果不成功也不会报错 比如这个对象默认不可配置
        Reflect.set(target,key,value)
    }
}

let proxy = new Proxy(obj,handler)

可以看到这次虽然我写了代理name.name,但是没有取到name.name,它并不会真正的代理

 

 这次触发了两次收集依赖。

接下来看看数组的代理过程:

let obj = {
    name:{name:'hhh'},
    arr: ['吃','喝','玩']
}
//proxy兼容性差 可以代理13种方法 get set
//defineProperty 只对特定 的属性进行拦截 

let handler = {
    get (target,key) { //target就是obj key就是要取obj里面的哪个属性
        console.log('收集依赖')
        if(typeof target[key] === 'object' && target[key] !== null){
            //递归代理,只有取到对应值的时候才会代理
            return new Proxy(target[key],handler)
        }
        
        // return target[key]
        //Reflect 反射 这个方法里面包含了很多api
        return Reflect.get(target,key)
    },
    set (target,key,value) {
        console.log('触发更新')
        // target[key] = value //这种写法设置时如果不成功也不会报错 比如这个对象默认不可配置
        return Reflect.set(target,key,value)
    }
}

let proxy = new Proxy(obj,handler)
//通过代理后的对象取值和设置值
// proxy.name.name = '123' //设置值,取一次,设置一次
proxy.arr.push(456)

这里面它会走两次触发更新的操作,因为第一次需要修改数组的长度,第二次再把元素放进数组里。所以我们需要判断一下它是新增操作还是修改操作

set (target,key,value) {
        let oldValue = target[key]
        console.log(key, oldValue, value)
        if(!oldValue){
            console.log('新增属性')
        }else if(oldValue !== value){
            console.log('修改属性')
        }
        // target[key] = value //这种写法设置时如果不成功也不会报错 比如这个对象默认不可配置
        return Reflect.set(target,key,value)
    }

首先拿到它的旧值,如果这个值不存在就是新增,如果存在但不相等就是修改操作

 

 可以看到最后一次判断结果是两个相等,什么也不做

 

 这是一次修改操作。

我们知道,vue2.0是不会监控到之前不存在的属性的,但是proxy可以操作之前不存在的属性的,它会拦截设置操作,如下:

 

 xxx之前并不在obj对象里面,但是依旧可以新增。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 



Guess you like

Origin www.cnblogs.com/lyt0207/p/12540091.html