【问题标题】:Using this inside array of objects在对象数组中使用这个
【发布时间】:2017-06-30 15:43:01
【问题描述】:

我有一个用构造函数创建的对象数组。这是构造函数定义:

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 属性的语法如何。这当前会引发错误:

未捕获的类型错误:无法读取未定义的属性“元素” 在 HTMLSpanElement。

这在某些方面很棒,因为这些是 &lt;span&gt; 元素(控制台记录对象和数组显示它已正确填充)。

但由于我正在尝试这种构造函数模式,如何使用this 正确引用每个对象内的元素?

【问题讨论】:

  • 试试expanders[i].element.....
  • @PranavCBalan 实际上,我仍然遇到同样的错误(我也尝试过)

标签: javascript arrays javascript-objects


【解决方案1】:

表达式expanders[i].this.element 的意思是“在expanders 上查找名称为i 的属性,然后在结果中查找名为this 的属性,然后在 ,查找名为element 的属性。

但是您的Expander 对象上没有名为this 的属性。如果你想在expanders[i] 访问Expander 对象,你只需使用它,你不要添加this.

expanders[i].element.addEventListener("click", function (event) {
//          ^--- No this. here
    console.log("Clicked " + this);
    // Here, use `this` -----^
});

在事件处理程序中,this 将引用您挂钩事件的 DOM 元素,因此您根本不会通过您的 Expander 访问它。

如果您需要在那里访问您的扩展器,您需要给自己一个引用,当事件发生时该引用仍然有效。您不能在当前循环中使用expanders[i],因为i 的值会在事件发生之前发生变化。

这部分你有很多选择,在JavaScript closure inside loops – simple practical example 中讨论过。最简单的一种是使用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.
    });
});

在 ES2015(又名“ES6”)环境或更高版本中,您可以在 for 循环中使用 letfor (let i = 0; i &lt; rawElems.length; ++i) 然后 expanders[i] 正常工作。 (letvar 完全不同,尽管它们有相似的目的。)

或者您可以使用Function.prototype.bindexpanders[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)
}

【讨论】:

  • 哦!有趣的。我是否也可以简单地使用 .map() 方法将事件处理程序分配给数组中的每个 object.element?
  • @armadadrive:哇!当然可以:var expanders = Array.prototype.map.call(rawElems, function(element, index) { /* create, hook up, and return expander here */});我早该想到的。
  • 哈哈哈,好吧,我不会反对你。感谢您的宝贵时间和深思熟虑的答案。
猜你喜欢
  • 2021-02-16
  • 2011-08-29
  • 1970-01-01
  • 2021-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-11
  • 2012-07-16
相关资源
最近更新 更多