手撕Vue源码之——ref

前言

上一篇文章给大家介绍了reactive的原理及实现一个简单的reactive(手撕Vue源码之------reactive),这篇文章就给大家介绍一下refref也是实现响应式的一种方法,但是它一般用于让原始类型的数据变成响应式,当然也可以是引用类型,但是一般不用,至于为什么之后会给大家说明的

思路

从vue打造好的ref来看,它接收一个参数,可以是简单类型也可以是引用类型,然后返回的是一个对象,从获取值需要使用.value就可以看出来,ref返回的结果是一个对象。

js 复制代码
import { track, trigger } from './effect.js'
import { reactive } from './reactive.js'


export function ref(val) {      // 将原始类型数据变成响应式  引用类型也可以
    return createRef(val)
}

function createRef(val) {
    // 判断val是否已经是响应式
    if (val.__v_isRef) {
        return val
    }
    
    // 将val变为响应式
    return new RefIpml(val)
}

class RefIpml {
    constructor(val) {
        this.__v_isRef = true    // 给每一个被ref操作过的属性值都添加标记
        this._value = convert(val)       // 一种人为约定俗成的写法,加了_的属性都默认为私有属性,不会直接拿到外面去用
    }
    get value() {
        // 为this对象做依赖收集
        track(this, 'value')    // key可以随便写,就统一用value,track和trigger里的key要统一
        return this._value
    }
    set value(newVal) {
        if (newVal !== this._value) {
            this._value = convert(newVal)
            trigger(this, 'value')      // 触发掉'value'上的所有副作用函数
        }
    }
}

function convert(val) {
    if (typeof val !== 'object' || val === null) {      // 不是对象
        return val
    } else {
        return reactive(val)
    }
}

因为Proxy只接受对象作为参数,而ref可以把简单数据类型变成响应式,所以我们就自己打造一个RefIpml类,这里先补充一个知识点,js中的对象天生拥有getset的能力。

js 复制代码
let obj = {
    name: 'Tom',
    get age() {
        return 18
    },
    set age(newVal) {
        console.log(newVal);
    }
}

obj.age = 18
console.log(obj.age);    // 相当于obj.age()

在函数前面加上get就可以直接使用对象名.函数名获取函数的返回结果,同理set也是,这样就不用每次都要去调用这个函数进行触发。

这里面还用到了我们上次在reactive中使用到的track方法和trigger方法,既然是响应式,那么ref自然也需要进行依赖收集和触发,代码片段里都有注释,相信大家也能看的懂,接下来我就讲讲为什么ref一般不用于引用类型而常用于简单数据类型。

从上面的代码也能看到,当ref如果接受的是一个对象的话,它是直接调用了reactive方法,把reactive的结果返回了出来,实际上vue的源码里也是这么写的,当给ref的参数是对象时,相当于就是在ref里面调用reactive,然后使用reactive返回的结果作为.value的值,这看着就有一点点多此一举。

结语

实际上变成响应式的核心就是Proxy方法,但是Proxy只能接受对象作为参数,所以才不得已再多打造一个ref用来使简单数据类型也能变成响应式数据,所以一般数据源比较多的时候就用reactive,数据源比较少的时候就用ref

假如您也和我一样,在准备春招。欢迎加我微信shunwuyu,这里有几十位一心去大厂的友友可以相互鼓励,分享信息,模拟面试,共读源码,齐刷算法,手撕面经。来吧,友友们!

相关推荐
adminwolf1 小时前
基于Vue.js和Golang构建高效在线客服系统:前端实现与后端交互详解
前端·vue.js·golang
二哈喇子!3 小时前
Vue3生命周期
前端·javascript·vue.js
运维帮手大橙子6 小时前
完整的登陆学生管理系统(配置数据库)
java·前端·数据库·eclipse·intellij-idea
_Kayo_7 小时前
CSS BFC
前端·css
二哈喇子!8 小时前
Vue3 组合式API
前端·javascript·vue.js
二哈喇子!10 小时前
Vue 组件化开发
前端·javascript·vue.js
C4程序员10 小时前
北京JAVA基础面试30天打卡03
java·开发语言·面试
chxii10 小时前
2.9 插槽
前端·javascript·vue.js
姑苏洛言11 小时前
扫码点餐小程序产品需求分析与功能梳理
前端·javascript·后端
Freedom风间11 小时前
前端必学-完美组件封装原则
前端·javascript·设计模式