1

I'm having an issue with this function that recursively removes empty values from an object:

const _ = require('lodash')

function sanitize(object) {
  Object.entries(object).forEach(([key, val]) => {
    if (
      val == null ||
      Number.isNaN(val) ||
      (typeof val === 'string' && isOnlyWhitespace(val)) ||
      (typeof val === 'object' && Object.keys(sanitize(val)).length === 0)
    ) {
      delete object[key]
    }
  });

    // Remove `undefined` values leftover from using `delete` on an array.
  if (Array.isArray(object)) {
    _.pull(object, undefined); // THIS IS THE LINE IM TRYING TO CHANGE
  }

  return object;
}

function isOnlyWhitespace(str) {
  return !(/\S/).test(str.trim());
}

I'm trying to replace _.pull(object, undefined) with vanilla JS, but nothing seems to give the right output (I've tried using stuff like filter.)

Here is a snippet you can run to see both outputs:

// LODASH VERSION
function lodashSanitize(object) {
  Object.entries(object).forEach(([key, val]) => {
    if (
      val == null ||
      Number.isNaN(val) ||
      (typeof val === 'string' && isOnlyWhitespace(val)) ||
      (typeof val === 'object' && Object.keys(lodashSanitize(val)).length === 0)
    ) {
      delete object[key]
    }
  });

  // Remove `undefined` values leftover from using `delete` on an array.
  if (Array.isArray(object)) {
    _.pull(object, undefined); // THIS IS THE LINE IM TRYING TO CHANGE
  }

  return object;
}

// MY VERSION
function mySanitize(object) {
  Object.entries(object).forEach(([key, val]) => {
    if (
      val == null ||
      Number.isNaN(val) ||
      (typeof val === 'string' && isOnlyWhitespace(val)) ||
      (typeof val === 'object' && Object.keys(mySanitize(val)).length === 0)
    ) {
      delete object[key]
    }
  });

  // Remove `undefined` values leftover from using `delete` on an array.
  if (Array.isArray(object)) {
    object = object.filter(val => val != null) // THIS IS MY ATTEMPT
  }

  return object;
}

function isOnlyWhitespace(str) {
  return !(/\S/).test(str.trim());
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
<button id="lodash">Show lodash output</button>
<button id="me">Show my output</button>
<p id="output" />
<script>
  /**
   * Fiddle-related code, you can ignore this
   */ 
  const lodashBtn = document.querySelector('#lodash')
  const meBtn = document.querySelector('#me')
  const output = document.querySelector('#output')
  
  function createExampleInput() {
    const input = {
      name: 'John',
      grades: [
        90,
        undefined,
        50,
        null
      ]
    };
    
    return input;
  }
  
  lodashBtn.addEventListener('click', () => {
    output.textContent = JSON.stringify(lodashSanitize(createExampleInput()), null, 4)
  });
  
  meBtn.addEventListener('click', () => {
    output.textContent = JSON.stringify(mySanitize(createExampleInput()), null, 4)
  });
</script>
inhwrbp
  • 569
  • 2
  • 4
  • 17
  • This isn't really a duplicate. I still have the issue when using direct modification of the array instead of using a duplicate array. Once the `Array.isArray` line is reached, the array may have `undefined` values due to the `delete` from above. It seems like `_.pull` normalizes the arrays somehow and fixes the indexes somehow. – inhwrbp May 05 '17 at 23:17

1 Answers1

0

The problem is that filter returns a new array. Why not just use a for loop and splice:

if (Array.isArray(object)) {
  for (var i = object.length - 1; i >= 0; i--) {
    if (object[i] === undefined) {
      object.splice(i, 1);
    }
  }
}
Stefan Haustein
  • 18,427
  • 3
  • 36
  • 51