成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

在javascript中安全地訪問深層嵌套的值

zacklee / 3381人閱讀

摘要:介紹這是一篇短文,旨在展示多種在中安全地訪問深層嵌套值的方式。所以每次我們想要訪問深度嵌套的數(shù)據(jù)時(shí),都必須明確地進(jìn)行手動(dòng)檢查。我們還觸及了,可以更新深度嵌套數(shù)據(jù)而不會(huì)改變對象。

介紹

這是一篇短文,旨在展示多種在javascript中安全地訪問深層嵌套值的方式。
下面的例子通過不同的方式來解決這一問題。

開始之前,讓我們看下實(shí)際遇到這種狀況時(shí)..

假設(shè)有一個(gè)props對象(如下),當(dāng)我們需要獲取user對象的posts的第一條的comments對象,通常會(huì)如何操作?

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

最直白的方式是確保每一個(gè)key或index的存在再去訪問它的下一級??紤]的多點(diǎn),當(dāng)需求變化需要去請求第一條comments時(shí),這個(gè)式子會(huì)變得越來越長。

// 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ù)據(jù)時(shí),都必須明確地進(jìn)行手動(dòng)檢查?;蛟S很難說清這一點(diǎn),試想一下當(dāng)我們不希望檢驗(yàn)users對象下的posts,只是希望獲取到users下的最后一條comment,和前面的解決思路是相違背的。

這個(gè)例子可能有些夸張,但你懂我的意思,為了得到深層嵌套的值,我們需要檢驗(yàn)整個(gè)結(jié)構(gòu)的每一級(所有父級)。

所以,現(xiàn)在我們已經(jīng)更好地理解了實(shí)際想要解決的問題,讓我們來看看不同的解決方案。前面一些是通過javascript,再后面通過Ramda,再再后面是Ramda和Folktale。將通過一些比較有趣并且不算高級的例子來說明,希望大家在本次專題里有所收益。

JavaScript

首先,我們不希望手動(dòng)檢驗(yàn)每一級是否為空或是未定義,我們希望有一種精簡且靈活的方式來應(yīng)對各種數(shù)據(jù)源。

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這個(gè)方法

const get = (p, o) =>
  p.reduce((xs, x) =>
    (xs && xs[x]) ? xs[x] : null, o)

我們傳入路徑(path)作為第一個(gè)參數(shù),需要獲取的對象(object)作為第二個(gè)參數(shù)。
思考一下這第二個(gè)參數(shù)o(object),你可能會(huì)問自己:我們期望這個(gè)方法有什么功能?應(yīng)該是一個(gè)輸入特定路徑并且針對任何對象都能返回是否存在預(yù)期對象的方法。

const get = p => o =>
  p.reduce((xs, x) =>
    (xs && xs[x]) ? xs[x] : null, o)

const getUserComments = get(["user", "posts", 0, "comments"])

通過這種方式,我們可以調(diào)用getUserComments和之前的props對象或是任何其他對象。這也暗示我們必須得像這樣不停琢磨這個(gè)get函數(shù),

最終我們能打印出結(jié)果,驗(yàn)證下是否如預(yù)期得結(jié)果。

console.log(getUserComments(props))
// [ "Good one!", "Interesting..." ]
console.log(getUserComments({user:{posts: []}}))
// null

get函數(shù)實(shí)質(zhì)上就是在減少先前的路徑。

讓我們來簡化一下,現(xiàn)在我們只想訪問這個(gè)id。

["id"].reduce((xs, x) => (xs && xs[x]) ? xs[x] : null, {id: 10})

我們用提供的對象初始化reduce函數(shù),每一層通過(xs && xs[x]) 檢驗(yàn)對象是否被定義且有效, 然后依次遞歸或是返回null退出。
就像上面的例子一樣,我們可以輕巧地解決這一問題。當(dāng)然如果你偏向習(xí)慣用字符串路徑而不是數(shù)組來表達(dá)路徑,還需要對get函數(shù)做一些小改動(dòng),我將留給感興趣的讀者來實(shí)現(xiàn)。

Ramda

我們也可以利用Ramda函數(shù)庫來實(shí)現(xiàn)相同的功能,而不是編寫自己的函數(shù)。
Ramda提供了一個(gè)path方法,兩個(gè)參數(shù)輸入, path以及object。讓我們用Ramda重寫這個(gè)例子。

const getUserComments = R.path(["user", "posts", 0, "comments"])

現(xiàn)在通過getUserComments傳入數(shù)據(jù)源就能得到我們希望的值,如果沒有找到就會(huì)得到null

getUserComments(props) // [ "Good one!", "Interesting..." ]
getUserComments({}) // null

但是如果我們想要返回的無效值不是null呢?Ramda提供了pathOrpathOr需要傳入默認(rèn)值作為參數(shù)。

const getUserComments = R.pathOr([], ["user", "posts", 0, "comments"])
getUserComments(props) // [ "Good one!", "Interesting..." ]
getUserComments({}) // []

感謝Gleb Bahmutov提供對于path和pathOr的見解。

Ramda + Folktale

讓我們再加入FolktaleMaybe。例如我們可以構(gòu)建一個(gè)更通用的getPath函數(shù)(同樣傳入path和object)。

const getPath = R.compose(Maybe.fromNullable, R.path)
const userComments =
  getPath(["user", "posts", 0, "comments"], props)

