【问题标题】:Recursively remove nullish values from a JavaScript object从 JavaScript 对象中递归删除空值
【发布时间】:2019-12-23 22:17:43
【问题描述】:

我搜索了这个,但找不到满意的答案,所以我在这里发布我自己的答案。

基本上我想要一个函数:

  • 将对象作为参数
  • 递归删除值为nullundefined[]{}''的属性
  • 保留0false
  • 返回删除了这些属性的新对象
  • 最好采用没有突变的功能样式

【问题讨论】:

  • 数组中的无效项会发生什么?
  • 例如[null, null, null] 是一个非空数组,也是一个对象,具有三个属性,即null。在这里做什么?此外,对于例如的输入{ x: { y: null }},我认为删除应该是深度优先的,结果应该是{} 而不是{ x: {}}
  • 根据我的要求,如果对象的属性为[null, null, null],则应删除整个数组和属性。对于{ x: { y: null } },我们应该得到{}

标签: javascript recursion immutability


【解决方案1】:

这就是我想出的。 (感谢 Nina 提供样本;)

const is_obj = x => x !== null && typeof x === 'object';
const is_arr = x => Array.isArray(x);

const nullish = x =>

  (   typeof x !== 'number'
  &&  typeof x !== 'boolean'
  &&  typeof x !== 'function'
  )

  &&

  (   x === undefined
  ||  x === null
  ||  x === ''
  ||  Object.values(x).reduce((res, x) =>
        res && nullish(x), true)
  );

const clean = x =>
  [x]
    .map(x => Object.entries(x))
    .map(x => x.map(([k, v]) =>
        is_arr(v) ? [ k
                    , v.map(vv => is_obj(vv) ? clean(vv) : vv)
                    ]
      : is_obj(v) ? [ k
                    , clean(v)
                    ]
                  : [ k
                    , v
                    ]))
    .map(x => x.filter(([k, v]) => !nullish(v)))
    .map(x => Object.fromEntries(x))
    .pop();

console.log(clean(data));
<script>
var data = {
    emptyArray: [],
    arrayWithNullish: [null, {}, [], undefined],
    null: null,
    undefined: undefined,
    emptyString: '',
    zero: 0,
    false: false,
    true: true,
    emptyObject: {},
    objectWithNullish: { null: null, emptyArray: [], undefined: undefined },
    nestedObject: {
        nestedObject: {
            null: null,
            one: 1,
            emptyObject: {}
        },
        nestedEmptyArray: [[], [[]]]
    }
};
</script>

【讨论】:

  • 非常优雅!几乎看起来像Haskell。 :-)
【解决方案2】:

您可以将三种类型的数据分开

  • 数组,
  • 对象
  • 原始值

并通过减少复杂数据类型和检查原始值来获得想要的子集。

const
    isNullish = x => [
        v => v === '',
        v => v === null,
        v => v === undefined,
        v => v && typeof v === 'object' && !Object.keys(v).length
    ].some(f => f(x)),
    getArray = array => {
        var temp = array.reduce((r, v) => {
                v = getNotNullish(v);
                if (v !== undefined) r.push(v);
                return r;
            }, []);

        return temp.length ? temp : undefined;
    },
    getObject = object => {
        var hasValues = false,
            temp = Object.entries(object).reduce((r, [k, v]) => {
                v = getNotNullish(v);
                if (v !== undefined) {
                    r[k] = v;
                    hasValues = true;
                }
                return r;
            }, {});

        return hasValues ? temp : undefined;
    },
    getNotNullish = value => {
        if (Array.isArray(value)) return getArray(value);
        if (value && typeof value === 'object') return getObject(value);
        return isNullish(value) ? undefined : value;
    };


var data = {
        emptyArray: [],
        arrayWithNullish: [null, {}, [], undefined],
        null: null,
        undefined: undefined,
        emptyString: '',
        zero: 0,
        false: false,
        true: true,
        emptyObject: {},
        objectWithNullish: { null: null, emptyArray: [], undefined: undefined },
        nestedObject: {
            nestedObject: {
                null: null,
                one: 1,
                emptyObject: {}
            },
            nestedEmptyArray: [[], [[]]]
        }
    };

