You said with Formatter.timesRun = 10; We access timesRun variable and change it. But actually when we call makeUpperCase method we see that timesRun is still 0 and it doesn't change. Could you please explain this strange behavior?
I think this behaviour because it's called Immediately Invoked Function Expression ... As a result it returned the property Immediately when it was equal to 0 before any calling for the public methods and any changes wouldn't affect the returned property unless you change it directly by Formatter.timesRun = ## .... That's my thought about this matter correct me if I'm wrong, I'm just a fellow learner just like you not an expert or something... Hope it helps!
If we add console.log(timesRun);in the setTimesRun method right after ++timesRun; we can see in the console that timesRun is not 10. But with Formatter.timesRun it's 10.
Hi, sorry for replying late, I've seen this before (I guess I didn't try it), but I'll try to come up with something in the upcoming days ;)
-- edit
In the meantime (and actually all the time) you should have explicit functions modifying such values. Take a look here: codesandbox.io/s/busy-field-2yf01
When you do Formatter.timesRun = 10; you don't assign this value to the variable, but to the property of Formatter. You don't have directly access to variables in module pattern. Look here.
I'm still confused, why is the property different from the variable? Where is it stored if the variable is not used and why does incrementing the property does not increment the variable?
I'm only learning, so take this all with a grain of salt, but I was confused here to and this is what helped increment my understand of this error forward: The variable itself isn't returned because "return { timesRun }" is actually object property: value shorthand for "return { timesRun: timesRun }", so it is only creating the property to be stored in Formatter and setting the initial value, which is only set the first time Formatter is created. If you want to get a counter accessible from outside the function you can either:
a) create a function that gets and returns the current private value, because a function declared within the same scope of the private value will retain access to it when called from outside
b) make the property Formatter.timesRun a getter for timesRun, also declared within the same scope, or
c) use the property itself as the counter within the function.
Hey there! I'm diving into the exciting world of JavaScript, HTML, CSS, Node.js, and React. While I'm still getting the hang of things, I'm passionate about learning and creating cool stuff on the web
Old post, but I'll share my solution: The reason you're always seeing 0 for timesRun is due to the closure behavior. When you call Formatter.makeUppercase(), it increments timesRun, but the closure keeps the reference to the original timesRun within the IIFE. So, calls made to the Formatter.timesRun will be the initial value 0.
To fix this, you should modify your code slightly. Instead of directly returning timeRun as a property of the Formatter object, return a function that retrieves the current value of timesRun. This way, the closure will keep a reference to the function, and it will always reflect the updated value.
This is because the F.timesRun, and the IIFE's timesRun (which means the timesRun that inner function modified) are different things.
code sample:
const F = (function() {
let timesRun = 0;
function getTimesRun() {
console.log(timesRun);
}
function plusTimesRun() {
timesRun++;
}
return {
timesRun,
getTimesRun,
plusTimesRun
};
})();
F.getTimesRun();
F.plusTimesRun();
F.plusTimesRun();
F.getTimesRun();
console.log(F.timesRun);
F.timesRun += 10;
console.log(F.timesRun);
When the IIFE run, the new object created which is
{
timesRun,
getTimesRun,
plusTimesRun
}
This is F, new created object, since 'timesRun' is a primitive value, it is copied by value.
After it's being created the 'timesRun' in the new created object is no relationship with the 'timesRun' in IIFE.
Inside this new created returne object, 'timesRun' got the value copied from the IIFE when IIFE run.
At the same time, the 'getTimesRun' and 'plusTimesRun' also remember a different 'timesRun' by closure, which is the original 'timesRun' in the IIFE, and is different from the 'timesRun' property of the new created object.
So, when you change the F.timesRun, only this property changed.
When you run plusTimesRun, the closure timesRun changed, two different properties, this timesRun is remembered via closure by plusTimesRun.
You said with Formatter.timesRun = 10; We access timesRun variable and change it. But actually when we call makeUpperCase method we see that timesRun is still 0 and it doesn't change. Could you please explain this strange behavior?
I think this behaviour because it's called Immediately Invoked Function Expression ... As a result it returned the property Immediately when it was equal to 0 before any calling for the public methods and any changes wouldn't affect the returned property unless you change it directly by Formatter.timesRun = ## .... That's my thought about this matter correct me if I'm wrong, I'm just a fellow learner just like you not an expert or something... Hope it helps!
Hi Bayazz!
Can you reproduce the problem or show the code? I did run the one from example on codesandbox and it seems fine.
Hi Tomek,
thanks for the reply.
If we add console.log(timesRun);in the setTimesRun method right after ++timesRun; we can see in the console that timesRun is not 10. But with Formatter.timesRun it's 10.
codesandbox.io/s/lingering-sound-g...
Any ideas? Im still struggling to understand it.
Thanks
Hi, sorry for replying late, I've seen this before (I guess I didn't try it), but I'll try to come up with something in the upcoming days ;)
-- edit
In the meantime (and actually all the time) you should have explicit functions modifying such values. Take a look here: codesandbox.io/s/busy-field-2yf01
I actually wanted to understand why it's like this.
Anyway thanks for the reply:)
When you do
Formatter.timesRun = 10;you don't assign this value to thevariable, but to thepropertyof Formatter. You don't have directly access to variables in module pattern. Look here.I hope this is more clear now :)
Hey, I've totally forgot about this. Well, this is what you are getting when you are old :D
Yeah it happens:)
Thanks, it's clear now:)
I'm still confused, why is the property different from the variable? Where is it stored if the variable is not used and why does incrementing the property does not increment the variable?
I'm only learning, so take this all with a grain of salt, but I was confused here to and this is what helped increment my understand of this error forward: The variable itself isn't returned because "return { timesRun }" is actually object property: value shorthand for "return { timesRun: timesRun }", so it is only creating the property to be stored in Formatter and setting the initial value, which is only set the first time Formatter is created. If you want to get a counter accessible from outside the function you can either:
a) create a function that gets and returns the current private value, because a function declared within the same scope of the private value will retain access to it when called from outside
b) make the property Formatter.timesRun a getter for timesRun, also declared within the same scope, or
c) use the property itself as the counter within the function.
Old post, but I'll share my solution: The reason you're always seeing 0 for
timesRunis due to the closure behavior. When you callFormatter.makeUppercase(), it incrementstimesRun, but the closure keeps the reference to the originaltimesRunwithin the IIFE. So, calls made to theFormatter.timesRunwill be the initial value 0.To fix this, you should modify your code slightly. Instead of directly returning
timeRunas a property of the Formatter object, return a function that retrieves the current value oftimesRun. This way, the closure will keep a reference to the function, and it will always reflect the updated value.You might be referring to object shorthand notation:
This is because the F.timesRun, and the IIFE's timesRun (which means the timesRun that inner function modified) are different things.
code sample:
When the IIFE run, the new object created which is
This is F, new created object, since 'timesRun' is a primitive value, it is copied by value.
After it's being created the 'timesRun' in the new created object is no relationship with the 'timesRun' in IIFE.
Inside this new created returne object, 'timesRun' got the value copied from the IIFE when IIFE run.
At the same time, the 'getTimesRun' and 'plusTimesRun' also remember a different 'timesRun' by closure, which is the original 'timesRun' in the IIFE, and is different from the 'timesRun' property of the new created object.
So, when you change the F.timesRun, only this property changed.
When you run plusTimesRun, the closure timesRun changed, two different properties, this timesRun is remembered via closure by plusTimesRun.
You can totally modify the return sentence like:
Then use
F.newTimesRun = 10;to change the new created property.And change the closure 'timesRun' via 'plusTimesRun'.
Hope I made this clear.