This might be a vague question (or even answered before, if so just cast a close vote and I'm happy with the point in the right direction), and if I just read up on the different scopes of JavaScript a few more times I might be wiser, but seeing as I've done that over several years and still get perplexed by the way JavaScript scopes work - some of you might have a good/proper explanation of why the below snippet works in the way it does:
(I understand that there's scope/context involved, or maybe mutable variable types, but can't figure out the difference in the below code snippet and why it's illogical)
class test {
constructor() {
this.obj = document.createElement('div');
let style = {'padding' : '5px'};
this.obj.innerHTML = '<h3>Click the button:</h3>';
for (let key in style) {
this.obj.style[key] = style[key];
}
this.some_var = 55;
this.update_state.call(this, 'test');
this.update_state_working.call(this, 'test');
}
update_state(state) {
if (state == 'test') {
const frame = document.createElement('div');
frame.innerHTML = '<input style="background-color: #00FF00;" type="submit" value="Not working" />';
frame.onclick = function(event) {
console.log('You pressed: ' + this.some_var);
};
this.obj.appendChild(frame);
}
}
}
This will fail, logging You pressed: undefined
. Which to me coming from other language backgrounds, is a bit confusing.
update_state(state) {
let test_var = this.some_var;
if (state == 'test') {
const frame = document.createElement('div');
frame.innerHTML = '<input style="background-color: #00FF00;" type="submit" value="Working" />';
frame.onclick = function(event) {
console.log('You pressed: ' + test_var);
};
this.obj.appendChild(frame);
}
}
While this on the other hand will work.
I assume it's because test_var
is a block scope locally defined in update_state
and some how gets frozen in to the event function? But I don't get why the difference? The context in my mind would be the same since the event is bound to a certain DOM object or outer class scope/instance?
I found What is the scope of variables in JavaScript? which has a pretty good explanation of what the different scopes are in practical examples, and I thought that this.some_var
would be accessible according to example #6. And this question, scope of variable inside an event listener callback function - hints that this.index
should be accessible inside a onclick
function, which to me - it isn't?
What is the best practice method in solving this context issue? Because I rarely see anyone solving it by doing let
declarations, but maybe I've just missed something obvious?
I'm looking for an explanation (or a resource describing the pickle) to why this locally declared variable works, why the context of the test
instance can't be used as a variable source like the link above suggested, and what the appropriate solution to this might be (if not declaring by block scope local variable).
JsFiddle: https://jsfiddle.net/2cbfhzt5/