I'm learning JavaScript, coming from Ruby, have done some stuff in C as well. One example in my reading is:
function letCounter() {
let counter = 0;
return () => ++counter;
}
and is compared to
function thisCounter() {
this._count = 0;
}
thisCounter.prototype.fire = function() {
this._count ++;
return this._count;
}
In the first example, the count is NOT accessible on an instance of letCounter:
let let_counter_ins = letCounter();
let_counter_ins.counter // <- undefined
while in the second, count, ~I think~, is an attribute of all instances of the function itself?
let this_counter_ins = new thisCounter();
this_counter_ins.count // <- 0
Seems like a function in JavaScript can have 'state' (calls to console.log(let_counter_ins())
will continuously increment a counter, as opposed to it starting over at 0). But also this 'state', set with let
is somehow different than a 'state' set with this
? Seems like instances of both letCounter
and thisCounter
are keeping track of some counter, but how it is accessible is different? Trying to understand what the difference is between setting function attributes with this
vs let
and why one of them is available externally.
In the first code, a local variable counter
is initialized, and the returned function closes over the variable (in a "closure"). The value only exists in the local scope of the function - in a Lexical Environment that, once the function finishes, is only referenceable via the () => ++counter
. There's no way to directly observe the contents of a closure, other than by the methods that the closure may (or may not) have returned or use that deliberately expose its contents.
Every call of letCounter
will result in a new binding for counter
being created, a new Lexical Environment for it, and a new closure, so separate calls of letCounter
will result in separate counts being kept track of.
In the second code, with this
, counter
is not a local variable, but a normal property of the instance object. Object properties are completely public (with the exception of the extremely new #
private member syntax I won't get into), so anything, including thisCounter.prototype.fire
and external code can access this.counter
(where this
references the instance) or this_counter_ins.count
(where this_counter_ins
references the instance) and get the current value on the object.