一文搞懂vue中provide和inject實(shí)現(xiàn)原理對(duì)抗平庸
前言
在沒(méi)有面試又似乎馬上就會(huì)有面試的躁動(dòng)不安的日子里,迷迷糊糊的看到一個(gè)面試題“你知道provide和inject的實(shí)現(xiàn)原理嗎”,我學(xué)著面試官的樣子試問(wèn)自己"你知道嗎",我的大腦翻遍了記憶,也沒(méi)有找到,可能是沒(méi)有記載,亦可能是時(shí)間過(guò)長(zhǎng)被積壓在了記憶深處,我始終沒(méi)有回答我自己,這讓我非常懊惱,又滿是無(wú)奈。所以我想搞懂它,用它的原理來(lái)?yè)崞轿业膬?nèi)心。
provide & inject 的用法
provide("num", 0); const num = inject("num")
這大致就是它們的美貌,它們示人的一面,如此優(yōu)雅,如此簡(jiǎn)潔。它們隱藏了內(nèi)心,從這里讓我無(wú)法了解到它的內(nèi)心它到底在想什么呢,在做什么呢,我嘗試著與它親近,逐漸發(fā)現(xiàn)它的有趣。
在provide中,它留了兩個(gè)深入了解它的窗口provide(key, value),同樣在inject中,目前只能看到一個(gè)inject(key),結(jié)合它們的功能知道,它們的主要功能不就是存和取,所以想要了解它們就要搞清楚如何存,怎么取,先讓這疑問(wèn)留在心底罷,來(lái)看看"下面例子"
下面例子
有這樣一串代碼,讓我們實(shí)現(xiàn)provide 和 inject這兩個(gè)函數(shù),達(dá)到在foo對(duì)象中的fooObj取的是app對(duì)象中provide提供的對(duì)象obj,我們?nèi)绾螌?shí)現(xiàn)
const obj = { name: "app" }; const foo = { name: "foo", provides: {}, parent: null, setup() { foo.parent = app; // 先忽略 const fooObj = inject("obj"); console.log("app -> foo: obj ", fooObj === obj); // 要求打印true }, children: null, }; const app = { name: "app", provides: {}, parent: null, setup() { app.parent = app; // 先忽略 provide("obj", obj); }, children: foo, }; (function () { app.setup(); foo.setup(); })();
需要實(shí)現(xiàn)什么
首先我們需要明確我們要干什么:
- 其實(shí)本質(zhì)就是要實(shí)現(xiàn)provide和inject函數(shù)
- 明確代碼在做什么
- 有兩個(gè)對(duì)象app 和 foo,它兩長(zhǎng)得一樣美麗,初始化階段,它兩內(nèi)部的setup方法會(huì)依次執(zhí)行,在內(nèi)部它們分別使用了provide提供數(shù)據(jù),以及使用inject獲取數(shù)據(jù),要求fooObj === obj為true,這其實(shí)就是判斷是否是同一個(gè)數(shù)據(jù)的根本方法。
知道了這些后,我們一起來(lái)認(rèn)識(shí)一下provide和inject吧,我們以主觀意識(shí)去了解它們,把我認(rèn)為它是什么樣子畫(huà)出來(lái)。
首先畫(huà)出它的骨架:
function provide(key, value) { // 靈魂深處 } function inject(key) { // 靈魂深處 }
我們要一起探聽(tīng)我們理想中它們的靈魂
內(nèi)心中的呈現(xiàn)
provide分析
- 提供了key-value
- 我們需要存儲(chǔ)在各自對(duì)象中的provides屬性中
function provide(key, value) { // 獲取當(dāng)前提供provide的對(duì)象 const currentInstance = app; // 將provide提供的key-value存儲(chǔ)到當(dāng)前對(duì)象的provides中 let { provides } = currentInstance; provides[key] = value; }
inject分析
- 從parent下的provides開(kāi)始取值,因?yàn)樵谧约哼@里提供的provide不需要進(jìn)行inject,多此一舉
function inject(key) { const currentInstance = foo; // 從parent的provides取值 const parentProvides = currentInstance.parent.provides; // 如果提供了值,就可以取到并返回 if (key in parentProvides) { return parentProvides[key]; } }
這時(shí)候我們可以打印出(fooObj === obj) === true了
在沉浸喜悅的同時(shí),在provide和inject靈魂處蹦出字來(lái)你還是不夠了解我,我仔細(xì)思考,好像也是,它們還有一個(gè)特性就是跨層級(jí),這恰恰是遺忘了它最有靈魂的地方,所以我們重新規(guī)劃下面例子
下面例子
const obj = { name: "app" }; const baz = { name: "foo", provides: {}, parent: null, setup() { baz.parent = foo; const bazObj = inject("obj"); console.log("app -> baz: obj ", bazObj === obj); // 要求打印true }, children: null, }; const foo = { name: "foo", provides: {}, parent: null, setup() { foo.parent = app; }, children: baz, }; const app = { name: "app", provides: {}, parent: null, setup() { app.parent = app; provide("obj", obj); }, children: foo, }; (function () { app.setup(); foo.setup(); baz.setup(); })();
這時(shí)候就會(huì)打印false了PS: 如果你還是true,那是因?yàn)槟阍?inject 里 currentInstance沒(méi)有改變,這里是需要改變的,只能指到當(dāng)前對(duì)象,所以我們?nèi)绾谓鉀Q呢?
這里說(shuō)到如果currentInstance 是 foo,那就沒(méi)有問(wèn)題,但是又因?yàn)檫@里是只能指向當(dāng)前對(duì)象的,所以不能直接賦值,突然,靈光一閃,無(wú)非不就是查找的時(shí)候需要繼續(xù)向下查找,這不是和原型鏈一樣嘛內(nèi)心:哈哈哈,我真聰明,所以我們給它進(jìn)行原型連接不就好了,讓一直向parent上找,直到找不到。
跨層級(jí)查找
進(jìn)行原型連接,實(shí)現(xiàn)跨層級(jí):Object.create(obj): 創(chuàng)造一個(gè)原型為obj的空對(duì)象
const foo = { name: "foo", provides: {}, parent: null, setup() { foo.parent = app; // 執(zhí)行原型連接 foo.provides = Object.create(foo.parent.provides); }, children: baz, };
這樣就又打印true了,因?yàn)樗苯釉趂oo.provides上查找,無(wú)法找到提供的obj所以會(huì)undefined,原型連接后,查找會(huì)順著原型鏈查找,直到找不到,那找不到的時(shí)候怎么辦呢,它會(huì)報(bào)錯(cuò)的呀,這是不能容忍的,所以inject向我敞開(kāi)心扉,和我聊自己是怎么樣的一個(gè)API,它說(shuō):"我其實(shí)有三種外貌,對(duì)應(yīng)不同心情,分別是inject(key)、inject(key, defaultValue)和 defaultValue 可以是函數(shù)",至此我們之間的關(guān)系好像又進(jìn)一步,我好像更了解它們了。
inject放下偽裝,吐露心聲
inject 的形態(tài):
- inject(key) —— 已實(shí)現(xiàn)
- inject(key, defaultValue) —— 未實(shí)現(xiàn)
- inject(key, () => defaultValue) —— 未實(shí)現(xiàn)
回顧一下inject:
function inject(key) { const currentInstance = baz; const parentProvides = currentInstance.parent.provides; if (key in parentProvides) { return parentProvides[key]; } }
這是我們最后實(shí)現(xiàn)inject的樣子,這會(huì)inject告訴了我們其他狀態(tài),所以我們需要和它更進(jìn)一步,它會(huì)提供一個(gè)defaultValue屬性,所以我們?cè)趐arent鏈中沒(méi)有找到key的時(shí)候,就需要賦值defaultValue了
function inject(key, defaultValue) { const currentInstance = baz; const parentProvides = currentInstance.parent.provides; // 當(dāng)沒(méi)有在 parent 鏈中找到對(duì)應(yīng)key,就返回默認(rèn)值 if (key in parentProvides) { return parentProvides[key]; } else if (defaultValue) { return defaultValue; } }
將baz對(duì)象修改為:
const baz = { name: "foo", provides: {}, parent: null, setup() { baz.parent = foo; const defaultBaz = inject("baz", "我是默認(rèn)值啦!"); console.log(defaultBaz, "baz"); }, children: null, };
打印出了:我是默認(rèn)值啦!
但是當(dāng)defaultValue是回調(diào)函數(shù)的時(shí)候,我們所以需要添加判斷條件,如果是回調(diào)函數(shù),那就直接執(zhí)行。
修改后的inject:
function inject(key, defaultValue) { const currentInstance = baz; const parentProvides = currentInstance.parent.provides; if (key in parentProvides) { return parentProvides[key]; } else if (defaultValue) { // 新增判斷 if (typeof defaultValue === "function") { return defaultValue(); } return defaultValue; } }
修改后的baz中的inject使用:
const defaultBaz = inject("baz", () => "我是默認(rèn)值啦!");
同樣也會(huì)打印出:我是默認(rèn)值啦!
現(xiàn)在我們好像成為好朋友了,所以,你好,provide!你好,inject!你們好,各位大帥b!
總結(jié)
- 每個(gè)provide提供的數(shù)據(jù)都存在當(dāng)前組件的provides屬性上
- inject取值的時(shí)候,會(huì)從當(dāng)前的父組件中的provides開(kāi)始取值
- 其實(shí)已經(jīng)懂了 provide 和 inject 原理了,因?yàn)樵赩ue中,他的每個(gè)組件也會(huì)生成組件實(shí)例,而這些屬性全都在實(shí)例對(duì)象上。
以上就是一文搞懂vue中provide和inject實(shí)現(xiàn)原理對(duì)抗平庸的詳細(xì)內(nèi)容,更多關(guān)于vue provide inject實(shí)現(xiàn)原理的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Vue-Ant Design Vue-普通及自定義校驗(yàn)實(shí)例
這篇文章主要介紹了Vue-Ant Design Vue-普通及自定義校驗(yàn)實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-10-10Vue項(xiàng)目實(shí)現(xiàn)簡(jiǎn)單的權(quán)限控制管理功能
這篇文章主要介紹了Vue項(xiàng)目實(shí)現(xiàn)簡(jiǎn)單的權(quán)限控制功能,文中給大家介紹了兩種方式進(jìn)行權(quán)限限制,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2019-07-07vue的el-select綁定的值無(wú)法選中el-option問(wèn)題及解決
這篇文章主要介紹了vue的el-select綁定的值無(wú)法選中el-option問(wèn)題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09Vue3?在<script?setup>里設(shè)置組件name屬性的方法
這篇文章主要介紹了Vue3?在<script?setup>里設(shè)置組件name屬性的方法,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧2023-11-11詳解vuex中mutations方法的使用與實(shí)現(xiàn)
這篇文章主要為大家詳細(xì)介紹了vuex中mutations方法的使用與實(shí)現(xiàn)的相關(guān)知識(shí),文中的示例代碼簡(jiǎn)潔易懂,具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以跟隨小編一起了解一下2023-11-11Ant?Design?Vue?走馬燈實(shí)現(xiàn)單頁(yè)多張圖片輪播效果
這篇文章主要介紹了Ant?Design?Vue?走馬燈實(shí)現(xiàn)單頁(yè)多張圖片輪播,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-07-07Vue動(dòng)態(tài)加載ECharts圖表數(shù)據(jù)的方式
這篇文章主要介紹了Vue動(dòng)態(tài)加載ECharts圖表數(shù)據(jù)的方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07Vue實(shí)例中生命周期created和mounted的區(qū)別詳解
這篇文章主要給大家介紹了關(guān)于Vue實(shí)例中生命周期created和mounted區(qū)別的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面跟著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-08-08