如何检查深度嵌套的道具

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 &&,如果photosactivePhotos 未定义,我的整个应用程序将崩溃。

有没有办法检查这些道具而不必检查我的最终项目的每个父对象/数组?

【问题讨论】:

length 是多余的,如果 photos 可以是未定义的或数组。 检查.lengththis.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。

【讨论】:

以上是关于如何检查深度嵌套的道具的主要内容,如果未能解决你的问题,请参考以下文章

使用 Flow 对 React 中深度嵌套的 props 进行类型检查

如何将深度嵌套的列表转换为字符串

数据中的Vue深度克隆道具没有响应

如何使用深度嵌套查询处理 Vue Apollo 中的删除?

如何要求深度嵌套的 NodeJS 模块?

如何使用 mongoose 在深度嵌套的数组上进行切片