返回顶部
首页 > 资讯 > 精选 >Vue3中Provide和Inject的实现原理是什么
  • 604
分享到

Vue3中Provide和Inject的实现原理是什么

2023-06-29 04:06:01 604人浏览 泡泡鱼
摘要

这篇文章主要介绍了vue3中Provide和Inject的实现原理是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Vue3中Provide和Inject的实现原理是什么文章都会有所收获,下面我们一起来看看吧

这篇文章主要介绍了vue3中Provide和Inject的实现原理是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Vue3中Provide和Inject的实现原理是什么文章都会有所收获,下面我们一起来看看吧。

Vue3中Provide和Inject的实现原理是什么

原型和原型链的知识回顾

  • prototype 与 __proto__

prototype 一般称为显式原型,__proto__一般称为隐式原型。 每一个函数在创建之后,在默认情况下,会拥有一个名为 prototype 的属性,这个属性表示函数的原型对象。

  • 原型链

当我们访问一个js对象属性的时候,JS先会在这个对象定义的属性里找,找不到就会沿着这个对象的__proto__这个隐式原型关联起来的链条向上一个对象查找,这个链条就叫原型链。

function Fn() {}Fn.prototype.name = 'coboy'let fn1 = new Fn()fn1.age = 18console.log(fn1.name) // coboyconsole.log(fn1.age) // 18

fn1是Fn函数new出来的实例对象,fn1.age是这个实例对象上属性,fn1.name则从Fn.prototype原型对象而来,因为fn1的__proto__隐式原型就是指向Fn这个函数的原型对象Fn.prototype。原型链某种意义上是让一个引用类型继承另一个引用类型的属性和方法。

function Fn() {}Fn.prototype.name = 'coboy'let fn1 = new Fn()fn1.name = 'cobyte'console.log(fn1.name) // cobyte

当访问fn1这个实例对象的属性name的时候,JS先会在fn1这个实例对象的属性里查找,刚好fn1定义了一个name属性,所以就直接返回自身属性的值cobyte,否则就会继续沿着原型链向Fn.prototype上去找,那么就会返回coboy。

复习完原型和原型链的知识之后,我们就开始进入Provide/Inject的实现原理探索。

使用 Provide

setup() 中使用 provide 时,我们首先从 vue 显式导入 provide 方法。这使我们能够调用 provide 来定义每个 property。

provide 函数允许你通过两个参数定义 property

  • name (<String> 类型)

  • value

import { provide } from 'vue'export default {  setup() {    provide('name', 'coboy')  }}

provide API实现原理

那么这个provide api实现原理是什么呢?

provide 函数可以简化为

