Vue3响应式-ref、reactive

446 阅读2分钟

这是我参与11月更文挑战的第2天

reactive

reactive()函数的参数只能是Object

reactive通过ES6的new Proxy()给对象添加代理实现数据劫持

reactive 源码核心实现


function reactive( obj ){
    return createReactiveObject(obj)
}

function createReactiveObject(obj){
    const proxy = new Proxy(obj, {
        get : function (obj, key, receiver= {}){
            const res = Reflect.get(obj, key, receiver)
            // 调用track(),收集依赖
            return res
        },
        set : function(obj, key, value, receiver = {} ){
             let oldValue = obj[key]
            // 此时的receiver为this,即为proxy代理
            const result = Reflect.set(obj, key, value, receiver)
            if(oldValue !== value){
                // 调用trigger() ,触发更新
            }
            return result
        },
        
    })
    return proxy
}

let obj = {a : 1}
let objProxy = reactive(obj)
objProxy.a = 2
console.log(objProxy.a)

ref

ref()函数的参数可以是Object也可以是基本数据类型

如果是Object直接转给reactive()

如果是基本数据类型,通过ES6 Class的getter和setter实现数据劫持

ES6的Class的getter和setter本质就是通过Object.defineProperty与get、set方法实现

ref 源码核心实现

function ref(value){
    return createRef(value)
}

function createRef(rawValue){
    return new RefImpl(rawValue)
}

class RefImpl {
    constructor(_rawValue){
        // 类的this执行类的实例
        this._value = _rawValue
    }
    
    get value(){
        // 取值时,调用effect的track,收集依赖
        track()
        return this._value
    }
    
    set value(newVal){
        // 赋值时,调用effect的trigger,触发更新
        trigger()
        this._value = newVal
    }
}

let a = ref("123")
console.log(a.value)
a.value = "456"
console.log(a.value)

reactive 和 ref的区别

reactive 和 ref 都是用来定义响应式数据的。

reactive的参数只能是复杂的数据类型; ref的参数可以是基本能数据类型也可以是复杂的数据类型

reactive更推荐去定义复杂的数据类型; ref更推荐去定义基本类型。

reactive 是通过ES6的Proxy实现的数据劫持; ref是通过调用reactive实现复杂数据类型的数据劫持, 通过Object.defineProperty的get/set实现基本数据类型的数据劫持。

ES6 Proxy 代理

Proxy对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义

ES6 Reflect 反射

Reflect是ES6为了操作对象而新增的API。

Reflect继承Object

Reflect.__proto__ === Object.prototype

Reflect与Object类似,但是更易读,为操作对象提供了一种更优雅的方式。它的方法与Proxy是对应得

ES6中将Object的一些明显属于语言内部的方法移植到Reflect对象上(当前某些方法会同时存在于Object和Reflect对象上),未来的新方法会只部署在Reflect对象上。

Reflect对象对某些方法的返回结果进行了修改,使其更合理。

Reflect对象使用函数的方式实现了Object的命令式操作。

Reflect.set(target, propertyKey, value[, receiver])

  • target 设置属性的目标对象

  • propertyKey 设置的属性的名称

  • value 设置的值

  • receiver 如果目标对象上有setter,receiver则为setter调用时的this值。

//反射
var obj = {
     a: 1,
     set : function(a){
        this.a = a
     }
}
var receiver = {
    a : 2
}

Reflect.set(obj, 'a', 11)
console.log(obj.a)
console.log(receiver.a)

Reflect.set(obj, 'a', 3, receiver)

console.log(obj.a)
console.log( receiver.a)