JavaScript Static Variables via IIFEs

I am trying something new: emulating static variables in JavaScript. Even though JavaScript does not have static variables like some languages (e.g., C++), I have done some searches and it seems there are a few ways to provide the same behaviour.

Here’s a sample of basic code, similar to what I am trying to do.

function calculate_ABCDE(inPar1, inPar2, inPar3){

	var dummy1, dummy2, dummy3;
	var endResult1, endResult2;

	dummy1 = Math.cosh(inPar1) + Math.tanh(inPar1);
    dummy2 = cos(Math.PI /180.0 * inPar2);

	dummy3 = inPar3 + dummy1 + dummy2;

 	// MANY MORE CALCULATIONS
      
	endResult1 = ...
	endResult2 = ...

	return;
}

Basically, dummy1 and dummy2 are calculated the first time the function is called, and these values are used in MANY MORE CALCULATIONS–but the values of dummy1 and dummy2 do not change any other time the function is called. Since these variables are the results of trigonometric and hyperbolic trigonometric calculations, they are quite expensive to calculate, and I would like to avoid re-calculating them. Hence my interest in static variables.

I have read on some pages that Immediately Invoked Function Expressions (IIFEs) are one way to go, but I am having troubles wrapping my brain around this technique. To me, the name connotes a fancy function, which means re-calculating the values, which is what I am trying to avoid. Am I mistaken? If not, how do I go about this? Any suggestions and help much appreciated.

An IIFE (immediately invoked function expression) is a module-like technique.

It doesn’t have to be called an iife, but that’s better than nothing until you come up with a better name for the function. If an iife is making a function called calculator, I usually like to add “make” onto the front of the function name so that the iife ends up being called makeCalculator

const calculator = (function makeCalculator() { // iife
    var privateVar = "...";
    var publicVar = "...";

    function privateFunc() {
        ...
    }
    function publicFunc() {
        ...
    }
    function init() {
        ...
    }        
    return {
        publicVar,
        publicFunc,
        init
    };
}());

calculator.init();
calculator.publicFunc();

As the values of those dummyN variables depend on the arguments passed to the function, are you sure you want to keep the values from the first function call? From looking at your code I’d say it makes more sense to store the values for the given arguments only, which is called memoization… like e.g.

// Basic memoization implementation
var memoize = function (fn) {
  var cache = {}

  return function memoized () {
    var argSring = JSON.stringify(arguments)
    cache[argSring] = cache[argSring] || fn.apply(this, arguments)
    return cache[argSring]
  }
}

// Function to get the dummy variables, memoized
var getDummyVariables = memoize(function (inPar1, inPar2, inPar3) {
  var dummy1 = Math.cosh(inPar1) + Math.tanh(inPar1)
  var dummy2 = Math.cos(Math.PI /180.0 * inPar2)
  var dummy3 = inPar3 + dummy1 + dummy2

  return [dummy1, dummy2, dummy2]
})

// Then elsewhere
function calculate (inPar1, inPar2, inPar3) {
  var [dummy1, dummy2, dummy3] = getDummyVariables(inPar1, inPar2, inPar3)
  // etc.
}

Hi, Paul and “m3g4p0p”.

Thanks for the replies.

“m3g4p0p”, I may have created a bad example (off the top of my head). True, the values of inPar1 and inPar 2 never change, so I suppose I could have just passed in a few more unchanging parameters.

This brings up a good question: when should memoization be preferred over static variables?

However, I do want to learn about IIFEs: how to declare them, how to use them, their strengths and weaknesses, etc. (I’d like to learn more about memoization too, but not at the moment.)

One other aspect I am curious about: do they add much overhead to program execution? By that I mean, would their use, in fact, make the program execute faster than what I already have? (I hope the program executes faster with an IIFE than it does if it re-calculates the same values repeatedly.)

Measurements can be important, but frequently what we find is more important is a persons ability to clearly understand the code.

There is no relevant speed difference when using IIFE’s.