調(diào)用getPath會(huì)返回Maybe.Just或是Maybe.Nothing

console.log(userComments) // Just([ "Good one!", "Interesting..." ])

將我們的返回結(jié)果包在Maybe中有什么用呢?通過采用這種方式,我們可以安全地使用userComments,無需手動(dòng)檢驗(yàn)userComments是否返回nul。

console.log(userComments.map(x => x.join(",")))
// Just("Good one!,Interesting...")

沒有任何值時(shí)也是如此。

const userComments =
    getPath(["user", "posts", 8, "title"], props)

console.log(userComments.map(x => x.join(",")).toString())
// Nothing

我們可以把所有屬性包裹在Maybe內(nèi)。這使我們能夠使用composeK來實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用。

// 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方法其實(shí)就足夠了。不過讓我簡單看下下面這個(gè)例子(通過Ramda地composechain實(shí)現(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也能實(shí)現(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就帶有lensProplensPath

// lenses
const findUserComments =
  R.lensPath(["user", "posts", 0, "comments"])
console.log(R.view(findUserComments, props))
// [ "Good one!", "Interesting..." ]
總結(jié)

我們應(yīng)該對如何檢索嵌套數(shù)據(jù)的多種方法有了清楚的理解。除了知道如何自己實(shí)現(xiàn)外,還應(yīng)該對Ramda提供的關(guān)于這個(gè)問題的功能有一個(gè)基本的了解。甚至可以更好地i理解為什么將結(jié)果包含Either或Maybe中。我們還觸及了Lenses,可以更新深度嵌套數(shù)據(jù)而不會(huì)改變對象。
最后,你再也不會(huì)去編寫下面這樣的代碼了。

// updating the previous example...
props.user &&
props.user.posts &&
props.user.posts[0] &&
props.user.posts[0].comments &&
props.user.posts[0].comments[0]

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/107638.html

相關(guān)文章

  • 【譯】教你如何避開「Cannot read property of undefined」

    摘要:比如的,的提供訪問安全對象的支持。在使用的情況下,這意味著表達(dá)式在達(dá)到其第一個(gè)假值后將停止向后執(zhí)行。這便可用于安全地訪問嵌套屬性。與上述短路示例類似,此方法通過檢查值是否為假來進(jìn)行操作。該方法優(yōu)于該方法的地方是避免屬性名稱的重復(fù)。 Uncaught TypeError: Cannot read property foo of undefined.這種錯(cuò)誤想必在我們?nèi)粘i_發(fā)中都到過,這有...

    xiaoqibTn 評論0 收藏0
  • 如何優(yōu)雅安全深層數(shù)據(jù)結(jié)構(gòu)取值

    摘要:如果這個(gè)結(jié)構(gòu)非常復(fù)雜,那么想要安全優(yōu)雅地取出一個(gè)值,也并非簡單。這是為了在對象中相關(guān)取值的過程,需要驗(yàn)證每一個(gè)和的存在性。并且這個(gè)數(shù)據(jù)結(jié)構(gòu)必然是動(dòng)態(tài)生成的,存在有時(shí)有時(shí)的情況。在測試過程中,很難復(fù)現(xiàn)。 古有趙子龍面對沖鋒之勢,有進(jìn)無退,陷陣之志,有死無生的局面,能萬軍叢中取敵將首級。在我們的Javascript中,往往用對象(Object)來存儲一個(gè)數(shù)據(jù)結(jié)構(gòu)。如果這個(gè)結(jié)構(gòu)非常復(fù)雜,那么...

    RobinQu 評論0 收藏0
  • 如何優(yōu)雅安全深層數(shù)據(jù)結(jié)構(gòu)取值

    摘要:如果這個(gè)結(jié)構(gòu)非常復(fù)雜,那么想要安全優(yōu)雅地取出一個(gè)值,也并非簡單。這是為了在對象中相關(guān)取值的過程,需要驗(yàn)證每一個(gè)和的存在性。并且這個(gè)數(shù)據(jù)結(jié)構(gòu)必然是動(dòng)態(tài)生成的,存在有時(shí)有時(shí)的情況。在測試過程中,很難復(fù)現(xiàn)。 古有趙子龍面對沖鋒之勢,有進(jìn)無退,陷陣之志,有死無生的局面,能萬軍叢中取敵將首級。在我們的Javascript中,往往用對象(Object)來存儲一個(gè)數(shù)據(jù)結(jié)構(gòu)。如果這個(gè)結(jié)構(gòu)非常復(fù)雜,那么...

    liaorio 評論0 收藏0
  • 前端數(shù)據(jù)扁平化與持久化

    摘要:與持久化工程師花了年時(shí)間打造,與同期出現(xiàn)。有持久化數(shù)據(jù)結(jié)構(gòu),如等,并發(fā)安全??偨Y(jié)篇幅有限,時(shí)間也比較晚了,關(guān)于前端數(shù)據(jù)的扁平化與持久化處理先講這么多了,有興趣的同學(xué)可以關(guān)注下,后面有時(shí)間會(huì)多整理分享。 (PS: 時(shí)間就像海綿里的水,擠到?jīng)]法擠,只能擠擠睡眠時(shí)間了~ 知識點(diǎn)還是需要整理的,付出總會(huì)有收獲,tired but fulfilled~) 前言 最近業(yè)務(wù)開發(fā),從零搭建網(wǎng)頁生成器,...

    dreamtecher 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<