The expression expanders[i].this.element
means "look up the property on expanders
whose name is the value of i
, then on the result look up a property called this
, and on the result of that, look up a property called element
.
But your Expander
object doesn't have a property on it called this
. If you want to access the Expander
object at expanders[i]
, you just use that, you don't add this.
to it:
expanders[i].element.addEventListener("click", function (event) {
// ^--- No this. here
console.log("Clicked " + this);
// Here, use `this` -----^
});
Within the event handler, this
will refer to the DOM element that you hooked the event on, so you don't access it via your Expander
at all.
If you need to access your expander in there, you need to give yourself a reference to it that will still be valid when the event occurs. You can't use expanders[i]
for that with your current loop, because i
's value will have changed before the event happens.
You have lots of options for this part, discussed in JavaScript closure inside loops – simple practical example. One of the simplest is to use Array.prototype.forEach
instead of for
:
Array.prototype.forEach.call(rawElems, function(element, index) {
var expander = expanders[index] = new Expander(element, false);
element.addEventListener("click", function (event) {
// You can use `element` and `expander` here
// If you liked, you could *not* have the `expander` variable
// and use `expanders[index]` here, because unlike the `i` in
// your `for` loop, the value `index` won't change.
});
});
In an ES2015 (aka "ES6") environment or later, you could use let
in your for
loop: for (let i = 0; i < rawElems.length; ++i)
and then expanders[i]
would work correctly. (let
is quite different from var
even though they have similar purposes.)
Or you could use Function.prototype.bind
to bind expanders[i]
to the event handler function, then use this
to refer to the expander, and this.element
(or event.currentTarget
) to refer to the element. That has the advantage that you can define the handler once and reuse it:
for (var i = 0; i < rawElems.length; i++) {
expanders[i] = new Expander(rawElems[i], false);
expanders[i].element.addaddEventListener("click", handleExpanderClick.bind(expanders[i]));
}
function handleExpanderClick(event) {
// `this` = the expander
// `this.element` = the element
// `event.currentTarget` = the element (also)
}