解密Vue中的神奇原理:深入剖析reactive和ref的工作机制(二)

上一篇文章我们讲了reactive的源码解析,相信大家已经对其已经有了深刻的理解,那么ref和它有什么不同呢?

这一篇文章,我们就来了解一下ref是如何实现的。上一篇文章说到,reactive是用于让对象变成响应式,那么原始类型怎么办呢,使用ref实现吗,,没错,正如大家所想的那样,原始类型的响应式实现正是依靠ref,并且ref功能更为强大,它还能使对象变成响应式,也就是说,它涵盖了reactive的功能。

引入

js 复制代码
import { ref } from 'vue';
const count = ref(1)
console.log(count.value); // 1

上面的打印结果是1,相信大家都能接受,但是为什么count后面要接.value呢。

首先呢,ref返回的是一个对象,访问对象里面的属性使用.xxx没毛病吧,至于为什么是.value,咱来看看这个对象里面有什么:

js 复制代码
console.log(count.value); 

大家也看到了,里面封装的就是value,所以合情合理。那么究竟是怎么实现的呢?

实现一个简单的ref

我们已经知道reactive实现的核心就是Proxy,那么ref肯定是不能这样的,因为Proxy只能接受对象作为为参数。所以我们只能自己打造一个代理函数来实现响应式。那应该怎么做呢?首先我们得知道

  1. 当数据是对象时,继续使用Proxy代理
  2. 在函数内部我们也使用一个this.__V_isRef = true属性来记录是否已经是响应式
  3. 使用this._value = target存放传进来的数据
  4. get value() {} 用于获取值 相当于 Proxy中的get
  5. set value(newVal) {} 用于修改值 相当于 Proxy中的set
js 复制代码
class RefImal { // 创建一个构造函数,用于将val变成响应式
    constructor(target) {
        this.__V_isRef = true // 给已经代理过的target打上标记,用于判断是否已经是响应式
    if(typeof target !== 'object' || target === null) {
        this._value = target
    } else {  // 对象使用Proxy代理
        this._value = new Proxy(target,{
            get: (target,key,receiver) => {
                const res = Reflect.get(target,key,receiver) // 获取值
                // 收集副作用函数(即用到了这个属性的函数)
                track(target,key) // 用于收集副作用函数,详细代码参考上一篇reactive的文章
                return res
            },
            set: (target,key,value,receiver) => {
                Reflect.set(target,key,value,receiver) // 修改值
                // 值变更时触发副作用函数
                trigger(target,key) // 用于触发副作用函数,详细代码参考上一篇reactive的文章
                return true 
            }
        })
    }
    }
    // 获取值
    get value() {
        const res = this._value
        if(typeof res === 'object' && res !== null) {
            return res // 是对象,已经收集过副作用函数,直接返回
          }
        track(this, 'value')
        return res
    }
    // 修改值
    set value(newVal) {
        this._value = newVal
        trigger(this, 'value')
        return true
    }
}

上面的是核心,接下来就是主体部分,这个比较简单,和reactive差不多

js 复制代码
export function ref(target) {
    // 判断是否已经是响应式
    if(target.__V_isRef){
        return
    }
    // 将val变成响应式
    const refimal = new RefImal(target) 

    // 返回val
    return refimal
}

这样我们就实现了一个简单的ref,是不是很简单,接下来我们来说说它们的区别。

区别

  • 功能方面:
  1. ref的功能显然是比reactive强大的,它不仅可以使原始类型变成响应式,还能使引用类型变成响应式。
  2. reactive只能使对象变成响应式。
  • 运用:
  1. ref代理的数据在使用时要加上xxx.value,如果代理的数据是对象还要加上key,如xxx.value.key
  2. reactive代理的数据使用时只需要xxx.key
  3. 所以原始类型的代理我们通常使用ref,对象通常使用reactive,这就是为什么ref明明涵盖了reactive的功能,还要打造一个reactive

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

相关推荐
志尊宝4 小时前
Vue3 零基础每日笔记(080):Vue3 + ECharts 数据可视化——封装可复用图表组件
前端·javascript·vue.js·笔记·信息可视化·echarts
李剑一5 小时前
AI翻译都这么强了,为什么程序员还是躲不开英语?假如你想用上GPT6,我劝你还是早点背单词吧!
面试·产品·创业
斯内普吖5 小时前
(开源)校园充电宝租借管理系统实战指南 基于 Java + SSM + Vue + MySQL
java·vue.js·mysql·开源
2603_965896625 小时前
JS ES6常用新特性|let/const、解构赋值、展开运算符
前端·javascript·es6
衡石科技5 小时前
一个门户只保留一个智能助理:衡石嵌入式 Data Agent 的运行与渲染边界
前端·javascript·html·data agent
Hilaku5 小时前
一个前端工程师除了写代码,还能靠什么赚钱?
前端·javascript·程序员
我先测了5 小时前
Midscene.js 全栈学习指南:从入门到精通的 AI 视觉自动化框架
javascript·人工智能·自动化·agent·midscene
程序员Sunday5 小时前
JavaScript 闭包是什么?为什么变量没有被释放,什么时候会内存泄漏?
前端·javascript
救救孩子把5 小时前
AI面试八股文-01_1-LLM基础概念(Token-上下文窗口-幻觉)
人工智能·面试·职场和发展·llm·token
此时不提桶,更待何时6 小时前
06-24-B-RabbitMQ面试与生产事故实战
分布式·面试·rabbitmq