1

I am learning closures. I understand the javascript module pattern, but it seems like the only other "practical application" of closures is to avoid problems with functions being created in a loop and pushed to an array.

I can't think of a single reason to do this. Here is an example of a closure issue in a loop taken from here: JavaScript closure inside loops – simple practical example

var funcs = [];
for (var i = 0; i < 3; i++) {      // let's create 3 functions
  funcs[i] = function() {          // and store them in funcs
    console.log("My value: " + i); // each should log its value.
  };
}
for (var j = 0; j < 3; j++) {
  funcs[j]();                      // and now let's run each one to see
}

When would you ever do this in real software? I am at a loss. I wrote a factoryand it works fine, so I am really failing to see a real world applications here.

VSO
  • 11,546
  • 25
  • 99
  • 187
  • 1
    I do a similar thing in my game engine. I have an array of objects with closures on them, then on each frame I loop through the object and call that object's `update()` closure. – Get Off My Lawn Nov 06 '17 at 21:46
  • 1
    Yes, there are reasons to use this pattern in real software. Of course it depends on your use case. There are probably ways to do whatever you need to without a function array if you want. But, for example, I have some code that defers updates to a page when it's not visible by pushing a function that updates the view into an array. When the page becomes visible again, I iterate through them to update the view. So I wouldn't say its a useless or even uncommon pattern. – CRice Nov 06 '17 at 21:50
  • @GetOffMyLawn I don't understand - why does it need to be a closure? CRice - is it raw javascript or something? Why not just have a state object and check it on the page becoming visible? I appreciate the replies btw. – VSO Nov 06 '17 at 22:03
  • 1
    @VSO think of it this way: sometimes, there's a numeric computation that becomes handy to use as an input to a simple mapping operation when what you need is a function to call. There are multitudes of ways that might come up. Think of a machine language simulator: the instruction codes are numbers! – Pointy Nov 06 '17 at 22:07

2 Answers2

2

A week or so ago I was working on a thing to draw simple bar graphs. The graphs compare particular values for a property of comparable things. The graphs can show both positive and negative numbers, though sometimes all the comparable numbers are negative or all are positive.

It turns out there are 8 cases:

  1. There are both signs in the set, and the graph I'm drawing is for the negative minimum
  2. There are both signs in the set, and the graph I'm drawing is for the positive maximum
  3. There are both signs in the set, and the graph I'm drawing is for a negative value that's not the minimum
  4. There are both signs in the set, and the graph I'm drawing is for a positive value that's not the maximum
  5. All values are negative, and the graph I'm drawing is for the negative minimum
  6. All values are positive, and the graph I'm drawing is for the positive maximum
  7. All values are negative, and the graph I'm drawing is for a negative value that's not the minimum
  8. All values are positive, and the graph I'm drawing is for a positive value that's not the maximum

Given that, I created a simple function to look at the qualities of a particular set of values and give me a number between 0 and 7. I then made an array of functions, and the code just calls whichever function that result value indicates. That allows a clean separation of code that would otherwise be something of a mess. I can also log or otherwise remember that "situation code" for debugging; if one particular kind of bar looks wrong, I know exactly which function to look at.

Pointy
  • 405,095
  • 59
  • 585
  • 614
1

To better explain my situation of an array of closures in my game engine.

First I create some fun components that modify the gameObjects:

  • x/y position
  • rotation
  • scale

They would look something like this:

class ComponentA extends Component {
    update() {
        console.log('Component A')
    }
}

class ComponentB extends Component {
    update() {
        console.log('Component B')
    }
}

Next, whenever I want a gameObject to have access to that object's functionality, I just attach that component to the gameObject. Now on every frame it runs that update function. It looks something like this:

let gameObject1 = new GameObject()
gameObject1.addComponent(ComponentA) // component instance gets added to global array

let gameObject2 = new GameObject()
gameObject2.addComponent(ComponentA) // component instance gets added to global array
gameObject2.addComponent(ComponentB) // component instance gets added to global array

In the above gameObject1 and gameObject2 share the same functionality from ComponentA but gameObject2 also has additional functionality from ComponentB.

Now once all of our gameObject's have been created, (this is where we relate to your question) the engine loops through the array of components and runs their update like this:

class engine {

    static components = []

    tick() {
        // Here is what you need to pay attention to:
        engine.components.forEach(comp => {
            if(typeof comp == 'function') {
                comp['update']()
            }
        })
        window.requestAnimationFrame(this.tick.bind(this))
    }

    run() {
        window.requestAnimationFrame(this.tick.bind(this))
        startRenderer()
    }
}

new engine().run()

That is how my engine works, which is very similar to what your doing, it is just a different way of doing it.

Get Off My Lawn
  • 34,175
  • 38
  • 176
  • 338