Is it possible to define an inline "static" lambda (arrow) function?

Viewed 375

My code involves lots of event handlers, which do not require any context (scope) to execute. When I use inline lambda functions in contrast to statically declared (constant) lambda functions, a new event handler is created each time I assign the event handler.

Question: Is it possible to define an inline lambda function, which does not create a new Function object for each time the lambda is passed as a callback. (Given that no unique context scope is required.)

Two examples illustrating the trade-off between notation and memory usage.

1. Inline lambda: (desired notation, unnecesarry memory consumption)

for (const divId of ["div1", "div2", "div3"]) {
     documentgetElementById(divId).addEventListener("click", e => console.log(e));
}                                                         // Creates a new Function
                                                          // object for each loop
                                                          // cycle.

Desired notation, but creates a new Function callback (e => console.log(e)) for each divId, despite the callback not depending on any context information (hence being functionally equivalent for each divId). It would be great if there was a way to just pass a pointer to this function.

2. Statically declared lambda: (undesired notation, desired and minimal memory consumption)

const staticLambda = e => console.log(e); // Function object created only once.
for (const divId of ["div1", "div2", "div3"]) {
     documentgetElementById(divId).addEventListener("click", staticLambda);
}

Undesired notation (needs the extra constant), but on the up-side only creates the Function callback (staticLambda) once for all three divIds. Imagine how this would look inside a class method; the lambda function needs to be declared outside of its respective method as a static property of the class, hence destroying the elegance of lambdas (which are so good at keeping the callback code at the location where it is passed).

Note: This is a simplified example. I realize that creating 2 (out of 3) unnecessary callbacks does not affect performance substantially, however, I am interested in properly handling cases with orders of magnitude more callbacks.

3 Answers

You might want to add the event listeners in a function, like this:

function addListeners(ids, listener){
  for( const divId of ids){
     document.getElementById(divId).addEventListener("click", listener);
  }
}

Now you can call your function like this:

addListeners(["div1", "div2", "div3"], e => console.log(e));

While these kinds of optimizations do help in performance (Does use of anonymous functions affect performance?) I don't think it has a very large impact and shouldn't be pursued just for performance reasons, but your case can of course be a valid one.

If you are managing many event listeners you should also take care to remove them when they become unused. Removing an event listener is the easiest if you still have a reference to the original handler around and thus declaring the handler somewhere outside the scope where it is attached.

I would also argue that it is good practice to put 'simple' event handlers in their own functions and keep them in a separate module or file, this allows for easier refactoring. This also solves the performance issue.

Memory usage should not be the reason you choose one form over the other. For two reasons:

  1. The usage is so small as to be almost unmeasurable in most cases.

  2. Javascript interpreters will most likely compile a single function where it can when optimizing bytecode or JIT machine code.

However you should choose either form due to their properties:

  1. Declare implicit function when you have more than one place using the same logic. Always look for opportunities to refactor code especially an easy refactor as naming a function. It reduces future workload when fixing bugs.

  2. When you need to instantiate a new closure each time you call your function then use an IIFE (inline). Modern javascript may compile it to a single function but they will create a new closure each time the function is "redeclared".

Related