在开发中,链式取值是非常正常的操作,尤其是与服务端数据交互时,数据格式往往不受我们控制,这样一来,一不小心往往就出现类似于空指针错误,如果层级过深,一层一层的非空判断又易导致代码不够美观。那么如何优雅的链式取值呢?
optional chaining
这是新语法,目前已经有了babel的插件babel-plugin-transform-optional-chaining。具体看来源咯
通过函数解析字符串
一层一层的非空判断是繁琐的,这些步骤我们完全可以自动化,比如lodash的get方法就是这个原理,实现起来的也十分简单,简单的字符串解析,画外音:越来越觉得正则很强
function get (obj, props, def) {
if((obj == null) || obj == null || typeof props !== 'string') return def;
const temp = props.split('.');
const fieldArr = [].concat(temp);
temp.forEach((e, i) => {
if(/^(\w+)\[(\w+)\]$/.test(e)) {
const matchs = e.match(/^(\w+)\[(\w+)\]$/);
const field1 = matchs[1];
const field2 = matchs[2];
const index = fieldArr.indexOf(e);
fieldArr.splice(index, 1, field1, field2);
}
})
return fieldArr.reduce((pre, cur) => {
const target = pre[cur] || def;
if(target instanceof Array) {
return [].concat(target);
}
if(target instanceof Object) {
return Object.assign({}, target)
}
return target;
}, obj)
}
使用解构赋值
具体可以看You-Dont-Need-Lodash-Underscore这个repo
缺点:可读性堪忧
使用Proxy
简单实现如下
function pointer(obj, path = []) {
return new Proxy({}, {
get (target, property) {
return pointer(obj, path.concat(property))
},
apply (target, self, args) {
let val = obj;
let parent;
for(let i = 0; i < path.length; i++) {
if(val === null || val === undefined) break;
parent = val;
val = val[path[i]]
}
if(val === null || val === undefined) {
val = args[0]
}
return val;
}
})
}
使用如下
let c = {a: {b: [1, ,2 ,3]}}
pointer(c).a(); // {b: [1,2,3]}
pointer(c).a.b(); // [1,2,3]
pointer(d).a.b.d('default value'); // default value
对于Proxy的学习,可以参考阮一峰教程proxy