Revealing Module Pattern And Scope - javascript

I ran into an issue with some javascript I was running and broke it down to the code below. I'm confused as to why the _localVar variable doesn't change after init() is called. I find that if I reference this._localVar in the revealingModule, the results are as expected. I am confused about the scope. Could someone please clarify why this is occurring. I thought that if I didn't use this, then the next scope would be the module, but I don't think that's happening.
var myRevealingModule = (function () {
var _localVar = "Default";
function init() {
console.log(_localVar);
_localVar = "Init";
}
function getTest() {
console.log(_localVar);
}
return {
init: init,
getTest: getTest,
localVar: _localVar
};
})();
myRevealingModule.getTest(); // "Default"
console.log(myRevealingModule.localVar); // "Default"
myRevealingModule.init(); // "Default"
myRevealingModule.getTest(); // "Init"
console.log(myRevealingModule.localVar); // "Default" * WHY *

myRevealingModule.localVar is not a reference to the variable's value; it simply copied the string when it's created.
When you use this.localVar, you're using the variable in the returned object. Hence, when you change that identifier, it also updates with myRevealingModule.localVar.

Note that your module uses a self-invoking function. Therefore the value of myRevealingModule.localVar is determined right after the definition and built-in invocation of myRevealingModule. At this time the value of _localVar is "Default", which is copied to returned object's localVar property. Even if you change _localVar afterwards this has no effect on myRevealingModule.localVar anymore.
Basically the following example show the same effect:
var a = 42;
var b = a;
console.log(a); // 42
console.log(b); // 42
a = 84;
console.log(a); // 84
console.log(b); // 42
b copies the value of a. If you change a afterwards that has no impact on b.

Related

In a closure, why does the main variable not get reset every time it is called?

