摘要:介紹這是一篇短文,旨在展示多種在中安全地訪問深層嵌套值的方式。所以每次我們想要訪問深度嵌套的數(shù)據時,都必須明確地進行手動檢查。我們還觸及了,可以更新深度嵌套數(shù)據而不會改變對象。
介紹
這是一篇短文,旨在展示多種在javascript中安全地訪問深層嵌套值的方式。
下面的例子通過不同的方式來解決這一問題。
開始之前,讓我們看下實際遇到這種狀況時..
假設有一個props對象(如下),當我們需要獲取user對象的posts的第一條的comments對象,通常會如何操作?
const props = { user: { posts: [ { title: "Foo", comments: [ "Good one!", "Interesting..." ] }, { title: "Bar", comments: [ "Ok" ] }, { title: "Baz", comments: [] }, ] } }
// access deeply nested values... props.user && props.user.posts && props.user.posts[0] && props.user.posts[0].comments
最直白的方式是確保每一個key或index的存在再去訪問它的下一級。考慮的多點,當需求變化需要去請求第一條comments時,這個式子會變得越來越長。
// updating the previous example... props.user && props.user.posts && props.user.posts[0] && props.user.posts[0].comments && props.user.posts[0].comments[0]
所以每次我們想要訪問深度嵌套的數(shù)據時,都必須明確地進行手動檢查。或許很難說清這一點,試想一下當我們不希望檢驗users對象下的posts,只是希望獲取到users下的最后一條comment,和前面的解決思路是相違背的。
這個例子可能有些夸張,但你懂我的意思,為了得到深層嵌套的值,我們需要檢驗整個結構的每一級(所有父級)。
所以,現(xiàn)在我們已經更好地理解了實際想要解決的問題,讓我們來看看不同的解決方案。前面一些是通過javascript,再后面通過Ramda,再再后面是Ramda和Folktale。將通過一些比較有趣并且不算高級的例子來說明,希望大家在本次專題里有所收益。
JavaScript首先,我們不希望手動檢驗每一級是否為空或是未定義,我們希望有一種精簡且靈活的方式來應對各種數(shù)據源。
const get = (p, o) => p.reduce((xs, x) => (xs && xs[x]) ? xs[x] : null, o) // let"s pass in our props object... console.log(get(["user", "posts", 0, "comments"], props)) // [ "Good one!", "Interesting..." ] console.log(get(["user", "post", 0, "comments"], props)) // null
看一下get這個方法
const get = (p, o) => p.reduce((xs, x) => (xs && xs[x]) ? xs[x] : null, o)
我們傳入路徑(path)作為第一個參數(shù),需要獲取的對象(object)作為第二個參數(shù)。
思考一下這第二個參數(shù)o(object),你可能會問自己:我們期望這個方法有什么功能?應該是一個輸入特定路徑并且針對任何對象都能返回是否存在預期對象的方法。
const get = p => o => p.reduce((xs, x) => (xs && xs[x]) ? xs[x] : null, o) const getUserComments = get(["user", "posts", 0, "comments"])
通過這種方式,我們可以調用getUserComments和之前的props對象或是任何其他對象。這也暗示我們必須得像這樣不停琢磨這個get函數(shù),
最終我們能打印出結果,驗證下是否如預期得結果。
console.log(getUserComments(props)) // [ "Good one!", "Interesting..." ] console.log(getUserComments({user:{posts: []}})) // null
get函數(shù)實質上就是在減少先前的路徑。
讓我們來簡化一下,現(xiàn)在我們只想訪問這個id。
["id"].reduce((xs, x) => (xs && xs[x]) ? xs[x] : null, {id: 10})
我們用提供的對象初始化reduce函數(shù),每一層通過(xs && xs[x]) 檢驗對象是否被定義且有效, 然后依次遞歸或是返回null退出。
就像上面的例子一樣,我們可以輕巧地解決這一問題。當然如果你偏向習慣用字符串路徑而不是數(shù)組來表達路徑,還需要對get函數(shù)做一些小改動,我將留給感興趣的讀者來實現(xiàn)。
我們也可以利用Ramda函數(shù)庫來實現(xiàn)相同的功能,而不是編寫自己的函數(shù)。
Ramda提供了一個path方法,兩個參數(shù)輸入, path以及object。讓我們用Ramda重寫這個例子。
const getUserComments = R.path(["user", "posts", 0, "comments"])
現(xiàn)在通過getUserComments傳入數(shù)據源就能得到我們希望的值,如果沒有找到就會得到null。
getUserComments(props) // [ "Good one!", "Interesting..." ] getUserComments({}) // null
但是如果我們想要返回的無效值不是null呢?Ramda提供了pathOr。pathOr需要傳入默認值作為參數(shù)。
const getUserComments = R.pathOr([], ["user", "posts", 0, "comments"]) getUserComments(props) // [ "Good one!", "Interesting..." ] getUserComments({}) // []
感謝Gleb Bahmutov提供對于path和pathOr的見解。
Ramda + Folktale讓我們再加入Folktale的Maybe。例如我們可以構建一個更通用的getPath函數(shù)(同樣傳入path和object)。
const getPath = R.compose(Maybe.fromNullable, R.path) const userComments = getPath(["user", "posts", 0, "comments"], props)
調用getPath會返回Maybe.Just或是Maybe.Nothing。
console.log(userComments) // Just([ "Good one!", "Interesting..." ])
將我們的返回結果包在Maybe中有什么用呢?通過采用這種方式,我們可以安全地使用userComments,無需手動檢驗userComments是否返回nul。
console.log(userComments.map(x => x.join(","))) // Just("Good one!,Interesting...")
沒有任何值時也是如此。
const userComments = getPath(["user", "posts", 8, "title"], props) console.log(userComments.map(x => x.join(",")).toString()) // Nothing
我們可以把所有屬性包裹在Maybe內。這使我們能夠使用composeK來實現(xiàn)鏈式調用。
// example using composeK to access a deeply nested value. const getProp = R.curry((name, obj) => Maybe.fromNullable(R.prop(name, obj))) const findUserComments = R.composeK( getProp("comments"), getProp(0), getProp("posts"), getProp("user") ) console.log(findUserComments(props).toString()) // Just([ "Good one!", "Interesting..." ]) console.log(findUserComments({}).toString()) // Nothing
這種方式是非常前衛(wèi)的,使用Ramda地path方法其實就足夠了。不過讓我簡單看下下面這個例子(通過Ramda地compose和chain實現(xiàn)同樣的效果)
// using compose and chain const getProp = R.curry((name, obj) => Maybe.fromNullable(R.prop(name, obj))) const findUserComments = R.compose( R.chain(getProp("comments")), R.chain(getProp(0)), R.chain(getProp("posts")), getProp("user") ) console.log(findUserComments(props).toString()) // Just([ "Good one!", "Interesting..." ]) console.log(findUserComments({}).toString()) // Nothing
通過pipeK也能實現(xiàn)同樣的效果。
// example using pipeK to access a deeply nested value. const getProp = R.curry((name, obj) => Maybe.fromNullable(R.prop(name, obj))) const findUserComments = R.pipeK( getProp("user"), getProp("posts"), getProp(0), getProp("comments") ) console.log(findUserComments(props).toString()) // Just([ "Good one!", "Interesting..." ]) console.log(findUserComments({}).toString()) // Nothing
還可以用map配合pipeK。感謝Tom Harding提供pipeK的例子。
Lenses最后,我們還可以使用Lenses。Ramda就帶有lensProp和lensPath
// lenses const findUserComments = R.lensPath(["user", "posts", 0, "comments"]) console.log(R.view(findUserComments, props)) // [ "Good one!", "Interesting..." ]總結
我們應該對如何檢索嵌套數(shù)據的多種方法有了清楚的理解。除了知道如何自己實現(xiàn)外,還應該對Ramda提供的關于這個問題的功能有一個基本的了解。甚至可以更好地i理解為什么將結果包含Either或Maybe中。我們還觸及了Lenses,可以更新深度嵌套數(shù)據而不會改變對象。
最后,你再也不會去編寫下面這樣的代碼了。
// updating the previous example... props.user && props.user.posts && props.user.posts[0] && props.user.posts[0].comments && props.user.posts[0].comments[0]
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/107638.html
摘要:比如的,的提供訪問安全對象的支持。在使用的情況下,這意味著表達式在達到其第一個假值后將停止向后執(zhí)行。這便可用于安全地訪問嵌套屬性。與上述短路示例類似,此方法通過檢查值是否為假來進行操作。該方法優(yōu)于該方法的地方是避免屬性名稱的重復。 Uncaught TypeError: Cannot read property foo of undefined.這種錯誤想必在我們日常開發(fā)中都到過,這有...
摘要:如果這個結構非常復雜,那么想要安全優(yōu)雅地取出一個值,也并非簡單。這是為了在對象中相關取值的過程,需要驗證每一個和的存在性。并且這個數(shù)據結構必然是動態(tài)生成的,存在有時有時的情況。在測試過程中,很難復現(xiàn)。 古有趙子龍面對沖鋒之勢,有進無退,陷陣之志,有死無生的局面,能萬軍叢中取敵將首級。在我們的Javascript中,往往用對象(Object)來存儲一個數(shù)據結構。如果這個結構非常復雜,那么...
摘要:如果這個結構非常復雜,那么想要安全優(yōu)雅地取出一個值,也并非簡單。這是為了在對象中相關取值的過程,需要驗證每一個和的存在性。并且這個數(shù)據結構必然是動態(tài)生成的,存在有時有時的情況。在測試過程中,很難復現(xiàn)。 古有趙子龍面對沖鋒之勢,有進無退,陷陣之志,有死無生的局面,能萬軍叢中取敵將首級。在我們的Javascript中,往往用對象(Object)來存儲一個數(shù)據結構。如果這個結構非常復雜,那么...
摘要:與持久化工程師花了年時間打造,與同期出現(xiàn)。有持久化數(shù)據結構,如等,并發(fā)安全。總結篇幅有限,時間也比較晚了,關于前端數(shù)據的扁平化與持久化處理先講這么多了,有興趣的同學可以關注下,后面有時間會多整理分享。 (PS: 時間就像海綿里的水,擠到沒法擠,只能擠擠睡眠時間了~ 知識點還是需要整理的,付出總會有收獲,tired but fulfilled~) 前言 最近業(yè)務開發(fā),從零搭建網頁生成器,...
閱讀 2689·2021-10-22 09:55
閱讀 2018·2021-09-27 13:35
閱讀 1272·2021-08-24 10:02
閱讀 1494·2019-08-30 15:55
閱讀 1205·2019-08-30 14:13
閱讀 3478·2019-08-30 13:57
閱讀 1980·2019-08-30 11:07
閱讀 2456·2019-08-29 17:12