2017-02-12 61 views
3

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

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。目前这引发错误:

Uncaught TypeError: Cannot read property 'element' of undefined at HTMLSpanElement.

这在某些方面是很大的,因为这些都是<span>元素(控制台登录的对象和数组表明它是正确填充)。

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

+2

尝试'扩展[I] .element .....' –

+0

@PranavCBalan我仍然得到同样的错误,其实(我也试过了) – armadadrive

回答

6

表达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 < rawElems.length; ++i)然后expanders[i]正常工作。 (letvar完全不同的,即使他们有类似的目的。)

或者你可以使用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) 
} 
+0

哦!有趣。我是否也可以简单地使用'.map()'方法将事件处理程序分配给数组中的每个object.element? – armadadrive

+0

@armadadrive:Doh!当然你可以:'var expanders = Array.prototype.map.call(rawElems,function(element,index){/ * create,hook up,return expander here//});'我应该想到这一点。 –

+0

哈哈哈,好吧,我不会持有它反对你。感谢您的时间和深思熟虑的答案。 – armadadrive

相关问题