我有一个使用构造函数创建的对象数组。这是构造函数定义:
function Expander(elem, startingFlipped) {
this.element = elem;
this.flipped = startingFlipped;
}
(下面,rawElems
只是document.getElementsByClassName('foo');
)
一旦DOMContentLoaded事件触发,我就会执行此操作来查找,构造新对象并将其推送到数组中:
for (var i = 0; i < rawElems.length; i++) {
expanders[i] = new Expander(rawElems[i], false);
expanders[i].this.element.addEventListener("click", function (event) {
console.log("Clicked " + expanders[i].this.element);
});
}
问题是,我不知道如何访问this
的属性。这当前抛出错误:
未捕获的TypeError:无法读取未定义的属性“element” 在HTMLSpanElement。
这在某些方面很棒,因为这些是<span>
元素(控制台记录对象,数组显示它已正确填充)。
但是因为我正在尝试这个构造函数模式,如何使用this
正确引用每个对象中的元素?
答案 0 :(得分:6)
表达式expanders[i].this.element
表示“查找名称为expanders
的{{1}}上的属性,然后在结果中查找名为i
的属性,并且在 的结果上,查找名为this
的属性。
但是您的element
对象上没有名为Expander
的属性。如果您要访问this
处的Expander
对象,只需使用该对象,就不要向其添加expanders[i]
:
this.
在事件处理程序中,expanders[i].element.addEventListener("click", function (event) {
// ^--- No this. here
console.log("Clicked " + this);
// Here, use `this` -----^
});
将引用您挂接事件的DOM元素,因此您根本无法通过this
访问它。
如果您需要访问那里的扩展器,您需要给自己一个在事件发生时仍然有效的引用。您不能在当前循环中使用Expander
,因为expanders[i]
的值会在事件发生之前发生变化。
这部分有很多选项,在JavaScript closure inside loops – simple practical example中讨论过。最简单的方法之一是使用i
代替Array.prototype.forEach
:
for
在ES2015(又名“ES6”)环境或更高版本中,您可以在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.
});
});
循环中使用let
:for
然后for (let i = 0; i < rawElems.length; ++i)
将< / em>正常工作。 (expanders[i]
与let
完全不同,即使它们具有相似的用途。)
或者您可以使用var
将Function.prototype.bind
绑定到事件处理函数,然后使用expanders[i]
来引用扩展器,this
(或this.element
})引用元素。这样做的好处是您可以定义处理程序一次并重复使用它:
event.currentTarget