调用成员方法时键入错误问题

时间:2017-10-10 16:26:57

标签: javascript ecmascript-6

我正在使用ES2016编写一个课程而且我不明白为什么,控制台会向我发出这个错误。

我已经四处寻找可能的原因但是:

  • 它不能是函数名中的拼写错误,我已经反复检查过,函数声明和我用来调用它的函数名匹配;
  • highlightSelected未与任何预先存在的属性共享其名称;
  • 我在highlightSelected函数内执行的所有操作都允许作为参数传递的变量类型。

那是怎么回事?为什么这不起作用?

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

&#13;
&#13;
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;
&#13;
&#13;

2 个答案:

答案 0 :(得分:1)

将方法绑定到事件时,this不再是类。要保留上下文,可以使用中间变量:

此示例显示问题...

window.setTimeout(this.showText, 50);

将正确调用showText方法,但在方法中使用此方法将会失败...修复:

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

您也可以使用bindapply或箭头功能获得相同的效果。这是一只可以通过多种方式剥皮的猫。 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内的mapaddEventListener不是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?