1

I'm building my first framework. I need to be able to generate a semi-dynamic object, to which end, I want to re-use a single variable that points to a unique-value-returning function. I have a JS object literal like this:

let myObject = {
  [test] : "placeholder text 1",
  [test] : "lorem ipsum 2"
};

The [test] bit refers to a function of this sort:

const test = (function() {
  return String("morePlaceholderText" + getRandInt() )
})();


const validatorCache = new Set();
let max;

function getRandInt() {
    let length = validatorCache.size;
    const initMax = 15; // set the starting maximum value
    if(length < initMax){ // determine the mode of setting the maximum value
      max = initMax;
    } else {
      max++
      //max = max + 20; // alternatively, jump the pool up by a fixed amount when the ceiling is reached.
    };
    const min = 1; // set the starting minimum value - if desired.

    let newRand;
    do {
      newRand = Math.floor(Math.random() * (max - min + 1)) + min; 
    } while (validatorCache.has(newRand)); // Validate against cache

    validatorCache.add(newRand); // Add to cache
    return newRand;
};

console.log(getRandInt());

But if I console.log it after running this, I get only one of the properties:

console.log(JSON.stringify(myObject));
{"morePlaceholderText7":"lorem ipsum 2"}

Demo:

const test = (function() {
  return String("morePlaceholderText" + getRandomInt() )
})();
function getRandomInt() {
  return Math.floor(Math.random() * 15);
};

let myObject = {
  [test] : "placeholder text 1",
  [test] : "lorem ipsum 2"
};

console.log(JSON.stringify(myObject));

So far, I've tried several different structures. It didn't seem to like arrow functions. Doesn't work at all without the square brackets on the property name function.

I could get a similar effect by simply storing a specific property inside my object, with unique object identifier metadata stored as to the value, and I did try that... But the readability impact was so severe on some of the more complex data structures, that got scrapped out as an absolute last ditch resort. If I can get something that's pretty close in brevity and readability to what I have here, that would be ideal.

Do I have something wrong with my syntax somewhere? Having a tough time finding documentation on this sort of thing.

3
  • 1
    why not use an array and pick randomly? Commented Feb 5 at 13:11
  • 1
    There's no need to call String(). The + operator returns a string when either of the arguments is a string. Commented Feb 5 at 16:44
  • 1
    sounds like just an array? let myObject = ["placeholder text 1", "lorem ipsum 2"];. Though if you're convinced you want random keys then you could use randomUUID {[crypto.randomUUID()]: "value"} Commented Feb 5 at 21:34

1 Answer 1

3

The problem you've got is that you only execute the name-creation function once and assign it to the test variable, before you declare myObject. Therefore it then tries to create two properties with the same name within the same object, which of course isn't allowed.

If you write it so that test is actually a function, and is called separately for each property in the object, then you'll get a different value back each time (barring an extremely unlikely accident where Math.random() returns the same value twice in a row).

Demo:

var props = ["x"]
const test = function() {
  return String("morePlaceholderText" + getRandomInt() )
};
function getRandomInt() {
  return Math.floor(Math.random() * 15);
};

let myObject = {
  [test()] : "placeholder text 1",
  [test()] : "lorem ipsum 2"
};

console.log(JSON.stringify(myObject));

Relevant background info: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#computed_property_names

Sign up to request clarification or add additional context in comments.

8 Comments

"(barring an extremely unlikely accident where Math.random() returns the same value twice in a row)." Two things here: 1. it doesn't have to be in a row. If you get "a", "b", "a" as keys, that still clashes, without being in a row. 2. Depending on the range of values, it's not that unlikely due to the birthday paradox. With a range of 15 possible random values and calculating a random value 3 times, the chance for a collision is about 20%. If we go with 4 calculations, that's 35% chance.
True - I was considering the strict case here where there are only 2 properties in the object. No doubt a scenario will arise where there are more. And the problem is exacerbated by rounding the values, greatly decreasing the possible outcomes that are passed to the object - Math.random generates a far larger possible number of values by itself. However, the OP did indicate that this isn't the real function, so probably it's a moot point for them in their actual work
In my actual use case, there absolutely can and will be far more than two items. Definitely hundreds, possibly thousands; on an off chance, tens of thousands, though at that point we'd likely be looking to branch some of our data into something like SQL. They're all being handled on a procedural basis, so you don't really need to keep track of all that - but in the event you need to trace the stack down for bugfixing, or perhaps on a rare case access a part of the datastructure directly to modify it (think useRef) you'll be able to.
Instead of random numbers, why not just increment a counter?
That might be a question to ask the OP, not me :-)
I meant it for the OP, it was in response to their "In my actual use case" comment. I forgot to write @Neokithera.
I think in this new comment style they'll see if it you write it as a direct reply to their comment instead of mine - it's not a single linear list anymore :-)
I don't see the new comment style, I guess I'm opted out of it. But I assumed the OP would be notified of all comments on answers to their questions, so I don't need @Neokythera

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.