Js链式取值方式总汇

更新日期: 2022-04-21阅读: 817标签: 链式

本文概要

对于对象的属性存在性检测一直是我们判断条件几乎每天遇到的,但是你是否又在具有‘坏味道’ 代码很绝望,现在我们提供几种处理‘坏味道’ 对象链式取值方式

  • reduce函数式编程
  • Proxy妙用
  • Ramda 函数式类库
  • Maybe函数式编程
  • 函数解析字符串
  • 解构赋值

例子:

const props = {
    a: {
        b: [
            { c: 'fe', d: [ 'hello', 'laodao' ] },
            { c: 'fe', d: [ 'hello' ] },
            { c: 'fe', d: []}
        ],
        d: [...]
    }
}
props.a &&
props.a.b &&
props.a.b[0] &&
props.a.b[0].d


方法一: reduce函数式编程

想到这种方法主要是还是之前有compose以及pipe这种函数,如果没有了解过函数式编程的人,可以参考我之前写的函数式编程教程

const get = (p, o) => p.reduce((xs, x) => (xs && xs[x]) ? xs[x] : null, o)

console.log(get(['a', 'b', 0, 'd'], props)) // [ 'hello', 'laodao' ]
console.log(get(['a', 'bs', 0, 'd'], props)) // null

关于此表达式的参数p代表就是get第一参数数组,o为props,当第一次时候xs为props,x为’a‘,如果xs && xs[x]都存在那么结果就为xs[x]即 a,那么a就会赋值给o,此时的o就为a,由此可以看来reduce非常适合对于数组和对象之间转换的场景,可以定制更多细节,例如:

let names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];

let nameNum = names.reduce((pre,cur)=>{
  if(cur in pre){
    pre[cur]++
  }else{
    pre[cur] = 1 
  }
  return pre
},{})
console.log(nameNum); //{Alice: 2, Bob: 1, Tiff: 1, Bruce: 1}


2 proxy

想到这个方法因为proxy对obj的代理,可以定制get函数以及set函数,可以对获取以及设置进行更加详细的设置

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(props).a();   // {b:[],d:[]}

pointer(props).a.b(); // [,,,]

pointer(props).a.b.d('default value');  // default value


3 Ramda 函数式类库

可以使用Ramda 函数式类库完成

const get = R.path(['a', 'b', 0, 'd'])
get(props) // [ 'hello', 'laodao' ]
get({}) // null


4 Maybe

Maybe 是函数式编程中的一个概念,是一种常用的函子(functor),通常用来处理函数式编程中可能存在的空值问题。

Maybe 原始参考用法,很传统:

// MayBe 函数定义
const MayBe = function (val) {
  this.value = val;
}
MayBe.of = function (val) {
  return new MayBe(val);
}
// MayBe map 函数定义
MayBe.prototype.isNothing = function () {
  return (this.value === null || this.value === underfind)
}
MayBe.prototype.map = function (fn) {
  return this.isNothing() ? MayBe.of(null) : MayBe.of(fn(this.value));
}

Maybe结果不确定,即可能是Just(value),又可能是Nothing,所以我们一般使用getOrElse来对异常处理,这样我们就可以去除具有 '坏味道' 的防御型代码:folktale/maybe

const Maybe = require('folktale/maybe')

const foo = Maybe.fromNullable(Math.random() >= 0.5 ? 'bar' : undefined)
//=> 50%概率为 Maybe.Just('bar'),50%概率为 Maybe.Nothing()

const unsafe_result = foo.get()
// 有50%的概率会报错:
// TypeError: Can't extract the value of a Nothing.

// 为了安全起见,我们使用 getOrElse()
const result = foo.getOrElse('nothing!!!')
// 50%:'bar',50%:'nothing!!!'

实际应用:

const Maybe = require('folktale/maybe')
const list = [{ name: 'tom', age: 18 }]

// 坏味道的防御式代码
const person = list.find(person => person.name === 'stark')
let ageText = 'No Age'
if (person && person.age !== undefined) {
    ageText = `User Age: ${person.age}`
}

// Maybe
const ageText = Maybe.fromNullable(
        list.find(person => person.name === 'stark')
    )
    .map(person => `User Age: ${person.age}`)
    .getOrElse('No Age')

使用maybe实现get函数

const Maybe = require('folktale/maybe')
function get(object, ...keys) {
    if (keys.length === 0) {
        return Maybe.Just(object)
    } else if (object[keys[0]]) {
        return get(object[keys[0]], ...keys.slice(1))
    } else {
        return Maybe.Nothing()
    }
}

const foo = { a: { b: { c: { d: 42 } } } }
const bar = {}

get(foo 'a', 'b', 'c', 'd').getOrElse(0)
//=> 42

get(bar 'a', 'b', 'c', 'd').getOrElse(0)
//=> 0

------------------------------------
const data = await fetchData()
const firstUserName = get(data, 'list', 0, 'name').getOrElse('no user found')

-------对比
const data = await fetchData()
let firstUserName = 'no user found'
if (data && data.list && data.list.length > 0 && data.list[0].name !== undefined) {
    firstUserName = data.list[0].name
}


5 解析字符串 lodash的_.get

var object = { a: [{ b: { c: 3 } }] };
var result = _.get(object, 'a[0].b.c', 1);
console.log(result);
// output: 3
--------------------------------------
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)
}
var c = {a: {b : [1,2,3] }}
get(c ,'a.b')     // [1,2,3]
get(c, 'a.b[1]')  // 2
get(c, 'a.d', 12)  // 12


6 解构赋值

解构赋值语法是一种 Javascript 表达式。通过解构赋值, 可以将属性/值从对象/数组中取出,赋值给其他变量。

const c = {a:{b: 3}}
const { a: result } = c;// result : {b: 3}
const {a: { c: result = 4 }} = c;// result: 4


链接: https://www.fly63.com/article/detial/11366

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!