2017-02-12 3 views
3

私はコンストラクタで作成されたオブジェクトの配列を持っています。これは、コンストラクタの定義である:このオブジェクトの内部配列の使用

function Expander(elem, startingFlipped) { 
    this.element = elem; 
    this.flipped = startingFlipped; 
} 

(以下、rawElemsdocument.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のプロパティにアクセスするための構文を知らない、です。これらは<span>要素です(オブジェクトをロギングコンソールは、配列は、それが適切に移入され表示されます)ので、いくつかの点で素晴​​らしいです

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

:これは、現在エラーがスローされます。

しかし、私はこのコンストラクタパターンを試しているので、どのようにして各オブジェクト内の要素を正しく参照するのですかthis

+2

は(実際には、..... ' –

+0

@PranavCBalan私はまだ同じエラーを取得し.element [i]は'パンダを試みるIそれも試みた) – armadadrive

答えて

6

expanders[i].this.elementは名前がexpandersのプロパティを調べる」を意味表現は、その後、その結果にelementと呼ばれるプロパティを検索し、thisというプロパティを検索し、その結果に、iの値です。

しかし、あなたのExpanderオブジェクトは、その上にプロパティがthisと呼ばれていないあなたはexpanders[i]Expanderオブジェクトにアクセスしたい場合、あなたはちょうどあなたがそれにthis.を追加していない、ということを使用します。

イベントハンドラ内では、thisはイベントをフックしたDOM要素を参照するため、Expanderからアクセスしないでください。

ここでエキスパンダーにアクセスする必要がある場合は、イベントが発生したときに有効となる参照を自分自身に与える必要があります。イベントが発生する前にiの値が変更されているため、現在のループではexpanders[i]を使用することはできません。

JavaScript closure inside loops – simple practical exampleで説明されているこの部分には、多くのオプションがあります。正しく作業うfor (let i = 0; i < rawElems.length; ++i)、その後expanders[i]を:最も簡単なの一つは、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ループでletを使用することができます。

letは。彼らは同様の目的を持っているにもかかわらずvarとは全く異なる)または、エクスパンダを参照するためにthisを使用します。その後、イベントハンドラ関数にexpanders[i]をバインドするFunction.prototype.bindを使用することができ、かつ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

ああ!面白い。配列の各object.elementにイベントハンドラを割り当てるために '.map()'メソッドを使うこともできますか? – armadadrive

+0

@armadadrive:Doh!もちろん、次のようにすることもできます: 'var expanders = Array.prototype.map.call(rawElems、function(element、index){/ *作成、フックアップ、ここでエクスパンダを返す* /}); –

+0

ハハハ、私はあなたに対抗しない。あなたの時間とよく考えられた答えに感謝します。 – armadadrive

関連する問題