Wrapping JavaScript function getter with IIFE

Viewed 110

I am looking at a JavaScript code, and I've noticed the following pattern across multiple functions

function getValues() {
    var values = ['a', 'b', 'c'];
    return (getValues = function () {
        return values;
    })();
}

from what I know the following function has the same effect of

function getValues() {
    return ['a', 'b', 'c'];
}

Does wrapping it in an IIFE here have a special effect? especially the following section return (fnName = function() {...})() Noticing that a variable always get assigned with the same name of the function.

Note: I am very familiar with IIFE concept and when it's useful, and not to confuse with the following pattern

var fn = (function() {
    function fn() {
    }
    fn.prototype.function1 = function () { /* ... */ }
    return fn;
})();

In my question the variable get assigned inside the function and not the opposite.

1 Answers

Well, in this case it's part of a weird memoization technique.

The key point to notice is that the function reassigns itself:

return (getValues = function () {
        ^^^^^^^^^^^^

So, what happens when getValues is called for the first time is that getValues creates a new function that has values as a closure, then it replaces itself with that new function.

Because of that, further calls to getValues will call the same inner function, that returns the value from the closure without creating a different object every time.

You can check this behaviour by checking the return values:

console.log(getValues() === getValues()); //true

While, with your implementation, that wouldn't work:

function getValues() {
    return ['a', 'b', 'c'];
}

console.log(getValues() === getValues()); //false

Reassigning the function means that the value of getValues itself will change between the first and second calls. So:

var gv0 = getValues;
getValues();
console.log(gv0 === getValues); // false

That behaviour has ist own risks if multiple references are created to the function:

var gv0 = getValues;
console.log(getValues() === gv0()); // false!

By the way, the usual (and more readable) way to write memoization is to make the outer function an IIFE, that returns the inner function. It also eliminates the need for reassignment.

var getValues = (function () {
    var values = ['a', 'b', 'c'];
    return function () {
        return values;
    };
})();

That will, however, create the object immediately, while the code in question will only create it on the first call.

This difference is important if the creation of the object is expensive.

Related