如何检查深度嵌套的道具
Posted
技术标签:
【中文标题】如何检查深度嵌套的道具【英文标题】:How to check for deeply nested props 【发布时间】:2019-07-12 20:41:32 【问题描述】:我经常发现自己必须在映射数组之前构建长链以检查它是否已定义:
this.props.photos &&
this.props.photos.activePhotos &&
this.props.photos.activePhotos.map(...
如果我省略了this.props.photos &&
和this.props.photos.activePhotos.length &&
,如果photos
或activePhotos
未定义,我的整个应用程序将崩溃。
有没有办法检查这些道具而不必检查我的最终项目的每个父对象/数组?
【问题讨论】:
length
是多余的,如果 photos
可以是未定义的或数组。
检查.length
的this.props.photos.activePhotos
的目的是什么?
【参考方案1】:
2020 年 1 月更新
根据the TC39 proposal,optional chaining 将很快在 javascript 标准中可用(目前在stage 4
)。
语法如下:
const active = this.props?.photos?.activePhotos
或者你的情况如下:
(this.props?.photos?.activePhotos || []).map(...
在实现此功能时,您可能需要查看 Typescript 或 js 编译器以尝试最新的 ES 功能
旧答案
另一种方法是在解构它们时为你的道具使用默认值:
const photos = = this.props
const activePhotos = [] = photos
activePhotos.map(/* */)
在这种情况下,如果photos
没有定义,它将被替换为一个空对象。尝试从中取出 activePhotos
会给您一个空数组,让您在任何情况下都可以对其进行映射。
【讨论】:
为什么在这种情况下使用const
?
const
是默认情况下应赋予变量的属性,除非您打算修改它们,在这种情况下您将需要使用let
。我不会提及var
的可怕用途。由于 OP 似乎没有修改他的道具(无论如何他都不应该),我使用了const
【参考方案2】:
我猜你指的是可选链,这是 TC39 的第 1 阶段
https://github.com/tc39/proposal-optional-chaining
编辑:该提案现在处于第 4 阶段(截至 2020 年 1 月),并将被添加到 JavaScript 标准中
【讨论】:
【参考方案3】:根据嵌套级别,我看到了两种可能的方法。
#1。如果您有许多嵌套的道具级别:
您可以使用lodash.get。
这里是如何渲染activePhotos
,前提是它们存在:
// Please note how do we pass default `[]` as third parameter
// in order to not break the `.map` function
_.get(this.props, 'photos.activePhotos', []).map(...)
如果你只想检查深度嵌套的 pro,那么你可以使用lodash.has
方法:
// Will return `true` / `false`
_.has(this.props, 'photos.activePhotos')
#2。如果嵌套层数不超过 2-3 层:
只需使用原生 ES6 解构赋值 + 默认值特性。
const photos = = this.props
const activePhotos = [] = photos
// Now you can safely map over the `activePhotos`
activePhotos.map(...)
【讨论】:
【参考方案4】:有没有办法检查这些道具而不必检查每个 我的最终项目的父对象/数组?
一般来说,不会。
不清楚为什么在问题的代码中检查了潜力的.length
。
如果目标是减少代码长度,您可以联系我们 JSON.stringify()
和 RegExp
if (/"activePhotos":\[.*\]/.test(JSON.stringify(this.props))) // do stuff
或者如果首选方法是使用AND
运算符
/"activePhotos":\[.*\]/.test(JSON.stringify(this.props)) && // do stuff
【讨论】:
注意,在这种情况下,“每个父对象”没有被检查,因为"activePhotos"
应该是只有"photos"
属性的属性,我们可以省略检查"photos"
属性以满足要求.【参考方案5】:
undefsafe 是一个足够好的库来使用。还有很多其他可用的库。
如何使用它的简单示例
var object =
a:
b:
c: 1,
d: [1,2,3],
e: 'remy'
;
console.log(undefsafe(object, 'a.b.e')); // "remy"
console.log(undefsafe(object, 'a.b.not.found')); // undefined
【讨论】:
【参考方案6】:这是一个可选链接的函数式方法,返回默认值。该方法使用Maybe
monad 和Proxy
。
wrap()
函数用于包装可以安全访问任何属性的对象。在内部,wrap
在您的对象周围创建一个代理,并使用 Maybe 包装器管理缺失值。在链的末尾,通过将getOrElse(default)
与属性访问失败时返回的默认值链接起来,解开该值:
class Maybe
constructor(value)
this.__value = value;
static of(value)
if (value instanceof Maybe) return value;
return new Maybe(value);
getOrElse(elseVal)
return this.isNothing() ? elseVal : this.__value;
isNothing()
return this.__value === null || this.__value === undefined;
map(fn)
return this.isNothing()
? Maybe.of(null)
: Maybe.of(fn(this.__value));
function wrap(obj)
function fix(object, property)
const value = object[property];
return typeof value === 'function' ? value.bind(object) : value;
return new Proxy(Maybe.of(obj),
get: function(target, property)
if (property in target)
return fix(target, property);
else
return wrap(target.map(val => fix(val, property)));
);
const obj = a: 1, b: c: [4, 1, 2] , c: () => 'yes' ;
console.log(wrap(obj).a.getOrElse(null)) // returns 1
console.log(wrap(obj).a.b.c.d.e.f.getOrElse(null)) // returns null
console.log(wrap(obj).b.c.getOrElse([])) // returns [4, 1, 2]
console.log(wrap(obj).b.c[0].getOrElse(null)) // returns 4
console.log(wrap(obj).b.c[100].getOrElse(-1)) // out-of-bounds index: returns -1
console.log(wrap(obj).c.getOrElse(() => 'no')()) // returns 'yes'
console.log(wrap(obj).d.getOrElse(() => 'no')()) // returns 'no'
有关 Maybe monad 和代理使用的更多信息,请参阅 this blog post 和 this link。
【讨论】:
以上是关于如何检查深度嵌套的道具的主要内容,如果未能解决你的问题,请参考以下文章