0

I'm currently learning JavaScript, and I wrote some codes that work just using basic functions, but now I'm trying to convert my codes into a Class and I got everything working except 1 thing. I'm trying to call a function from within a function in a class:

class Donut {
  constructor(
    donutCountSpan,
    autoClickerPriceSpan,
    autoClickerCountSpan,
    donutMultiplierCountSpan,
    donutMultiplierPriceSpan
  ) {
    this.donutCountSpan = donutCountSpan;
    this.autoClickerPriceSpan = autoClickerPriceSpan;
    this.autoClickerCountSpan = autoClickerCountSpan;
    this.donutMultiplierCountSpan = donutMultiplierCountSpan;
    this.donutMultiplierPriceSpan = donutMultiplierPriceSpan;
    this.donutCount = 200;
    this.donutMultiplierCount = 0;
    this.autoClickerCount = 0;
    this.autoClickerPrice = 100;
    this.donutMultiplierCount = 0;
    this.donutMultiplierPrice = 10;
  }

  activateAutoClickers() {
    setInterval(function () {
      this.donutCount +=
        this.autoClickerCount * Math.pow(1.2, this.donutMultiplierCount);
      this.donutCountSpan.innerText = Math.round(this.donutCount);
    }, 1000);
  }

  buyAutoClicker() {
    if (this.donutCount >= this.autoClickerPrice) {
      this.donutCount -= this.autoClickerPrice;
      this.autoClickerCount += 1;
      this.autoClickerPrice = Math.round(this.autoClickerPrice * 1.1);
      this.donutCountSpan.innerText = Math.round(this.donutCount);
      this.autoClickerPriceSpan.innerText = this.autoClickerPrice;
      this.autoClickerCountSpan.innerText = this.autoClickerCount;
      if (this.autoClickerCount <= 1) {
        this.activateAutoClickers();  //THIS IS THE METHOD THAT ISN'T BEING CALLED
      }
    }
  }

Here are the event listeners for my buttons:

donut.addEventListener("click", () => {
  donutClicker.addDonut();
});

buyAutoClickerButton.addEventListener("click", ()=> {
  donutClicker.buyAutoClicker();
});

buyDonutMultiplierButton.addEventListener("click",  ()=> {
  donutClicker.buyDonutMultiplier();
});
jrob11
  • 315
  • 1
  • 9
  • You have missing closing bracket - add `}` and the end of code – Gesha Jul 02 '20 at 13:50
  • How is `buyAutoClicker` called? How did you verify that `activateAutoClickers` really is not called? The implementation of `activateAutoClickers` is certainly not correct. `this` inside the `setInterval` callback won't refer to the class instance. Likely a duplicate of [How to access the correct `this` inside a callback?](https://stackoverflow.com/q/20279484/218196) – Felix Kling Jul 02 '20 at 13:51
  • did u make functions as public and try? – mr. pc_coder Jul 02 '20 at 13:51
  • @pc_coder: All methods are public in JavaScript. – Felix Kling Jul 02 '20 at 13:51
  • @Gesha I didn't post all of my functions, I do have a closing brace on my actual code. Thank you tho :) – jrob11 Jul 02 '20 at 13:55
  • @Felix Kling Hi, buyAutoClicker is called from an eventListener on a button. – jrob11 Jul 02 '20 at 13:57
  • @jrob11 so `onclick="donut.buyAutoClicker"` or `button.addEventListener("click", donut.buyAutoClicker)`? – VLAZ Jul 02 '20 at 14:04
  • @VLAZ the 2nd one. We are taught separation of concerns, and we aren't supposed to put js in the html. – jrob11 Jul 02 '20 at 14:06
  • 1
    Then that's a similar (and additional) issue as the one I pointed out. See https://stackoverflow.com/q/20279484/218196 , "Common problem: Using object methods as callbacks/event handlers" – Felix Kling Jul 02 '20 at 14:07
  • @Felix Kling I'm still trying to wrap my head around the post you send. If I'm not to use "this" in the setInterval, then do I use something else? or just call the fields by themselves? I'm a little confused. – jrob11 Jul 02 '20 at 14:08
  • @jrob11 the issue is that `button.addEventListener("click", donut.buyAutoClicker)` will *loose* the context and so within the method `this` will be `undefined`. you need `button.addEventListener("click", () => donut.buyAutoClicker())` or `button.addEventListener("click", donut.buyAutoClicker.bind(donut))`. I personally dislike the second one because of the repetition of `donut` on both sides but it's still valid. – VLAZ Jul 02 '20 at 14:10
  • Also change `setInterval(function ()` to `setInterval(() =>` to preserve the lexical `this` within the interval. – VLAZ Jul 02 '20 at 14:11
  • @VLAZ thank you. I actually did use the () =>. I just updated my post to reflect the actual event listeners I used. I will try the setInterval thing. – jrob11 Jul 02 '20 at 14:13
  • @VLAZ the setInterval thing worked. I'm still going to read through the other post that Felix Kling sent and see if I can understand. – jrob11 Jul 02 '20 at 14:18
  • 1
    @jrob11 They are written by Felix himself and are one of the best writeups on how `this` works especially around loosing the correct value for it. For completeness, there is [How does the “this” keyword work?](https://stackoverflow.com/q/3127429) a broader overview of how `this` works. Here is my rule of thumb which I hope aids in understanding `this`: the value is determined at call time and will be whatever is before the last dot. For example, `a.b.foo()` -> `this = a.b`; with `a.foo()` -> `this = a`; and if you have `foo()` then `this = undefined` (slightly simplified). – VLAZ Jul 02 '20 at 14:29
  • 2
    @jrob11 If you have a function that takes a callback `fn = cb => cb()` and you call it as `fn(a.b.foo)` then what you actually execute doesn't have `a.b` in front of it. Hence `cb()` will execute `foo` but `this = undefined` in that case. – VLAZ Jul 02 '20 at 14:29

0 Answers0