2017-10-10 5 views
0

私はES2016を使用してクラスを作成していますが、理由はわかりません。コンソールがこのエラーを返します。タイプメンバメソッドを呼び出すときのエラーの問題

私が原因のために周りを見回したがきました:

  • それは、関数名のタイプミスすることはできません、私は何度も何度も確認しており、関数宣言と関数名が私の目的で使用しますそれを呼び出す。
  • highlightSelectedは、その名前を既存のプロパティと共有しません。
  • highlightSelected関数内で実行するすべての操作は、パラメータとして渡される変数型で許可されます。

何が起こっているのですか?なぜこれは機能しないのですか?

Uncaught TypeError: this.highlightSelected is not a function 
    at HTMLAnchorElement.<anonymous> (app.js:40) 

window.document.addEventListener('DOMContentLoaded', function() { 
 
    new Filter("nf"); 
 
}); 
 

 
class Filter { 
 
    constructor(category) { 
 
    this.products = [...document.querySelectorAll('.product')]; 
 
    this.filterButtons = [...document.querySelectorAll('a.filter')]; 
 
    this.lastClicked = null; 
 
    this.registerListeners(); 
 
    console.log(this.filterProducts(category)); 
 
    } 
 

 
    filterProducts(category) { 
 
    let filtered = this.products.filter(function(item) { 
 
     return (item.dataset[category] === "true"); 
 
    }); 
 

 
    return filtered; 
 
    } 
 

 
    registerListeners() { 
 
    this.filterButtons.map(function(button) { 
 
     button.addEventListener("click", function(event) { 
 
     console.log(event.target.dataset.cat + " has been clicked!"); 
 
     if (this.lastClicked !== event.target.dataset.cat) { 
 
      this.highlightSelected(event.target) 
 
      this.lastClicked = event.target; 
 
     } 
 
     }); 
 
    }); 
 
    } 
 

 
    highlightSelected(clickedButton) { 
 
    if ((this.lastClicked !== undefined) && (this.lastClicked !== null)) { 
 
     if (this.lastClicked.classList.contains('currently-selected')) { 
 
     this.lastClicked.classList.remove('currently-selected'); 
 
     } 
 

 
     if (!clickedButton.classList.contains('currently-selected')) { 
 
     clickedButton.classList.add('currently-selected'); 
 
     } 
 
    } 
 
    } 
 
}
html { 
 
    font-size: 16px; 
 
} 
 

 
.container { 
 
    width: 85%; 
 
    margin: 4% auto; 
 
} 
 

 
#button-area { 
 
    display: flex; 
 
    justify-content: space-around; 
 
    margin-bottom: 4rem; 
 
} 
 

 
#button-area a { 
 
    text-decoration: none; 
 
    font-family: sans-serif; 
 
    background-color: mistyrose; 
 
    color: #000; 
 
    padding: .8rem 2rem; 
 
} 
 

 
#button-area a.currently-selected { 
 
    background-color: purple; 
 
    color: white; 
 
} 
 

 
#product-area { 
 
    display: flex; 
 
    justify-content: space-around; 
 
} 
 

 
.product { 
 
    font-family: sans-serif; 
 
    font-size: 1rem; 
 
    background-color: goldenrod; 
 
    padding: .8rem 2rem; 
 
}
<html> 
 

 
<head> 
 
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 
 
    <title>Query Selector</title> 
 
    <link rel="stylesheet" href="style.css"> 
 
</head> 
 

 
<body> 
 

 
    <div class="container"> 
 

 
    <div id="button-area"> 
 
     <a class="filter" href="#" data-cat="ef"> Cat E </a> 
 
     <a class="filter" href="#" data-cat="lf"> Cat L </a> 
 
     <a class="filter" href="#" data-cat="gf"> Cat G </a> 
 
     <a class="filter" href="#" data-cat="nf"> Cat N </a> 
 
    </div> 
 

 
    <div id="product-area"> 
 
     <div class="product" data-ef="true" data-lf="true" data-nf="true" data-gf="true"> 
 
     <p> Car </p> 
 
     </div> 
 
     <!-- /. product --> 
 

 
     <div class="product" data-ef="false" data-lf="false" data-nf="false" data-gf="false"> 
 
     <p> Airplane </p> 
 
     </div> 
 
     <!-- /. product --> 
 

 
     <div class="product" data-ef="true" data-lf="false" data-nf="false" data-gf="true"> 
 
     <p> Pizza </p> 
 
     </div> 
 
     <!-- /. product --> 
 

 
     <div class="product" data-ef="true" data-lf="false" data-nf="false" data-gf="true"> 
 
     <p> Ficus </p> 
 
     </div> 
 
     <!-- /. product --> 
 

 
     <div class="product" data-ef="false" data-lf="false" data-nf="true" data-gf="true"> 
 
     <p> Keyboard </p> 
 
     </div> 
 
     <!-- /. product --> 
 

 
     <div class="product" data-ef="true" data-lf="false" data-nf="false" data-gf="false"> 
 
     <p> Shirt </p> 
 
     </div> 
 
     <!-- /. product --> 
 

 
     <div class="product" data-ef="true" data-lf="false" data-nf="true" data-gf="true"> 
 
     <p> Vanilla </p> 
 
     </div> 
 
     <!-- /. product --> 
 
    </div> 
 

 
    </div> 
 

 
</body> 
 

 
<script src="app.js"></script> 
 

 
</html>

+1

イベントコールバックをクラスにバインドする必要があります。 –

+0

これはES6というタグが付いているので、 'map'ではなく' for ... of'を使うべきで、arrowは 'function'式ではなく(unbound!)機能します。 – Bergi

答えて

0

あなたの問題は、このコードの塊である:

registerListeners() { 
    this.filterButtons.map(function(button) { 
    button.addEventListener("click", function(event) { 
     console.log(event.target.dataset.cat + " has been clicked!"); 
     if (this.lastClicked !== event.target.dataset.cat) { 
     this.highlightSelected(event.target) 
     this.lastClicked = event.target; 
     } 
    }); 
    }); 
} 

問題は、JavaScriptがそうthismapの内側とaddEventListenerではない関数スコープを使用していることですFilterのインスタンス。これを修正する方法はいくつかありますが、arrow functionsは同じ語彙thisを保持しているので、最も簡単な方法はarrow functionsです。あなたがイベントにメソッドをバインドすると

registerListeners() { 
    this.filterButtons.map((button) => { 
    button.addEventListener("click", (event) => { 
     console.log(event.target.dataset.cat + " has been clicked!"); 
     if (this.lastClicked !== event.target.dataset.cat) { 
     this.highlightSelected(event.target) 
     this.lastClicked = event.target; 
     } 
    }); 
    }); 
} 

これについてより詳細な情報については、How to access the correct this inside a callback?

1

をチェックアウトし、thisはもはやクラスではありません。あなたのコンテキストを維持するためには、中間変数を使用することができます。

この例で問題を示しています...

window.setTimeout(this.showText, 50); 

showTextメソッドが正しく呼び出されますが、メソッド内で、この任意の使用が落ちるでしょう。 ...修正:

let _this = this; 
window.setTimeout(function() { _this.showText(); }, 50); 

また、同じ効果のためにbindapply、または矢印の機能を使用することができます。これは、多くの点で皮をむくことができる1匹の猫です。 Arrow関数はECMAScriptクラスと似たブラウザサポートを持っているので、あなたのブラウザを失うことはありません。

関連する問題