Reputation: 176
I will try to keep this short and neat. I have two files, Main.js and Component1.js. I am trying to implement the module pattern but i am having troubles with getting changes to persist after being made in an event handler. I will explain the code as i go along, i am writing this in nodejs and this is the short version of each file:
Main.js
var component1 = require("Component1");
var components = { compA: component1(), compB: {} };
Component1.js
module.exports = function () {
var count = 0;
function listener(e) { // Event handler of custom event.
console.log(count);
count++;
}
return { count: count }
}
Now, if i add the following line to Main.js
components.compA.randomString = "Hello";
and change listener() in Component1.js to
function listener(e) { // Event handler of custom event.
console.log(typeof randomString);
console.log(count);
count++;
}
i get the following print-out after issuing 1 custom event tied to the listener:
undefined
0
If i were to issue a second custom event the print-out would read:
undefined
1
but if i were to now console.log the compA.count in Main.js i would see that it was still zero.
I am guessing that this means that the listener either has access to a different scope, and therefore neither change "persisted" from the perspective of the other (count === 0 for Main.js, string undefined for the listener), or that compA and the listener referes to two different objects? I am arriving at this conclusion because if i now change Component1.js to
module.exports = function () {
var count = 0;
var _this;
function listener(e) { // Event handler of custom event.
console.log(typeof _this.randomString);
console.log(_this.count);
_this.count++;
}
function init() {
_this = this;
}
return { count : count, init: init }
}
and add the following line to the end of Main.js:
components.compA.init();
and issue 2 new custom events i get the following print-out:
string
0
string
1
and the correct count would persist to components.compA.count.
Can someone please explain this behaviour?
Upvotes: 2
Views: 577
Reputation: 31692
First let's start with some facts about data types:
var a = 5;
var b = a;
b++;
console.log(a); // a is still 5
console.log(b); // b is 6
var a = { prop: 5 };
var b = a;
b.prop++;
console.log(a); // a is changed to ...
console.log(b); // ... b's value, because both a and b are pointing to the same object so changing one will alter the other.
1. Case of randomString
:
In the first code, you are adding the randomString
property to the object returned at this line:
return { count: count }
which clearly won't magically create a new variable called randomString
to be available to use inside the function in Component1.js. If you have stored that object into a variable called myObject
for example, you could have accessed it using myObject.randomString
.
2. Case of count
:
You're accessing the count
property of the aforementioned object, which is a copy of count
variable, since the value is a primitive value (Fact #1), changing one won't affect the other. Thus when you update the variable count
inside listener
, the property count
of the object (which is assigned to components.compA
in Main.js) won't get updated.
Just get rid of the standalone variables and use an object (to benefit from Fact #2):
module.exports = function () {
var myObject = { count: 0 }; // use an object
function listener(e) {
console.log(myObject.randomString); // when randomString get assigned on the other side (Main.js) this will be defined
console.log(myObject.count); // use myObject.count not count
myObject.count++; // ... same here
}
return myObject; // return the object, according to Fact #2, any changes to this object (either on this side or the other) will be reflected, ie both this side and the other point to the same object
}
Now, when you do:
var components = { compA: component1(), compB: {} };
in Main.js, both myObject
and components.compA
will point to the same object, thus any changes made by one will be reflected on the other. If you add a randomString
property to components.compA
, you can access it from Component1.js via myObject.randomString
. When you increment count
in Component1.js, components.compA.count
is also incremented, because, in fact, both are the same thing.
Well, because you're kind of doing the same as the fix code above. Your init
function just assignes its this
value to the variable _this
. Since init
is called on "THE OBJECT" (our returned object), the value of this
is that object. So basically it's the same as the above fix code, but you needed a whole new function just to assign the object to a variable, which is redundant.
Upvotes: 1