js对象如何优雅的取一个深度的值?

问题描述

比如后台可能返回一个对象

let obj = {
    school: {
      class1: {
        student: 50
      }
    }
}

我需要取出里面student的值,但是有可能后台返回给我的是 {school: null} 或者 {} 甚至是 undefined

因此我取值时可能是

let student = obj?(obj.school?(obj.school.class1?(obj.school.class1.studnet?obj.school.class1.studnet:''):''):''):'';

这显然可读性不好,也麻烦,请问有什么方式可以优雅的处理这种取值

并且防止Cannot read property 'xxx' of undefined 的报错吗

阅读 3.6k
评论
    9 个回答
    • 8.5k

    如果不用考虑兼容性的话,加个Proxy监听get是个很合适的办法

    /**
     * @param target
     * @param exec 取值属性
     * @returns {*}
     */
    function getter(target, exec = '_') {
      return new Proxy({}, {
        get: (o, n) => {
          return n === exec ?
            target :
            getter(typeof target === 'undefined' ? target : target[n], exec)
        }
      });
    }
    let obj = {
      school: {
        class1: {
          student: 50
        }
      }
    };
    
    console.log(getter(obj).school.class1.student._)//50
    console.log(getter(obj).school1.class11.student._)//undefined
      function safeProps(func, defaultVal) {
          try {
              return func();
          } catch (e) {
              return defaultVal;
          }
      }
      
      safeProps(function(){
          student = obj.school.class1.student
      }, -1)
        • 1.3k

        lodash/get 了解一下,_.get(obj,'school.class1.student', undefined), lodash/get

          • 3.2k

          楼主你好!可以使用以下方法来做防御性编程

          function getIn(p, o) {
            return p.reduce(function(xs, x) {
              return (xs && xs[x]) ? xs[x] : null;
            }, o);
          }
          
          var obj = {
              school: {
                class1: {
                  student: 50
                }
              }
          }
          
          var student = getIn(['school', 'class1', 'student'], obj);
          console.log(student);
          // 50

          此方法是参照Facebook的immutable里的编写的。函数库 ramdajs也有类似的方法,可自行查找。

            • 5.9k
            const defaultObj = {
              school: {
                class1: {
                  student: ''
                }
              }
            }
            let obj1 = {
              school: {
                class1: {
                  student: 50
                }
              }
            }
            let obj2 = Object.assign({}, defaultObj, obj1) // obj2.school.class1是50
            obj2 = Object.assign({}, defaultObj, undefined) // obj2.school.class1是''
            obj2 = Object.assign({}, defaultObj, null) // obj2.school.class1是''
            obj2 = Object.assign({}, defaultObj, {}) // obj2.school.class1是''
            let student = obj2.school.class1

              用 es6 的解构赋值

              const {school:{class1:{student=''}=''}=''}=obj

                利用逻辑运算的特性可以很优雅的解决!

                obj.school.class1 && obj.school.class1.student
                  • 0
                  • 新人请关照

                  如果是我,我会这么做。let student = obj&&obj.school&&&obj.school.class1&&obj.school.class1.student
                  希望对你有帮助

                    撰写回答

                    登录后参与交流、获取后续更新提醒