1

I was reading this example on w3schools about Javascript closure applied to the "counter dilemma":

https://www.w3schools.com/js/js_function_closures.asp

In practical use, this example seems almost nonsense. Why should I wrap the variable "counter" into a closure, protecting from accidentally modifications in global scope, when I can't protect the variable "add" containing the function itself?

To be more specific... I have this code:

var add = (function () {
    var counter = 0;
    return function () {return counter += 1;}
})();

add();
add();
add();

// the counter is now 3

W3schools says at start: "The problem is, that any script [in global scope] on the page can change the counter, without calling add()."... the closure above is proposed as a solution. Ok. But what about protecting "add" from subscribing? This make the variable still "vulnerable".

So, what is the advantage of closure implementation?

Lore
  • 1,286
  • 1
  • 22
  • 57

4 Answers4

4

In the example given by w3schools, the problem they are solving with the above closure is protecting the variable counter from being modified directly. If counter was in the global scope and then you defined a function, such as add to increment the counter by some value, then what you have done is defined an interface for other parts of code to interact with the counter variable.

When you define an interface between some data and other parts of the codebase, it stands to reason that you probably want that interface to be enforced. In other words, if you place counter in the global scope, then there is no way to enforce the use of your add function because I can just do this: counter += 7 right in the global scope.

Wrapping the counter variable in a closure allows you to hide the counter variable from the global scope, meaning that the only way to modify counter is through the add function. This enforces the use of add by preventing the modification of the value of the counter variable directly.

So this is a simple, but good example, of how to use closures to create private variables.

1

It's not useless because it keeps counter as a property of add. If you need to protect add you could wrap that in yet another closure.

var add = "something";
(()=>{
    var add = (function () {
        var counter = 0;
        return function () {return counter += 1;}
    })();
    console.log(add());
    console.log(add());
})();
console.log(add);

Of course, in real life, you should avoid using super generic names like add in the first place, and in real life, if you need your methods to have properties you would probably use OOP instead...

class counter{
    constructor(){
        this.counter = 0;
    }
    add(){
        this.counter++;
    }
}

var c = new counter();
c.add();
c.add();
console.log(c.counter);

If you just want to make sure the variable name is never reassigned you could use const (a JS "constant") instead.

const add = (function(){
    var add = 0;
    return function(){ return ++add };
})();

try{
    // this won't work
    add = "something";
}catch(e){
    console.log(e.message);
}

// Add is still a function here
console.log(add());
console.log(add());
console.log(add());
I wrestled a bear once.
  • 22,983
  • 19
  • 69
  • 116
  • Of course... in fact, the first piece of code you've written doesn't seem protecting add from overwriting. – Lore Feb 12 '18 at 14:55
  • @Lore - that's exactly what it does... you see `add` is defined twice. in the outer scope it's a string, in the inner scope its a function. Both work and neither is being overwritten. make sense? – I wrestled a bear once. Feb 12 '18 at 14:57
  • Yeah ok, but then @Lore will say: it's not "fully protected" because you can delete the outer function.. :-/ – Niels Bom Feb 12 '18 at 15:05
  • What can't be globally invoked? – Niels Bom Feb 12 '18 at 15:09
  • 1
    @Lore - That is correct, you can't have your cake and eat it too. Anything that can be invoked can also be overwritten. The idea is to keep similar code grouped together in a safe space where it can operate... if you want to completely reserve a variable name so it can't be used again you have to use `const` instead of var.. i will add an example of that.. – I wrestled a bear once. Feb 12 '18 at 15:12
  • @Lore - did my additional explanation help at all? – I wrestled a bear once. Feb 12 '18 at 15:17
  • 1
    @Lore - Why, that's a separate topic? W3schools is not intended to be complete documentation, it's a quick reference for new learners. If you want complete documentation you should read MDN instead. The point of the W3S example is to show you that the `counter` variable is protected from the outside scope. – I wrestled a bear once. Feb 12 '18 at 15:24
0

Examples are often made extra simple for educational purposes. To make them less distracting.

The thing the example is trying to show is that you can only increase the counter using this closure. You cannot decrement, you cannot reach the counter variable to do anything else with it. You can of course throw away the whole function but that's not something you'd likely do by accident.

Accidentally changing the value of a variable that is not in a closure is easily done.

Niels Bom
  • 8,728
  • 11
  • 46
  • 62
  • 1
    It protects the counter from getting any operation other than adding 1. There's no such thing as "fully protecting" variables in programming. Not as far as I know. – Niels Bom Feb 12 '18 at 15:04
-1

Here is an example "less problematic" and "more useful".

Memoization

var fibonacci = (function() {
  var memo = {};

  return function f(n) {
    if (!(n in memo)) {
      memo[n] = n === 0 || n === 1 ? n : f(n - 1) + f(n - 2);
    }

    return memo[n];
  }
})();

Closure allows to access the “memo” object, which stores all of its previous results.

mazza
  • 41
  • 2
  • 3
  • 2
    Isn't this example completely beside the point? Whether it's a counter or a fibonacci sequence is moot. – Niels Bom Feb 12 '18 at 15:07
  • @NielsBom - I don't really understand what is the problem. – mazza Feb 12 '18 at 15:15
  • Fibonacci can be overwritten. – Lore Feb 12 '18 at 15:21
  • 2
    Ok, i realized. Your question is like "Why I have a private members, if I can overwrite the object". Please read about Encapsulation. – mazza Feb 12 '18 at 15:28
  • 1
    i get that this is a more practical example of a closure but it doesn't address the actual question and is probably better suited a comment linking to a jsfiddle. it needs much more explaination to be a good answer. what is *memoization* and how is it relevant? what is this function doing exactly? – I wrestled a bear once. Feb 12 '18 at 15:30
  • I know what encapsulation is. I'm discussing about the value of w3schools example. – Lore Feb 12 '18 at 15:45