手撕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,这里有几十位一心去大厂的友友可以相互鼓励,分享信息,模拟面试,共读源码,齐刷算法,手撕面经。来吧,友友们!

相关推荐
有梦想的刺儿2 分钟前
webWorker基本用法
前端·javascript·vue.js
cy玩具23 分钟前
点击评论详情,跳到评论页面,携带对象参数写法:
前端
customer081 小时前
【开源免费】基于SpringBoot+Vue.JS周边产品销售网站(JAVA毕业设计)
java·vue.js·spring boot·后端·spring cloud·java-ee·开源
qq_390161771 小时前
防抖函数--应用场景及示例
前端·javascript
John.liu_Test2 小时前
js下载excel示例demo
前端·javascript·excel
Yaml42 小时前
智能化健身房管理:Spring Boot与Vue的创新解决方案
前端·spring boot·后端·mysql·vue·健身房管理
PleaSure乐事2 小时前
【React.js】AntDesignPro左侧菜单栏栏目名称不显示的解决方案
前端·javascript·react.js·前端框架·webstorm·antdesignpro
哟哟耶耶2 小时前
js-将JavaScript对象或值转换为JSON字符串 JSON.stringify(this.SelectDataListCourse)
前端·javascript·json
getaxiosluo2 小时前
react jsx基本语法,脚手架,父子传参,refs等详解
前端·vue.js·react.js·前端框架·hook·jsx
理想不理想v2 小时前
vue种ref跟reactive的区别?
前端·javascript·vue.js·webpack·前端框架·node.js·ecmascript