0

I have groupedTags and I need to add fields to it and add new tags across field.:

let groupedTags = {
     'other': {}
}

if (!groupedTags.other[field]) {
    groupedTags.other[field] = [];
}
groupedTags.other[field].push(tag);

I understand that it is necessary to initialize a new field to push new tag - Is there a more beautiful way to check if a field exists every time? I mean avoid explicit check. or is there nothing terrible about this check? there are just a lot of places where it can be repeated

Cœur
  • 37,241
  • 25
  • 195
  • 267
Lola
  • 2,591
  • 6
  • 24
  • 49
  • 2
    Possible duplicate of [How to check if object property exists with a variable holding the property name?](https://stackoverflow.com/questions/11040472/how-to-check-if-object-property-exists-with-a-variable-holding-the-property-name) – rlemon Nov 01 '18 at 12:10
  • 5
    or maybe `groupedTags.other.hasOwnProperty(field)` ? – Calvin Nunes Nov 01 '18 at 12:10
  • i added changes - I mean avoid explicit check. or is there nothing terrible about this check? there are just a lot of places where it can be repeated – Lola Nov 01 '18 at 12:16
  • The check is (should be) [O(1)](https://stackoverflow.com/questions/12241676/javascript-objects-as-hashes-is-the-complexity-greater-than-o1) so in theory go wild. – James Nov 01 '18 at 12:18
  • Note the difference between checking whether a property exists on the object (like Calvin's example, or using `in`), and the truthiness of the key's value (e.g. your example of `groupedTags.other[field]` as it is checking the value of the key referenced by `field`). – chazsolo Nov 01 '18 at 12:26
  • 1
    @Lola you could setup a trap with Proxy and handle this, but honestly it isn't worth it. do the checks, they're more explicit and no one is left scratching their heads while reading parts of your code. – rlemon Nov 01 '18 at 12:28

3 Answers3

0

Maybe you should investigate using Proxies for achieving your desired result.

Here's short example of doing so CodeSandbox -example

1) Create proxy handler to customise Object behaviour

const handler = {
  set: function(obj, key, value) {
    if (!obj[key]) {
      obj[key] = [];
    }

    obj[key].push(value);
    return true;
  }
};

2) Assign Proxy to your Object

let groupedTags = {
  other: new Proxy({}, handler)
};

Now assigning new value will go trough Proxy

groupedTags.other.b = "bar";
// {"other":{"b":["bar"]}}
Jimi Pajala
  • 2,358
  • 11
  • 20
-1

If you want to create an array of elements on an empty (or not) object, you can try this. So you don't have to check if the property you want to push your element(s) already exists.

If it doesn't it will concat with an empty array, giving you an array with the one element, otherwise the value will be added to that array. Hope this helps.

const o = {};

const toAdd = [1,2,3,4];

toAdd.forEach((v) => {
  o.other = (o.other || []).concat(v);
});

o.other2 = (o.other2 || []).concat(123);

console.log(o);
Alex G
  • 1,897
  • 2
  • 10
  • 15
-1

I believe there is no way around checking for a value + if needed initalizing it, other than doing it yourself explicitly.

You can take out one occurrence of groupedTags.other[field] using || like this:

let field = "foo", tag = "bar";
let groupedTags = {
  'other': {}
}

// Get the existing items, or assign a new list & use it:
var items = groupedTags.other[field] || (groupedTags.other[field] = []);
items.push(tag);

console.log(groupedTags);

You could also make use of a helper method that encapsulates the check-and-init part:

let groupedTags = {
  'other': {}
}

AddTag(groupedTags.other, "foo1", "bar1");
AddTag(groupedTags.other, "foo2", "bar2a");
AddTag(groupedTags.other, "foo2", "bar2b");

console.log(groupedTags);

// Can put this in a library.js
function AddTag(obj, field, tag) {
  var items = obj[field] || (obj[field] = []);
  items.push(tag);
}
Peter B
  • 22,460
  • 5
  • 32
  • 69