一年多过去了, Optional Chaining终于到Stage 3了, vscode 之类编辑器也有办法支持该语法了, 现在想用, 可以用babel来实现了

安装插件

# yarn add @babel/plugin-proposal-optional-chaining --dev // 可选链
# yan add @babel/plugin-proposal-nullish-coalescing-operator --dev // 空值合并

在 babel 配置文件里添加插件

plugins: [
    // 其他插件
    '@babel/plugin-proposal-optional-chaining',
    '@babel/plugin-proposal-nullish-coalescing-operator'
]

这样就可以在 js, jsx, vue 里面用了

在 .jsx 中使用:
render() {
    const { data } = this.props.article
    const age = null
    return (
        <div>
            {data?.author?.loginname}
            年龄: {age ?? 18}
        </div>
    )
}
在 .js 中使用:
const adventurer = {
  name: 'Alice',
  cat: {
    name: 'Dinah',
    age: undefined,
    num: 0
  }
}

const dogName = adventurer.dog?.name;
console.log(dogName);
// 打印: undefined
console.log(adventurer?.cat?.age ?? 18)
// 打印: 18
console.log(adventurer?.cat?.num ?? 1)
// 打印: 0
在 .vue 中使用:

注意, 在.vue中, 只能在script标签里使用, 不能在template中使用, 因为template里的 js 表达式是不会经过babel编译的(至少到目前为止的 vue2 版本都不行, 也许 vue3 就可以了), 所以除非浏览器原生支持, 不然就会报错

template中可以借助lodash.get和过滤器来写, 这样看起来会优雅些

<template>
<div>
  <p>{{ obj | oc('a.b.c') }}</p>
  <p>{{ obj | oc('a.c.d') }}</p>
</div>
</template>
<script>
import get from 'lodash.get'
export default {
  filters: {
    oc(obj, path) {
      if (!obj) return null
      if (!path) return obj
      return get(obj, path)
    }
  },
  data() {
    return {
      obj: {
        a: {
          b: {
            c: 'mmxiaowu'
          }
        }
      }
    }
  }
}
</script>

华丽的分割线


Optional Chaining是个好东西, 可惜现在还处于Stage 1阶段, 虽然 babel 已经实现了该功能, 但是编辑器, eslint 之类还是不支持, 想用还是遥遥无期

Optional Chaining的作用, 主要是让开发者告别一堆的&&:

const obj = {
    abc: {
        def: {
            ghi: '123'
        }
    }
}

上面的对象, 如果想取最后的123, 在不确定前面 abc, def 是否为 null, undefined 的情况下, 我们就得这么写:

const str = obj && obj.abc && obj.abc.def && obj.abc.def.ghi

天长地久的一串, 但是有Optional Chaining之后, 你只需要这么写:

const str = obj?.abc?.def?.ghi

是不是简单了很多...

既然Optional Chaining还用不了, 就自己写个简单的曲线救国的方法:

const oc = (props, property, def) => {
    // 如果props不是对象, 则直接返回原值
    if (Object.prototype.toString.call(props) !== '[object Object]') return props
    // 如果property不是字符串, 则直接返回原值
    if (!property || typeof property !== 'string') return props
    const arrProperty = property.split('.')
    const $return = arrProperty.reduce((prev, curr) => {
        if (prev === null || prev === undefined) return
        if (Object.prototype.toString.call(prev) === '[object Object]') return prev[curr]
    }, props)
    return def && $return === undefined ? def : $return
}
var obj = {
    abc: {
        def: {
            ghi: '123'
        }
    }
}
oc(obj, 'abc')
// 输出:
/*
{
    def: {
        ghi: '123'
    }
}
*/
oc(obj, 'xyz') // 输出 undefined
oc(obj, 'abc.def')
// 输出:
/*
{
    ghi: '123'
}
*/
oc(obj, 'abc.def.ghi') // 输出 '123'
var obj = {
    abc: {
        def: [{
            ghi: '123'
        }]
    }
}
oc(obj, 'abc.def.ghi') // 输出 undefined
oc(obj, 'abc.def.ghi', {}) // 输出 {}
oc(obj, 'abc.def.0.ghi') // 输出 '123'
oc(obj, 'abc.def.length') // 输出 1
var a = {
    b: null,
    c: {
        d: 1
    },
    d: 0
}
console.log(oc(a, 'b')) // null
console.log(oc(a, 'b.c')) // undefined
console.log(oc(a, 'c.d')) // 1
console.log(oc(a, 'c.d.e')) // undefined
console.log(oc(a, 'd')) // 0
发表评论
It's Ok!
回复 @Heronix: 22
Heronix
Bbb
frt
gg
sarkerdo
回复 @sarkerdo: 121212
sarkerdo
111