I'm trying to get a solid understanding of closures, and I'm struggling with the mechanics of it. I've looked on w3schools (https://www.w3schools.com/js/js_function_closures.asp) and MDN (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures) and a few other places. I understand what a closure is and how to make it work but I don't understand why subsequent calls after the first call to the outer function just seem to go straight to the inner one instead.
Here is my code - a simple, working closure:
var add = (function () {
var a = 0;
alert('hi');
function addInner(){
a += 1;
return a;
}
return addInner;
})();
function getAdd() {
document.getElementById("test").innerHTML = add();
}
I have two questions that probably both have the same answer: Why does a not get reset every time I call add()? And why does the alert not pop up except for on the first time?
I attached getAdd() to a button, and it works great, but it but doesn't pop up with the alert past the first time. Why does it do this?
Edit: I also found the first answer to this question (Why Don't Variables Reset in a Closure (Javascript)) really helpful.
add is a reference to addInner, not the anonymous "outer" function, since the "outer" function returns addInner. Then, you call that anonymous function once - that last set of ()- and store the resulting function, with its own private 'a', in add.
Imagine that the outer function was a named function called constructAdder, and you called
var add = constructAdder();
var add2 = constructAdder();
That's basically what you've done, but with an anonymous function, if that makes it any clearer. You have an outer function that constructs an inner function that can count, due to the magic of closures.
Those questions do both have the same answer. And it's fairly simple. This statement:
var val = (function() {
return 42
}())
sets val to 42. Not a function. This is called an IIFE, or immediately-invoked function expression. We are declaring a function and calling it immediately. We never save that function. We just use it once to get the value it returns:
val // 42
Contrast that to:
var val = function() {
return 42
}
In this case we set val to a function that, when called, returns 42.
val() // 42
val() // 42
We can get pretty crazy with IIFEs:
var val = (function() {
return (function() {
return (function() {
return 42
}())
}())
}())
The value returned by that mess is still 42.
val // 42
All those functions are declared once, used once, and thrown away. But IIFEs are capable of so much more:
var add = (function() {
var counter = 0
return function() {
return counter++
}
}())
We're now using the IIFE to create a private variable! counter cannot be accessed outside the scope of the IIFE. It's safe. But the inner function can access and modify it. It's a fully encapsulated, stateful function!
add() // 0
add() // 1
counter // Uncaught ReferenceError: counter is not defined
This is what your code is doing:
var add = (function () {
var a = 0;
alert('hi');
function addInner(){
a += 1;
return a;
}
return addInner;
})();
It is encapsulating the a variable so that it cannot be accessed outside the scope of the IIFE. The addInner function, however, does have access to a and can modify it at will.
The alert() is only called once because that IIFE is only called once, then thrown away. Note that the function itself is the only thing thrown away. Since addInner maintains a reference to the scope (closure) created by the IIFE, that scope is safe from garbage collection.
In fact, that's a helpful way to think about IIFEs:
var val = function() {}
creates a function and
val()
creates a closure (the context that the function's body runs in). IIFEs are used when we don't care about the function, we just want the closure it creates.
Hope this helps. Have fun out there!
var add = (function () {
var a = 0;
alert('hi');
function addInner(){
a += 1;
return a;
}
return addInner;
})(); <-- This
The () at the end means that add is added forever, and if you look at the line above, then it says return addInner. This means that add() is actually addInner(), the good thing with this is that addInner has access to a. Actually writing the function like this is more proper.
var add = (function () {
this.a = 0;
alert('hi');
var addInner = function(){
this.a += 1;
return this.a;
}.bind(this);
return addInner;
})();
Because now you would think that add.a would make a available because it is written as this.a, but since addInner is returned, then it is not available.
You should focus on the
(function(){
// impl
})()
block.
It is called an Immediately Invoked Function Expression or IIFE.MDN reference
So when the code executes to line 1, it first evaluate the right side and the IIFE returns a closure which was then assigned to the variable add. Meanwhile, an alert was invoked in the IIFE. Understanding the IIFE can help you solve the problems.
In my opinion , the key is IIFE, after the code below is executed at the first time,
var add = (function () {
var a = 0;
alert('hi');
function addInner(){
a += 1;
return a;
}
return addInner;
})();
(Look out ! There is no add() in the code above because IIFE will be Invoked Immediately and the return addInner finished the initialization of variable add )
the function add has been changed to :
add = function addInner() {
a += 1;
return a;
}
Of course, the alert() only executed one time because the add has been changed at the begining.
Why does a not get reset every time I call add()?
And why does the alert not pop up except for on the first time?
that is the answer of your question.
variable a didn't destroy because the function add still have a reference, and this is about the closure.

How to reference different locations inside a JavaScript function

I am trying to access settings and values/functions from within other functions in JavaScript, and believe there is probably a simple rule which I am missing. Here is a very simplified code example:
function h(){
// example settings I want to declare for h()
this.settings = {
critical: 400,
readCritical: function(){
return this.settings.critical; // /!\ but this does not work
}
}
this.hsub = function(){
return this.settings.critical; // /!\ this does not work either
}
}
var x = new h();
console.log(x.settings.critical); // This works fine
console.log(x.settings.readCritical()); // I can *call* this fine, but it can't read outside itself
console.log(x.hsub()); // I can also call this but same problem
console.log(h.settings); // `undefined`; I understand I can't see directly into the function
You can see the this.settings.critical value, which I'm trying to access from inside the respective functions readCritical and hsub. How can I do this? Specifically from the instantiated x.
Also a secondary question but related, I would prefer to declare var settings = {} instead of this.settings. Is this possible or preferable?
Only change you need to make is to remove .settings from within the readCritical function.
The hsub works as is. Not sure why you thought there was a problem
function h(){
this.settings = {
critical: 400,
readCritical: function(){
return this.critical; // reference `critical` directly
}
}
this.hsub = function(){
return this.settings.critical; // this works just fine
}
}
var x = new h();
console.log(x.settings.critical); // 400
console.log(x.settings.readCritical()); // 400
console.log(x.hsub()); // 400
// This is expected to be `undefined`
console.log(h.settings);
Ahh, another old classic closure problem.
There are two ways to solve it:
function h(){
var self = this;
this.settings = {
critical: 400;
readCritical: function() {
return self.settings.critical(); // otherwise this.settings will 'cover' `this`.
}
}
}
readCritical: () => this.settings.critical(); // arrow functions won't form a function scope
The scope of this (and binding functions to set it) are much discussed topics in JS. However, you seem not to be looking for this specifically, but sharing variables, there's another alternative. All in all, there's no best answer, but since you would also like to declare var settings = {}: you actually can and have access to that local variable available inside the other functions.
function h(){
var settings = { //var settings is a local variable of the function h (or instance of it). If ES6 is allowed 'let' or 'const' are preferrable
critical: 400,
readCritical: function(){
return settings.critical;
}
};
this.settings = settings; //this.settings is not the same variable as var settings, making this statement valid
this.hsub = function(){
return settings.critical; //the local (var) settings is used
}
}
var x = new h();
console.log(x.settings.critical);
console.log(x.settings.readCritical());
console.log(x.hsub());
Pitfall here, is that if the calling code changes x.settings to something else, the variables will not point to the same instance (if they change a value inside x.settings, all is well). If that is a risk, it could be exposed as a property method instead
It looks like you only want to have one instance. If that is so, then just create the instance immediately with an object literal notation:
var h = {
settings: {
critical: 400,
readCritical: function(){
return this.critical;
}
},
hsub: function(){
return this.settings.critical;
}
}
console.log(h.settings.critical);
console.log(h.settings.readCritical());
console.log(h.hsub());
console.log(h.settings);
Now all four property accesses work as expected when given the singleton object h.

Adding a function to global windows object

I was playing around with javascript objects to understand "this" and function context better. I stumbled across this problem. I get the error "obj2 is not defined" unless I run window.obj2() after assigning it, but I don't know why. Shouldn't it be enough to assign the function to window.obj2 without also executing it immediately afterwards? I know that you're not supposed to pollute the window object, this is just a test.
Thanks!
window.obj2 = function(){
console.log('obj2 in window.object',this);
}
window.obj2(); // problem when this line is commented out
(function () {
var parent = {
obj : function(){
//console.log(this);
obj2();
this.obj2();
window.obj2();
},
obj2 :function(){
console.log('obj2 in parent',this);
}
}
parent.obj();
}());
EXPLANATION
OP asks why does he have to execute the function after defining it in order for it to become defined later in the code... See what happens when you comment out the problem line.
Solution to the mystery:
You forgot a semicolon:
window.obj2 = function(){
console.log('obj2 in window.object',this);
}; // <--
Without it, the code will be interpreted as
// I'm naming the functions to refer to them later
window.obj2 = function a(){
...
}(function b() { ... }());
I.e. the parenthesis around b are interpreted as call operation of a (just like you did with b itself: (function b() {...}()).
The engine first executes b in order to pass the return value as argument to a, and only after that the return value is assigned to window.obj2.
So, at the moment b is called, window.obj2 does indeed not exist yet.
So, the reason why adding window.obj2() makes it work is not because you are accessing window.obj2, but because it makes the code un-ambigious. The following parenthesis cannot be interpreted as call operation anymore. You could use any statement there, e.g.
window.obj2 = function(){
console.log('obj2 in window.object',this);
}
"foo";
(function () {
obj2();
}());
If you defined function window.obj2 inside the anonymous function which does call itself then it works fine, have a look code.
<script>
//window.obj2(); // problem
(function (window) {
window.obj2 = function(){
console.log('obj2 in window.object',this);
}
var parent = {
obj : function(){
//console.log(this);
obj2();
this.obj2();
window.obj2();
},
obj2 :function(){
console.log('obj2 in parent',this);
}
}
parent.obj();
}(window));
</script>
<body>
</body>

Passing a global variable to a function

How come the following code is giving me a 0 instead of a 1? I want my function to change a variable declared outside the function but I do not want to specify the variable in the function declaration.
that = 0;
function go(input) {
input++;
}
go(that);
console.log(that);
As answered by Oriol, it doesn't work because the variable is passed by value, so you're not changing the "that" variable. A workaround would be to pass the variable name :
that = 0;
function test(input) {
window[input]++;
}
test("that");
console.log(that); // 1
That's because you are passing the variable by value, not by reference.
In javascript, all variables are passed by value, except objects, which are passed by reference (well, in fact they are passed by value too but they are a reference, see below).
And you can't change that behaviour.
Edit: If you don't know what passing by value/reference means, you should read a tutorial. But here you have some examples:
Variable passed by value
function foo(bar){
console.log(bar); // 1
bar++;
console.log(bar); // 2
}
var mybar = 1;
console.log(mybar); // 1
foo(mybar);
console.log(mybar); // 1
Variable passed by (value but used as a) reference
function foo(bar){
console.log(bar.a); // 'b'
bar.a = 'c';
console.log(bar.a); // 'c'
}
var mybar = {a:'b'};
console.log(mybar.a); // 'b'
foo(mybar);
console.log(mybar.a); // 'c'
In your case
You can do
Make your variable a property of an object (in your case, since it's a global variable, use window) and pass the object (reference), so you can alter it
window.that = 0;
function go(obj) {
obj.that++;
}
go(window);
console.log(that); // 1
Use a return value
var that = 0;
function go(input) {
return input++;
}
that = go(that);
console.log(that); // 1
Note that you can't do
Convert your variable into an object
var that = new Number(0); // Now it's an object number
function go(input) {
input++;
}
go(that);
that *= 1; // Now it's a literal number
console.log(that); // 0
That's because objects are passed by value too, but they are a reference. That means that inside the function you can change the properties of the outer object (because it's a reference) but you can't change the entire object, because it's passed by value.
See examples here: https://stackoverflow.com/a/3638034/1529630
This has to do with pointers, scope, passing variables by reference, and all that jazz.
If you really want to do this, you can pass an object in Javascript like this:
var that = {value: 0};
function go(input) {
input.value++;
}
go(that);
console.log(that.value);
All we've done is made that an object which is by definition passed as a reference in Javascript. Then we just make sure we properly modify the object's attributes.
Your code
that = 0; //Global variable
function go(input) { //input is argument and is not passed by reference
input++; //This just increments a local copy i.e 0
}
go(that); //Passed 0
console.log(that);
Instead do this
that = 0;
function go() {
that++;
}
go(); //Not passing any variable .. function can already see the gloabl "that"
console.log(that); // This will print gloabl i.e. 1
Actually you could just add console.log(input) inside the function and it would work just fine.
Please correct me if i'm wrong. Hope i helped !!
I would be glad if somebody could explain why im wrong

javascript - can we have self invoking function modules assigned to variables

Can variable be assigned self invoking function module so that the variable reference would trigger calling the function without the () operator. I want the variable to have the latest value based on the code in the function module.
the code could be
count = 0
var x = function(){ return count }();
alert x; // should give 0
count = 7
alert x ; // should give 7
thanks
This behaviour can be achieved via a getter, using Object.defineProperty, for example:
// Add a `somemethod` property to `window`
Object.defineProperty(window, 'somemethod', {
get: function() {
return Math.random();
}
});
console.log(window.somemethod);
console.log(window.somemethod); // Different value
No, but you can use getters and setters of object properties: https://developer.mozilla.org/en/JavaScript/Guide/Working_with_Objects#Defining_getters_and_setters

Categories