Oh, no! I was really hoping to wring as much speed out of the program as possible.

Perhaps I will have to reconsider the option of passing in more parameters, or m3g4p0p’s suggestion to use memoization. Or one more option: to create a couple more properties and assign them to the function. Perhaps something like the following:

function calculate_ABCDE(inPar1, inPar2, inPar3){

    calculate_ABCDE.notDef = 1; // Treat as boolean, to indicate "not defined"

	if (calculate_ABCDE.notDef === 1){
		calculate_ABCDE.dummy1 = Math.cosh(inPar1) + Math.tanh(inPar1);
        calculate_ABCDE.dummy2 = cos(Math.PI /180.0 * inPar2);
		calculate_ABCDE.notDef  = 0;
	}

    var dummy3;
	var endResult1, endResult2;

. . .


	return;
}

dummy1 and dummy2 are now part of the calculate_ABCDE Object. The third property, notDef, is created solely for the purpose of testing if the other two properties have already been defined or not. Pretending it’s a boolean, I want the condition to pass or fail as fast as possible (in this example, fail every time after the first time.) The first time through it is 1, then set to 0, so should fail every time after that. Does this method offer any speed gains? Is there any other method you can suggest to make this function execute faster?

If you’re after faster speed, don’t use calculations at all.

For example, instead of Math.PI / 180 you can replace that with 0.017453292519943295

Instead of dummy1 = formula, just calculate it the one time on your test machine, and replace all of the formula with the appropriate numeric value instead.

There is a standard idea though that putting too much early effort into performance gains, results in a much greater loss of being able to understand the code. Premature optimization is something that’s best to be avoided.

Do you have any actual measurements for the performance problems that you’re wanting to solve?

1 Like

No. I’m just anal.

But you’ve given me some food for thought. So … I’m back to my coding. Thanks for all your help.

Memoization is used to store the return value of a function for the given parameters, so that subsequent function calls with the same arguments can be looked up in the cache rather than having to be calculated anew. Static variables OTOH just hold the one value that gets assigned to them during the first function call; in JS it might look something like this:

var staticValue

function calculateSomething () {
  if (staticValue === undefined) {
    staticValue = Math.cos(Math.PI / 180 * 42)
  }

  // Do something with staticValue...
}

In a way that’s similar to memoization, just with single values instead of function calls (you might actually replace the calculation with a memoized, nullary getter function). The more common term in JS would be “lazy evaluation” though: calculate the value only when needed, and then store that value for future use.

Anyway there is no IIFE required here, but you’d typically wrap your code in an IIFE to avoid polluting the global scope with those “static” variables:

;(function () {
  var staticValue
  
  function calculateSomething () {
    if (staticValue === undefined) {
      staticValue = Math.cos(Math.PI / 180 * 42)
    }
  
    // Do something with staticValue...
  }
})()

// Can't access staticValue from here..

You can then use closures in combination with IIFEs to keep those values encapsulated with the function using them:

var calculateSomething = (function () {
  var staticValue
  
  return function calculateSomething () {
    if (staticValue === undefined) {
      staticValue = Math.cos(Math.PI / 180 * 42)
    }

    // Do something with staticValue...
  }
})()

The revealing module pattern as shown by @Paul_Wilkins is form of this technique where you return an object with multiple methods rather than a single function. Note that you don’t really need either technique if you’re organising your code in actual modules though, such as e.g.

var staticValue
  
export function calculateSomething () {
  if (staticValue === undefined) {
    staticValue = Math.cos(Math.PI / 180 * 42)
  }

  // ...
}

That all being said, creating closures generally increases the cognitive overhead and occupies memory for things that modern JS engines would be able to optimise much more efficiently by themselves – so as @Paul_Wilkins says, weigh up carefully if it’s actually worth it.

1 Like

Take measurements! So that you can tell if you’re being effective, and if it’s worth saving an extra 10 milliseconds in exchange for hard to understand code.

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.