不安装babel插件,如何实现类似可选链功能

214 阅读2分钟

需求说明

获取对象类型中深层嵌套的value值

比如我们定义一个对象类型:
var object = {
    a: 1,
    b: '2',
    c: [3, '4', [5], {d: 6}],
    e: {f: 7}
}

如果要取到d的值我们需要object.c[3].d,如果这个对象数据是后台返回的值为:

var object = {
    a: 1,
    b: '2',
    c: [3, '4', undefined, null],
    e: undefined
}

此时按照上述的方法进行取值肯定会报错,这个时候我们就需要使用多重条件判断来解决这个问题:

var value = object && object.c && object.c[3] && object.c[3].d

很明显,这种写法太啰嗦,于是我们想到了使用可选链

可选链的使用

使用MDN介绍的可选链方式我们只需要

var value = object?.c?[3]?.d

这样写确实简洁了太多,但是从MDN上可以得知这个方式浏览器兼容性不太好,因此我们需要安装Babel插件(@babel/plugin-proposal-optional-chaining)从编译时角度来解决可选链的问题。

还有其他的解决方式是使用safeGet或者lodash库里的get函数,但是这些实现起来都不够优雅, 有没有更好的解决方式呢?

从运行时的角度解决取值问题

这里我们可以使用safedata-get这个库

首先,先安装这个库:

npm install safedata-get

然后在代码中我们可以这样进行取值:

import safeData from 'safedata-get';
var object = {
    a: 1,
    b: '2',
    c: [3, '4', undefined, null],
    e: undefined
}

var safeObject = safeData(object);
var value = safeObject.c[3].d(); // undefined

这样,即使中间出现了undefined取值也不会报错,如果我们需要给undefined一个兜底值,可以这样:

var value = safeObject.c[3].d('hello'); // 'hello'

safeData函数即使给undefined,null等空值进行包裹也不会报错:

var safeUndefined = safeData(undefined);
var safeNull = safeData(null);

console.log(safeUndefined.hello.world.juejin.nihao()) // undefined
console.log(safeNull.hello.world.juejin.nihao()) // null

safeData能够完整保留对象的this:

var object = {
    a: 'hello',
    sayHello() {
        return this.a + ' juejin!'
    }
}
var safeObject = safeData(object);
console.log(object.sayHello()) //hello juejin!
console.log(safeObject.sayHello()()) //hello juejin!

从原理角度,safeData是如何实现的呢? 其实safeData是基于Proxy的getter来实现的, 具体源码可以查看这个库的源码,只有短短几十行。

总结

今天简单介绍了可选链相关的使用以及safedata-get这个库的使用方式,喜欢的话赶快用起来吧!