console.log(getNotNullish(data));
.as-console-wrapper { max-height: 100% !important; top: 0; }

【讨论】:

    【解决方案3】:

    我正在使用此处答案之一的数据样本。

    var data = {
        emptyArray: [],
        arrayWithNullish: [null, {}, [], undefined],
        null: null,
        undefined: undefined,
        emptyString: '',
        zero: 0,
        false: false,
        true: true,
        emptyObject: {},
        objectWithNullish: { null: null, emptyArray: [], undefined: undefined },
        nestedObject: {
            nestedObject: {
                null: null,
                one: 1,
                emptyObject: {}
            },
            nestedEmptyArray: [[], [[]], 6]
        }
    }; 
    
    function clean(data){
        return (function inner(data, output){
            if (!isObject(data)){
            return data;
          }
          Object.keys(data).forEach(function(key){
          if(isObject(data[key]) && !Array.isArray(data[key])){
            var result = clean(data[key], output);
            updateVal(output, key, result);
          }else if(Array.isArray(data[key])){
            var new_arr = [];
            data[key].forEach(function(a_item){
               var a_result = clean(a_item, output);
               if (!isFalsy(a_result)){
                    new_arr.push(a_item);
               }
            });
            updateVal(output, key, new_arr);
          }else{
              updateVal(output, key, data[key]);
           }
        });
        return output;
      })(data, {});
    }
    
    function updateVal(output,key, val){
        if(!isFalsy(val)){
        output[key] = val;
      }
    }
    
    function isObject(data){
        return typeof data === "object" && data !== null;
    }
    
    function isFalsy(val){
        return ['', undefined, null].indexOf(val) !== -1 ? 
            true:
            (()=>{
                return typeof(val) === "object" && Object.keys(val).length === 0 ? true: false;
            })();
    }
    
    console.log(clean(data));
    

    【讨论】:

      【解决方案4】:

      这是我想出的(感谢 Nina 提供的测试数据):

      function stripNullsFromObject(obj) {
        function stripNullsFromArray(arr) {
          return arr.reduce((acc, cur) => {
            if (typeof cur === 'object' && !Array.isArray(cur) && cur !== null) {
              const nestedObj = stripNullsFromObject(cur);
              if (Object.entries(nestedObj).length > 0) {
                return acc.concat(nestedObj);
              }
            }
            if (Array.isArray(cur)) {
              const nestedArr = stripNullsFromArray(cur);
              if (nestedArr.length > 0) {
                return acc.concat(nestedArr);
              }
            }
            if (typeof cur !== 'object' && (!!cur || cur === 0 || cur === false)) {
              return acc.concat(cur);
            }
            return acc;
          }, []);
        }
      
        return Object.entries(obj).reduce((acc, [key, val]) => {
          if (typeof val === 'object' && !Array.isArray(val) && val !== null) {
            const nestedObj = stripNullsFromObject(val);
            if (Object.entries(nestedObj).length > 0) {
              return {
                ...acc,
                [key]: nestedObj,
              };
            }
          }
          if (Array.isArray(val)) {
            const nestedArr = stripNullsFromArray(val);
            if (nestedArr.length > 0) {
              return {
                ...acc,
                [key]: nestedArr,
              };
            }
          }
          if (typeof val !== 'object' && (!!val || val === 0 || val === false)) {
            return {
              ...acc,
              [key]: val,
            };
          }
          return acc;
        }, {});
      }
      
      const data = {
        emptyArray: [],
        arrayWithNullish: [null, {}, [], undefined],
        null: null,
        undefined: undefined,
        emptyString: '',
        zero: 0,
        false: false,
        true: true,
        emptyObject: {},
        objectWithNullish: { null: null, emptyArray: [], undefined: undefined },
        nestedObject: {
          nestedObject: {
            null: null,
            one: 1,
            emptyObject: {}
          },
          nestedEmptyArray: [[], [[]]]
        }
      };
      
      console.log(stripNullsFromObject(data))

      我很好奇是否有其他人有替代方法,或者关于如何改进的建议。

      【讨论】:

      猜你喜欢
      • 2021-05-11
      • 1970-01-01
      • 2016-06-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-29
      相关资源
      最近更新 更多