1. 首页
  2. IT资讯

Javascript 优雅实现链式取值

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

1 reduce函数式编程

2 Proxy妙用

3 Ramda 函数式类库

4 Maybe函数式编程

5 函数解析字符串

6 解构赋值

例子:

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 函数式类库完成

Javascript 优雅实现链式取值
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 优雅实现链式取值

主题测试文章,只做测试使用。发布者:酒颂,转转请注明出处:http://www.cxybcw.com/25288.html

联系我们

13687733322

在线咨询:点击这里给我发消息

邮件:1877088071@qq.com

工作时间:周一至周五,9:30-18:30,节假日休息

QR code