从JSON中提取属性的姿势

650 阅读2分钟

  无论我们开发产品、组件还是工具集,都需要接收外部(上游或用户)输入。通常会有一些结构的约定,比如:

{
	info?: {
    	children?: Array,
        keywords?: Array
    }
}

  这么多的可选,因为我们无法要求用户如此有耐心地创造一堆空结构,但是要用children和keywords怎么办?或者说如何提取更舒适,更满足场景需求?

逻辑运算符

const noChildren = !data.info || !data.info.children;
const noKeywords = !data.info || !data.info.keywords;
const children = noChildren ? [] : data.info.children;
const keywords = noKeywords ? [] : data.info.keywords;

  emmm, 结果是符合期望的,但是产生了两个只用了一次的中间变量,改进一下。

const children = data.info && data.info.children || [];
const keywords = data.info && data.info.keywords || [];

  但是data.info的书写显得『啰嗦』,更严重的是逻辑运算符的混合降低了可读性。

解构赋值

const {
	children = [],
    keywords = []
} = data.info || {};

  运用解构赋值的默认值写法,很清楚的表达了提取两个属性并赋默认值的想法。而且与逻辑运算符的写法不同的是,解构赋值在=== undefined才会应用默认值,而不是Boolean() === false。

  局限是它更适合同层级多属性的提取,对于嵌套层级较深的情况,频繁的默认{}维持解构也破坏可读性。

ES2020运算符

const children = data?.info?.children || [];
const keywords = data?.info?.keywords || [];

  ?.可以确保访问属性的过程,若中间出现非object属性、属性不存在的状况,会返回undefined。但是『或』运算还是以Boolean() === false判断,改进一下。

const children = data?.info?.children ?? [];
const keywords = data?.info?.keywords ?? [];

  ??以undefined|null判断,可以作为『严格』的『或』使用。所以,?. ??混合=== undefined|null才会应用默认值

  这种方式适合于嵌套层级较深的情况,但是需要用babel做相关转换,以兼容低版本。

lodash get

const children = _.get(data, 'info.children', []);
const keywords = _.get(data, 'info.keywords', []);

  get方法也是在=== undefined才会应用默认值,三个参数的形式也便于理解,但调用的方式适合于嵌套较深的单个属性。


综上

  • 逻辑运算符原生兼容性好,可读性不佳。
  • 解构赋值和lodash.get都判断undefined,前者适合『集』型,后者适合『链』型,结合可满足复杂需求。
  • ?. ??运算符判断undefined|null,适合『链』型,可作为不引入依赖时,lodash.get的替代,添加babel配置。