我正在使用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');
}
}
}
}
&#13;
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;
}
&#13;
<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>
&#13;
答案 0 :(得分:1)
将方法绑定到事件时,this
不再是类。要保留上下文,可以使用中间变量:
此示例显示问题...
window.setTimeout(this.showText, 50);
将正确调用showText方法,但在方法中使用此方法将会失败...修复:
let _this = this;
window.setTimeout(function () { _this.showText(); }, 50);
您也可以使用bind
,apply
或箭头功能获得相同的效果。这是一只可以通过多种方式剥皮的猫。 Arrow函数对ECMAScript类具有类似的浏览器支持,因此您不会丢失任何浏览器。
答案 1 :(得分: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使用函数作用域,因此this
内的map
和addEventListener
不是Filter
的实例。有几种方法可以解决这个问题,但对你而言,最简单的方法是使用arrow functions,因为它们保留了相同的词汇this
。
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?