arm*_*ive 3 javascript arrays javascript-objects
我有一个使用构造函数创建的对象数组.这是构造函数定义:
function Expander(elem, startingFlipped) {
this.element = elem;
this.flipped = startingFlipped;
}
Run Code Online (Sandbox Code Playgroud)
(下面,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);
});
}
Run Code Online (Sandbox Code Playgroud)
问题是,我不知道如何访问该属性的语法this.这当前抛出错误:
未捕获的TypeError:无法读取HTMLSpanElement中未定义的属性"元素".
这在某些方面很棒,因为这些ARE <span>元素(控制台记录对象和数组显示它已正确填充).
但是因为我正在尝试这个构造函数模式,如何使用this?正确引用每个对象内的元素?
表达expanders[i].this.element的意思是"查找的财产expanders,其名称是的值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` -----^
});
Run Code Online (Sandbox Code Playgroud)
在事件处理程序中,this将引用您挂接事件的DOM元素,因此您根本不能通过它访问它Expander.
如果您需要访问扩展器,则需要为自己提供一个在事件发生时仍然有效的引用.你不能expanders[i]在当前循环中使用它,因为i在事件发生之前它的值会发生变化.
这个部分有很多选项,在循环内部的JavaScript闭包中讨论过- 简单实用的例子.最简单的方法之一是使用Array.prototype.forEach而不是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.
});
});
Run Code Online (Sandbox Code Playgroud)
在ES2015(又名"ES6")环境或更高版本的环境中,您可以let在for循环中使用:for (let i = 0; i < rawElems.length; ++i)然后expanders[i] 可以正常工作.(尽管它们有类似的用途,但是let完全不同var.)
或者您可以使用Function.prototype.bind绑定expanders[i]到事件处理函数,然后用于this引用扩展器,以及this.element(或event.currentTarget)引用该元素.这样做的好处是您可以定义一次处理程序并重用它:
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)
}
Run Code Online (Sandbox Code Playgroud)