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

相关推荐
Summer不秃2 分钟前
Flutter之使用mqtt进行连接和信息传输的使用案例
前端·flutter
旭日猎鹰7 分钟前
Flutter踩坑记录(二)-- GestureDetector+Expanded点击无效果
前端·javascript·flutter
Viktor_Ye13 分钟前
高效集成易快报与金蝶应付单的方案
java·前端·数据库
hummhumm15 分钟前
第 25 章 - Golang 项目结构
java·开发语言·前端·后端·python·elasticsearch·golang
J老熊25 分钟前
JavaFX:简介、使用场景、常见问题及对比其他框架分析
java·开发语言·后端·面试·系统架构·软件工程
猿java30 分钟前
什么是 Hystrix?它的工作原理是什么?
java·微服务·面试
乐闻x42 分钟前
Vue.js 性能优化指南:掌握 keep-alive 的使用技巧
前端·vue.js·性能优化
一条晒干的咸魚44 分钟前
【Web前端】创建我的第一个 Web 表单
服务器·前端·javascript·json·对象·表单
Amd7941 小时前
Nuxt.js 应用中的 webpack:compiled 事件钩子
前端·webpack·开发·编译·nuxt.js·事件·钩子
生椰拿铁You1 小时前
09 —— Webpack搭建开发环境
前端·webpack·node.js