使用这个内部对象数组

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?正确引用每个对象内的元素?

T.J*_*der 6

表达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")环境或更高版本的环境中,您可以letfor循环中使用: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)