简体   繁体   中英

how to pass this keyword to javascript class functions

I'm running into the undefinded error when trying to access the this.numberObject from another function init .

I'm pretty sure it's because my this keyword is referencing the window object.

My problem is that I can't figure out an elegant way to structure my code.

Current Code:

class IncrementNumbers {
  constructor() {
    this.numberObject = document.querySelector(".incrementNum");
    if (this.numberObject != null) {
      console.log(this.numberObject.innerHTML);
      this.num = this.numberObject.innerHTML;
      this.events();
    }
  }

  events() {
    console.log("events function ran");
    this.init();
  }

  init() {
    let target = 345;
    let current = 0;
    function addOneToElement() {
      if (current === target) {
        clearInterval(addOne);
      }
      current++;
      this.numberObject.innerHTML = current; <---- ERROR HERE
    }
    let addOne = setInterval(addOneToElement, 10);
  }
}

export default IncrementNumbers;

Error:

IncrementNumbers.js:44 Uncaught TypeError: Cannot set property 'innerHTML' of undefined

I can fix the error by adding in

  this.numberObject = document.querySelector(".incrementNum");

to the following function

init() {
    let target = 345;
    let current = 0;
    function addOneToElement() {
      this.numberObject = document.querySelector(".incrementNum");  <--- ADDED HERE
      if (current === target) {
        clearInterval(addOne);
      }
      current++;
      this.numberObject.innerHTML = current;
    }
    let addOne = setInterval(addOneToElement, 10);
  }

However this feels a bit redundant because I'm already referencing the element Object in my constructor. I'd like the function, init to run once the page has loaded.

Is there a better way?

Thank you

Your problem seems to come from a misspropagation of the this object.
In your function init you set a new function named addOneToElement that is called inside of a setInterval , this setInterval instance does not have access to the this element of your class .

To fix the problem you could try to do something like

class IncrementNumbers {
  constructor() {
    this.numberObject = document.querySelector(".incrementNum");
    if (this.numberObject != null) {
      console.log(this.numberObject.innerHTML);
      this.num = this.numberObject.innerHTML;
      this.events();
    }
  }

  events() {
    console.log("events function ran");
    this.init();
  }

  init() {
    let target = 345;
    let current = 0;
    function addOneToElement() {
      if (current === target) {
        clearInterval(addOne);
      }
      current++;
      this.numberObject.innerHTML = current; // <---- ERROR HERE
    }
    let addOne = setInterval(addOneToElement.bind(this), 10);
  }
}

export default IncrementNumbers;
let addOne = setInterval(addOneToElement.bind(this), 10);

Where you bind the this instance of your class to the function addOneToElement .

The problem is the inner function addOneToElement that creates its own this context within init.

A simple fix would be to use arrow functions which don't have a this context:

class IncrementNumbers {
  init() {
    let target = 345;
    let current = 0;
    // Use an arrow function here.
    const addOneToElement = () => {
      if (current === target) {
        clearInterval(addOne);
      }
      current++;
      this.numberObject.innerHTML = current; <---- ERROR HERE
    }
    let addOne = setInterval(addOneToElement, 10);
  }
}

Another option would be to bind the this context to addOneToElement:

let addOne = setInterval(addOneToElement.bind(this), 10);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM