silverlight513
silverlight513

Reputation: 5666

Is there a way to create an object using variables and ignore undefined variables?

I'm trying to find a way of creating an object where upon creation it ignores the values that are undefined.

In the example below, the variable someNames has unknown content when creating the object.

const someNames = {
  catName: 'purry',
  rabbitName: 'floppy',
  turtleName: 'shelly'
};

const { catName, dogName, hamsterName, rabbitName } = someNames;

const animalNames = Object.assign({}, {
  catName,
  dogName,
  hamsterName,
  rabbitName
});

console.log(animalNames);// {catName: 'purry', rabbitName: 'floppy'}

What actually gets logged is this:

{
  catName: 'purry',
  dogName: undefined,
  hamsterName: undefined,
  rabbitName: 'floppy'
}

Upvotes: 14

Views: 14893

Answers (6)

JYC
JYC

Reputation: 393

I think you can do that:

const someNames = {
  catName: 'purry',
  rabbitName: 'floppy',
  turtleName: 'shelly'
};

const { catName, dogName, hamsterName, rabbitName } = someNames;

const animalNames = Object.assign({}, Object.fromEntries(Object.entries({
  catName,
  dogName,
  hamsterName,
  rabbitName
}).filter(([key,value])=>value!==undefined)));

console.log(animalNames);// {catName: 'purry', rabbitName: 'floppy'}

Upvotes: 0

nomadoda
nomadoda

Reputation: 4942

Old thread, however not quite pleased with previous answers. Thought I'd chip in on a cleaner solution:

const someNames = {
  catName: 'purry',
  rabbitName: 'floppy',
  notAnAnimal: 'car',
};

const allowedKeys = ['catName', 'rabbitName'];
const animalNames = Object.keys(someNames).reduce((animals, key) => {
  if (allowedKeys.includes(key)) animals[key] = someNames[key];
  return animals;
}, {});

Upvotes: 3

silverlight513
silverlight513

Reputation: 5666

This is what I went for afterwards. It's just a refactor of @Bergi's code. I've done it this way because it has a reduced number of loops. @Bergi's answer allows for as many object parameters as possible. In this solution, you can just use spreads to create the second object if you have object spreads enabled in babel (https://babeljs.io/docs/plugins/transform-object-rest-spread/).

  const someNames = {
    catName: 'purry',
    rabbitName: 'floppy',
    turtleName: 'shelly'
  };

  function assignDefined(target, source) {

    Object.keys(source).map((key, index) => {
      if(source[key] !== undefined) {
        target[key] = source[key];
      }
    });

    return target;
  }

  const { catName, dogName, hamsterName, rabbitName } = someNames;
  const animalNames = assignDefined({}, {
    catName,
    dogName,
    hamsterName,
    rabbitName
  });

  console.log(animalNames);

Thanks @Bergi!

Upvotes: 2

Bergi
Bergi

Reputation: 665090

Don't use Object.assign which copies all own enumerable properties regardless of their value but your own custom function that can filter out undefined properties:

function assignDefined(target, ...sources) {
    for (const source of sources) {
        for (const key of Object.keys(source)) {
            const val = source[key];
            if (val !== undefined) {
                target[key] = val;
            }
        }
    }
    return target;
}

…
const animalNames = assignDefined({}, {
  catName,
  dogName,
  hamsterName,
  rabbitName
});

Upvotes: 10

Diego ZoracKy
Diego ZoracKy

Reputation: 2285

'use strict';

const someNames = {
  catName: 'purry',
  rabbitName: 'floppy'
};

const expectedProperties = ['catName', 'dogName', 'hamsterName', 'rabbitName'];
const animalNames = Object.assign({}, expectedProperties.reduce((o, prop) => (someNames[prop]) ? (o[prop] = someNames[prop]) && o : o, {}));

console.log(animalNames);

Upvotes: 1

taguenizy
taguenizy

Reputation: 2265

You could do something like this just to clean those properties

Object.keys(animalNames).forEach(function (key) {
    if(animalNames[key] === undefined) delete animalNames[key];
});

Upvotes: 5

Related Questions