Better

Ethan的博客,欢迎访问交流

如何优雅地链式取值

在开发中,链式取值是非常正常的操作,尤其是与服务端数据交互时,数据格式往往不受我们控制,这样一来,一不小心往往就出现类似于空指针错误,如果层级过深,一层一层的非空判断又易导致代码不够美观。那么如何优雅的链式取值呢?

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

来源



留言