I'm trying to dynamically create getters and setters on a class using defineProperty, but the definition of their function depends on variables above the scope of the defineProperty function call. So when the value of some variable and run defineProperty, the getter, when called later, should behave differently than when this variable has a different value at the time defineProperty was invoked.
So something like:
var/let/const/whatever i=5;
defineProperty(SomeClass, 'prop00', ... get() {
some code that depends on i, but the value of i should be snapshot
} ...)
I've been trying some things, but I'm getting some behavior I do not understand.
In below code, I have a 2x nested loop from 0..1, and a counter (cA), defined in the outer loop, which I reference inside the getter function within the inner loop:
class TestA {}
for (let i = 0; i < 2; i++) {
let cA = 0;
for (let j = 0; j < 2; j++) {
Object.defineProperty(TestA.prototype, 'prop_' + i + "_" + j, {
get() { return "val_" + i + "_" + j + ":" + cA; }
});
cA++;
}
}
tA = new TestA();
for (let i = 0; i < 2; i++) {
let cA = 0;
for (let j = 0; j < 2; j++) {
console.log(
"not-really-but-lets-say-expected", "val_" + i + "_" + j + ":" + cA,
"got", tA["prop_" + i + "_" + j]
);
cA++;
}
}
This is the output:
"not-really-but-lets-say-expected", "val_0_0:0", "got", "val_0_0:2"
"not-really-but-lets-say-expected", "val_0_1:1", "got", "val_0_1:2"
"not-really-but-lets-say-expected", "val_1_0:0", "got", "val_1_0:2"
"not-really-but-lets-say-expected", "val_1_1:1", "got", "val_1_1:2"
Notice the :2 at the end of each line vs. the :0/:1 on the expected values. So you see that values use the last registered value for the counter cA at the end of each iteration of the outer loop. It appears that for each iteration of the outer loop, a separate scope is defined, and kept, and the references inside the getter are to the counter value in that scope, which is shared among the iterations of the inner loop.
I then tried to define a variable inside the inner loop, and copied the value from the counter inside the parent outer loop:
class TestB {}
for (let i = 0; i < 2; i++) {
let cA = 0;
for (let j = 0; j < 2; j++) {
let cB = cA;
Object.defineProperty(TestB.prototype, 'prop_' + i + "_" + j, {
get() { return "val_" + i + "_" + j + ":" + cB; }
});
cA++;
}
}
tB = new TestB();
for (let i = 0; i < 2; i++) {
let cB = 0;
for (let j = 0; j < 2; j++) {
console.log(
"not-really-but-lets-say-expected", "val_" + i + "_" + j + ":" + cB,
"got", tB["prop_" + i + "_" + j]
);
cB++;
}
}
This results in:
"not-really-but-lets-say-expected", "val_0_0:0", "got", "val_0_0:0"
"not-really-but-lets-say-expected", "val_0_1:1", "got", "val_0_1:1"
"not-really-but-lets-say-expected", "val_1_0:0", "got", "val_1_0:0"
"not-really-but-lets-say-expected", "val_1_1:1", "got", "val_1_1:1"
So unless I'm misinterpreting what's happening here, it seems that these scopes are kept, and assigned somehow to the scope of the getter that was created by the defineProperty function at that point.
Can someone shed some light on this? I've Googled till my eyes bled, but I'm fairly new to JS otherwise. Here's the Fiddle.