0

I have a number of calls to the same function where I am passing objects as well as specific object parameters as arguments. I've had no issue passing the object alone or passing an object parameter in the form object.param. However, I would also like to pass the object name and the parameter name as separate arguments so that I can combine them freely in the function. However, I can't figure out the syntax (or if my idea is supported).

The primary question is is my syntax correct: foo(param) and this[objectName].param?

My simple example below seems to work on playcode.io, but the same principle isn't working in my primary code.

Here is the simple version of the code:

var options = {
  bar: 0
};

foo('bar'); // parameter name as string

function foo(param) {
  var objectName = "options";
  this[objectName].param = 2; // assembling object name with parameter name as string here
  console.log('param = ' + this[objectName].param)
}

UPDATE: Here is an example of the working code using @CertainPerformance suggesting of not using .this.

const optionNames = {
  optionsA: {
    startMin: 3
  },
  // other option names
};
const constObjectNames = {
  optionsConstA: {
    maxVolume: 1
    // etc
  }
  // other const object names
};

var objectName = "optionsA";
var constObjectName = "optionsConstA";

function callCalculateNewValue(optionName, constOptionName) {
  var param = optionName;
  return param;
}

foo('startMin');

function foo(param) {
  optionNames[objectName][param] = callCalculateNewValue(optionNames[objectName][param], constObjectNames[constObjectName]);
  console.log('= ' + optionNames[objectName][param]);
}

Here is my actual code for context The ridiculously named function callCallCalculateNewValue is the one in question:

function getRandom(min, max) { // returns a random number between min and max (both included)
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

function valBetween(v, min, max) { // current value, min/max that I want to make sure v doesn't go under/over
    return (Math.min(max, Math.max(min, v)));
}

var optionsConstA = {
    // not recalculating each stage
    soundFileName: 'audio/60.wav',
    maxVolume: 1,
    startMinSeparation: 1000,       // the minimum distance appart the min/max values can be
    slaveStatusMin: 'master',
    minSeparation: 1000,
    // recalculating each stage
    startMin: 1050,                 // min time function waits before a sound is played
    startMax: 8000,                 // max time function waits before a sound is played
    playDurationMin: 15000,         // min play time for each sound 
    playDurationMax: 20000,         // max play time for each sound 
    fadeInMin: 10,                  // for individual sounds
    fadeInMax: 8000,                // for individual sounds
    fadeOutMin: 8000,               // for individual sounds
    fadeOutMax: 8000,               // for individual sounds
    chanceRandomMin: 90,            // values below the result won't be random, so for less chance variables are random, make min/max high
    chanceRandomMax: 99,            // values below the result won't be random
    rampMin: 0,
    rampMax: 4,
    rampVolumeMin: 0,               // number of stages the sounds will be faded in (total volume at each stage will be reduced by a percentage)
    rampVolumeMax: 4,
    volatilityMin: 1,              // result is multiplied by CalculatedChange. @@ This should possibly be unique for each parameter pair, though it is now calculating randomly within these values. 
    volatilityMax: 1              // result is multiplied by CalculatedChange
};

var optionsA = {
    startMin: 0,
    startMax: 0
};

function calculateNewValue(oldValue, min, max, volatilityMin, volatilityMax, slaveStatus, chanceRandomMin, chanceRandomMax, minSeparation, newMasterValue) {
    var randomThreshold = getRandom(chanceRandomMin, chanceRandomMax);                      
    var randomValue = getRandom(0, 100);                                                    // random number used against the threshold to see if the paramater should be reandomly determined
    console.log("random value: " + randomValue)                                             // the random number between 0-100 that if > the threshold value, it will use the random function 
    if (randomValue > randomThreshold || oldValue == 0) {                                   // if random = yes OR if the oldValue is 0 (which would mean that it's the very first tiem the function is being called and this will keep it from getting stuck near the Min value to start) parameter is determined randomly
        newValue = getRandom(min, max);                                                     // yes, it's random, so move randomly not incrementally from old value
        console.log('Was random: ' + newValue)
    }
    else {                                                                                  // if not random, determine its move from oldValue
        var changeLimit = (max - min) * .1;                                                 // @@ I'm setting the max possible incremental move at a pecentage (e.g., 10%) of difference betten max and min value. I can make this more detailed per parameter later. Maybe send a percentage artument along.
        var calculatedChange = getRandom(-changeLimit, changeLimit);                        // determines base value for parameter change (aka, change from oldValue)
        console.log('Calculated change: ' + calculatedChange)
        var volatility = getRandom(volatilityMin, volatilityMax);                           // @ I should refine volatility's relationship with calculatedChange
        newValue = valBetween(oldValue + (calculatedChange * volatility), min, max);        // make sure calculatedChange can be negative
    }
    if (slaveStatus == 'master') {
        newValue = valBetween(newValue, min, max - minSeparation);                          // if master (aka Min value), make sure Min is not so large that it doesn't have room for minSeparation (if it is added to Max)
    }
    if (slaveStatus !== 'master') {                                                         // now that the the value is determined, if you are a slave (aka a Max value which goes second), make sure you are >= to your master
        if (newValue < newMasterValue) {                                                    // if newValue is less than the calculated value of its min/max counterpart...
            newValue = newMasterValue;
        }
        if (newValue - newMasterValue < minSeparation) {                                    // i.e, there isn't enough separation between the Max value and the newly defined Min Value
            newValue = newValue + (minSeparation - (newValue - newMasterValue));            // adds needed separation value
            console.log('Max: Separation added')
        }
    }
    return newValue;
}

function callCalculateNewValue(objectName, constObjectName) {
    objectName = calculateNewValue(constObjectName.startMin, constObjectName.startMin, constObjectName.startMax, constObjectName.volatilityMin, constObjectName.volatilityMax, constObjectName.slaveStatusMin, constObjectName.chanceRandomMin, constObjectName.chanceRandomMax, constObjectName.minSeparation);
    return objectName;
}

var masterLoopStage = 0;

var calc = (function masterLoop(i) {
    setTimeout(function () {
        ++i;
        masterLoopStage = i; 
        console.log('masterLoopStage is: ' + i);

        callCallCalculateNewValue('startMin');
        function callCallCalculateNewValue(param) {
            var objectName = "optionsA";
            var constObjectName = "optionsConstA";
            this[objectName].param = callCalculateNewValue(this[objectName].param, this[constObjectName]);
            console.log('optionsA.startMin: ' + this[objectName].param)
        }

        optionsA.startMax = calculateNewValue(optionsA.startMax, optionsConstA.startMin, optionsConstA.startMax, optionsConstA.volatilityMin, optionsConstA.volatilityMax, optionsConstA.startMin, optionsConstA.chanceRandomMin, optionsConstA.chanceRandomMax, optionsConstA.minSeparation, optionsA.startMin);
        console.log('Min: ' + optionsA.startMin);
        console.log('Max: ' + optionsA.startMax);
        console.log('______________');
        /////////////////
        masterLoop(i);
    }, 3000)                                                                                //  time between increments
})(1);

console.log('____________');
console.log('Min: ' + optionsA.startMin);
console.log('Max: ' + optionsA.startMax);
forestkelley
  • 341
  • 3
  • 14

1 Answers1

1

With your current setup, it's not possible without eval, which should not be used - however, if you change around the data structure so that everything that can be an objectName is a property of a larger object, rather than a standalone variable (and do the same for the dynamic constObjectName), it would be doable. For example:

const optionNames = {
  optionsA: {
    startMin: 0,
    startMax: 0
  },
  // other option names
};
const constObjectNames = {
  optionsConstA: {
    soundFileName: 'audio/60.wav',
    maxVolume: 1,
    // etc
  }
  // other const object names
};

Then, you can use ordinary bracket notation, just like your foo function in the first snippet is doing. Your param also contains a string which is the property name you want to access, so you need to use bracket notation when using param too, eg [param] rather than .param. In full:

const optionNames = {
  optionsA: {
    startMin: 1,
  },
  // other option names
};
const constObjectNames = {
  optionsConstA: {
    startMinB: 1,
  }
  // other const object names
};


function calculate(optionName, constOptionName) {
  var value = optionName + constOptionName.startMinB;
  return value;
}

foo('startMin'); // I'm still not sure what the syntax is for passing parameter name, or if I can

function foo(param) {
  var objectName = "optionsA";
  var constObjectName = "optionsConstA";

  optionNames[objectName][param] = calculate(optionNames[objectName][param], constObjectNames[constObjectName]);

  console.log('= ' + optionNames[objectName][param])
}

Your use of this will only work if the code in question is operating on the top level, which is not a good idea to depend on (you'd be polluting the global scope unnecessarily).

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • @ CertainPerformance This is a great answer. Some of it is a bit over my head at the moment, but it's very helpful in letting me know how to approach moving forward. Thanks! – forestkelley Mar 29 '19 at 13:38
  • I believe I now understand the principle you outlined of avoiding the use of `.this`. I added an update of my code with your idea. It doesn't seem like your solution solves my initial question of how to dynamically (am I using this term correctly?) pass the object and object name as separate arguments, and later putting them together inside a called function. My update does work if I pass the full `object.name`, but as I have written it with the object and object name being passed as separate arguments, it doesn’t work. – forestkelley Mar 29 '19 at 16:17
  • Ah, your `param` contains a string which is a a dynamic property reference too, so you need to put it in bracket notation as well – CertainPerformance Mar 29 '19 at 19:01
  • Fantastic, it took me a little time to figure out the syntax of bracket notation for my case, but I think I got it working correctly. My code above is updated again to reflect the update. :) – forestkelley Mar 29 '19 at 22:29