export function provide(key, value) {    // 获取当前组件实例    const currentInstance: any = getCurrentInstance()    if(currentInstance) {        // 获取当前组件实例上provides属性        let { provides } = currentInstance        // 获取当前父级组件的provides属性        const parentProvides = currentInstance.parent.provides        // 如果当前的provides和父级的provides相同则说明还没赋值        if(provides === parentProvides) {            // Object.create() es6创建对象的另一种方式,可以理解为继承一个对象, 添加的属性是在原型下。            provides = currentInstance.provides = Object.create(parentProvides)        }        provides[key] = value    }}

综上所述provide API就是通过获取当前组件的实例对象,将传进来的数据存储在当前的组件实例对象上的provides上,并且通过ES6的新API Object.create把父组件的provides属性设置到当前的组件实例对象的provides属性的原型对象上。

组件实例对象初始化时provides属性的处理

Vue3中Provide和Inject的实现原理是什么

我们通过查看instance对象的源码,可以看到,在instance组件实例对象上,存在parent和provides两个属性。在初始化的时候如果存在父组件则把父组件的provides赋值给当前的组件实例对象的provides,如果没有就创建一个新的对象,并且把应用上下文的provides属性设置为新对象的原型对象上的属性。

使用 Inject

setup() 中使用 inject 时,也需要从 vue 显式导入。导入以后,我们就可以调用它来定义暴露给我们的组件方式。

inject 函数有两个参数:

  • 要 inject 的 property 的 name

  • 默认值 (可选)

import { inject } from 'vue'export default {  setup() {    const name = inject('name', 'cobyte')    return {      name    }  }}

inject API实现原理

那么这个inject API实现原理是什么呢?

inject 函数可以简化为

export function inject(  key,  defaultValue,  treatDefaultAsFactory = false) {  // 获取当前组件实例对象  const instance = currentInstance || currentRenderingInstance  if (instance) {    // 如果intance位于根目录下,则返回到appContext的provides,否则就返回父组件的provides    const provides =      instance.parent == null        ? instance.vnode.appContext && instance.vnode.appContext.provides        : instance.parent.provides    if (provides && key in provides) {      return provides[key]    } else if (arguments.length > 1) {      // 如果存在1个参数以上      return treatDefaultAsFactory && isFunction(defaultValue)        // 如果默认内容是个函数的,就执行并且通过call方法把组件实例的代理对象绑定到该函数的this上        ? defaultValue.call(instance.proxy)         : defaultValue    }  }}

通过inject源码分析我们可以知道,inject里面先获取当前组件的实例对象,然后判断是否根组件,如果是根组件则返回到appContext的provides,否则就返回父组件的provides。

如果当前获取的key在provides上有值,那么就返回该值,如果没有则判断是否存在默认内容,默认内容如果是个函数,就执行并且通过call方法把组件实例的代理对象绑定到该函数的this上,否则就直接返回默认内容。

provide/inject实现原理总结

通过上面的分析,可以得知provide/inject实现原理还是比较简单的,就是巧妙地利用了原型和原型链进行数据的继承和获取。provide API调用设置的时候,设置父级的provides为当前provides对象原型对象上的属性,在inject获取provides对象中的属性值时,优先获取provides对象自身的属性,如果自身查找不到,则沿着原型链向上一个对象中去查找。

拓展:Object.create原理

方法说明

  • Object.create()方法创建一个新的对象,并以方法的第一个参数作为新对象的__proto__属性的值(以第一个参数作为新对象的构造函数的原型对象)

  • Object.create()方法还有第二个可选参数,是一个对象,对象的每个属性都会作为新对象的自身属性,对象的属性值以descriptor(Object.getOwnPropertyDescriptor(obj, 'key'))的形式出现,且enumerable默认为false

源码模拟

Object.myCreate = function (proto, propertyObject = undefined) {    if (propertyObject === null) {        // 这里没有判断propertyObject是否是原始包装对象        throw 'TypeError'    } else {        function Fn () {}        // 设置原型对象属性        Fn.prototype = proto        const obj = new Fn()        if (propertyObject !== undefined) {            Object.defineProperties(obj, propertyObject)        }        if (proto === null) {            // 创建一个没有原型对象的对象,Object.create(null)            obj.__proto__ = null        }        return obj    }}

定义一个空的构造函数,然后指定构造函数的原型对象,通过new运算符创建一个空对象,如果发现传递了第二个参数,通过Object.defineProperties为创建的对象设置key、value,最后返回创建的对象即可。

示例

// 第二个参数为null时,抛出TypeError// const throwErr = Object.myCreate({name: 'coboy'}, null)  // Uncaught TypeError// 构建一个以const obj1 = Object.myCreate({name: 'coboy'})console.log(obj1)  // {}, obj1的构造函数的原型对象是{name: 'coboy'}const obj2 = Object.myCreate({name: 'coboy'}, {    age: {        value: 18,        enumerable: true    }})console.log(obj2)  // {age: 18}, obj2的构造函数的原型对象是{name: 'coboy'}

拓展:两个连续赋值的表达式

provides = currentInstance.provides = Object.create(parentProvides) 发生了什么?

Object.create(parentProvides) 创建了一个新的对象引用,如果只是把 currentInstance.provides 更新为新的对象引用,那么provides的引用还是旧的引用,所以需要同时把provides的引用也更新为新的对象引用。

来自《javascript权威指南》的解析

  • JavaScript总是严格按照从左至右的顺序来计算表达式

  • 一切都是表达式,一切都是运算

provides = currentInstance.provides = Object.create(parentProvides)

上述的provides是一个表达式,它被严格地称为“赋值表达式的左手端(Ihs)操作数”。而右侧 currentInstance.provides = Object.create(parentProvides) 这一个整体也当做一个表达式,这一个整体赋值表达式的计算结果是赋值给了最左侧的providescurrentInstance.provides = Object.create(parentProvides) 这个表达式同时也是一个赋值表达式,Object.create(parentProvides)创建了一个新的引用赋值给了currentInstance这个引用上的provides属性

currentInstance.provides这个表达式的语义是:

  • 计算单值表达式currentInstance,得到currentInstance的引用

  • 将右侧的名字provides理解为一个标识符,并作为“.”运算的右操作数

  • 计算currentInstance.provides表达式的结果(Result)

currentInstance.provides当它作为赋值表达式的左操作数时,它是一个被赋值的引用,而当它作为右操作数时,则计算它的值。

注意:赋值表达式左侧的操作数可以是另一个表达式,而在声明语句中的等号左边,绝不可能是一个表达式。例如上面的如果写成了let provides = xxx,那么这个时候,provides只是一个表达名字的、静态语法分析期作为标识符来理解的字面文本,而不是一个表达式

关于“Vue3中Provide和Inject的实现原理是什么”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“Vue3中Provide和Inject的实现原理是什么”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注编程网精选频道。

--结束END--

本文标题: Vue3中Provide和Inject的实现原理是什么

本文链接: https://lsjlt.com/news/322739.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Vue3中Provide和Inject的实现原理是什么
    这篇文章主要介绍了Vue3中Provide和Inject的实现原理是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Vue3中Provide和Inject的实现原理是什么文章都会有所收获,下面我们一起来看看吧...
    99+
    2023-06-29
  • Vue3中Provide/Inject的实现原理是什么
    本文小编为大家详细介绍“Vue3中Provide/Inject的实现原理是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“Vue3中Provide/Inject的实现原理是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来...
    99+
    2023-06-29
  • Vue3中Provide / Inject的实现原理分享
    目录前言原型和原型链的知识回顾使用 Provideprovide API实现原理组件实例对象初始化时provides属性的处理使用 Injectinject API实现原理provi...
    99+
    2024-04-02
  • vue3中 provide 和 inject 用法及原理
    前言: 在父子组件传递数据时,通常使用的是 props 和 emit,父传子时,使用的是 props,如果是父组件传孙组件时,就需要先传给子组件,子组件再传给孙组件,如果多个子组件或...
    99+
    2024-04-02
  • vue3中provide和inject怎么用
    这篇文章将为大家详细讲解有关vue3中provide和inject怎么用,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。provide 和 inject 的讲解provide和inject可以实现嵌套组件之...
    99+
    2023-06-20
  • vue3中provide和inject的使用
    1.provide 和 inject 的讲解 provide和inject可以实现嵌套组件之间进行传递数据。 这两个函数都是在setup函数中使用的。 父级组件使用provide向...
    99+
    2024-04-02
  • vue3中provide和inject怎么使用
    本篇内容主要讲解“vue3中provide和inject怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“vue3中provide和inject怎么使用”吧!前言:在父子组件传递数据时,通常...
    99+
    2023-06-21
  • vue中provide和inject怎么实现原理对抗平庸
    本篇内容主要讲解“vue中provide和inject怎么实现原理对抗平庸”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“vue中provide和inject怎么实现原理对抗平庸”吧!provid...
    99+
    2023-07-06
  • Vue3中的provide、inject怎么使用
    一. 场景再现先别着急考虑标题这个 api 的含义。在这里我先动手写一个比较常见的场景。所对应的组件内部代码比较简单,这里我就不展示了,逻辑上就是 这三个组件层层引用。所对应的页面效果如下:如上图,这是一个在项目中很常见的一个场景,三层嵌套...
    99+
    2023-05-14
    Vue3 provide inject
  • Vue3插件中怎么使用Provide和Inject
    今天小编给大家分享一下Vue3插件中怎么使用Provide和Inject的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。为什么...
    99+
    2023-07-04
  • 一文搞懂vue中provide和inject实现原理对抗平庸
    目录前言provide & inject 的用法下面例子需要实现什么内心中的呈现下面例子跨层级查找inject放下伪装,吐露心声总结前言 在没有面试又似乎马上就会有面试的躁...
    99+
    2023-05-16
    vue provide inject实现原理 vue provide inject
  • vue2和vue3中provide/inject的基本用法示例
    目录前言vue2基本用法:1.provide2.inject如何成为响应式?1.方法一:函数方法2.方法二:传递thisvue3的基本用法:总结前言 昨天看一个项目代码看到了prov...
    99+
    2023-05-17
    vue中provideinject vue中provide的用法 vue中的inject
  • Vue中的provide和inject怎么使用
    今天小编给大家分享一下Vue中的provide和inject怎么使用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。在vue2...
    99+
    2023-07-06
  • 解析vue的provide和inject使用方法及其原理
    首先来谈谈我们为什么要使用provide/inject呢?对于爷爷和孙子组件之间,甚至太爷爷组件与孙子组件通信我们用vuex不就ok了。 那事实的确如此,但是,请听我说但是,有时候你...
    99+
    2024-04-02
  • Vue3 effectScope API实现原理是什么
    本篇内容介绍了“Vue3 effectScope API实现原理是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!vue3新增e...
    99+
    2023-07-05
  • Vue3插槽Slot的实现原理是什么
    这篇文章主要介绍了Vue3插槽Slot的实现原理是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Vue3插槽Slot的实现原理是什么文章都会有所收获,下面我们一起来看看吧。Vue官方对插槽的定义Vue 实现...
    99+
    2023-07-02
  • Vue3侦听器的实现原理是什么
    侦听响应式对象前面我们聊到计算属性,它可以自动计算并缓存响应式数据的值。而如果我们仅需要在响应式数据变化时,执行一些预设的操作,就可以使用watch侦听器。我们还是先来实现一个最简单的例子,然后来一点一点扩充它。const data = {...
    99+
    2023-05-16
    Vue3
  • Vue3中key的作用和工作原理是什么
    这篇文章主要介绍“Vue3中key的作用和工作原理是什么”,在日常操作中,相信很多人在Vue3中key的作用和工作原理是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Vue3中key的作用和工作原理是什么...
    99+
    2023-06-20
  • Vue2和Vue3的nextTick实现原理
    目录一次弄懂 Vue2 和 Vue3 的 nextTick 实现原理Vue2 中的 nextTick异步任务队列宏任务和微任务总结Vue3 中的 nextTickPromise 在浏...
    99+
    2023-05-18
    Vue2和Vue3的nextTick实现原理 Vue2 nextTick实现原理 Vue3 nextTick 实现原理
  • Vue3中Teleport 组件的原理是什么
    这篇文章将为大家详细讲解有关Vue3中Teleport 组件的原理是什么,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。使用场景业务开发的过程中,我们经常会封...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作